Date: Thu, 23 May 2002 05:00:15 +0000 From: Dima Dorfman <dima@trit.org> To: audit@freebsd.org Subject: %j for printf(9) Message-ID: <20020523050017.E3A2A3E22@turbine.trit.org>
next in thread | raw e-mail | index | archive | help
Attached is a patch that implements the %j length modifier in printf(9). I would appreciate it if someone could test it on one (or more) of the 64-bit architectures (applying and checking if ddb ps output looks sensible should be sufficient); I have no reason to think it will break there, but breaking printf for !i386 would be a Bad Thing(tm). I would also appreciate it if someone could review this, particularly looking for anywhere I assume signed or unsigned where I shouldn't (I'm concerned with mis-{sign,zero}-extension). See message-id <20020405080000.754FB3E31@bazooka.trit.org> for the discussion on -standards. The patch has not changed since then. I would also like to solicit comments on what to do with %z; C99 says this is the length modifier for size_t, but the kernel treats it as signed hex. This patch implements the C99 length modifier as %Z, but that probably shouldn't stay. IIRC, I couldn't find any place in the kernel that we actually use %z; can it perhaps be removed? I'd like to get this into the tree pretty soon, since someone already used %j in the kernel. Thanks. Index: subr_prf.c =================================================================== RCS file: /ref/cvsf/src/sys/kern/subr_prf.c,v retrieving revision 1.80 diff -u -r1.80 subr_prf.c --- subr_prf.c 1 Apr 2002 21:30:49 -0000 1.80 +++ subr_prf.c 4 Apr 2002 02:33:56 -0000 @@ -40,6 +40,7 @@ */ #include <sys/param.h> +#include <sys/stdint.h> #include <sys/systm.h> #include <sys/lock.h> #include <sys/mutex.h> @@ -78,6 +79,12 @@ size_t remain; }; +/* Length modifier. */ +enum lenmod { + LM_POINTER, LM_QUAD, LM_UQUAD, LM_LONG, LM_ULONG, + LM_INT, LM_UINT, LM_INTMAX, LM_UINTMAX, LM_SIZET +}; + extern int log_open; struct tty *constty; /* pointer to console "window" tty */ @@ -86,8 +93,9 @@ static void msglogchar(int c, int pri); static void msgaddchar(int c, void *dummy); static void putchar(int ch, void *arg); -static char *ksprintn(char *nbuf, u_long num, int base, int *len); -static char *ksprintqn(char *nbuf, u_quad_t num, int base, int *len); +static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len); +static uintmax_t lm_arg(va_list *app, enum lenmod lm); +static enum lenmod lm_unsigned(enum lenmod in); static void snprintf_func(int ch, void *arg); static int consintr = 1; /* Ok to handle console interrupts? */ @@ -419,9 +427,9 @@ * The buffer pointed to by `nbuf' must have length >= MAXNBUF. */ static char * -ksprintn(nbuf, ul, base, lenp) +ksprintn(nbuf, um, base, lenp) char *nbuf; - u_long ul; + uintmax_t um; int base, *lenp; { char *p; @@ -429,29 +437,92 @@ p = nbuf; *p = '\0'; do { - *++p = hex2ascii(ul % base); - } while (ul /= base); + *++p = hex2ascii(um % base); + } while (um /= base); if (lenp) *lenp = p - nbuf; return (p); } -/* ksprintn, but for a quad_t. */ -static char * -ksprintqn(nbuf, uq, base, lenp) - char *nbuf; - u_quad_t uq; - int base, *lenp; + +/* + * Retrieve the next argument in `app' according to `lm'. + */ +static uintmax_t +lm_arg(va_list *app, enum lenmod lm) { - char *p; + uintmax_t um; - p = nbuf; - *p = '\0'; - do { - *++p = hex2ascii(uq % base); - } while (uq /= base); - if (lenp) - *lenp = p - nbuf; - return (p); + switch (lm) { + case LM_POINTER: + um = (uintptr_t)va_arg(*app, void *); + break; + case LM_QUAD: + um = (quad_t)va_arg(*app, quad_t); + break; + case LM_UQUAD: + um = (u_quad_t)va_arg(*app, u_quad_t); + break; + case LM_LONG: + um = (long)va_arg(*app, long); + break; + case LM_ULONG: + um = (u_long)va_arg(*app, u_long); + break; + case LM_INT: + um = (int)va_arg(*app, int); + break; + case LM_UINT: + um = (u_int)va_arg(*app, u_int); + break; + case LM_INTMAX: + um = (intmax_t)va_arg(*app, intmax_t); + break; + case LM_UINTMAX: + um = (uintmax_t)va_arg(*app, uintmax_t); + break; + case LM_SIZET: + um = (size_t)va_arg(*app, size_t); + break; + default: + panic("lm_arg: unknown lm=%d", lm); + } + return (um); +} + +/* + * Return the unsigned counerpart of the length modifier passed in. + */ +static enum lenmod +lm_unsigned(enum lenmod in) +{ + enum lenmod out; + + switch (in) { + case LM_QUAD: + out = LM_UQUAD; + break; + case LM_LONG: + out = LM_ULONG; + break; + case LM_INT: + out = LM_UINT; + break; + case LM_INTMAX: + out = LM_UINTMAX; + break; + case LM_UQUAD: + case LM_ULONG: + case LM_UINT: + case LM_UINTMAX: + case LM_POINTER: + case LM_SIZET: /* Should we do something special with this? */ + /* These are already unsigned, so just return the input. */ + out = in; + break; + default: + panic("lm_unsigned: unknown lm=%d", in); + } + return (out); } /* @@ -488,15 +559,14 @@ char *p, *q, *d; u_char *up; int ch, n; - u_long ul; - u_quad_t uq; - int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; + uintmax_t um; + enum lenmod lm; + int base, tmp, width, ladjust, sharpflag, neg, sign, dot; int dwidth; char padc; int retval = 0; - ul = 0; - uq = 0; + um = 0; if (!func) d = (char *) arg; else @@ -516,7 +586,8 @@ return (retval); PCHAR(ch); } - qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; + lm = LM_INT; + ladjust = 0; sharpflag = 0; neg = 0; sign = 0; dot = 0; dwidth = 0; reswitch: switch (ch = (u_char)*fmt++) { case '.': @@ -564,17 +635,17 @@ width = n; goto reswitch; case 'b': - ul = va_arg(ap, int); + um = va_arg(ap, int); p = va_arg(ap, char *); - for (q = ksprintn(nbuf, ul, *p++, NULL); *q;) + for (q = ksprintn(nbuf, um, *p++, NULL); *q;) PCHAR(*q--); - if (!ul) + if (!um) break; for (tmp = 0; *p;) { n = *p++; - if (ul & (1 << (n - 1))) { + if (um & (1 << (n - 1))) { PCHAR(tmp ? ',' : '<'); for (; (n = *p) > ' '; ++p) PCHAR(n); @@ -604,48 +675,34 @@ } break; case 'd': - if (qflag) - uq = va_arg(ap, quad_t); - else if (lflag) - ul = va_arg(ap, long); - else - ul = va_arg(ap, int); + um = lm_arg(&ap, lm); sign = 1; base = 10; goto number; + case 'j': + lm = LM_INTMAX; + goto reswitch; case 'l': - if (lflag) { - lflag = 0; - qflag = 1; - } else - lflag = 1; + if (lm == LM_LONG) + lm = LM_QUAD; + else + lm = LM_LONG; goto reswitch; case 'o': - if (qflag) - uq = va_arg(ap, u_quad_t); - else if (lflag) - ul = va_arg(ap, u_long); - else - ul = va_arg(ap, u_int); + um = lm_arg(&ap, lm_unsigned(lm)); base = 8; goto nosign; case 'p': - ul = (uintptr_t)va_arg(ap, void *); + um = lm_arg(&ap, LM_POINTER); base = 16; sharpflag = (width == 0); goto nosign; case 'q': - qflag = 1; + lm = LM_QUAD; goto reswitch; case 'n': case 'r': - if (qflag) - uq = va_arg(ap, u_quad_t); - else if (lflag) - ul = va_arg(ap, u_long); - else - ul = sign ? - (u_long)va_arg(ap, int) : va_arg(ap, u_int); + um = lm_arg(&ap, sign ? lm : lm_unsigned(lm)); base = radix; goto number; case 's': @@ -670,50 +727,29 @@ PCHAR(padc); break; case 'u': - if (qflag) - uq = va_arg(ap, u_quad_t); - else if (lflag) - ul = va_arg(ap, u_long); - else - ul = va_arg(ap, u_int); + um = lm_arg(&ap, lm_unsigned(lm)); base = 10; goto nosign; case 'x': case 'X': - if (qflag) - uq = va_arg(ap, u_quad_t); - else if (lflag) - ul = va_arg(ap, u_long); - else - ul = va_arg(ap, u_int); + um = lm_arg(&ap, lm_unsigned(lm)); base = 16; goto nosign; + case 'Z': /* XXX: This should be 'z'. */ + lm = LM_SIZET; + goto reswitch; case 'z': - if (qflag) - uq = va_arg(ap, u_quad_t); - else if (lflag) - ul = va_arg(ap, u_long); - else - ul = sign ? - (u_long)va_arg(ap, int) : va_arg(ap, u_int); + um = lm_arg(&ap, sign ? lm : lm_unsigned(lm)); base = 16; goto number; nosign: sign = 0; number: - if (qflag) { - if (sign && (quad_t)uq < 0) { - neg = 1; - uq = -(quad_t)uq; - } - p = ksprintqn(nbuf, uq, base, &tmp); - } else { - if (sign && (long)ul < 0) { - neg = 1; - ul = -(long)ul; - } - p = ksprintn(nbuf, ul, base, &tmp); + if (sign && (intmax_t)um < 0) { + neg = 1; + um = -(intmax_t)um; } - if (sharpflag && (qflag ? uq != 0 : ul != 0)) { + p = ksprintn(nbuf, um, base, &tmp); + if (sharpflag && um != 0) { if (base == 8) tmp++; else if (base == 16) @@ -727,7 +763,7 @@ PCHAR(padc); if (neg) PCHAR('-'); - if (sharpflag && (qflag ? uq != 0 : ul != 0)) { + if (sharpflag && um != 0) { if (base == 8) { PCHAR('0'); } else if (base == 16) { @@ -746,7 +782,17 @@ break; default: PCHAR('%'); - if (lflag) + /* + * XXX: This is bogus. We can have more flags + * than just `l', and we can even have `l' + * more than once. The old test was + * + * if (lflag) + * + * and we're just imitating that for now. + */ + if (lm == LM_LONG || lm == LM_ULONG || + lm == LM_QUAD || lm == LM_UQUAD) PCHAR('l'); PCHAR(ch); break; @@ -776,7 +822,7 @@ dangling = 0; } msgaddchar('<', NULL); - for (p = ksprintn(nbuf, (u_long)pri, 10, NULL); *p;) + for (p = ksprintn(nbuf, (uintmax_t)pri, 10, NULL); *p;) msgaddchar(*p--, NULL); msgaddchar('>', NULL); lastpri = pri; To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-audit" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020523050017.E3A2A3E22>