summaryrefslogtreecommitdiffstats
path: root/lib/libc/stdio
diff options
context:
space:
mode:
authorfenner <fenner@FreeBSD.org>2001-11-30 06:12:15 +0000
committerfenner <fenner@FreeBSD.org>2001-11-30 06:12:15 +0000
commit5f34351719ae589baa319e74d4a5432cc99775ac (patch)
tree64b30cdc0268a462bfb03bb9181400291f7b96d2 /lib/libc/stdio
parent5dc107c9938a36ea720fe815c81da168e892d4b0 (diff)
downloadFreeBSD-src-5f34351719ae589baa319e74d4a5432cc99775ac.zip
FreeBSD-src-5f34351719ae589baa319e74d4a5432cc99775ac.tar.gz
Implement several of the c99 updates to printf(3):
- New length modifiers: hh, j, t, z. - New flag: '. Note that %'f is not yet implemented. - Use "inf"/"nan" for efg formats, "INF"/"NAN" for EFG formats. - Implemented %q in terms of %ll; if "quad_t" is not "long long" %q will break. Still to do: - %C, %S, %lc, %ls (wide character support) - %'f (thousands in integer portion of %f) - %a/%A (exact hex representation of floating-point numbers) Garrett Wollman wrote the first version of the vfprintf.c update; Mike Barcroft wrote the first version of the printf.3 changes.
Diffstat (limited to 'lib/libc/stdio')
-rw-r--r--lib/libc/stdio/printf.3321
-rw-r--r--lib/libc/stdio/vfprintf.c348
2 files changed, 458 insertions, 211 deletions
diff --git a/lib/libc/stdio/printf.3 b/lib/libc/stdio/printf.3
index 784bb77..d9cbd95 100644
--- a/lib/libc/stdio/printf.3
+++ b/lib/libc/stdio/printf.3
@@ -36,7 +36,7 @@
.\" @(#)printf.3 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
-.Dd June 4, 1993
+.Dd November 8, 2001
.Dt PRINTF 3
.Os
.Sh NAME
@@ -191,12 +191,9 @@ If unaccessed arguments in the format string are interspersed with ones that
are accessed the results will be indeterminate.
.It
Zero or more of the following flags:
-.Bl -hyphen
-.It
-A
-.Cm #
-character
-specifying that the value should be converted to an
+.Bl -tag -width ".So \&\ \& Sc (space)" -compact -offset indent
+.It Sq Cm #
+The value should be converted to an
.Dq alternate form .
For
.Cm c , d , i , n , p , s ,
@@ -220,7 +217,7 @@ for
.Cm X
conversions) prepended to it.
For
-.Cm e , E , f , g ,
+.Cm a , A , e , E , f , F , g ,
and
.Cm G
conversions, the result will always contain a decimal point, even if no
@@ -232,11 +229,8 @@ and
.Cm G
conversions, trailing zeros are not removed from the result as they
would otherwise be.
-.It
-A
-.Cm 0
-(zero)
-character specifying zero padding.
+.It So Cm 0 Sc (zero)
+Zero padding.
For all conversions except
.Cm n ,
the converted value is padded on the left with zeros rather than blanks.
@@ -247,10 +241,9 @@ and
the
.Cm 0
flag is ignored.
-.It
-A negative field width flag
-.Cm \-
-indicates the converted value is to be left adjusted on the field boundary.
+.It Sq Cm \&\-
+A negative field width flag;
+the converted value is to be left adjusted on the field boundary.
Except for
.Cm n
conversions, the converted value is padded on the right with blanks,
@@ -260,20 +253,30 @@ A
overrides a
.Cm 0
if both are given.
-.It
-A space, specifying that a blank should be left before a positive number
+.It So \&\ \& Sc (space)
+A blank should be left before a positive number
produced by a signed conversion
-.Cm ( d , e , E , f , g , G ,
+.Cm ( a , A , d , e , E , f , F , g , G ,
or
.Cm i ) .
-.It
-A
-.Cm +
-character specifying that a sign always be placed before a
+.It Sq Cm +
+A sign must always be placed before a
number produced by a signed conversion.
A
.Cm +
overrides a space if both are used.
+.It Sq Cm '
+Decimal conversions
+.Cm ( d , u ,
+or
+.Cm i )
+or the integral portion of a floating point conversion
+.Cm ( f
+or
+.Cm F )
+should be grouped and separated by thousands using
+the non-monetary seperator returned by
+.Xr localeconv 3 .
.El
.It
An optional decimal digit string specifying a minimum field width.
@@ -292,9 +295,9 @@ This gives the minimum number of digits to appear for
and
.Cm X
conversions, the number of digits to appear after the decimal-point for
-.Cm e , E ,
+.Cm a , A , e , E , f ,
and
-.Cm f
+.Cm F
conversions, the maximum number of significant digits for
.Cm g
and
@@ -304,79 +307,69 @@ string for
.Cm s
conversions.
.It
-The optional character
-.Cm h ,
-specifying that a following
-.Cm d , i , o , u , x ,
+An optional length modifier, that specifies the size of the argument.
+The following length modifiers are valid for the
+.Cm d , i , n , o , u , x ,
or
.Cm X
-conversion corresponds to a
-.Vt short int
-or
-.Vt unsigned short int
-argument, or that a following
-.Cm n
-conversion corresponds to a pointer to a
-.Vt short int
-argument.
-.It
-The optional character
-.Cm l
-(ell) specifying that a following
-.Cm d , i , o , u , x ,
-or
-.Cm X
-conversion applies to a pointer to a
-.Vt long int
-or
-.Vt unsigned long int
-argument, or that a following
-.Cm n
-conversion corresponds to a pointer to a
-.Vt long int
-argument.
-.It
-The optional characters
-.Cm ll
-(ell ell) specifying that a following
-.Cm d , i , o , u , x ,
-or
-.Cm X
-conversion applies to a pointer to a
-.Vt long long int
-or
-.Vt unsigned long long int
-argument, or that a following
-.Cm n
-conversion corresponds to a pointer to a
-.Vt long long int
-argument.
-.It
-The optional character
-.Cm q ,
-specifying that a following
-.Cm d , i , o , u , x ,
+conversion:
+.Bl -column ".Cm q Em (deprecated)" ".Vt signed char" ".Vt unsigned long long" ".Vt unsigned long long *"
+.It Sy Modifier Ta Cm d , i Ta Cm o , u , x , X Ta Cm n
+.It Cm hh Ta Vt signed char Ta Vt unsigned char Ta Vt signed char *
+.It Cm h Ta Vt short Ta Vt unsigned short Ta Vt short *
+.It Cm l No (ell) Ta Vt long Ta Vt unsigned long Ta Vt long *
+.It Cm ll No (ell ell) Ta Vt long long Ta Vt unsigned long long Ta Vt long long *
+.It Cm j Ta Vt intmax_t Ta Vt uintmax_t Ta Vt intmax_t *
+.It Cm t Ta Vt ptrdiff_t Ta Sy * Ta Vt ptrdiff_t *
+.It Cm z Ta Sy * Ta Vt size_t Ta Sy *
+.It Cm q Em (deprecated) Ta Vt quad_t Ta Vt u_quad_t Ta Vt quad_t *
+.El
+.Pp
+.Bl -tag -width ".Cm * No -"
+.It Cm * No -
+The
+.Cm t
+modifier, when applied to a
+.Cm o , u , x ,
or
.Cm X
-conversion corresponds to a
-.Vt quad int
-or
-.Vt unsigned quad int
-argument, or that a following
+conversion, indicates that the argument is of an unsigned type
+equivalent in size to a
+.Vt ptrdiff_t .
+The
+.Cm z
+modifier, when applied to a
+.Cm d or
+.Cm i
+conversion, indicates that the argument is of a signed type equivalent in
+size to a
+.Vt size_t .
+Similarly, when applied to an
.Cm n
-conversion corresponds to a pointer to a
-.Vt quad int
-argument.
-.It
-The character
-.Cm L
-specifying that a following
-.Cm e , E , f , g ,
+conversion, it indicates that the argument is a pointer to a signed type
+equivalent in size to a
+.Vt size_t .
+.El
+.Pp
+The following length modifier is valid for the
+.Cm a , A , e , E , f , F , g ,
or
.Cm G
-conversion corresponds to a
-.Vt long double
-argument.
+conversion:
+.Bl -column ".Sy Modifier" ".Cm a , A , e , E , f , F , g , G"
+.It Sy Modifier Ta Cm a , A , e , E , f , F , g , G
+.It Cm L Ta Vt long double
+.El
+.Pp
+The following length modifier is valid for the
+.Cm c
+or
+.Cm s
+conversion:
+.Bl -column ".Sy Modifier" ".Vt wint_t" ".Vt wchar_t *"
+.It Sy Modifier Ta Cm c Ta Cm s
+.It Cm l No (ell) Ta Vt wint_t Ta Vt wchar_t *
+.El
.It
A character that specifies the type of conversion to be applied.
.El
@@ -457,7 +450,26 @@ conversion uses the letter
to introduce the exponent.
The exponent always contains at least two digits; if the value is zero,
the exponent is 00.
-.It Cm f
+.Pp
+For
+.Cm a , A , e , E , f , F , g ,
+and
+.Cm G
+conversions, positive and negative infinity are represented as
+.Li inf
+and
+.Li -inf
+respectively when using the lowercase conversion character, and
+.Li INF
+and
+.Li -INF
+respectively when using the uppercase conversion character.
+Similarly, NaN is represented as
+.Li nan
+when using the lowercase conversion, and
+.Li NAN
+when using the uppercase conversion.
+.It Cm fF
The
.Vt double
argument is rounded and converted to decimal notation in the style
@@ -475,6 +487,8 @@ argument is converted in style
or
.Cm e
(or
+.Cm F
+or
.Cm E
for
.Cm G
@@ -488,12 +502,74 @@ is used if the exponent from its conversion is less than -4 or greater than
or equal to the precision.
Trailing zeros are removed from the fractional part of the result; a
decimal point appears only if it is followed by at least one digit.
+.It Cm aA
+The
+.Vt double
+argument is converted to hexadecimal notation in the style
+.Oo \- Oc Ns 0xh Ns Cm \&. Ns hhhp Ns Oo +- Oc Ns d ,
+where the number of digits after the hexadecimal-point character
+is equal to the precision specification.
+If the precision is missing, it is taken as enough to exactly
+represent the floating-point number; if the precision is
+explicitly zero, no hexadecimal-point character appears.
+This is an exact coversion of the mantissa+exponent internal
+floating point representation; the
+.Oo \- Oc Ns 0xh Ns Cm \&. Ns hhh
+portion represents exactly the mantissa; only denormalized
+mantissas have a zero value to the left of the hexadecimal
+point.
+The
+.Cm p
+is a literal character
+.Qq p ;
+the exponent is preceded by a positive or negative sign
+and is represented in decimal, using only enough characters
+to represent the exponent.
+The
+.Cm A
+conversion uses the prefix
+.Cm 0X
+(rather than
+.Cm 0x ) ,
+the letters
+.Cm ABCDEF
+(rather than
+.Cm abcdef )
+to represent the hex digits, and the letter
+.Cm P
+(rather than
+.Cm p )
+to seperate the mantissa and exponent.
+
+.It Cm C
+Treated as
+.Cm c
+with the
+.Cm l
+(ell) modifier.
.It Cm c
The
.Vt int
argument is converted to an
.Vt unsigned char ,
and the resulting character is written.
+.Pp
+If the
+.Cm l
+(ell) modifier is used, the
+.Vt wint_t
+argument shall be converted to a
+.Vt wchar_t ,
+and the (potentially multi-byte) sequence representing the
+single wide character is written, including any shift sequences.
+If a shift sequence is used, the shift state is also restored
+to the original state after the character.
+.It Cm S
+Treated as
+.Cm s
+with the
+.Cm l
+(ell) modifier.
.It Cm s
The
.Vt char *
@@ -510,6 +586,30 @@ need be present; if the precision is not specified, or is greater than
the size of the array, the array must contain a terminating
.Dv NUL
character.
+.Pp
+If the
+.Cm l
+(ell) modifier is used, the
+.Vt wchar_t *
+argument is expected to be a pointer to an array of wide characters
+(pointer to a wide string).
+For each wide character in the string, the (potentially multi-byte)
+sequence representing the
+wide character is written, including any shift sequences.
+If any shift sequence is used, the shift state is also restored
+to the original state after the string.
+Wide characters from the array are written up to (but not including)
+a terminating wide
+.Dv NUL
+character;
+if a precision is specified, no more than the number of bytes specified are
+written (including shift sequences). Partial characters are never written.
+If a precision is given, no null character
+need be present; if the precision is not specified, or is greater than
+the number of bytes required to render the multibyte representation of
+the string, the array must contain a terminating wide
+.Dv NUL
+character.
.It Cm p
The
.Vt void *
@@ -538,7 +638,8 @@ character is defined in the program's locale (category
.Dv LC_NUMERIC ) .
.Pp
In no case does a non-existent or small field width cause truncation of
-a field; if the result of a conversion is wider than the field width, the
+a numeric field; if the result of a conversion is wider than the field
+width, the
field is expanded to contain the conversion result.
.Sh EXAMPLES
To print a date and time in the form
@@ -581,7 +682,8 @@ char *newfmt(const char *fmt, ...)
.Ed
.Sh SEE ALSO
.Xr printf 1 ,
-.Xr scanf 3
+.Xr scanf 3 ,
+.Xr setlocale 3
.Sh STANDARDS
The
.Fn fprintf ,
@@ -675,4 +777,31 @@ for later interpolation by
.Pp
Always use the proper secure idiom:
.Pp
-.Dl snprintf(buffer, sizeof(buffer), "%s", string);
+.Dl snprintf(buffer, sizeof(buffer), \*q%s\*q, string);
+.Pp
+The
+.Nm
+family of functions currently lack the ability to use the
+.Qq '
+flag in conjunction with the
+.Qq f
+conversion specifier. The
+.Qq a
+and
+.Qq A
+conversion specifiers have not yet been implemented.
+The
+.Qq l
+(ell) modifier for the
+.Qq c
+and
+.Qq s
+conversion specifiers, for wide characters and strings, have not yet
+been implemented.
+The
+.Qq L
+modifier for floating point formats simply round the
+.Vt long double
+argument to
+.Vt double ,
+providing no additional precision.
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
index bc0e06e..904fcb0 100644
--- a/lib/libc/stdio/vfprintf.c
+++ b/lib/libc/stdio/vfprintf.c
@@ -51,7 +51,10 @@ static const char rcsid[] =
#include "namespace.h"
#include <sys/types.h>
+#include <ctype.h>
#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -75,26 +78,45 @@ union arg {
u_int uintarg;
long longarg;
u_long ulongarg;
- quad_t quadarg;
- u_quad_t uquadarg;
+ 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;
- quad_t *pquadarg;
+ 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 __P((FILE *, struct __suio *));
static int __sbprintf __P((FILE *, const char *, va_list)) __printflike(2, 0);
-static char * __ultoa __P((u_long, char *, int, int, char *));
-static char * __uqtoa __P((u_quad_t, char *, int, int, char *));
+static char * __ujtoa __P((uintmax_t, char *, int, int, char *, const char *));
+static char * __ultoa __P((u_long, char *, int, int, char *, const char *));
static void __find_arguments __P((const char *, va_list, union arg **));
-static void __grow_type_table __P((int, unsigned char **, int *));
+static void __grow_type_table __P((int, enum typeid **, int *));
/*
* Flush out all the vectors defined by the given uio,
@@ -161,10 +183,12 @@ __sbprintf(FILE *fp, const char *fmt, va_list ap)
* 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,
+ const char *thousep)
{
register char *cp = endp;
register long sval;
+ int ndig;
/*
* Handle the three cases separately, in the hope of getting
@@ -176,6 +200,7 @@ __ultoa(u_long val, char *endp, int base, int octzero, char *xdigs)
*--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
@@ -184,11 +209,16 @@ __ultoa(u_long val, char *endp, int base, int octzero, char *xdigs)
*/
if (val > LONG_MAX) {
*--cp = to_char(val % 10);
+ ndig++;
sval = val / 10;
} else
sval = val;
do {
*--cp = to_char(sval % 10);
+ if (++ndig == 3 && thousep && *thousep != '\0') {
+ *--cp = *thousep;
+ ndig = 0;
+ }
sval /= 10;
} while (sval != 0);
break;
@@ -215,30 +245,39 @@ __ultoa(u_long val, char *endp, int base, int octzero, char *xdigs)
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(uintmax_t val, char *endp, int base, int octzero, char *xdigs,
+ const char *thousep)
{
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,
+ thousep));
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);
+ if (++ndig == 3 && thousep && *thousep != '\0') {
+ *--cp = *thousep;
+ ndig = 0;
+ }
sval /= 10;
} while (sval != 0);
break;
@@ -284,7 +323,7 @@ vfprintf(FILE *fp, const char *fmt0, va_list ap)
#include <math.h>
#include "floatio.h"
-#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
+#define BUF ((MAXEXP*4/3)+MAXFRACT+1) /* + decimal point */
#define DEFPREC 6
static char *cvt __P((double, int, int, char *, int *, int, int *, char **));
@@ -292,7 +331,7 @@ static int exponent __P((char *, int, int));
#else /* no FLOATING_POINT */
-#define BUF 68
+#define BUF 90
#endif /* FLOATING_POINT */
@@ -306,10 +345,16 @@ static int exponent __P((char *, int, int));
#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 */
+ /* C99 additional size modifiers: */
+#define SIZET 0x200 /* size_t */
+#define PTRDIFFT 0x400 /* ptrdiff_t */
+#define INTMAXT 0x800 /* intmax_t */
+#define CHARINT 0x1000 /* print char using int format */
+
/*
* Non-MT-safe version
*/
@@ -326,8 +371,9 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
int width; /* width from format (%8d), or 0 */
int prec; /* precision from format (%.3d), or -1 */
char sign; /* sign prefix (' ', '+', '-', or \0) */
+ const char *thousands_sep;
#ifdef FLOATING_POINT
- char *decimal_point = localeconv()->decimal_point;
+ char *decimal_point;
char softsign; /* temporary negative sign for floats */
double _double; /* double precision arguments %[eEfgG] */
int expt; /* integer value of exponent */
@@ -337,7 +383,7 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
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 */
@@ -347,9 +393,9 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
#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 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 *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 */
@@ -411,11 +457,24 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
#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
@@ -443,8 +502,10 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
}
+ thousands_sep = NULL;
#ifdef FLOATING_POINT
dtoaresult = NULL;
+ decimal_point = localeconv()->decimal_point;
#endif
/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
if (cantwrite(fp))
@@ -520,6 +581,9 @@ reswitch: switch (ch) {
case '+':
sign = '+';
goto rflag;
+ case '\'':
+ thousands_sep = localeconv()->thousands_sep;
+ goto rflag;
case '.':
if ((ch = *fmt++) == '*') {
GETASTER (n);
@@ -565,16 +629,30 @@ reswitch: switch (ch) {
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; /* not necessarily */
+ goto rflag;
+ case 't':
+ flags |= PTRDIFFT;
+ goto rflag;
+ case 'z':
+ flags |= SIZET;
goto rflag;
case 'c':
*(cp = buf) = GETARG(int);
@@ -586,10 +664,10 @@ reswitch: switch (ch) {
/*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 {
@@ -602,9 +680,14 @@ reswitch: switch (ch) {
base = 10;
goto number;
#ifdef FLOATING_POINT
+#ifdef HEXFLOAT
+ case 'a':
+ case 'A':
+#endif
case 'e':
case 'E':
case 'f':
+ case 'F':
goto fp_begin;
case 'g':
case 'G':
@@ -621,12 +704,18 @@ fp_begin: if (prec == -1)
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;
}
@@ -643,13 +732,13 @@ fp_begin: if (prec == -1)
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)
@@ -669,12 +758,25 @@ fp_begin: if (prec == -1)
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 */
@@ -682,8 +784,8 @@ fp_begin: if (prec == -1)
flags |= LONGINT;
/*FALLTHROUGH*/
case 'o':
- if (flags & QUADINT)
- uqval = GETARG(u_quad_t);
+ if (flags & INTMAX_SIZE)
+ ujval = UJARG();
else
ulval = UARG();
base = 8;
@@ -696,10 +798,10 @@ fp_begin: if (prec == -1)
* 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':
@@ -727,8 +829,8 @@ fp_begin: if (prec == -1)
flags |= LONGINT;
/*FALLTHROUGH*/
case 'u':
- if (flags & QUADINT)
- uqval = GETARG(u_quad_t);
+ if (flags & INTMAX_SIZE)
+ ujval = UJARG();
else
ulval = UARG();
base = 10;
@@ -738,14 +840,15 @@ fp_begin: if (prec == -1)
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;
/* unsigned conversions */
@@ -764,14 +867,14 @@ number: if ((dprec = prec) >= 0)
* -- ANSI X3J11
*/
cp = buf + BUF;
- if (flags & QUADINT) {
- if (uqval != 0 || prec != 0)
- cp = __uqtoa(uqval, cp, base,
- flags & ALT, xdigs);
+ if (flags & INTMAX_SIZE) {
+ if (ujval != 0 || prec != 0)
+ cp = __ujtoa(ujval, cp, base,
+ flags & ALT, xdigs, thousands_sep);
} else {
if (ulval != 0 || prec != 0)
cp = __ultoa(ulval, cp, base,
- flags & ALT, xdigs);
+ flags & ALT, xdigs, thousands_sep);
}
size = buf + BUF - cp;
break;
@@ -904,27 +1007,6 @@ error:
}
/*
- * 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.
@@ -939,8 +1021,8 @@ __find_arguments (const char *fmt0, va_list ap, union arg **argtable)
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 */
@@ -955,12 +1037,18 @@ __find_arguments (const char *fmt0, va_list ap, union arg **argtable)
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.
@@ -1011,6 +1099,7 @@ reswitch: switch (ch) {
goto rflag;
case '-':
case '+':
+ case '\'':
goto rflag;
case '.':
if ((ch = *fmt++) == '*') {
@@ -1042,16 +1131,30 @@ reswitch: switch (ch) {
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; /* not necessarily */
+ goto rflag;
+ case 't':
+ flags |= PTRDIFFT;
+ goto rflag;
+ case 'z':
+ flags |= SIZET;
goto rflag;
case 'c':
ADDTYPE(T_INT);
@@ -1061,13 +1164,13 @@ reswitch: switch (ch) {
/*FALLTHROUGH*/
case 'd':
case 'i':
- if (flags & QUADINT) {
- ADDTYPE(T_QUAD);
- } else {
- ADDSARG();
- }
+ ADDSARG();
break;
#ifdef FLOATING_POINT
+#ifdef HEXFLOAT
+ case 'a':
+ case 'A':
+#endif
case 'e':
case 'E':
case 'f':
@@ -1080,12 +1183,20 @@ reswitch: switch (ch) {
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 */
@@ -1093,10 +1204,7 @@ reswitch: switch (ch) {
flags |= LONGINT;
/*FALLTHROUGH*/
case 'o':
- if (flags & QUADINT)
- ADDTYPE(T_U_QUAD);
- else
- ADDUARG();
+ ADDUARG();
break;
case 'p':
ADDTYPE(TP_VOID);
@@ -1108,17 +1216,9 @@ reswitch: switch (ch) {
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();
+ ADDUARG();
break;
default: /* "%?" prints ?, unless ? is NUL */
if (ch == '\0')
@@ -1138,14 +1238,11 @@ done:
(*argtable) [0].intarg = 0;
for (n = 1; n <= tablemax; n++) {
switch (typetable [n]) {
- case T_UNUSED:
- (*argtable) [n].intarg = va_arg (ap, int);
- break;
- case T_SHORT:
+ case T_UNUSED: /* whoops! */
(*argtable) [n].intarg = va_arg (ap, int);
break;
- case T_U_SHORT:
- (*argtable) [n].intarg = va_arg (ap, int);
+ case TP_SCHAR:
+ (*argtable) [n].pschararg = va_arg (ap, signed char *);
break;
case TP_SHORT:
(*argtable) [n].pshortarg = va_arg (ap, short *);
@@ -1168,14 +1265,35 @@ done:
case TP_LONG:
(*argtable) [n].plongarg = va_arg (ap, long *);
break;
- case T_QUAD:
- (*argtable) [n].quadarg = va_arg (ap, quad_t);
+ 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 TP_SIZET:
+ (*argtable) [n].psizearg = va_arg (ap, ssize_t *);
+ break;
+ case T_INTMAXT:
+ (*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
break;
- case T_U_QUAD:
- (*argtable) [n].uquadarg = va_arg (ap, u_quad_t);
+ case T_UINTMAXT:
+ (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
break;
- case TP_QUAD:
- (*argtable) [n].pquadarg = va_arg (ap, quad_t *);
+ case TP_INTMAXT:
+ (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
break;
#ifdef FLOATING_POINT
case T_DOUBLE:
@@ -1202,11 +1320,11 @@ done:
* 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)
OpenPOWER on IntegriCloud