From 5cd8ebeb32279591176490cc207dfc7bd9250e87 Mon Sep 17 00:00:00 2001 From: Jung-uk Kim Date: Thu, 8 Jul 2010 22:21:18 +0000 Subject: [PATCH] Sync. printf() of libstand(3) with sys/kern/subr_prf.c. CVS r1.94 jhb: Cast the integer read as the first argument for %b to an unsigned integer so it's value is not sign extended when assigned to the uintmax_t variable used internally by printf. For example, if bit 31 is set in the cpuid feature word, then %b would print out the initial value as a 16 character hexadecimal value. Now it only prints out an 8 character value. CVS r1.109 njl: Add support for 'h' and 'hh' modifiers for printf(9). CVS r1.117 phk: If we ignore an unknown % sequence, we must stop interpreting the remaining % arguments because the varargs are now out of sync and there is a risk that we might for instance dereference an integer in a %s argument. SVN r209836 jkim: Implement optional 'precision' for numbers. Previously, it was parsed but ignored. Some third-party modules (e.g., APCICA) prefer this format over zero padding flag '0'. --- lib/libstand/printf.c | 57 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/lib/libstand/printf.c b/lib/libstand/printf.c index 5a2b5ddfd884..f6c94e358f08 100644 --- a/lib/libstand/printf.c +++ b/lib/libstand/printf.c @@ -159,10 +159,10 @@ kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap) int ch, n; uintmax_t num; int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; - int jflag, tflag, zflag; + int cflag, hflag, jflag, tflag, zflag; int dwidth, upper; char padc; - int retval = 0; + int stop = 0, retval = 0; num = 0; if (!func) @@ -179,7 +179,7 @@ kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap) for (;;) { padc = ' '; width = 0; - while ((ch = (u_char)*fmt++) != '%') { + while ((ch = (u_char)*fmt++) != '%' || stop) { if (ch == '\0') return (retval); PCHAR(ch); @@ -187,7 +187,7 @@ kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap) percent = fmt - 1; qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; sign = 0; dot = 0; dwidth = 0; upper = 0; - jflag = 0; tflag = 0; zflag = 0; + cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; reswitch: switch (ch = (u_char)*fmt++) { case '.': dot = 1; @@ -234,7 +234,7 @@ reswitch: switch (ch = (u_char)*fmt++) { width = n; goto reswitch; case 'b': - num = va_arg(ap, int); + num = (u_int)va_arg(ap, int); p = va_arg(ap, char *); for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) PCHAR(*q--); @@ -278,6 +278,13 @@ reswitch: switch (ch = (u_char)*fmt++) { base = 10; sign = 1; goto handle_sign; + case 'h': + if (hflag) { + hflag = 0; + cflag = 1; + } else + hflag = 1; + goto reswitch; case 'j': jflag = 1; goto reswitch; @@ -297,6 +304,10 @@ reswitch: switch (ch = (u_char)*fmt++) { *(va_arg(ap, long *)) = retval; else if (zflag) *(va_arg(ap, size_t *)) = retval; + else if (hflag) + *(va_arg(ap, short *)) = retval; + else if (cflag) + *(va_arg(ap, char *)) = retval; else *(va_arg(ap, int *)) = retval; break; @@ -368,6 +379,10 @@ reswitch: switch (ch = (u_char)*fmt++) { num = va_arg(ap, u_long); else if (zflag) num = va_arg(ap, size_t); + else if (hflag) + num = (u_short)va_arg(ap, int); + else if (cflag) + num = (u_char)va_arg(ap, int); else num = va_arg(ap, u_int); goto number; @@ -382,6 +397,10 @@ reswitch: switch (ch = (u_char)*fmt++) { num = va_arg(ap, long); else if (zflag) num = va_arg(ap, ssize_t); + else if (hflag) + num = (short)va_arg(ap, int); + else if (cflag) + num = (char)va_arg(ap, int); else num = va_arg(ap, int); number: @@ -389,7 +408,8 @@ reswitch: switch (ch = (u_char)*fmt++) { neg = 1; num = -(intmax_t)num; } - p = ksprintn(nbuf, num, base, &tmp, upper); + p = ksprintn(nbuf, num, base, &n, upper); + tmp = 0; if (sharpflag && num != 0) { if (base == 8) tmp++; @@ -399,9 +419,13 @@ reswitch: switch (ch = (u_char)*fmt++) { if (neg) tmp++; - if (!ladjust && width && (width -= tmp) > 0) - while (width--) - PCHAR(padc); + if (!ladjust && padc == '0') + dwidth = width - tmp; + width -= tmp + MAX(dwidth, n); + dwidth -= n; + if (!ladjust) + while (width-- > 0) + PCHAR(' '); if (neg) PCHAR('-'); if (sharpflag && num != 0) { @@ -412,18 +436,27 @@ reswitch: switch (ch = (u_char)*fmt++) { PCHAR('x'); } } + while (dwidth-- > 0) + PCHAR('0'); while (*p) PCHAR(*p--); - if (ladjust && width && (width -= tmp) > 0) - while (width--) - PCHAR(padc); + if (ladjust) + while (width-- > 0) + PCHAR(' '); break; default: while (percent < fmt) PCHAR(*percent++); + /* + * Since we ignore an formatting argument it is no + * longer safe to obey the remaining formatting + * arguments as the arguments will no longer match + * the format specs. + */ + stop = 1; break; } }