[patch] synch src/lib/stdio/vfprintf.c with FreeBSD rev 1.34

Chris Pressey cpressey at catseye.mine.nu
Thu Jan 13 22:32:45 PST 2005


Hi,

The attached patch synchs DFly's vfprintf.c with FreeBSD's 1.34. 
Basically this provides support for some C99 format length specifiers
(z, t, j, hh) and locale-sensitive "thousands" (grouping) seperators.

It's not been tested yet (buildworld+buildkernel currently in progress.)

Patching was done by hand, due to our style difference from FreeBSD,
plus I wanted to follow the logic of each of the changes.  They seem
sound, except for the assumption that quad_t == long long, so (on
Joerg's advice) I added a compile-time assertion on that assumption.

Your feedback/review/testing is of course appreciated :)

Thanks,
-Chris

Index: stdio/vfprintf.c
===================================================================
RCS file: /home/dcvs/src/lib/libc/stdio/vfprintf.c,v
retrieving revision 1.5
diff -u -r1.5 vfprintf.c
--- stdio/vfprintf.c	7 Jun 2004 20:35:41 -0000	1.5
+++ stdio/vfprintf.c	14 Jan 2005 05:42:46 -0000
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  * @(#)vfprintf.c	8.1 (Berkeley) 6/4/93
- * $FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.22.2.5 2002/10/12 10:46:37 schweikh Exp $
+ * $FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.34 2001/12/13 19:45:41 phantom Exp $
  * $DragonFly: src/lib/libc/stdio/vfprintf.c,v 1.5 2004/06/07 20:35:41 hmp Exp $
  */
 
@@ -46,7 +46,11 @@
 
 #include <sys/types.h>
 
+#include <ctype.h>
 #include <limits.h>
+#include <locale.h>
+#include <stddef.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -60,12 +64,61 @@
 /* Define FLOATING_POINT to get floating point. */
 #define	FLOATING_POINT
 
-static int	__sprint (FILE *, struct __suio *);
-static int	__sbprintf (FILE *, const char *, va_list);
-static char *	__ultoa (u_long, char *, int, int, char *);
-static char *	__uqtoa (u_quad_t, char *, int, int, char *);
-static void	__find_arguments (const char *, va_list, void ***);
-static void	__grow_type_table (int, unsigned char **, int *);
+/* Borrowed from sys/systm.h, which is _KERNEL-only: */
+#define	CTASSERT(x)		_CTASSERT(x, __LINE__)
+#define	_CTASSERT(x, y)		__CTASSERT(x, y)
+#define	__CTASSERT(x, y)	typedef char __assert ## y[(x) ? 1 : -1]
+
+/* This code assumes that a quad_t can fit in a long long: */
+CTASSERT(sizeof(quad_t) == sizeof(long long));
+
+union arg {
+	int			 intarg;
+	unsigned int		 uintarg;
+	long			 longarg;
+	unsigned long		 ulongarg;
+	long long		 longlongarg;
+	unsigned long long	 ulonglongarg;
+	ptrdiff_t		 ptrdiffarg;
+	size_t			 sizearg;
+	intmax_t		 intmaxarg;
+	uintmax_t		 uintmaxarg;
+	void			*pvoidarg;
+	char			*pchararg;
+	signed char		*pschararg;
+	short			*pshortarg;
+	int			*pintarg;
+	long			*plongarg;
+	long long		*plonglongarg;
+	ptrdiff_t		*pptrdiffarg;
+	size_t			*psizearg;
+	intmax_t		*pintmaxarg;
+#ifdef FLOATING_POINT
+	double			 doublearg;
+	long double		 longdoublearg;
+#endif
+};
+
+/*
+ * Type ids for argument type table.
+ */
+enum typeid {
+	T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
+	T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
+	T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET,
+	T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
+	T_DOUBLE, T_LONG_DOUBLE
+};
+
+static int	__sprint(FILE *, struct __suio *);
+static int	__sbprintf(FILE *, const char *, va_list) __printflike(2, 0);
+static char *	__ujtoa(uintmax_t, char *, int, int, char *, int,
+		     char, const char *);
+static char *	__ultoa(u_long, char *, int, int, char *, int,
+		     char, const char *);
+static char *	__uqtoa(u_quad_t, char *, int, int, char *);
+static void	__find_arguments(const char *, va_list, union arg **);
+static void	__grow_type_table(int, enum typeid **, int *);
 
 /*
  * Flush out all the vectors defined by the given uio,
@@ -132,10 +185,12 @@
  * use the given digits.
  */
 static char *
-__ultoa(u_long val, char *endp, int base, int octzero, char *xdigs)
+__ultoa(u_long val, char *endp, int base, int octzero, char *xdigs,
+	int needgrp, char thousep, const char *grp)
 {
 	char *cp = endp;
 	long sval;
+	int ndig;
 
 	/*
 	 * Handle the three cases separately, in the hope of getting
@@ -147,6 +202,7 @@
 			*--cp = to_char(val);
 			return (cp);
 		}
+		ndig = 0;
 		/*
 		 * On many machines, unsigned arithmetic is harder than
 		 * signed arithmetic, so we do at most one unsigned mod and
@@ -155,11 +211,29 @@
 		 */
 		if (val > LONG_MAX) {
 			*--cp = to_char(val % 10);
+			ndig++;
 			sval = val / 10;
 		} else
 			sval = val;
 		do {
 			*--cp = to_char(sval % 10);
+			ndig++;
+			/*
+			 * If (*grp == CHAR_MAX) then no more grouping
+			 * should be performed.
+			 */
+			if (needgrp && ndig == *grp && *grp != CHAR_MAX &&
+			    sval > 9) {
+				*--cp = thousep;
+ 				ndig = 0;
+				/*
+				 * If (*(grp+1) == '\0') then we have to
+				 * use *grp character (last grouping rule)
+				 * for all next cases
+				 */
+				if (*(grp + 1) != '\0')
+					grp++;
+			}
 			sval /= 10;
 		} while (sval != 0);
 		break;
@@ -186,32 +260,54 @@
 	return (cp);
 }
 
-/* Identical to __ultoa, but for quads. */
+/* Identical to __ultoa, but for intmax_t. */
 static char *
-__uqtoa(u_quad_t val, char *endp, int base, int octzero, char *xdigs)
+__ujtoa(u_quad_t val, char *endp, int base, int octzero, char *xdigs,
+	int needgrp, char thousep, const char *grp)
 {
 	char *cp = endp;
-	quad_t sval;
+	intmax_t sval;
+	int ndig;
 
 	/* quick test for small values; __ultoa is typically much faster */
 	/* (perhaps instead we should run until small, then call __ultoa?) */
 	if (val <= ULONG_MAX)
-		return (__ultoa((u_long)val, endp, base, octzero, xdigs));
+		return (__ultoa((u_long)val, endp, base, octzero, xdigs,
+		    needgrp, thousep, grp));
 	switch (base) {
 	case 10:
 		if (val < 10) {
 			*--cp = to_char(val % 10);
 			return (cp);
 		}
-		if (val > QUAD_MAX) {
+		ndig = 0;
+		if (val > INTMAX_MAX) {
 			*--cp = to_char(val % 10);
+			ndig++;
 			sval = val / 10;
 		} else
 			sval = val;
-		do {
-			*--cp = to_char(sval % 10);
-			sval /= 10;
-		} while (sval != 0);
+ 		do {
+ 			*--cp = to_char(sval % 10);
+			ndig++;
+			/*
+			 * If (*grp == CHAR_MAX) then no more grouping
+			 * should be performed.
+			 */
+			if (needgrp && *grp != CHAR_MAX && ndig == *grp &&
+			    sval > 9) {
+				*--cp = thousep;
+ 				ndig = 0;
+				/*
+				 * If (*(grp+1) == '\0') then we have to
+				 * use *grp character (last grouping rule)
+				 * for all next cases
+				 */
+				if (*(grp + 1) != '\0')
+					grp++;
+                        }
+ 			sval /= 10;
+ 		} while (sval != 0);
 		break;
 
 	case 8:
@@ -237,11 +333,10 @@
 }
 
 #ifdef FLOATING_POINT
-#include <locale.h>
 #include <math.h>
 #include "floatio.h"
 
-#define	BUF		(MAXEXP+MAXFRACT+1)	/* + decimal point */
+#define	BUF		((MAXEXP * 2) + MAXFRACT + 1)	/* + decimal point */
 #define	DEFPREC		6
 
 static char *cvt (double, int, int, char *, int *, int, int *, char **);
@@ -249,7 +344,7 @@
 
 #else /* no FLOATING_POINT */
 
-#define	BUF		68
+#define	BUF		136
 
 #endif /* FLOATING_POINT */
 
@@ -263,10 +358,16 @@
 #define	LADJUST		0x004		/* left adjustment */
 #define	LONGDBL		0x008		/* long double */
 #define	LONGINT		0x010		/* long integer */
-#define	QUADINT		0x020		/* quad integer */
+#define	LLONGINT	0x020		/* long long integer */
 #define	SHORTINT	0x040		/* short integer */
 #define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
-#define FPT		0x100		/* Floating point number */
+#define	FPT		0x100		/* Floating point number */
+#define	GROUPING	0x200		/* use grouping ("'" flag) */
+ 					/* C99 additional size modifiers: */
+#define	SIZET		0x400		/* size_t */
+#define	PTRDIFFT	0x800		/* ptrdiff_t */
+#define	INTMAXT		0x1000		/* intmax_t */
+#define	CHARINT		0x2000		/* print char using int format */
 int
 vfprintf(FILE *fp, const char *fmt0, va_list ap)
 {
@@ -280,8 +381,10 @@
 	int width;		/* width from format (%8d), or 0 */
 	int prec;		/* precision from format (%.3d), or -1 */
 	char sign;		/* sign prefix (' ', '+', '-', or \0) */
-#ifdef FLOATING_POINT
-	char *decimal_point = localeconv()->decimal_point;
+	char thousands_sep;	/* locale specific thousands separator */
+	const char *grouping;	/* locale specific numeric grouping rules */
+ #ifdef FLOATING_POINT
+	char *decimal_point;	/* locale specific decimal point */
 	char softsign;		/* temporary negative sign for floats */
 	double _double;		/* double precision arguments %[eEfgG] */
 	int expt;		/* integer value of exponent */
@@ -291,7 +394,7 @@
 	char *dtoaresult;	/* buffer allocated by dtoa */
 #endif
 	u_long	ulval;		/* integer arguments %[diouxX] */
-	u_quad_t uqval;		/* %q integers */
+	uintmax_t ujval;	/* %j, %ll, %q, %t, %z integers */
 	int base;		/* base for [diouxX] conversion */
 	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
 	int realsz;		/* field size expanded by dprec, sign, etc */
@@ -301,10 +404,10 @@
 #define NIOV 8
 	struct __suio uio;	/* output information: summary */
 	struct __siov iov[NIOV];/* ... and individual io vectors */
-	char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */
-	char ox[2];		/* space for 0x hex-prefix */
-        void **argtable;        /* args, built due to positional arg */
-        void *statargtable [STATIC_ARG_TBL_SIZE];
+	char buf[BUF];		/* space for %c, %[diouxX], %[eEfFgG] */
+ 	char ox[2];		/* space for 0x hex-prefix */
+        union arg *argtable;	/* args, built due to positional arg */
+        union arg statargtable[STATIC_ARG_TBL_SIZE];
         int nextarg;            /* 1-based argument index */
         va_list orgap;          /* original argument pointer */
 
@@ -355,7 +458,7 @@
          * argument (and arguments must be gotten sequentially).
          */
 #define GETARG(type) \
-        ((argtable != NULL) ? *((type*)(argtable[nextarg++])) : \
+        ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
             (nextarg++, va_arg(ap, type)))
 
 	/*
@@ -365,11 +468,24 @@
 #define	SARG() \
 	(flags&LONGINT ? GETARG(long) : \
 	    flags&SHORTINT ? (long)(short)GETARG(int) : \
+	    flags&CHARINT ? (long)(signed char)GETARG(int) : \
 	    (long)GETARG(int))
 #define	UARG() \
 	(flags&LONGINT ? GETARG(u_long) : \
 	    flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
+	    flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
 	    (u_long)GETARG(u_int))
+#define	INTMAX_SIZE	(INTMAXT|SIZET|PTRDIFFT|LLONGINT)
+#define	SJARG() \
+	(flags&INTMAXT ? GETARG(intmax_t) : \
+	    flags&SIZET ? (intmax_t)GETARG(size_t) : \
+	    flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
+	    (intmax_t)GETARG(long long))
+#define	UJARG() \
+	(flags&INTMAXT ? GETARG(uintmax_t) : \
+	    flags&SIZET ? (uintmax_t)GETARG(size_t) : \
+	    flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
+	    (uintmax_t)GETARG(unsigned long long))
 
         /*
          * Get * arguments, including the form *nn$.  Preserve the nextarg
@@ -395,10 +511,13 @@
         } else { \
 		val = GETARG (int); \
         }
-        
 
+
+	thousands_sep = '\0';
+	grouping = NULL;
 #ifdef FLOATING_POINT
 	dtoaresult = NULL;
+	decimal_point = localeconv()->decimal_point;
 #endif
 	FLOCKFILE(fp);
 	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
@@ -479,6 +598,11 @@
 		case '+':
 			sign = '+';
 			goto rflag;
+		case '\'':
+			flags |= GROUPING;
+			thousands_sep = *(localeconv()->thousands_sep);
+			grouping = localeconv()->grouping;
+			goto rflag;
 		case '.':
 			if ((ch = *fmt++) == '*') {
 				GETASTER (n);
@@ -524,16 +648,30 @@
 			goto rflag;
 #endif
 		case 'h':
-			flags |= SHORTINT;
+			if (flags & SHORTINT) {
+				flags &= ~SHORTINT;
+				flags |= CHARINT;
+			} else
+				flags |= SHORTINT;
+			goto rflag;
+		case 'j':
+			flags |= INTMAXT;
 			goto rflag;
 		case 'l':
-			if (flags & LONGINT)
-				flags |= QUADINT;
-			else
+			if (flags & LONGINT) {
+				flags &= ~LONGINT;
+				flags |= LLONGINT;
+			} else
 				flags |= LONGINT;
 			goto rflag;
 		case 'q':
-			flags |= QUADINT;
+			flags |= LLONGINT;
+			goto rflag;
+		case 't':
+			flags |= PTRDIFFT;
+			goto rflag;
+		case 'z':
+			flags |= SIZET;
 			goto rflag;
 		case 'c':
 			*(cp = buf) = GETARG(int);
@@ -545,10 +683,10 @@
 			/*FALLTHROUGH*/
 		case 'd':
 		case 'i':
-			if (flags & QUADINT) {
-				uqval = GETARG(quad_t);
-				if ((quad_t)uqval < 0) {
-					uqval = -uqval;
+			if (flags & INTMAX_SIZE) {
+				ujval = SJARG();
+				if ((intmax_t)ujval < 0) {
+					ujval = -ujval;
 					sign = '-';
 				}
 			} else {
@@ -561,9 +699,22 @@
 			base = 10;
 			goto number;
 #ifdef FLOATING_POINT
+#ifdef HEXFLOAT
+		case 'a':
+		case 'A':
+#endif
 		case 'e':
 		case 'E':
+			/*
+			 * Grouping apply to %i, %d, %u, %f, %F, %g, %G
+			 * conversion specifiers only. For other conversions
+			 * behavior is undefined.
+			 *	-- POSIX
+			 */
+			flags &= ~GROUPING;
+			/*FALLTHROUGH*/
 		case 'f':
+		case 'F':
 			goto fp_begin;
 		case 'g':
 		case 'G':
@@ -580,12 +731,18 @@
 			if (isinf(_double)) {
 				if (_double < 0)
 					sign = '-';
-				cp = "Inf";
+				if (isupper(ch))
+					cp = "INF";
+				else
+					cp = "inf";
 				size = 3;
 				break;
 			}
 			if (isnan(_double)) {
-				cp = "NaN";
+				if (isupper(ch))
+					cp = "NAN";
+				else
+					cp = "nan";
 				size = 3;
 				break;
 			}
@@ -602,13 +759,13 @@
 				else
 					ch = 'g';
 			}
-			if (ch <= 'e') {	/* 'e' or 'E' fmt */
+			if (ch == 'e' || ch == 'E') {
 				--expt;
 				expsize = exponent(expstr, expt, ch);
 				size = expsize + ndig;
 				if (ndig > 1 || flags & ALT)
 					++size;
-			} else if (ch == 'f') {		/* f fmt */
+			} else if (ch == 'f' || ch == 'F') {
 				if (expt > 0) {
 					size = expt;
 					if (prec || flags & ALT)
@@ -628,12 +785,25 @@
 			break;
 #endif /* FLOATING_POINT */
 		case 'n':
-			if (flags & QUADINT)
-				*GETARG(quad_t *) = ret;
+			/*
+			 * Assignment-like behavior is specified if the
+			 * value overflows or is otherwise unrepresentable.
+			 * C99 says to use `signed char' for %hhn conversions.
+			 */
+			if (flags & LLONGINT)
+				*GETARG(long long *) = ret;
+			else if (flags & SIZET)
+				*GETARG(ssize_t *) = (ssize_t)ret;
+			else if (flags & PTRDIFFT)
+				*GETARG(ptrdiff_t *) = ret;
+			else if (flags & INTMAXT)
+				*GETARG(intmax_t *) = ret;
 			else if (flags & LONGINT)
 				*GETARG(long *) = ret;
 			else if (flags & SHORTINT)
 				*GETARG(short *) = ret;
+			else if (flags & CHARINT)
+				*GETARG(signed char *) = ret;
 			else
 				*GETARG(int *) = ret;
 			continue;	/* no output */
@@ -641,8 +811,8 @@
 			flags |= LONGINT;
 			/*FALLTHROUGH*/
 		case 'o':
-			if (flags & QUADINT)
-				uqval = GETARG(u_quad_t);
+			if (flags & INTMAX_SIZE)
+				ujval = UJARG();
 			else
 				ulval = UARG();
 			base = 8;
@@ -655,10 +825,10 @@
 			 * defined manner.''
 			 *	-- ANSI X3J11
 			 */
-			ulval = (u_long)GETARG(void *);
+			ujval = (uintmax_t)(uintptr_t)GETARG(void *);
 			base = 16;
 			xdigs = "0123456789abcdef";
-			flags = (flags & ~QUADINT) | HEXPREFIX;
+			flags = flags | INTMAXT | HEXPREFIX;
 			ch = 'x';
 			goto nosign;
 		case 's':
@@ -686,8 +856,8 @@
 			flags |= LONGINT;
 			/*FALLTHROUGH*/
 		case 'u':
-			if (flags & QUADINT)
-				uqval = GETARG(u_quad_t);
+			if (flags & INTMAX_SIZE)
+				ujval = UJARG();
 			else
 				ulval = UARG();
 			base = 10;
@@ -697,16 +867,18 @@
 			goto hex;
 		case 'x':
 			xdigs = "0123456789abcdef";
-hex:			if (flags & QUADINT)
-				uqval = GETARG(u_quad_t);
+hex:
+			if (flags & INTMAX_SIZE)
+				ujval = UJARG();
 			else
 				ulval = UARG();
 			base = 16;
 			/* leading 0x/X only if non-zero */
 			if (flags & ALT &&
-			    (flags & QUADINT ? uqval != 0 : ulval != 0))
+			    (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
 				flags |= HEXPREFIX;
 
+			flags &= ~GROUPING;
 			/* unsigned conversions */
 nosign:			sign = '\0';
 			/*
@@ -723,15 +895,19 @@
 			 *	-- ANSI X3J11
 			 */
 			cp = buf + BUF;
-			if (flags & QUADINT) {
-				if (uqval != 0 || prec != 0)
-					cp = __uqtoa(uqval, cp, base,
-					    flags & ALT, xdigs);
-			} else {
-				if (ulval != 0 || prec != 0)
-					cp = __ultoa(ulval, cp, base,
-					    flags & ALT, xdigs);
-			}
+ 			if (flags & INTMAX_SIZE) {
+ 				if (ujval != 0 || prec != 0)
+ 					cp = __ujtoa(ujval, cp, base,
+					    flags & ALT, xdigs,
+					    flags & GROUPING, thousands_sep,
+					    grouping);
+ 			} else {
+ 				if (ulval != 0 || prec != 0)
+ 					cp = __ultoa(ulval, cp, base,
+					    flags & ALT, xdigs,
+					    flags & GROUPING, thousands_sep,
+					    grouping);
+ 			}
 			size = buf + BUF - cp;
 			break;
 		default:	/* "%?" prints ?, unless ? is NUL */
@@ -864,34 +1040,13 @@
 }
 
 /*
- * Type ids for argument type table.
- */
-#define T_UNUSED	0
-#define T_SHORT		1
-#define T_U_SHORT	2
-#define TP_SHORT	3
-#define T_INT		4
-#define T_U_INT		5
-#define TP_INT		6
-#define T_LONG		7
-#define T_U_LONG	8
-#define TP_LONG		9
-#define T_QUAD		10
-#define T_U_QUAD	11
-#define TP_QUAD		12
-#define T_DOUBLE	13
-#define T_LONG_DOUBLE	14
-#define TP_CHAR		15
-#define TP_VOID		16
-
-/*
  * Find all arguments when a positional parameter is encountered.  Returns a
  * table, indexed by argument number, of pointers to each arguments.  The
  * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
  * It will be replaces with a malloc-ed one if it overflows.
  */ 
 static void
-__find_arguments (const char *fmt0, va_list ap, void ***argtable)
+__find_arguments (const char *fmt0, va_list ap, union arg **argtable)
 {
 	char *fmt;		/* format string */
 	int ch;			/* character from fmt */
@@ -899,8 +1054,8 @@
 	char *cp;		/* handy char pointer (short term usage) */
 	int flags;		/* flags as above */
 	int width;		/* width from format (%8d), or 0 */
-	unsigned char *typetable; /* table of types */
-	unsigned char stattypetable [STATIC_ARG_TBL_SIZE];
+	enum typeid *typetable; /* table of types */
+	enum typeid stattypetable[STATIC_ARG_TBL_SIZE];
 	int tablesize;		/* current size of type table */
 	int tablemax;		/* largest used index in table */
 	int nextarg;		/* 1-based argument index */
@@ -915,12 +1070,18 @@
 	typetable[nextarg++] = type)
 
 #define	ADDSARG() \
-	((flags&LONGINT) ? ADDTYPE(T_LONG) : \
-		((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))
+	((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \
+		((flags&SIZET) ? ADDTYPE(T_SIZET) : \
+		((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
+		((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
+		((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT))))))
 
 #define	ADDUARG() \
-	((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \
-		((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))
+	((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \
+		((flags&SIZET) ? ADDTYPE(T_SIZET) : \
+		((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
+		((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
+		((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT))))))
 
 	/*
 	 * Add * arguments to the type array.
@@ -971,6 +1132,7 @@
 			goto rflag;
 		case '-':
 		case '+':
+		case '\'':
 			goto rflag;
 		case '.':
 			if ((ch = *fmt++) == '*') {
@@ -1001,18 +1163,32 @@
 			flags |= LONGDBL;
 			goto rflag;
 #endif
-		case 'h':
-			flags |= SHORTINT;
+ 		case 'h':
+			if (flags & SHORTINT) {
+				flags &= ~SHORTINT;
+				flags |= CHARINT;
+			} else
+				flags |= SHORTINT;
 			goto rflag;
-		case 'l':
-			if (flags & LONGINT)
-				flags |= QUADINT;
-			else
-				flags |= LONGINT;
+		case 'j':
+			flags |= INTMAXT;
 			goto rflag;
-		case 'q':
-			flags |= QUADINT;
+ 		case 'l':
+			if (flags & LONGINT) {
+				flags &= ~LONGINT;
+				flags |= LLONGINT;
+			} else
+ 				flags |= LONGINT;
+ 			goto rflag;
+ 		case 'q':
+			flags |= LLONGINT;
 			goto rflag;
+		case 't':
+			flags |= PTRDIFFT;
+			goto rflag;
+		case 'z':
+			flags |= SIZET;
+ 			goto rflag;
 		case 'c':
 			ADDTYPE(T_INT);
 			break;
@@ -1020,14 +1196,14 @@
 			flags |= LONGINT;
 			/*FALLTHROUGH*/
 		case 'd':
-		case 'i':
-			if (flags & QUADINT) {
-				ADDTYPE(T_QUAD);
-			} else {
-				ADDSARG();
-			}
-			break;
+ 		case 'i':
+			ADDSARG();
+ 			break;
 #ifdef FLOATING_POINT
+#ifdef HEXFLOAT
+		case 'a':
+		case 'A':
+#endif
 		case 'e':
 		case 'E':
 		case 'f':
@@ -1040,12 +1216,20 @@
 			break;
 #endif /* FLOATING_POINT */
 		case 'n':
-			if (flags & QUADINT)
-				ADDTYPE(TP_QUAD);
+			if (flags & INTMAXT)
+				ADDTYPE(TP_INTMAXT);
+			else if (flags & PTRDIFFT)
+				ADDTYPE(TP_PTRDIFFT);
+			else if (flags & SIZET)
+				ADDTYPE(TP_SIZET);
+			else if (flags & LLONGINT)
+				ADDTYPE(TP_LLONG);
 			else if (flags & LONGINT)
 				ADDTYPE(TP_LONG);
 			else if (flags & SHORTINT)
 				ADDTYPE(TP_SHORT);
+			else if (flags & CHARINT)
+				ADDTYPE(TP_SCHAR);
 			else
 				ADDTYPE(TP_INT);
 			continue;	/* no output */
@@ -1053,10 +1237,7 @@
 			flags |= LONGINT;
 			/*FALLTHROUGH*/
 		case 'o':
-			if (flags & QUADINT)
-				ADDTYPE(T_U_QUAD);
-			else
-				ADDUARG();
+			ADDUARG();
 			break;
 		case 'p':
 			ADDTYPE(TP_VOID);
@@ -1067,19 +1248,11 @@
 		case 'U':
 			flags |= LONGINT;
 			/*FALLTHROUGH*/
-		case 'u':
-			if (flags & QUADINT)
-				ADDTYPE(T_U_QUAD);
-			else
-				ADDUARG();
-			break;
-		case 'X':
-		case 'x':
-			if (flags & QUADINT)
-				ADDTYPE(T_U_QUAD);
-			else
-				ADDUARG();
-			break;
+ 		case 'u':
+ 		case 'X':
+ 		case 'x':
+			ADDUARG();
+ 			break;
 		default:	/* "%?" prints ?, unless ? is NUL */
 			if (ch == '\0')
 				goto done;
@@ -1091,63 +1264,77 @@
 	 * Build the argument table.
 	 */
 	if (tablemax >= STATIC_ARG_TBL_SIZE) {
-		*argtable = (void **)
-		    malloc (sizeof (void *) * (tablemax + 1));
+		*argtable = (union arg *)
+		    malloc(sizeof(union arg) * (tablemax + 1));
 	}
-
-	(*argtable) [0] = NULL;
+	(*argtable)[0].intarg = 0;
 	for (n = 1; n <= tablemax; n++) {
 		switch (typetable [n]) {
-		    case T_UNUSED:
-			(*argtable) [n] = (void *) &va_arg (ap, int);
-			break;
-		    case T_SHORT:
-			(*argtable) [n] = (void *) &va_arg (ap, int);
-			break;
-		    case T_U_SHORT:
-			(*argtable) [n] = (void *) &va_arg (ap, int);
+		    case T_UNUSED: /* "whoops" */
+		    case T_INT:
+			(*argtable)[n].intarg = va_arg(ap, int);
 			break;
+		    case TP_SCHAR:
+			(*argtable) [n].pschararg = va_arg (ap, signed char *);
 		    case TP_SHORT:
-			(*argtable) [n] = (void *) &va_arg (ap, short *);
-			break;
-		    case T_INT:
-			(*argtable) [n] = (void *) &va_arg (ap, int);
+			(*argtable)[n].pshortarg = va_arg(ap, short *);
 			break;
 		    case T_U_INT:
-			(*argtable) [n] = (void *) &va_arg (ap, unsigned int);
+			(*argtable)[n].uintarg = va_arg(ap, unsigned int);
 			break;
 		    case TP_INT:
-			(*argtable) [n] = (void *) &va_arg (ap, int *);
+			(*argtable)[n].pintarg = va_arg(ap, int *);
 			break;
 		    case T_LONG:
-			(*argtable) [n] = (void *) &va_arg (ap, long);
+			(*argtable)[n].longarg = va_arg(ap, long);
 			break;
 		    case T_U_LONG:
-			(*argtable) [n] = (void *) &va_arg (ap, unsigned long);
+			(*argtable)[n].ulongarg = va_arg(ap, unsigned long);
 			break;
 		    case TP_LONG:
-			(*argtable) [n] = (void *) &va_arg (ap, long *);
+			(*argtable)[n].plongarg = va_arg(ap, long *);
+			break;
+		    case T_LLONG:
+			(*argtable)[n].longlongarg = va_arg(ap, long long);
+			break;
+		    case T_U_LLONG:
+			(*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long);
+			break;
+		    case TP_LLONG:
+			(*argtable)[n].plonglongarg = va_arg(ap, long long *);
+			break;
+		    case T_PTRDIFFT:
+			(*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t);
+			break;
+		    case TP_PTRDIFFT:
+			(*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t *);
+			break;
+		    case T_SIZET:
+			(*argtable)[n].sizearg = va_arg(ap, size_t);
 			break;
-		    case T_QUAD:
-			(*argtable) [n] = (void *) &va_arg (ap, quad_t);
+		    case TP_SIZET:
+			(*argtable)[n].psizearg = va_arg(ap, ssize_t *);
 			break;
-		    case T_U_QUAD:
-			(*argtable) [n] = (void *) &va_arg (ap, u_quad_t);
+		    case T_INTMAXT:
+			(*argtable)[n].intmaxarg = va_arg(ap, intmax_t);
+ 			break;
+		    case T_UINTMAXT:
+			(*argtable)[n].uintmaxarg = va_arg(ap, uintmax_t);
 			break;
-		    case TP_QUAD:
-			(*argtable) [n] = (void *) &va_arg (ap, quad_t *);
+		    case TP_INTMAXT:
+			(*argtable)[n].pintmaxarg = va_arg (ap, intmax_t *);
 			break;
 		    case T_DOUBLE:
-			(*argtable) [n] = (void *) &va_arg (ap, double);
+			(*argtable)[n].doublearg = va_arg(ap, double);
 			break;
 		    case T_LONG_DOUBLE:
-			(*argtable) [n] = (void *) &va_arg (ap, long double);
+			(*argtable)[n].longdoublearg = va_arg(ap, long double);
 			break;
 		    case TP_CHAR:
-			(*argtable) [n] = (void *) &va_arg (ap, char *);
+			(*argtable)[n].pchararg = va_arg(ap, char *);
 			break;
 		    case TP_VOID:
-			(*argtable) [n] = (void *) &va_arg (ap, void *);
+			(*argtable)[n].pvoidarg = va_arg(ap, void *);
 			break;
 		}
 	}
@@ -1160,11 +1347,11 @@
  * Increase the size of the type table.
  */
 static void
-__grow_type_table (int nextarg, unsigned char **typetable, int *tablesize)
+__grow_type_table(int nextarg, enum typeid **typetable, int *tablesize)
 {
-	unsigned char *const oldtable = *typetable;
+	enum typeid * const oldtable = *typetable;
 	const int oldsize = *tablesize;
-	unsigned char *newtable;
+	enum typeid *newtable;
 	int newsize = oldsize * 2;
 
 	if (newsize < nextarg + 1)




More information about the Submit mailing list