[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

printf(3): add support for z and t modifiers



Hi,

this adds support for the C99 z and t modifiers to printf(3).

Currently, the only safe way to print a size_t v is:

	printf("%llu", (unsigned long long) v);

Since the size of size_t can be 32 or 64 bits, depending on arch.

With this diff you can just do:

	printf("%zu", v);

'%td' can be used in the same way for ptrdiff_t.

Please review and test this diff; it promises to make lives of C 
programmers easier.

Thanks,

	-Otto

Index: lib/libc/stdio/printf.3
===================================================================
RCS file: /cvs/src/lib/libc/stdio/printf.3,v
retrieving revision 1.43
diff -u -p -r1.43 printf.3
--- lib/libc/stdio/printf.3	17 Aug 2003 17:08:09 -0000	1.43
+++ lib/libc/stdio/printf.3	18 Sep 2004 18:56:16 -0000
@@ -394,6 +394,47 @@ The use of
 .Cm q
 has been deprecated as conversion character.
 .It
+The optional character
+.Cm t ,
+specifying that a following
+.Cm d ,
+.Cm i ,
+.Cm o ,
+.Cm u ,
+.Cm x ,
+or
+.Cm X
+conversion corresponds to a
+.Em ptrdiff_t
+or
+the corresponding unsigned integer type
+argument, or that a following
+.Cm n
+conversion corresponds to a pointer to a
+.Em ptrdiff_t
+argument.
+.It
+The optional character
+.Cm z ,
+specifying that a following
+.Cm d ,
+.Cm i ,
+.Cm o ,
+.Cm u ,
+.Cm x ,
+or
+.Cm X
+conversion corresponds to a
+.Em size_t
+or
+the corresponding signed integer type
+argument, or that a following
+.Cm n
+conversion corresponds to a pointer to a
+signed integer type corresponding to
+.Em size_t
+argument.
+.It
 The character
 .Cm L
 specifying that a following
Index: lib/libc/stdio/vfprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/vfprintf.c,v
retrieving revision 1.22
diff -u -p -r1.22 vfprintf.c
--- lib/libc/stdio/vfprintf.c	16 Sep 2004 20:21:03 -0000	1.22
+++ lib/libc/stdio/vfprintf.c	18 Sep 2004 18:56:16 -0000
@@ -43,6 +43,7 @@ static char *rcsid = "$OpenBSD: vfprintf
 #include <sys/types.h>
 #include <sys/mman.h>
 
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -150,6 +151,9 @@ static int exponent(char *, int, int);
 #define	SHORTINT	0x040		/* short integer */
 #define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
 #define FPT		0x100		/* Floating point number */
+#define PTRINT		0x200		/* (unsigned) ptrdiff_t */
+#define SIZEINT		0x400		/* (signed) size_t */
+
 int
 vfprintf(fp, fmt0, ap)
 	FILE *fp;
@@ -247,11 +251,15 @@ vfprintf(fp, fmt0, ap)
 #define	SARG() \
 	(flags&QUADINT ? va_arg(ap, quad_t) : \
 	    flags&LONGINT ? GETARG(long) : \
+	    flags&PTRINT ? GETARG(ptrdiff_t) : \
+	    flags&SIZEINT ? GETARG(ssize_t) : \
 	    flags&SHORTINT ? (long)(short)GETARG(int) : \
 	    (long)GETARG(int))
 #define	UARG() \
 	(flags&QUADINT ? va_arg(ap, u_quad_t) : \
 	    flags&LONGINT ? GETARG(u_long) : \
+	    flags&PTRINT ? GETARG(ptrdiff_t) : /* XXX */ \
+	    flags&SIZEINT ? GETARG(size_t) : \
 	    flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
 	    (u_long)GETARG(u_int))
 
@@ -434,6 +442,12 @@ reswitch:	switch (ch) {
 		case 'q':
 			flags |= QUADINT;
 			goto rflag;
+		case 't':
+			flags |= PTRINT;
+			goto rflag;
+		case 'z':
+			flags |= SIZEINT;
+			goto rflag;
 		case 'c':
 			*(cp = buf) = GETARG(int);
 			size = 1;
@@ -524,6 +538,10 @@ reswitch:	switch (ch) {
 				*GETARG(long *) = ret;
 			else if (flags & SHORTINT)
 				*GETARG(short *) = ret;
+			else if (flags & PTRINT)
+				*GETARG(ptrdiff_t *) = ret;
+			else if (flags & SIZEINT)
+				*GETARG(ssize_t *) = ret;
 			else
 				*GETARG(int *) = ret;
 			continue;	/* no output */
@@ -784,6 +802,11 @@ error:
 #define T_LONG_DOUBLE	14
 #define TP_CHAR		15
 #define TP_VOID		16
+#define T_PTRINT	17
+#define TP_PTRINT	18
+#define T_SIZEINT	19
+#define T_SSIZEINT	20
+#define TP_SSIZEINT	21
 
 /*
  * Find all arguments when a positional parameter is encountered.  Returns a
@@ -917,6 +940,12 @@ reswitch:	switch (ch) {
 		case 'q':
 			flags |= QUADINT;
 			goto rflag;
+		case 't':
+			flags |= PTRINT;
+			goto rflag;
+		case 'z':
+			flags |= SIZEINT;
+			goto rflag;
 		case 'c':
 			ADDTYPE(T_INT);
 			break;
@@ -925,11 +954,14 @@ reswitch:	switch (ch) {
 			/*FALLTHROUGH*/
 		case 'd':
 		case 'i':
-			if (flags & QUADINT) {
+			if (flags & QUADINT)
 				ADDTYPE(T_QUAD);
-			} else {
+			else if (flags & PTRINT)
+				ADDTYPE(T_PTRINT);
+			else if (flags & SIZEINT)
+				ADDTYPE(T_SSIZEINT);
+			else
 				ADDSARG();
-			}
 			break;
 #ifdef FLOATING_POINT
 		case 'e':
@@ -950,6 +982,10 @@ reswitch:	switch (ch) {
 				ADDTYPE(TP_LONG);
 			else if (flags & SHORTINT)
 				ADDTYPE(TP_SHORT);
+			else if (flags & PTRINT)
+				ADDTYPE(TP_PTRINT);
+			else if (flags & SIZEINT)
+				ADDTYPE(TP_SSIZEINT);
 			else
 				ADDTYPE(TP_INT);
 			continue;	/* no output */
@@ -981,6 +1017,10 @@ reswitch:	switch (ch) {
 		case 'x':
 			if (flags & QUADINT)
 				ADDTYPE(T_U_QUAD);
+			else if (flags & PTRINT)
+				ADDTYPE(T_PTRINT);
+			else if (flags & SIZEINT)
+				ADDTYPE(T_SIZEINT);
 			else
 				ADDUARG();
 			break;
@@ -1057,6 +1097,21 @@ done:
 			break;
 		case TP_VOID:
 			(void) va_arg(ap, void *);
+			break;
+		case T_PTRINT:
+			(void) va_arg(ap, ptrdiff_t);
+			break;
+		case TP_PTRINT:
+			(void) va_arg(ap, ptrdiff_t *);
+			break;
+		case T_SIZEINT:
+			(void) va_arg(ap, size_t);
+			break;
+		case T_SSIZEINT:
+			(void) va_arg(ap, ssize_t);
+			break;
+		case TP_SSIZEINT:
+			(void) va_arg(ap, ssize_t *);
 			break;
 		}
 	}
Index: regress/lib/libc/sprintf/sprintf_test.c
===================================================================
RCS file: /cvs/src/regress/lib/libc/sprintf/sprintf_test.c,v
retrieving revision 1.3
diff -u -p -r1.3 sprintf_test.c
--- regress/lib/libc/sprintf/sprintf_test.c	16 Sep 2004 20:22:26 -0000	1.3
+++ regress/lib/libc/sprintf/sprintf_test.c	18 Sep 2004 18:56:22 -0000
@@ -29,6 +29,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -48,10 +49,16 @@ char correct[] =
 	"|xx 41 42 43 44\n"
 	"|xx 45 -1 1 -1 1\n";
 
+char correct2[] =
+	"1 0 -1 1 1 2 1 3 -1 4 1  \n"
+	"1 -1 1 1 -1 1  \n";
+
 int
 main(int argc, char *argv[])
 {
 	char buf[1024];
+	size_t sz1, sz2, sz3, sz4;
+	ptrdiff_t p1, p2, p3, p4;
 
 	/* Test positional arguments */
 	snprintf(buf, sizeof buf,
@@ -77,8 +84,19 @@ main(int argc, char *argv[])
 	    "43", "44", 45, -1L, 1LL, -1, 1LL
 	    );
 
-	printf(buf);
-	if (strcmp(buf, correct) == 0)
-		exit(0);
-	exit(1);
+	if (strcmp(buf, correct) != 0)
+		exit(1);
+
+	sz1 = (size_t)1;
+	sz2 = (size_t)-1;
+	p1 = (ptrdiff_t)1;
+	p2 = (ptrdiff_t)-1;
+	snprintf(buf, sizeof buf,
+		"%zx %d %zd %d %zu %d %tx %d %td %d %tu %zn %tn\n"
+		"%1$zx %3$zd %5$zu %7$tx %9$td %11$tu %14$zn %15$tn\n",
+		sz1, 0, sz2, 1, sz1, 2, p1, 3, p2, 4, p1, &sz3, &p3, &sz4, &p4);
+	if (strcmp(buf, correct2) != 0 || sz3 != 24 || p3 != 25 ||
+	    sz4 != 40 || p4 != 41)
+		exit(1);
+	exit(0);
 }



Visit your host, monkey.org