%j for printf(9)

Dima Dorfman <[email protected]>
Newsgroups gmane.os.freebsd.devel.audit
Message-ID <[email protected]>
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 <[email protected]> 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 [email protected]
with "unsubscribe freebsd-audit" in the body of the message
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.