libstand: gzipfs unused variable
[unleashed.git] / usr / src / boot / lib / libstand / printf.c
blob66d809abeed9aef67f66d045c358c8e8b3dfaaa8
1 /*-
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.
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.
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.
34 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
37 #include <sys/cdefs.h>
40 * Standaloneified version of the FreeBSD kernel printf family.
43 #include <sys/types.h>
44 #include <sys/stddef.h>
45 #include <sys/stdint.h>
46 #include <limits.h>
47 #include <string.h>
48 #include "stand.h"
51 * Note that stdarg.h and the ANSI style va_start macro is used for both
52 * ANSI and traditional C compilers.
54 #include <machine/stdarg.h>
56 #define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1)
58 typedef void (kvprintf_fn_t)(int, void *);
60 static char *ksprintn (char *buf, uintmax_t num, int base, int *len, int upper);
61 static int kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap);
63 static void
64 putchar_wrapper(int cc, void *arg)
67 putchar(cc);
70 int
71 printf(const char *fmt, ...)
73 va_list ap;
74 int retval;
76 va_start(ap, fmt);
77 retval = kvprintf(fmt, putchar_wrapper, NULL, 10, ap);
78 va_end(ap);
79 return retval;
82 void
83 vprintf(const char *fmt, va_list ap)
86 kvprintf(fmt, putchar_wrapper, NULL, 10, ap);
89 int
90 sprintf(char *buf, const char *cfmt, ...)
92 int retval;
93 va_list ap;
95 va_start(ap, cfmt);
96 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
97 buf[retval] = '\0';
98 va_end(ap);
99 return retval;
102 struct print_buf {
103 char *buf;
104 size_t size;
107 static void
108 snprint_func(int ch, void *arg)
110 struct print_buf *pbuf = arg;
112 if (pbuf->size < 2) {
114 * Reserve last buffer position for the terminating
115 * character:
117 return;
119 *(pbuf->buf)++ = ch;
120 pbuf->size--;
124 asprintf(char **buf, const char *cfmt, ...)
126 int retval;
127 struct print_buf arg;
128 va_list ap;
130 *buf = NULL;
131 va_start(ap, cfmt);
132 retval = kvprintf(cfmt, NULL, NULL, 10, ap);
133 va_end(ap);
134 if (retval <= 0)
135 return (-1);
137 arg.size = retval + 1;
138 arg.buf = *buf = malloc(arg.size);
139 if (*buf == NULL)
140 return (-1);
142 va_start(ap, cfmt);
143 retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap);
144 va_end(ap);
146 if (arg.size >= 1)
147 *(arg.buf)++ = 0;
148 return (retval);
152 snprintf(char *buf, size_t size, const char *cfmt, ...)
154 int retval;
155 va_list ap;
156 struct print_buf arg;
158 arg.buf = buf;
159 arg.size = size;
161 va_start(ap, cfmt);
162 retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap);
163 va_end(ap);
165 if (arg.size >= 1)
166 *(arg.buf)++ = 0;
167 return retval;
170 void
171 vsprintf(char *buf, const char *cfmt, va_list ap)
173 int retval;
175 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
176 buf[retval] = '\0';
179 void
180 vsnprintf(char *buf, size_t size, const char *cfmt, va_list ap)
182 int retval;
183 struct print_buf arg;
185 arg.buf = buf;
186 arg.size = size;
188 retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap);
189 buf[retval] = '\0';
193 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
194 * order; return an optional length and a pointer to the last character
195 * written in the buffer (i.e., the first character of the string).
196 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
198 static char *
199 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
201 char *p, c;
203 p = nbuf;
204 *p = '\0';
205 do {
206 c = hex2ascii(num % base);
207 *++p = upper ? toupper(c) : c;
208 } while (num /= base);
209 if (lenp)
210 *lenp = p - nbuf;
211 return (p);
215 * Scaled down version of printf(3).
217 * Two additional formats:
219 * The format %b is supported to decode error registers.
220 * Its usage is:
222 * printf("reg=%b\n", regval, "<base><arg>*");
224 * where <base> is the output base expressed as a control character, e.g.
225 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
226 * the first of which gives the bit number to be inspected (origin 1), and
227 * the next characters (up to a control character, i.e. a character <= 32),
228 * give the name of the register. Thus:
230 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE");
232 * would produce output:
234 * reg=3<BITTWO,BITONE>
236 * XXX: %D -- Hexdump, takes pointer and separator string:
237 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
238 * ("%*D", len, ptr, " " -> XX XX XX XX ...
240 static int
241 kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap)
243 #define PCHAR(c) { \
244 int cc = (c); \
246 if (func) { \
247 (*func)(cc, arg); \
248 } else if (d != NULL) { \
249 *d++ = cc; \
251 retval++; \
254 char nbuf[MAXNBUF];
255 char *d;
256 const char *p, *percent, *q;
257 uint16_t *S;
258 u_char *up;
259 int ch, n;
260 uintmax_t num;
261 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
262 int cflag, hflag, jflag, tflag, zflag;
263 int dwidth, upper;
264 char padc;
265 int stop = 0, retval = 0;
267 num = 0;
268 if (!func)
269 d = (char *) arg;
270 else
271 d = NULL;
273 if (fmt == NULL)
274 fmt = "(fmt null)\n";
276 if (radix < 2 || radix > 36)
277 radix = 10;
279 for (;;) {
280 padc = ' ';
281 width = 0;
282 while ((ch = (u_char)*fmt++) != '%' || stop) {
283 if (ch == '\0')
284 return (retval);
285 PCHAR(ch);
287 percent = fmt - 1;
288 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
289 sign = 0; dot = 0; dwidth = 0; upper = 0;
290 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
291 reswitch: switch (ch = (u_char)*fmt++) {
292 case '.':
293 dot = 1;
294 goto reswitch;
295 case '#':
296 sharpflag = 1;
297 goto reswitch;
298 case '+':
299 sign = 1;
300 goto reswitch;
301 case '-':
302 ladjust = 1;
303 goto reswitch;
304 case '%':
305 PCHAR(ch);
306 break;
307 case '*':
308 if (!dot) {
309 width = va_arg(ap, int);
310 if (width < 0) {
311 ladjust = !ladjust;
312 width = -width;
314 } else {
315 dwidth = va_arg(ap, int);
317 goto reswitch;
318 case '0':
319 if (!dot) {
320 padc = '0';
321 goto reswitch;
323 case '1': case '2': case '3': case '4':
324 case '5': case '6': case '7': case '8': case '9':
325 for (n = 0;; ++fmt) {
326 n = n * 10 + ch - '0';
327 ch = *fmt;
328 if (ch < '0' || ch > '9')
329 break;
331 if (dot)
332 dwidth = n;
333 else
334 width = n;
335 goto reswitch;
336 case 'b':
337 num = (u_int)va_arg(ap, int);
338 p = va_arg(ap, char *);
339 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
340 PCHAR(*q--);
342 if (num == 0)
343 break;
345 for (tmp = 0; *p;) {
346 n = *p++;
347 if (num & (1 << (n - 1))) {
348 PCHAR(tmp ? ',' : '<');
349 for (; (n = *p) > ' '; ++p)
350 PCHAR(n);
351 tmp = 1;
352 } else
353 for (; *p > ' '; ++p)
354 continue;
356 if (tmp)
357 PCHAR('>');
358 break;
359 case 'c':
360 PCHAR(va_arg(ap, int));
361 break;
362 case 'D':
363 up = va_arg(ap, u_char *);
364 p = va_arg(ap, char *);
365 if (!width)
366 width = 16;
367 while(width--) {
368 PCHAR(hex2ascii(*up >> 4));
369 PCHAR(hex2ascii(*up & 0x0f));
370 up++;
371 if (width)
372 for (q=p;*q;q++)
373 PCHAR(*q);
375 break;
376 case 'd':
377 case 'i':
378 base = 10;
379 sign = 1;
380 goto handle_sign;
381 case 'h':
382 if (hflag) {
383 hflag = 0;
384 cflag = 1;
385 } else
386 hflag = 1;
387 goto reswitch;
388 case 'j':
389 jflag = 1;
390 goto reswitch;
391 case 'l':
392 if (lflag) {
393 lflag = 0;
394 qflag = 1;
395 } else
396 lflag = 1;
397 goto reswitch;
398 case 'n':
399 if (jflag)
400 *(va_arg(ap, intmax_t *)) = retval;
401 else if (qflag)
402 *(va_arg(ap, quad_t *)) = retval;
403 else if (lflag)
404 *(va_arg(ap, long *)) = retval;
405 else if (zflag)
406 *(va_arg(ap, size_t *)) = retval;
407 else if (hflag)
408 *(va_arg(ap, short *)) = retval;
409 else if (cflag)
410 *(va_arg(ap, char *)) = retval;
411 else
412 *(va_arg(ap, int *)) = retval;
413 break;
414 case 'o':
415 base = 8;
416 goto handle_nosign;
417 case 'p':
418 base = 16;
419 sharpflag = (width == 0);
420 sign = 0;
421 num = (uintptr_t)va_arg(ap, void *);
422 goto number;
423 case 'q':
424 qflag = 1;
425 goto reswitch;
426 case 'r':
427 base = radix;
428 if (sign)
429 goto handle_sign;
430 goto handle_nosign;
431 case 's':
432 p = va_arg(ap, char *);
433 if (p == NULL)
434 p = "(null)";
435 if (!dot)
436 n = strlen (p);
437 else
438 for (n = 0; n < dwidth && p[n]; n++)
439 continue;
441 width -= n;
443 if (!ladjust && width > 0)
444 while (width--)
445 PCHAR(padc);
446 while (n--)
447 PCHAR(*p++);
448 if (ladjust && width > 0)
449 while (width--)
450 PCHAR(padc);
451 break;
452 case 'S': /* Assume console can cope with wide chars */
453 S = va_arg(ap, uint16_t *);
454 if (S == NULL)
455 S = (uint16_t *)L"(null)";
456 if (!dot) {
457 for (n = 0; S[n] != 0; n++)
458 continue;
459 } else {
460 for (n = 0; n < dwidth && S[n]; n++)
461 continue;
464 width -= n;
466 if (!ladjust && width > 0)
467 while (width--)
468 PCHAR(padc);
469 while (n--)
470 PCHAR(*S++);
471 if (ladjust && width > 0)
472 while (width--)
473 PCHAR(padc);
474 break;
475 case 't':
476 tflag = 1;
477 goto reswitch;
478 case 'u':
479 base = 10;
480 goto handle_nosign;
481 case 'X':
482 upper = 1;
483 case 'x':
484 base = 16;
485 goto handle_nosign;
486 case 'y':
487 base = 16;
488 sign = 1;
489 goto handle_sign;
490 case 'z':
491 zflag = 1;
492 goto reswitch;
493 handle_nosign:
494 sign = 0;
495 if (jflag)
496 num = va_arg(ap, uintmax_t);
497 else if (qflag)
498 num = va_arg(ap, u_quad_t);
499 else if (tflag)
500 num = va_arg(ap, ptrdiff_t);
501 else if (lflag)
502 num = va_arg(ap, u_long);
503 else if (zflag)
504 num = va_arg(ap, size_t);
505 else if (hflag)
506 num = (u_short)va_arg(ap, int);
507 else if (cflag)
508 num = (u_char)va_arg(ap, int);
509 else
510 num = va_arg(ap, u_int);
511 goto number;
512 handle_sign:
513 if (jflag)
514 num = va_arg(ap, intmax_t);
515 else if (qflag)
516 num = va_arg(ap, quad_t);
517 else if (tflag)
518 num = va_arg(ap, ptrdiff_t);
519 else if (lflag)
520 num = va_arg(ap, long);
521 else if (zflag)
522 num = va_arg(ap, ssize_t);
523 else if (hflag)
524 num = (short)va_arg(ap, int);
525 else if (cflag)
526 num = (char)va_arg(ap, int);
527 else
528 num = va_arg(ap, int);
529 number:
530 if (sign && (intmax_t)num < 0) {
531 neg = 1;
532 num = -(intmax_t)num;
534 p = ksprintn(nbuf, num, base, &n, upper);
535 tmp = 0;
536 if (sharpflag && num != 0) {
537 if (base == 8)
538 tmp++;
539 else if (base == 16)
540 tmp += 2;
542 if (neg)
543 tmp++;
545 if (!ladjust && padc == '0')
546 dwidth = width - tmp;
547 width -= tmp + imax(dwidth, n);
548 dwidth -= n;
549 if (!ladjust)
550 while (width-- > 0)
551 PCHAR(' ');
552 if (neg)
553 PCHAR('-');
554 if (sharpflag && num != 0) {
555 if (base == 8) {
556 PCHAR('0');
557 } else if (base == 16) {
558 PCHAR('0');
559 PCHAR('x');
562 while (dwidth-- > 0)
563 PCHAR('0');
565 while (*p)
566 PCHAR(*p--);
568 if (ladjust)
569 while (width-- > 0)
570 PCHAR(' ');
572 break;
573 default:
574 while (percent < fmt)
575 PCHAR(*percent++);
577 * Since we ignore a formatting argument it is no
578 * longer safe to obey the remaining formatting
579 * arguments as the arguments will no longer match
580 * the format specs.
582 stop = 1;
583 break;
586 #undef PCHAR