blob: c1035624ecf0b3ba699f6107ad6d766620476371 [file] [log] [blame]
Achin Gupta4f6ad662013-10-25 09:08:21 +01001/*-
2 * Copyright (c) 1986, 1988, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
35 */
36
37/*
Dan Handleye83b0ca2014-01-14 18:17:09 +000038 * Portions copyright (c) 2009-2014, ARM Limited and Contributors.
Harry Liebelc81b1d02013-12-17 18:31:42 +000039 * All rights reserved.
Achin Gupta4f6ad662013-10-25 09:08:21 +010040 */
41
Harry Liebelc81b1d02013-12-17 18:31:42 +000042#include <stdio.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010043#include <stdint.h>
Harry Liebelc81b1d02013-12-17 18:31:42 +000044#include <stdarg.h>
45#include <stddef.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010046#include <string.h>
Harry Liebelc81b1d02013-12-17 18:31:42 +000047#include <ctype.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010048
Achin Gupta4f6ad662013-10-25 09:08:21 +010049typedef unsigned char u_char;
50typedef unsigned int u_int;
51typedef int64_t quad_t;
52typedef uint64_t u_quad_t;
53typedef unsigned long u_long;
54typedef unsigned short u_short;
55
56static inline int imax(int a, int b) { return (a > b ? a : b); }
57
58/*
59 * Note that stdarg.h and the ANSI style va_start macro is used for both
60 * ANSI and traditional C compilers.
61 */
62
63#define TOCONS 0x01
64#define TOTTY 0x02
65#define TOLOG 0x04
66
67/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
68#define MAXNBUF (sizeof(intmax_t) * 8 + 1)
69
70struct putchar_arg {
71 int flags;
72 int pri;
73 struct tty *tty;
74 char *p_bufr;
75 size_t n_bufr;
76 char *p_next;
77 size_t remain;
78};
79
80struct snprintf_arg {
81 char *str;
82 size_t remain;
83};
84
85extern int log_open;
86
87static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper);
88static void snprintf_func(int ch, void *arg);
89static int kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap);
90
91int vsnprintf(char *str, size_t size, const char *format, va_list ap);
92
93static char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
94#define hex2ascii(hex) (hex2ascii_data[hex])
95
96/*
97 * Scaled down version of sprintf(3).
98 */
99int
100sprintf(char *buf, const char *cfmt, ...)
101{
102 int retval;
103 va_list ap;
104
105 va_start(ap, cfmt);
106 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
107 buf[retval] = '\0';
108 va_end(ap);
109 return (retval);
110}
111
112/*
113 * Scaled down version of vsprintf(3).
114 */
115int
116vsprintf(char *buf, const char *cfmt, va_list ap)
117{
118 int retval;
119
120 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
121 buf[retval] = '\0';
122 return (retval);
123}
124
125/*
126 * Scaled down version of snprintf(3).
127 */
128int
129snprintf(char *str, size_t size, const char *format, ...)
130{
131 int retval;
132 va_list ap;
133
134 va_start(ap, format);
135 retval = vsnprintf(str, size, format, ap);
136 va_end(ap);
137 return(retval);
138}
139
140/*
141 * Scaled down version of vsnprintf(3).
142 */
143int
144vsnprintf(char *str, size_t size, const char *format, va_list ap)
145{
146 struct snprintf_arg info;
147 int retval;
148
149 info.str = str;
150 info.remain = size;
151 retval = kvprintf(format, snprintf_func, &info, 10, ap);
152 if (info.remain >= 1)
153 *info.str++ = '\0';
154 return (retval);
155}
156
157static void
158snprintf_func(int ch, void *arg)
159{
160 struct snprintf_arg *const info = arg;
161
162 if (info->remain >= 2) {
163 *info->str++ = ch;
164 info->remain--;
165 }
166}
167
168
169/*
170 * Kernel version which takes radix argument vsnprintf(3).
171 */
172int
173vsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap)
174{
175 struct snprintf_arg info;
176 int retval;
177
178 info.str = str;
179 info.remain = size;
180 retval = kvprintf(format, snprintf_func, &info, radix, ap);
181 if (info.remain >= 1)
182 *info.str++ = '\0';
183 return (retval);
184}
185
186
187/*
188 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
189 * order; return an optional length and a pointer to the last character
190 * written in the buffer (i.e., the first character of the string).
191 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
192 */
193static char *
194ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
195{
196 char *p, c;
197
198 p = nbuf;
199 *p = '\0';
200 do {
201 c = hex2ascii(num % base);
202 *++p = upper ? toupper(c) : c;
203 } while (num /= base);
204 if (lenp)
205 *lenp = p - nbuf;
206 return (p);
207}
208
209/*
210 * Scaled down version of printf(3).
211 *
212 * Two additional formats:
213 *
214 * The format %b is supported to decode error registers.
215 * Its usage is:
216 *
217 * printf("reg=%b\n", regval, "<base><arg>*");
218 *
219 * where <base> is the output base expressed as a control character, e.g.
220 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
221 * the first of which gives the bit number to be inspected (origin 1), and
222 * the next characters (up to a control character, i.e. a character <= 32),
223 * give the name of the register. Thus:
224 *
225 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
226 *
227 * would produce output:
228 *
229 * reg=3<BITTWO,BITONE>
230 *
231 * XXX: %D -- Hexdump, takes pointer and separator string:
232 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
233 * ("%*D", len, ptr, " " -> XX XX XX XX ...
234 */
235int
236kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
237{
238#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
239 char nbuf[MAXNBUF];
240 char *d;
241 const char *p, *percent, *q;
242 u_char *up;
243 int ch, n;
244 uintmax_t num;
245 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
246 int cflag, hflag, jflag, tflag, zflag;
247 int dwidth, upper;
248 char padc;
249 int stop = 0, retval = 0;
250
251 num = 0;
252 if (!func)
253 d = (char *) arg;
254 else
255 d = NULL;
256
257 if (fmt == NULL)
258 fmt = "(fmt null)\n";
259
260 if (radix < 2 || radix > 36)
261 radix = 10;
262
263 for (;;) {
264 padc = ' ';
265 width = 0;
266 while ((ch = (u_char)*fmt++) != '%' || stop) {
267 if (ch == '\0')
268 return (retval);
269 PCHAR(ch);
270 }
271 percent = fmt - 1;
272 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
273 sign = 0; dot = 0; dwidth = 0; upper = 0;
274 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
275reswitch: switch (ch = (u_char)*fmt++) {
276 case '.':
277 dot = 1;
278 goto reswitch;
279 case '#':
280 sharpflag = 1;
281 goto reswitch;
282 case '+':
283 sign = 1;
284 goto reswitch;
285 case '-':
286 ladjust = 1;
287 goto reswitch;
288 case '%':
289 PCHAR(ch);
290 break;
291 case '*':
292 if (!dot) {
293 width = va_arg(ap, int);
294 if (width < 0) {
295 ladjust = !ladjust;
296 width = -width;
297 }
298 } else {
299 dwidth = va_arg(ap, int);
300 }
301 goto reswitch;
302 case '0':
303 if (!dot) {
304 padc = '0';
305 goto reswitch;
306 }
307 case '1': case '2': case '3': case '4':
308 case '5': case '6': case '7': case '8': case '9':
309 for (n = 0;; ++fmt) {
310 n = n * 10 + ch - '0';
311 ch = *fmt;
312 if (ch < '0' || ch > '9')
313 break;
314 }
315 if (dot)
316 dwidth = n;
317 else
318 width = n;
319 goto reswitch;
320 case 'b':
321 num = (u_int)va_arg(ap, int);
322 p = va_arg(ap, char *);
323 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
324 PCHAR(*q--);
325
326 if (num == 0)
327 break;
328
329 for (tmp = 0; *p;) {
330 n = *p++;
331 if (num & (1 << (n - 1))) {
332 PCHAR(tmp ? ',' : '<');
333 for (; (n = *p) > ' '; ++p)
334 PCHAR(n);
335 tmp = 1;
336 } else
337 for (; *p > ' '; ++p)
338 continue;
339 }
340 if (tmp)
341 PCHAR('>');
342 break;
343 case 'c':
344 PCHAR(va_arg(ap, int));
345 break;
346 case 'D':
347 up = va_arg(ap, u_char *);
348 p = va_arg(ap, char *);
349 if (!width)
350 width = 16;
351 while(width--) {
352 PCHAR(hex2ascii(*up >> 4));
353 PCHAR(hex2ascii(*up & 0x0f));
354 up++;
355 if (width)
356 for (q=p;*q;q++)
357 PCHAR(*q);
358 }
359 break;
360 case 'd':
361 case 'i':
362 base = 10;
363 sign = 1;
364 goto handle_sign;
365 case 'h':
366 if (hflag) {
367 hflag = 0;
368 cflag = 1;
369 } else
370 hflag = 1;
371 goto reswitch;
372 case 'j':
373 jflag = 1;
374 goto reswitch;
375 case 'l':
376 if (lflag) {
377 lflag = 0;
378 qflag = 1;
379 } else
380 lflag = 1;
381 goto reswitch;
382 case 'n':
383 if (jflag)
384 *(va_arg(ap, intmax_t *)) = retval;
385 else if (qflag)
386 *(va_arg(ap, quad_t *)) = retval;
387 else if (lflag)
388 *(va_arg(ap, long *)) = retval;
389 else if (zflag)
390 *(va_arg(ap, size_t *)) = retval;
391 else if (hflag)
392 *(va_arg(ap, short *)) = retval;
393 else if (cflag)
394 *(va_arg(ap, char *)) = retval;
395 else
396 *(va_arg(ap, int *)) = retval;
397 break;
398 case 'o':
399 base = 8;
400 goto handle_nosign;
401 case 'p':
402 base = 16;
403 sharpflag = (width == 0);
404 sign = 0;
405 num = (uintptr_t)va_arg(ap, void *);
406 goto number;
407 case 'q':
408 qflag = 1;
409 goto reswitch;
410 case 'r':
411 base = radix;
412 if (sign)
413 goto handle_sign;
414 goto handle_nosign;
415 case 's':
416 p = va_arg(ap, char *);
417 if (p == NULL)
418 p = "(null)";
419 if (!dot)
420 n = strlen (p);
421 else
422 for (n = 0; n < dwidth && p[n]; n++)
423 continue;
424
425 width -= n;
426
427 if (!ladjust && width > 0)
428 while (width--)
429 PCHAR(padc);
430 while (n--)
431 PCHAR(*p++);
432 if (ladjust && width > 0)
433 while (width--)
434 PCHAR(padc);
435 break;
436 case 't':
437 tflag = 1;
438 goto reswitch;
439 case 'u':
440 base = 10;
441 goto handle_nosign;
442 case 'X':
443 upper = 1;
444 case 'x':
445 base = 16;
446 goto handle_nosign;
447 case 'y':
448 base = 16;
449 sign = 1;
450 goto handle_sign;
451 case 'z':
452 zflag = 1;
453 goto reswitch;
454handle_nosign:
455 sign = 0;
456 if (jflag)
457 num = va_arg(ap, uintmax_t);
458 else if (qflag)
459 num = va_arg(ap, u_quad_t);
460 else if (tflag)
461 num = va_arg(ap, ptrdiff_t);
462 else if (lflag)
463 num = va_arg(ap, u_long);
464 else if (zflag)
465 num = va_arg(ap, size_t);
466 else if (hflag)
467 num = (u_short)va_arg(ap, int);
468 else if (cflag)
469 num = (u_char)va_arg(ap, int);
470 else
471 num = va_arg(ap, u_int);
472 goto number;
473handle_sign:
474 if (jflag)
475 num = va_arg(ap, intmax_t);
476 else if (qflag)
477 num = va_arg(ap, quad_t);
478 else if (tflag)
479 num = va_arg(ap, ptrdiff_t);
480 else if (lflag)
481 num = va_arg(ap, long);
482 else if (zflag)
483 num = va_arg(ap, ssize_t);
484 else if (hflag)
485 num = (short)va_arg(ap, int);
486 else if (cflag)
487 num = (char)va_arg(ap, int);
488 else
489 num = va_arg(ap, int);
490number:
491 if (sign && (intmax_t)num < 0) {
492 neg = 1;
493 num = -(intmax_t)num;
494 }
495 p = ksprintn(nbuf, num, base, &n, upper);
496 tmp = 0;
497 if (sharpflag && num != 0) {
498 if (base == 8)
499 tmp++;
500 else if (base == 16)
501 tmp += 2;
502 }
503 if (neg)
504 tmp++;
505
506 if (!ladjust && padc == '0')
507 dwidth = width - tmp;
508 width -= tmp + imax(dwidth, n);
509 dwidth -= n;
510 if (!ladjust)
511 while (width-- > 0)
512 PCHAR(' ');
513 if (neg)
514 PCHAR('-');
515 if (sharpflag && num != 0) {
516 if (base == 8) {
517 PCHAR('0');
518 } else if (base == 16) {
519 PCHAR('0');
520 PCHAR('x');
521 }
522 }
523 while (dwidth-- > 0)
524 PCHAR('0');
525
526 while (*p)
527 PCHAR(*p--);
528
529 if (ladjust)
530 while (width-- > 0)
531 PCHAR(' ');
532
533 break;
534 default:
535 while (percent < fmt)
536 PCHAR(*percent++);
537 /*
538 * Since we ignore an formatting argument it is no
539 * longer safe to obey the remaining formatting
540 * arguments as the arguments will no longer match
541 * the format specs.
542 */
543 stop = 1;
544 break;
545 }
546 }
547#undef PCHAR
548}