Mail Archives: djgpp-workers/2008/04/24/09:31:10
Implements numeric conversion specifier and provides test programs.
Regards,
Juan M. Guerrero
2008-04-24 Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
Diffs against djgpp CVS head of 2008-04-22.
* src/libc/ansi/stdio/doprnt.c: Implementation of numeric conversion
specifier support. New function __traverse_argument_list added.
* src/libc/ansi/stdio/printf.txh: Description of numeric conversion
specifier for printf added.
* src/docs/kb/wc204.txi: Info about numeric conversion specifier
support for doprnt.c and printf family of functions added.
*tests/libc/ansi/stdio/makefile: Testcase file printf4.c for testing
numeric conversion specifiers added.
* tests/libc/ansi/stdio/printf4.c: New file. Implements tests for
numeric conversion specifiers.
* tests/libc/ansi/stdio/printf5.c: New file. Implements tests for
flags, conversion modifiers and numeric conversion specifiers for
the printf family of functions.
diff -aprNU3 djgpp.orig/src/docs/kb/wc204.txi djgpp/src/docs/kb/wc204.txi
--- djgpp.orig/src/docs/kb/wc204.txi 2008-04-24 15:09:08 +0000
+++ djgpp/src/docs/kb/wc204.txi 2008-04-24 15:13:20 +0000
@@ -1137,3 +1137,9 @@ of @code{Unnormal}.
The @code{a}, @code{A} and @code{F} conversion specifiers
are now supported by @code{_doprnt} and the @code{printf}
family of functions.
+
+@findex _doprnt AT r{, and numeric conversion specifiers}
+@findex printf AT r{, and numeric conversion specifiers}
+The @code{%n$} and @code{*m$} numeric conversion specifiers
+are now supported by @code{_doprnt} and the @code{printf}
+family of functions.
diff -aprNU3 djgpp.orig/src/libc/ansi/stdio/doprnt.c djgpp/src/libc/ansi/stdio/doprnt.c
--- djgpp.orig/src/libc/ansi/stdio/doprnt.c 2008-04-24 15:09:08 +0000
+++ djgpp/src/libc/ansi/stdio/doprnt.c 2008-04-24 15:13:20 +0000
@@ -1,3 +1,4 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
@@ -44,12 +45,12 @@ static char *grouping;
#define PUTC(ch) (void) putc(ch, fp)
-#define ARG(basetype) _ulonglong = \
- flags&LONGDBL ? va_arg(argp, long long basetype) : \
- flags&LONGINT ? va_arg(argp, long basetype) : \
- flags&SHORTINT ? (short basetype)va_arg(argp, int) : \
- flags&CHARINT ? (char basetype)va_arg(argp, int) : \
- (basetype)va_arg(argp, int)
+#define ARG(basetype) _ulonglong = \
+ flags & LONGDBL ? va_arg(argp, long long basetype) : \
+ flags & LONGINT ? va_arg(argp, long basetype) : \
+ flags & SHORTINT ? (short basetype)va_arg(argp, int) : \
+ flags & CHARINT ? (char basetype)va_arg(argp, int) : \
+ (basetype)va_arg(argp, int)
#define CONVERT(type, value, base, string, case) \
do { \
@@ -65,20 +66,20 @@ static char *grouping;
|| ((x).ldt.exponent == 0x0000U && !((x).ldt.mantissah & 0x80000000UL)))
#define IS_ZERO(x) ((x).ldt.exponent == 0x0U && (x).ldt.mantissah == 0x0UL && (x).ldt.mantissal == 0x0UL)
#define IS_NAN(x) ((x).ldt.exponent == 0x7FFFU && ((x).ldt.mantissah & 0x7FFFFFFFUL || (x).ldt.mantissal))
-#define IS_PSEUDO_NUMBER(x) (((x).ldt.exponent != 0x0000U && !((x).ldt.mantissah & 0x80000000UL)) /* Pseudo-NaN, Pseudo-Infinity and Unnormal. */ \
+#define IS_PSEUDO_NUMBER(x) (((x).ldt.exponent != 0x0000U && !((x).ldt.mantissah & 0x80000000UL)) /* Pseudo-NaN, Pseudo-Infinity and Unnormal. */ \
|| ((x).ldt.exponent == 0x0000U && (x).ldt.mantissah & 0x80000000UL)) /* Pseudo-Denormal. */
static __inline__ int todigit(char c)
{
- if (c<='0') return 0;
- if (c>='9') return 9;
+ if (c <= '0') return 0;
+ if (c >= '9') return 9;
return c-'0';
}
static __inline__ char tochar(int n)
{
- if (n>=9) return '9';
- if (n<=0) return '0';
- return n+'0';
+ if (n >= 9) return '9';
+ if (n <= 0) return '0';
+ return n + '0';
}
/* have to deal with the negative buffer count kludge */
@@ -105,6 +106,7 @@ static char *exponentl(char *p, int expv
static int isspeciall(long double d, char *bufp, int flags);
#endif
static __inline__ char * __grouping_format(char *string_start, char *string_end, char *buffer_end, int flags);
+static __inline__ va_list __traverse_argument_list(int index_of_arg_to_be_fetched, const char *format_string, va_list arg_list);
static char NULL_REP[] = "(null)";
static const char LOWER_DIGITS[] = "0123456789abcdef";
@@ -136,6 +138,10 @@ _doprnt(const char *fmt0, va_list argp,
char buf[BUF]; /* space for %c, %[diouxX], %[aAeEfFgG] */
int neg_ldouble = FALSE; /* TRUE if _ldouble is negative */
struct lconv *locale_info; /* current locale information */
+ int using_numeric_conv_spec; /* TRUE if using numeric specifier, FALSE else */
+ va_list arg_list; /* argument list */
+ va_list to_be_printed = NULL; /* argument to be printed if numeric specifier are used */
+ const char *pos; /* position in format string when checking for numeric conv spec */
locale_info = localeconv();
@@ -149,6 +155,8 @@ _doprnt(const char *fmt0, va_list argp,
if ((fp->_flag & _IOWRT) == 0)
return (EOF);
+ using_numeric_conv_spec = FALSE;
+ arg_list = argp;
fmt = fmt0;
for (cnt = 0;; ++fmt)
{
@@ -197,6 +205,16 @@ _doprnt(const char *fmt0, va_list argp,
* -- ANSI X3J11
* They don't exclude field widths read from args.
*/
+ pos = fmt;
+ for (n = 0, fmt++; isascii((unsigned char)*fmt) && isdigit((unsigned char)*fmt); fmt++)
+ n = 10 * n + todigit(*fmt);
+ if (*fmt == '$')
+ {
+ using_numeric_conv_spec = TRUE;
+ argp = __traverse_argument_list(n, fmt0, arg_list);
+ }
+ else
+ fmt = pos;
if ((width = va_arg(argp, int)) >= 0)
goto rflag;
width = -width;
@@ -209,7 +227,19 @@ _doprnt(const char *fmt0, va_list argp,
goto rflag;
case '.':
if (*++fmt == '*')
- n = va_arg(argp, int);
+ {
+ pos = fmt;
+ for (n = 0, fmt++; isascii((unsigned char)*fmt) && isdigit((unsigned char)*fmt); fmt++)
+ n = 10 * n + todigit(*fmt);
+ if (*fmt == '$')
+ {
+ using_numeric_conv_spec = TRUE;
+ argp = __traverse_argument_list(n, fmt0, arg_list);
+ }
+ else
+ fmt = pos;
+ n = va_arg(argp, int);
+ }
else
{
n = 0;
@@ -233,21 +263,30 @@ _doprnt(const char *fmt0, va_list argp,
do {
n = 10 * n + todigit(*fmt);
} while (isascii((unsigned char)*++fmt) && isdigit((unsigned char)*fmt));
- width = n;
- --fmt;
+ if (*fmt == '$')
+ {
+ using_numeric_conv_spec = TRUE;
+ to_be_printed = __traverse_argument_list(n, fmt0, arg_list);
+ }
+ else
+ {
+ width = n;
+ --fmt;
+ }
goto rflag;
case 'L':
flags |= LONGDBL;
goto rflag;
case 'h':
- if (flags & SHORTINT) {
+ if (flags & SHORTINT)
+ {
/* C99 */
/* for 'hh' - char */
flags |= CHARINT;
flags &= ~SHORTINT;
- } else {
- flags |= SHORTINT;
}
+ else
+ flags |= SHORTINT;
goto rflag;
case 'l':
if (flags & LONGINT)
@@ -274,6 +313,8 @@ _doprnt(const char *fmt0, va_list argp,
/*FALLTHROUGH*/
case 'd':
case 'i':
+ if (using_numeric_conv_spec)
+ argp = to_be_printed;
ARG(signed);
if ((long long)_ulonglong < 0)
{
@@ -292,6 +333,8 @@ _doprnt(const char *fmt0, va_list argp,
case 'e':
case 'f':
case 'g':
+ if (using_numeric_conv_spec)
+ argp = to_be_printed;
flags |= FLOAT;
if (*fmt == 'A' || *fmt == 'a')
{
@@ -378,6 +421,8 @@ _doprnt(const char *fmt0, va_list argp,
base = flags & HEXPREFIX ? 16 : 10;
goto pforw;
case 'n':
+ if (using_numeric_conv_spec)
+ argp = to_be_printed;
if (flags & LONGDBL)
*va_arg(argp, long long *) = cnt;
else if (flags & LONGINT)
@@ -393,6 +438,8 @@ _doprnt(const char *fmt0, va_list argp,
flags |= LONGINT;
/*FALLTHROUGH*/
case 'o':
+ if (using_numeric_conv_spec)
+ argp = to_be_printed;
ARG(unsigned);
base = 8;
flags |= FINITENUMBER;
@@ -406,10 +453,14 @@ _doprnt(const char *fmt0, va_list argp,
* -- ANSI X3J11
*/
/* NOSTRICT */
+ if (using_numeric_conv_spec)
+ argp = to_be_printed;
_ulonglong = (unsigned long)va_arg(argp, void *);
base = 16;
goto nosign;
case 's':
+ if (using_numeric_conv_spec)
+ argp = to_be_printed;
if (!(t = va_arg(argp, char *)))
t = NULL_REP;
if (prec >= 0)
@@ -438,6 +489,8 @@ _doprnt(const char *fmt0, va_list argp,
flags |= LONGINT;
/*FALLTHROUGH*/
case 'u':
+ if (using_numeric_conv_spec)
+ argp = to_be_printed;
ARG(unsigned);
base = 10;
flags |= FINITENUMBER;
@@ -446,6 +499,8 @@ _doprnt(const char *fmt0, va_list argp,
flags |= UPPERCASE;
/* FALLTHROUGH */
case 'x':
+ if (using_numeric_conv_spec)
+ argp = to_be_printed;
ARG(unsigned);
base = 16;
flags |= FINITENUMBER;
@@ -1251,3 +1306,158 @@ __grouping_format(char *string_start, ch
return (*dst == thousands_sep) ? dst + 1 : dst; /* Remove leading thousands separator character. */
}
+
+static __inline__ va_list
+__traverse_argument_list(int index_of_arg_to_be_fetched, const char *fmt0, va_list argp)
+{
+ /*
+ * Traverse an argument list until certain position.
+ * The argument list of type va_list is traversed
+ * according to the information extracted from the
+ * format string fmt. It stops at position given by
+ * index_of_arg_to_be_fetched so the next access by
+ * the calling context using va_arg() fetches the
+ * wanted element from the list.
+ */
+
+ const char *fmt = fmt0;
+ int arg_index = 0, prec_index = 0, list_index;
+ int ch, flags, n = index_of_arg_to_be_fetched + 1;
+ unsigned long long _ulonglong; /* discard value retrieved by ARG() */
+
+
+ for (list_index = 1; list_index < n;)
+ {
+ while ((ch = *fmt) && ch != '%')
+ fmt++;
+ if (!ch)
+ {
+ if (list_index < n)
+ fmt = fmt0;
+ else
+ return argp;
+ }
+
+ flags = 0;
+ rflag:
+ switch (*++fmt)
+ {
+ /* Flags */
+ case ' ': case '#': case '\'':
+ case '-': case '+':
+ goto rflag;
+
+ /* Numeric conversion specifier field width and precision: *n$.*m$ */
+ case '*':
+ for (prec_index = 0, fmt++; isascii((unsigned char)*fmt) && isdigit((unsigned char)*fmt); fmt++)
+ prec_index = 10 * prec_index + todigit(*fmt);
+ if (prec_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+ return argp;
+ if (prec_index == list_index)
+ {
+ va_arg(argp, int); /* discard */
+ list_index++;
+ }
+ goto rflag;
+ case '.':
+ if (*++fmt == '*')
+ {
+ for (prec_index = 0, fmt++; isascii((unsigned char)*fmt) && isdigit((unsigned char)*fmt); fmt++)
+ prec_index = 10 * prec_index + todigit(*fmt);
+ if (prec_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+ return argp;
+ if (prec_index == list_index)
+ {
+ va_arg(argp, int); /* discard */
+ list_index++;
+ }
+ }
+ goto rflag;
+
+ /* Numeric conversion specifier %n$ */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ for (arg_index = 0; isascii((unsigned char)*fmt) && isdigit((unsigned char)*fmt); fmt++)
+ arg_index = 10 * arg_index + todigit(*fmt);
+ goto rflag;
+
+ /* Length modifiers */
+ case 'h': case 't': case 'z': /* promoted to int */
+ goto rflag;
+ case 'L': /* a, A, e, E, f, F, g, G applies to long double */
+ flags |= LONGDBL;
+ goto rflag;
+ case 'l':
+ if (flags & LONGINT)
+ flags |= LONGDBL; /* d, i o, u, x, X applies to long long */
+ else
+ flags |= LONGINT; /* d, i o, u, x, X applies to long */
+ goto rflag;
+ case 'j': /* d, i o, u, x, X applies to intmax_t */
+ flags |= LONGDBL; /* long long */
+ goto rflag;
+
+ /* Conversion specifiers */
+ case 'c':
+ if (arg_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+ return argp;
+ if (arg_index == list_index)
+ {
+ va_arg(argp, int); /* discard */
+ list_index++;
+ }
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd': case 'i':
+ if (arg_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+ return argp;
+ if (arg_index == list_index)
+ {
+ ARG(signed); /* discard */
+ list_index++;
+ }
+ break;
+ case 'A': case 'E': case 'F': case 'G':
+ case 'a': case 'e': case 'f': case 'g':
+ if (arg_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+ return argp;
+ if (arg_index == list_index)
+ {
+ if (flags & LONGDBL)
+ va_arg(argp, long double); /* discard */
+ else
+ va_arg(argp, double); /* discard */
+ list_index++;
+ }
+ break;
+ case 'O': case 'U': case 'X':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o': case 'u': case 'x':
+ if (arg_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+ return argp;
+ if (arg_index == list_index)
+ {
+ ARG(unsigned); /* discard */
+ list_index++;
+ }
+ break;
+ case 'n': case 'p': case 's':
+ if (arg_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+ return argp;
+ if (arg_index == list_index)
+ {
+ va_arg(argp, void *); /* discard */
+ list_index++;
+ }
+ break;
+
+ case '\0':
+ return argp;
+ }
+ }
+
+ return argp;
+}
diff -aprNU3 djgpp.orig/src/libc/ansi/stdio/printf.txh djgpp/src/libc/ansi/stdio/printf.txh
--- djgpp.orig/src/libc/ansi/stdio/printf.txh 2008-04-24 15:09:44 +0000
+++ djgpp/src/libc/ansi/stdio/printf.txh 2008-04-24 15:13:20 +0000
@@ -13,8 +13,23 @@ int printf(const char *@var{format}, @do
Sends formatted output from the arguments (@dots{}) to @code{stdout}.
The format string contains regular characters to print, as well as
-conversion specifiers, which begin with a percent symbol. Each
-conversion speficier contains the following fields:
+conversion specifiers, which begin with a percent symbol. Conversions can
+be applied to the nth argument after the format string in the argument list,
+rather than to the next unused argument. In this case, the conversion
+specifier character @code{%} is replaced by the sequence @code{"%n$"}, where
+@code{n} is a decimal integer in the range [@code{1}, @code{number of the last argument}],
+giving the position of the argument in the argument list. The format string
+can contain either numbered argument conversion specifiers (that is, +@code{"%n$"}
+and @code{"*m$"}), or unnumbered argument conversion specifiers (that is @code{%}
+and @code{*}), but not both. The only exception to this is that @code{%%} can
+be mixed with @code{"%n$"} form. When numbered argument specifications are
+used, specifying the Nth argument requires that all the leading arguments,
+from the first to the (N-1)th, are specified in the format string. In format
+strings containing the @code{"%n$"} form of conversion specification, numbered
+arguments in the argument list can be referenced from the format string as many
+times as required.
+
+Each conversion specifier contains the following fields:
@itemize @bullet
@@ -59,6 +74,11 @@ A field width specifier, which specifies
This may also be an asterisk (@code{*}), which means that the actual
width will be obtained from the next argument. If the argument is
negative, it supplies a @code{-} flag and a positive width.
+In format strings containing the @code{"%n$"} form of a conversion
+specifier, a field width can be indicated by the sequence @code{"*m$"},
+where m is a decimal integer in the range [@code{1}, @code{number of the last argument}],
+giving the position in the argument list (after the format argument) of
+an integer argument containing the field width.
@item
@@ -68,6 +88,11 @@ The precision specifies the minimum numb
integer, the number of fraction digits for a floating point number (max
for @code{g} or @code{G}, actual for others), or the maximum number of
characters for a string.
+In format strings containing the @code{"%n$"} form of a conversion
+specifier, a precision can be indicated by the sequence @code{"*m$"},
+where m is a decimal integer in the range [@code{1}, @code{number of the last argument}],
+giving the position in the argument list (after the format argument) of
+an integer argument containing the precision.
@item
@@ -221,3 +246,37 @@ specifiers first appeared in the ANSI C9
@example
printf("%-3d %10.2f%% Percent of %s\n", index, per[index], name[index]);
@end example
+
+The following statement can be used to print date and time
+using language-independent format:
+
+@example
+printf(format, weekday, month, day, hour, precision, min);
+@end example
+
+
+For American usage, the format string could look like:
+
+@example
+"%s, %s %d, %d:%.*d\n"
+@end example
+
+The integer precision has the value 2.
+The above example will produce the following message:
+
+@example
+Sunday, October 27, 9:09
+@end example
+
+
+For German usage, the format string could look like:
+
+@example
+"%1$s, %3$d. %2$s, %4$d:%6$.*5$d\n"
+@end example
+
+The above example will produce the following message:
+
+@example
+Sonntag, 27. Oktober, 9:09
+@end example
diff -aprNU3 djgpp.orig/tests/libc/ansi/stdio/makefile djgpp/tests/libc/ansi/stdio/makefile
--- djgpp.orig/tests/libc/ansi/stdio/makefile 2008-04-24 15:09:08 +0000
+++ djgpp/tests/libc/ansi/stdio/makefile 2008-04-24 15:13:20 +0000
@@ -17,6 +17,7 @@ SRC += mktemp.c
SRC += printf.c
SRC += printf2.c
SRC += printf3.c
+SRC += printf4.c
SRC += sscanf.c
SRC += sscanf2.c
SRC += sscanf3.c
diff -aprNU3 djgpp.orig/tests/libc/ansi/stdio/printf4.c djgpp/tests/libc/ansi/stdio/printf4.c
--- djgpp.orig/tests/libc/ansi/stdio/printf4.c 1970-01-01 00:00:00 +0000
+++ djgpp/tests/libc/ansi/stdio/printf4.c 2008-04-24 14:33:00 +0000
@@ -0,0 +1,66 @@
+/*
+ * printf4.c
+ * Test cases for numeric conversion specifiers.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <libc/unconst.h>
+
+int main(void)
+{
+ int i, width, precision;
+ double darg[] = {1.1, 2.2, 3.3};
+ const char *title[] = {"En castellano:", "Auf deutsch:", "In english:"};
+ const char *format[] = {
+ "%5$s, %2$d de %1$s, %3$*6$.*7$d:%4$*6$.*7$d\n",
+ "%5$s, %2$d. %1$s, %3$*6$.*7$d:%4$*6$.*7$d\n",
+ "%5$s, %1$s %2$d, %3$*6$.*7$d:%4$*6$.*7$d\n"
+ };
+ const char *weekday[] = {"Sabado", "Samstag", "Saturday"};
+ const char *month[] = {"febrero", "Februar", "february"};
+ int day = 2;
+ int hour = 12;
+ int min = 34;
+
+
+ printf("Testing numeric conversion specifiers.\n"
+ "======================================\n");
+
+ width = 10;
+ precision = 1;
+ printf("Printing a sequence of numbers using a given field width and precision\n"
+ "accessing the variables a multiple times in different order.\n"
+ "The sequence of arguments after the format string is:\n"
+ " width, precision, darg[0], darg[1], darg[2]\n"
+ "with the values:\n"
+ " width: %d\n"
+ " precision: %d\n"
+ " darg[0]: %f\n"
+ " darg[1]: %f\n"
+ " darg[2]: %f\n",
+ width, precision, darg[0], darg[1], darg[2]);
+ printf("Format string: \"%%3$-*1$.*2$f###%%4$*1$.*2$f###%%5$*1$.*2$f\" <%3$-*1$.*2$f###%4$*1$.*2$f###%5$*1$.*2$f>\n"
+ "Printing again but accessing the arguments in inverse order:\n"
+ "Format string: \"%%5$-*1$.*2$f###%%4$*1$.*2$f###%%3$*1$.*2$f\" <%5$-*1$.*2$f###%4$*1$.*2$f###%3$*1$.*2$f>\n\n\n",
+ width, precision, darg[0], darg[1], darg[2]);
+
+
+
+ width = 2;
+ precision = 2;
+ printf("Printing Language-Independent Date and Time.\n\n");
+ for (i = 0; i < 3; i++)
+ {
+ char *fmt;
+ int len = strlen(format[i]);
+ printf("%s ", title[i]);
+ printf(format[i], month[i], day, hour, min, weekday[i], width, precision);
+ fmt = unconst((&format[i][--len]), char *);
+ *fmt = '\0';
+ printf("Produced with:\n"
+ " printf(\"%1$s\\n\", month[%2$i], day, hour, min, weekday[%2$i], width, precision);\n\n",
+ format[i], i);
+ }
+ return 0;
+}
diff -aprNU3 djgpp.orig/tests/libc/ansi/stdio/printf5.c djgpp/tests/libc/ansi/stdio/printf5.c
--- djgpp.orig/tests/libc/ansi/stdio/printf5.c 1970-01-01 00:00:00 +0000
+++ djgpp/tests/libc/ansi/stdio/printf5.c 2008-04-24 15:06:16 +0000
@@ -0,0 +1,839 @@
+/*
+ * This program test flags, conversion modifiers and conversion specifiers
+ * of the printf familiy of function. During compilation some warnings
+ * will be generated, this is part of the test and is intentional. Thus
+ * the program can not be compiled with the stock makefile because this
+ * stops at warnings. You must manually compile the program taking care
+ * that the library to be tested is used when linking.
+ */
+
+#include <stdio.h>
+#include <float.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <libc/ieee.h>
+
+
+void flags_test(FILE *out)
+{
+ fprintf(out, "Testing all flags.\n"
+ "==================\n");
+ fprintf(out, "Flag: \"'\"\n"
+ " The integer portion of the result of a decimal conversion (%%i, %%d, %%u, %%f,\n"
+ " %%F, %%g, or %%G) shall be formatted with thousands' grouping characters.\n"
+ " For other conversions the behavior is undefined. The non-monetary grouping\n"
+ " character is used.\n"
+ "arg: %d format string: \"%%'d\" <%'d>\n"
+ "arg: %d format string: \"%%'i\" <%'i>\n"
+ "arg: %d format string: \"%%'u\" <%'u>\n"
+ "arg: %.1f format string: \"%%'f\" <%'f>\n"
+ "arg: %.1f format string: \"%%'F\" <%'F>\n"
+ "arg: %.1f format string: \"%%'g\" <%'g>\n"
+ "arg: %.1f format string: \"%%'G\" <%'G>\n\n",
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0);
+
+
+
+ fprintf(out, "Flag: \"-\"\n"
+ " The result of the conversion shall be left-justified within the field. The\n"
+ " conversion is right-justified if this flag is not specified.\n"
+ "arg: %d format string: \"%%-5d\" <%-5d>\n"
+ "arg: %d format string: \"%%5d\" <%5d>\n"
+ "arg: %d format string: \"%%-5i\" <%-5i>\n"
+ "arg: %d format string: \"%%5i\" <%5i>\n"
+ "arg: %d format string: \"%%-5o\" <%-5o>\n"
+ "arg: %d format string: \"%% 5o\" <%5o>\n"
+ "arg: %d format string: \"%%-5u\" <%-5u>\n"
+ "arg: %d format string: \"%%5u\" <%5u>\n"
+ "arg: %d format string: \"%%-5x\" <%-5x>\n"
+ "arg: %d format string: \"%%5X\" <%5X>\n"
+ "arg: %.1f format string: \"%%-10a\" <%-10a>\n"
+ "arg: %.1f format string: \"%%10A\" <%10A>\n"
+ "arg: %.1f format string: \"%%-15e\" <%-15e>\n"
+ "arg: %.1f format string: \"%%15E\" <%15E>\n"
+ "arg: %.1f format string: \"%%-10f\" <%-10f>\n"
+ "arg: %.1f format string: \"%%10F\" <%10F>\n"
+ "arg: %.1f format string: \"%%-10g\" <%-10g>\n"
+ "arg: %.1f format string: \"%%10G\" <%10G>\n\n",
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 10, 10,
+ 15, 15,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0);
+
+
+
+ fprintf(out, "Flag: \"+\"\n"
+ " The result of a signed conversion shall always begin with a sign ('+' or\n"
+ " '-'). The conversion shall begin with a sign only when a negative value\n"
+ " is converted if this flag is not specified.\n"
+ "arg: %d format string: \"%%+d\" <%+d>\n"
+ "arg: %d format string: \"%%i\" <%i>\n"
+ "arg: %d format string: \"%%+o\" <%+o> WARNING: Sign flag used with unsigned magnitude. Flag ignored.\n"
+ "arg: %d format string: \"%%+u\" <%+u> WARNING: Sign flag used with unsigned magnitude. Flag ignored.\n"
+ "arg: %d format string: \"%%+x\" <%+x> WARNING: Sign flag used with unsigned magnitude. Flag ignored.\n"
+ "arg: %d format string: \"%%+X\" <%+X> WARNING: Sign flag used with unsigned magnitude. Flag ignored.\n"
+ "arg: %.1f format string: \"%%+a\" <%+a>\n"
+ "arg: %.1f format string: \"%%A\" <%A>\n"
+ "arg: %.1f format string: \"%%+e\" <%+e>\n"
+ "arg: %.1f format string: \"%%E\" <%E>\n"
+ "arg: %.1f format string: \"%%+f\" <%+f>\n"
+ "arg: %.1f format string: \"%%F\" <%F>\n"
+ "arg: %.1f format string: \"%%+g\" <%+g>\n"
+ "arg: %.1f format string: \"%%G\" <%G>\n\n",
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 10, 10,
+ 15, 15,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0);
+
+
+
+ fprintf(out, "Flag: \"<space>\"\n"
+ " If the first character of a signed conversion is not a sign or if a signed\n"
+ " conversion results in no characters, a <space> shall be prefixed to the\n"
+ " result. This means that if the <space> and '+' flags both appear, the\n"
+ " <space> flag shall be ignored.\n"
+ "arg: %d format string: \"%% i\" <% i>\n"
+ "arg: %d format string: \"%%+ i\" <%+ i> WARNING: Sign and space flags used simultaneously. Space flag ignored.\n"
+ "arg: %d format string: \"%% d\" <% d>\n"
+ "arg: %d format string: \"%% +d\" <% +d> WARNING: Sign and space flags used simultaneously. Space flag ignored.\n"
+ "arg: %d format string: \"%% o\" <% o> WARNING: Space flag used with unsigned magnitude. Flag ignored.\n"
+ "arg: %d format string: \"%%+ o\" <%+ o> WARNING: Sign and space flags used with unsigned magnitude. Flags ignored.\n"
+ "arg: %d format string: \"%% u\" <% u> WARNING: Space flag used with unsigned magnitude. Flag ignored.\n"
+ "arg: %d format string: \"%%+ u\" <%+ u> WARNING: Sign and space flags used with unsigned magnitude. Flags ignored.\n"
+ "arg: %d format string: \"%% x\" <% x> WARNING: Space flag used with unsigned magnitude. Flag ignored.\n"
+ "arg: %d format string: \"%%+ X\" <%+ X> WARNING: Sign and space flags used with unsigned magnitude. Flags ignored.\n"
+ "arg: %.1f format string: \"%% a\" <% a>\n"
+ "arg: %.1f format string: \"%%+ A\" <%+ A> WARNING: Sign and space flags used simultaneously. Space flag ignored.\n"
+ "arg: %.1f format string: \"%% e\" <% e>\n"
+ "arg: %.1f format string: \"%% +E\" <% +E> WARNING: Sign and space flags used simultaneously. Space flag ignored.\n"
+ "arg: %.1f format string: \"%% f\" <% f>\n"
+ "arg: %.1f format string: \"%%+ F\" <%+ F> WARNING: Sign and space flags used simultaneously. Space flag ignored.\n"
+ "arg: %.1f format string: \"%% g\" <% g>\n"
+ "arg: %.1f format string: \"%% +G\" <% +G> WARNING: Sign and space flags used simultaneously. Space flag ignored.\n\n",
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 10, 10,
+ 15, 15,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0);
+
+
+
+ fprintf(out, "Flag: \"#\"\n"
+ " Specifies that the value is to be converted to an alternative form. For o\n"
+ " conversion, it increases the precision (if necessary) to force the first\n"
+ " digit of the result to be zero. For x or X conversion specifiers, a non-\n"
+ " zero result shall have 0x (or 0X) prefixed to it. For a, A, e, E, f, F, g,\n"
+ " and G conversion specifiers, the result shall always contain a radix\n"
+ " character, even if no digits follow the radix character. Without this\n"
+ " flag, a radix character appears in the result of these conversions only if\n"
+ " a digit follows it. For g and G conversion specifiers, trailing zeros\n"
+ " shall not be removed from the result as they normally are. For other\n"
+ " conversion specifiers, the behavior is undefined.\n"
+ "arg: %d format string: \"%%#d\" <%#d> WARNING: # flag used with decimal magnitude. Flag ignored.\n"
+ "arg: %d format string: \"%%#i\" <%#i> WARNING: # flag used with decimal magnitude. Flag ignored.\n"
+ "arg: %d format string: \"%%#u\" <%#u> WARNING: # flag used with decimal magnitude. Flag ignored.\n"
+ "arg: %d format string: \"%%#o\" <%#o>\n"
+ "arg: %d format string: \"%%#o\" <%#o>\n"
+ "arg: %d format string: \"%%#x\" <%#x>\n"
+ "arg: %d format string: \"%%#X\" <%#X>\n"
+ "arg: %.1f format string: \"%%a\" <%a>\n"
+ "arg: %.1f format string: \"%%#A\" <%#A>\n"
+ "arg: %.1f format string: \"%%1.e\" <%1.e>\n"
+ "arg: %.1f format string: \"%%#1.E\" <%#1.E>\n"
+ "arg: %.1f format string: \"%%1.f\" <%1.f>\n"
+ "arg: %.1f format string: \"%%#1.F\" <%#1.F>\n"
+ "arg: %.1f format string: \"%%g\" <%g>\n"
+ "arg: %.1f format string: \"%%#G\" <%#G>\n\n",
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 0, 0,
+ 1, 1,
+ 0, 0,
+ 1.0, 1.0,
+ 0.0, 0.0,
+ 1.0, 1.0,
+ 0.0, 0.0,
+ 1.0, 1.0,
+ 0.0, 0.0,
+ 1.0, 1.0,
+ 0.0, 0.0);
+
+
+
+ fprintf(out, "Flag: \"0\"\n"
+ " For d, i, o, u, x, X, a, A, e, E, f, F, g, and G conversion specifiers,\n"
+ " leading zeros (following any indication of sign or base) are used to pad\n"
+ " to the field width; no space padding is performed. If the '0' and '-'\n"
+ " flags both appear, the '0' flag is ignored. For d, i, o, u, x, and X\n"
+ " conversion specifiers, if a precision is specified, the '0' flag is\n"
+ " ignored. If the '0' and ''' flags both appear, the grouping characters are\n"
+ " inserted before zero padding. For other conversions, the behavior is\n"
+ " undefined.\n"
+ "arg: %d format string: \"%%05d\" <%05d>\n"
+ "arg: %d format string: \"%%-05d\" <%-05d> WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+ "arg: %d format string: \"%%05.d\" <%05.d>\n"
+ "arg: %d format string: \"%%05i\" <%05i>\n"
+ "arg: %d format string: \"%%-05i\" <%-05i> WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+ "arg: %d format string: \"%%05.i\" <%05.i>\n"
+ "arg: %d format string: \"%%05o\" <%05o>\n"
+ "arg: %d format string: \"%%-05o\" <%-05o> WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+ "arg: %d format string: \"%%05.o\" <%05.o>\n"
+ "arg: %d format string: \"%%05u\" <%05u>\n"
+ "arg: %d format string: \"%%-05u\" <%-05u> WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+ "arg: %d format string: \"%%05.u\" <%05.u>\n"
+ "arg: %d format string: \"%%05x\" <%05x>\n"
+ "arg: %d format string: \"%%-05x\" <%-05x> WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+ "arg: %d format string: \"%%05.x\" <%05.x>\n"
+ "arg: %d format string: \"%%05X\" <%05X>\n"
+ "arg: %d format string: \"%%-05X\" <%-05X> WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+ "arg: %d format string: \"%%05.X\" <%05.X>\n"
+ "arg: %.1f format string: \"%%0-10a\" <%0-10a> WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+ "arg: %.1f format string: \"%%0+10A\" <%0+10A>\n"
+ "arg: %.1f format string: \"%%010A\" <%010A>\n"
+ "arg: %.1f format string: \"%%0-15e\" <%0-15e> WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+ "arg: %.1f format string: \"%%0+15E\" <%0+15E>\n"
+ "arg: %.1f format string: \"%%015E\" <%015E>\n"
+ "arg: %.1f format string: \"%%0-10f\" <%0-10f> WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+ "arg: %.1f format string: \"%%0+10F\" <%0+10F>\n"
+ "arg: %.1f format string: \"%%010F\" <%010F>\n"
+ "arg: %.1f format string: \"%%0-10g\" <%0-10g> WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+ "arg: %.1f format string: \"%%0+10G\" <%0+10G>\n"
+ "arg: %.1f format string: \"%%010G\" <%010G>\n\n",
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 10, 10,
+ 10, 10,
+ 10, 10,
+ 15, 15,
+ 15, 15,
+ 15, 15,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 1.0);
+}
+
+
+void length_modifiers_test(FILE *out)
+{
+ char cv, *pcv;
+ short int siv, *psiv;
+ long int liv, *pliv;
+ long long int lliv, *plliv;
+ intmax_t jiv, *pjiv;
+ size_t ziv, *pziv;
+ ptrdiff_t piv, *ppiv;
+ pcv = &cv;
+ psiv = &siv;
+ pliv = &liv;
+ plliv = &lliv;
+ pjiv = &jiv;
+ pziv = &ziv;
+ ppiv = ϖ
+
+
+ fprintf(out, "\n\nTesting all length modifiers.\n"
+ "=============================\n");
+ fprintf(out, "Length modifier: \"hh\"\n"
+ " Specifies that a following d, i, o, u, x, or X conversion\n"
+ " specifier applies to a signed char or unsigned char argument\n"
+ " (the argument will have been promoted according to the integer\n"
+ " promotions, but its value shall be converted to signed char or\n"
+ " unsigned char before printing); or that a following n conversion\n"
+ " specifier applies to a pointer to a signed char argument.\n"
+ "arg: CHAR_MAX format string: \"%%hhd\" <%hhd>\n"
+ "arg: CHAR_MIN format string: \"%%hhi\" <%hhi>\n"
+ "arg: UCHAR_MAX format string: \"%%hho\" <%hho>\n"
+ "arg: UCHAR_MAX format string: \"%%hhu\" <%hhu>\n"
+ "arg: CHAR_MIN format string: \"%%hhx\" <%hhx>\n"
+ "arg: CHAR_MAX format string: \"%%hhX\" <%hhX>\n"
+ "arg: - format string: \"%%hhn\" (pointer to cv)%hhn\n",
+ CHAR_MAX,
+ CHAR_MIN,
+ UCHAR_MAX,
+ UCHAR_MAX ,
+ CHAR_MIN,
+ CHAR_MAX,
+ pcv);
+ fprintf(out, "cv=%i\n\n", *pcv);
+
+
+
+ fprintf(out, "Length modifier: \"h\"\n"
+ " Specifies that a following d, i, o, u, x, or X conversion\n"
+ " specifier applies to a short or unsigned short argument (the\n"
+ " argument will have been promoted according to the integer\n"
+ " promotions, but its value shall be converted to short or\n"
+ " unsigned short before printing); or that a following n\n"
+ " conversion specifier applies to a pointer to a short argument.\n"
+ "arg: SHRT_MAX format string: \"%%hd\" <%hd>\n"
+ "arg: SHRT_MIN format string: \"%%hi\" <%hi>\n"
+ "arg: USHRT_MAX format string: \"%%ho\" <%ho>\n"
+ "arg: USHRT_MAX format string: \"%%hu\" <%hu>\n"
+ "arg: SHRT_MIN format string: \"%%hx\" <%hx>\n"
+ "arg: SHRT_MAX format string: \"%%hX\" <%hX>\n"
+ "arg: - format string: \"%%hn\" (pointer to siv)%hn\n",
+ SHRT_MAX,
+ SHRT_MIN,
+ USHRT_MAX,
+ USHRT_MAX,
+ SHRT_MIN,
+ SHRT_MAX,
+ psiv);
+ fprintf(out, "siv=%i\n\n", *psiv);
+
+
+
+ fprintf(out, "Length modifier: \"l\"\n"
+ " Specifies that a following d, i, o, u, x, or X conversion\n"
+ " specifier applies to a long or unsigned long argument; that a\n"
+ " following n conversion specifier applies to a pointer to a long\n"
+ " argument; that a following c conversion specifier applies to a\n"
+ " wint_t argument; that a following s conversion specifier\n"
+ " applies to a pointer to a wchar_t argument; or has no effect on\n"
+ " a following a, A, e, E, f, F, g, or G conversion specifier.\n"
+ "arg: LONG_MAX format string: \"%%ld\" <%ld>\n"
+ "arg: LONG_MIN format string: \"%%li\" <%li>\n"
+ "arg: ULONG_MAX format string: \"%%lo\" <%lo>\n"
+ "arg: ULONG_MAX format string: \"%%lu\" <%lu>\n"
+ "arg: LONG_MIN format string: \"%%lx\" <%lx>\n"
+ "arg: LONG_MAX format string: \"%%lX\" <%lX>\n"
+ "arg: - format string: \"%%ln\" (pointer to liv)%ln\n"
+ "arg: %.1f format string: \"%%la\" <%la>\n"
+ "arg: %.1f format string: \"%%A\" <%A>\n"
+ "arg: %.1f format string: \"%%le\" <%le>\n"
+ "arg: %.1f format string: \"%%E\" <%E>\n"
+ "arg: %.1f format string: \"%%lf\" <%lf>\n"
+ "arg: %.1f format string: \"%%F\" <%F>\n"
+ "arg: %.1f format string: \"%%lg\" <%lg>\n"
+ "arg: %.1f format string: \"%%G\" <%G>\n",
+ LONG_MAX,
+ LONG_MIN,
+ ULONG_MAX,
+ ULONG_MAX,
+ LONG_MIN,
+ LONG_MAX,
+ pliv,
+ 1.1, 1.1,
+ 1.1, 1.1,
+ 2.2, 2.2,
+ 2.2, 2.2,
+ 3.3, 3.3,
+ 3.3, 3.3,
+ 4.4, 4.4,
+ 4.4, 4.4);
+ fprintf(out, "liv=%li\n\n", *pliv);
+
+
+
+ fprintf(out, "Length modifier: \"ll\"\n"
+ " Specifies that a following d, i, o, u, x, or X conversion\n"
+ " specifier applies to a long long or unsigned long long argument;\n"
+ " or that a following n conversion specifier applies to a pointer\n"
+ " to a long long argument.\n"
+ "arg: LONG_LONG_MAX format string: \"%%lld\" <%lld>\n"
+ "arg: LONG_LONG_MIN format string: \"%%lli\" <%lli>\n"
+ "arg: ULONG_LONG_MAX format string: \"%%llo\" <%llo>\n"
+ "arg: ULONG_LONG_MAX format string: \"%%llu\" <%llu>\n"
+ "arg: LONG_LONG_MIN format string: \"%%llx\" <%llx>\n"
+ "arg: LONG_LONG_MAX format string: \"%%llX\" <%llX>\n"
+ "arg: - format string: \"%%lln\" (pointer to lliv)%lln\n",
+ LONG_LONG_MAX,
+ LONG_LONG_MIN,
+ ULONG_LONG_MAX,
+ ULONG_LONG_MAX,
+ LONG_LONG_MIN,
+ LONG_LONG_MAX,
+ plliv);
+ fprintf(out, "lliv=%lli\n\n", *plliv);
+
+
+
+ fprintf(out, "Length modifier: \"j\"\n"
+ " Specifies that a following d, i, o, u, x, or X conversion\n"
+ " specifier applies to an intmax_t or uintmax_t argument; or that\n"
+ " a following n conversion specifier applies to a pointer to an\n"
+ " intmax_t argument.\n"
+ "arg: LONG_LONG_MAX format string: \"%%jd\" <%jd>\n"
+ "arg: LONG_LONG_MIN format string: \"%%ji\" <%ji>\n"
+ "arg: ULONG_LONG_MAX format string: \"%%jo\" <%jo>\n"
+ "arg: ULONG_LONG_MAX format string: \"%%ju\" <%ju>\n"
+ "arg: LONG_LONG_MIN format string: \"%%jx\" <%jx>\n"
+ "arg: LONG_LONG_MAX format string: \"%%jX\" <%jX>\n"
+ "arg: - format string: \"%%jn\" (pointer to jiv)%jn\n",
+ (intmax_t)LONG_LONG_MAX,
+ (intmax_t)LONG_LONG_MIN,
+ (uintmax_t)ULONG_LONG_MAX,
+ (uintmax_t)ULONG_LONG_MAX,
+ (intmax_t)LONG_LONG_MIN,
+ (intmax_t)LONG_LONG_MAX,
+ pjiv);
+ fprintf(out, "jiv=%ji\n\n", *pjiv);
+
+
+
+ fprintf(out, "Length modifier: \"z\"\n"
+ " Specifies that a following d, i, o, u, x, or X conversion\n"
+ " specifier applies to a size_t or the corresponding signed\n"
+ " integer type argument; or that a following n conversion\n"
+ " specifier applies to a pointer to a signed integer type\n"
+ " corresponding to a size_t argument.\n"
+ "arg: LONG_MAX format string: \"%%zd\" <%zd>\n"
+ "arg: LONG_MIN format string: \"%%zi\" <%zi>\n"
+ "arg: LONG_MAX format string: \"%%zo\" <%zo>\n"
+ "arg: LONG_MAX format string: \"%%zu\" <%zu>\n"
+ "arg: LONG_MIN format string: \"%%zx\" <%zx>\n"
+ "arg: LONG_MAX format string: \"%%zX\" <%zX>\n"
+ "arg: - format string: \"%%zn\" (pointer to ziv)%zn\n",
+ (size_t)LONG_MAX,
+ (size_t)LONG_MIN,
+ (size_t)LONG_MAX,
+ (size_t)LONG_MAX,
+ (size_t)LONG_MIN,
+ (size_t)LONG_MAX,
+ pziv);
+ fprintf(out, "ziv=%zi\n\n", *pziv);
+
+
+
+ fprintf(out, "Length modifier: \"t\"\n"
+ " Specifies that a following d, i, o, u, x, or X conversion\n"
+ " specifier applies to a ptrdiff_t or the corresponding\n"
+ " unsigned type argument; or that a following n conversion\n"
+ " specifier applies to a pointer to a ptrdiff_t argument.\n"
+ "arg: LONG_MAX format string: \"%%td\" <%td>\n"
+ "arg: LONG_MIN format string: \"%%ti\" <%ti>\n"
+ "arg: LONG_MAX format string: \"%%to\" <%to>\n"
+ "arg: ULONG_MAX format string: \"%%tu\" <%tu>\n"
+ "arg: LONG_MIN format string: \"%%tx\" <%tx>\n"
+ "arg: LONG_MAX format string: \"%%tX\" <%tX>\n"
+ "arg: - format string: \"%%tn\" (pointer to piv)%tn\n",
+ (ptrdiff_t)LONG_MAX,
+ (ptrdiff_t)LONG_MIN,
+ (ptrdiff_t)LONG_MAX,
+ (ptrdiff_t)ULONG_MAX,
+ (ptrdiff_t)LONG_MIN,
+ (ptrdiff_t)LONG_MAX,
+ ppiv);
+ fprintf(out, "piv=%ti\n\n", *ppiv);
+
+
+
+ fprintf(out, "Length modifier: \"L\"\n"
+ "---------1---------2---------3---------4---------5---------6---------7---------8\n"
+ " Specifies that a following a, A, e, E, f, F, g, or G conversion\n"
+ " specifier applies to a long double argument.\n"
+ "arg: LDBL_MAX format string: \"%%La\" <%La>\n"
+ "arg: LDBL_MIN format string: \"%%LA\" <%LA>\n"
+ "arg: LDBL_MAX format string: \"%%Le\" <%Le>\n"
+ "arg: LDBL_MIN format string: \"%%LE\" <%LE>\n"
+ "arg: LDBL_MAX format string: \"%%Lf\" <%Lf>\n"
+ "arg: LDBL_MIN format string: \"%%LF\" <%LF>\n"
+ "arg: LDBL_MAX format string: \"%%Lg\" <%Lg>\n"
+ "arg: LDBL_MIN format string: \"%%LG\" <%LG>\n\n",
+ LDBL_MAX,
+ LDBL_MIN,
+ LDBL_MAX,
+ LDBL_MIN,
+ LDBL_MAX,
+ LDBL_MIN,
+ LDBL_MAX,
+ LDBL_MIN);
+}
+
+
+void numeric_conversion_specifiers_test(FILE *out)
+{
+ int i, width, precision;
+ double darg[] = {1.1, 2.2, 3.3};
+ char *title[] = {"En castellano:", "Auf deutsch:", "In english:"};
+ char *format[] = {
+ "%5$s, %2$d de %1$s, %3$*6$.*7$d:%4$*6$.*7$d\n",
+ "%5$s, %2$d. %1$s, %3$*6$.*7$d:%4$*6$.*7$d\n",
+ "%5$s, %1$s %2$d, %3$*6$.*7$d:%4$*6$.*7$d\n"
+ };
+ char *weekday[] = {"Sabado", "Samstag", "Saturday"};
+ char *month[] = {"febrero", "Februar", "february"};
+ int day = 2;
+ int hour = 12;
+ int min = 34;
+
+
+ fprintf(out, "\n\nTesting numeric conversion specifiers.\n"
+ "======================================\n");
+
+ width = 10;
+ precision = 1;
+ fprintf(out, "Printing a sequence of numbers using a given field width and precision\n"
+ "accessing the variables a multiple times in different order.\n"
+ "The sequence of arguments after the format string is:\n"
+ " width, precision, darg[0], darg[1], darg[2]\n"
+ "with the values:\n"
+ " width: %d\n"
+ " precision: %d\n"
+ " darg[0]: %f\n"
+ " darg[1]: %f\n"
+ " darg[2]: %f\n",
+ width, precision, darg[0], darg[1], darg[2]);
+ fprintf(out, "Format string: \"%%3$-*1$.*2$f###%%4$*1$.*2$f###%%5$*1$.*2$f\" <%3$-*1$.*2$f###%4$*1$.*2$f###%5$*1$.*2$f>\n"
+ "Printing again but accessing the arguments in inverse order:\n"
+ "Format string: \"%%5$-*1$.*2$f###%%4$*1$.*2$f###%%3$*1$.*2$f\" <%5$-*1$.*2$f###%4$*1$.*2$f###%3$*1$.*2$f>\n\n\n",
+ width, precision, darg[0], darg[1], darg[2]);
+
+
+ width = 2;
+ precision = 2;
+ fprintf(out, "Printing Language-Independent Date and Time.\n\n");
+ for (i = 0; i < 3; i++)
+ {
+ int len = strlen(format[i]);
+ fprintf(out, "%s ", title[i]);
+ fprintf(out, format[i], month[i], day, hour, min, weekday[i], width, precision);
+ format[i][--len] = '\0';
+ fprintf(out, "Produced with:\n"
+ " printf(\"%1$s\\n\", month[%2$i], day, hour, min, weekday[%2$i], width, precision);\n\n",
+ format[i], i);
+ }
+}
+
+
+void printf_test(FILE *out)
+{
+ char buf[100], *strbuf;
+ union {
+ unsigned int word[3];
+ long double value;
+ } x;
+ int strlng;
+
+
+
+ fprintf(out, "\n\nGeneral test of the printf familiy of functions.\n"
+ "================================================\n");
+
+ fprintf(out, "Infinity.\n");
+ sprintf(buf, "%La", 1.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%La\" arg: 1.0L / 0.0L\n"
+ "Shall return: \"inf\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%LA", -1.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%LA\" arg: -1.0L / 0.0L\n"
+ "Shall return: \"-INF\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%Lf", 1.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%Lf\" arg: 1.0L / 0.0L\n"
+ "Shall return: \"inf\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%LF", -1.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%LF\" arg: -1.0L / 0.0L\n"
+ "Shall return: \"-INF\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%Le", 1.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%Le\" arg: 1.0L / 0.0L\n"
+ "Shall return: \"inf\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%LE", -1.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%LE\" arg: -1.0L / 0.0L\n"
+ "Shall return: \"-INF\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%Lg", 1.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%Lg\" arg: 1.0L / 0.0L\n"
+ "Shall return: \"inf\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%LG", -1.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%LG\" arg: -1.0L / 0.0L\n"
+ "Shall return: \"-INF\" returns: \"%s\"\n\n", buf);
+
+ fprintf(out, "NaN.\n");
+ sprintf(buf, "%La", 0.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%La\" arg: 0.0L / 0.0L\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%LA", -0.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%LA\" arg: -0.0L / 0.0L\n"
+ "Shall return: \"NAN\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%Lf", 0.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%Lf\" arg: 0.0L / 0.0L\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%LF", -0.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%LF\" arg: -0.0L / 0.0L\n"
+ "Shall return: \"NAN\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%Le", 0.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%Le\" arg: 0.0L / 0.0L\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%LE", -0.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%LE\" arg: -0.0L / 0.0L\n"
+ "Shall return: \"NAN\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%Lg", 0.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%Lg\" arg: 0.0L / 0.0L\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", buf);
+ sprintf(buf, "%LG", -0.0L / 0.0L);
+ fprintf(out, "fmt str: \"%%LG\" arg: -0.0L / 0.0L\n"
+ "Shall return: \"NAN\" returns: \"%s\"\n\n", buf);
+
+
+ x.word[2] = 0x7FFF;
+ x.word[1] = 0xC000000C;
+ x.word[0] = 0x10000001;
+ fprintf(out, "Quiet NaN\n");
+ sprintf(buf, "%La", x.value);
+ fprintf(out, "fmt str: \"%%La\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Le", x.value);
+ fprintf(out, "fmt str: \"%%Le\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lf", x.value);
+ fprintf(out, "fmt str: \"%%Lf\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lg", x.value);
+ fprintf(out, "fmt str: \"%%Lg\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+ x.word[2] = 0x7FFF;
+ x.word[1] = 0x80000008;
+ x.word[0] = 0x10000001;
+ fprintf(out, "Signalling NaN\n");
+ sprintf(buf, "%La", x.value);
+ fprintf(out, "fmt str: \"%%La\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Le", x.value);
+ fprintf(out, "fmt str: \"%%Le\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lf", x.value);
+ fprintf(out, "fmt str: \"%%Lf\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lg", x.value);
+ fprintf(out, "fmt str: \"%%Lg\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+ x.word[2] = 0x7FFF;
+ x.word[1] = 0x40000004;
+ x.word[0] = 0x10000001;
+ fprintf(out, "Pseudo-NaN\n");
+ sprintf(buf, "%La", x.value);
+ fprintf(out, "fmt str: \"%%La\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Le", x.value);
+ fprintf(out, "fmt str: \"%%Le\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lf", x.value);
+ fprintf(out, "fmt str: \"%%Lf\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lg", x.value);
+ fprintf(out, "fmt str: \"%%Lg\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+ x.word[2] = 0xFFFF;
+ x.word[1] = 0x00000000;
+ x.word[0] = 0x00000000;
+ fprintf(out, "Pseudo-Infinity\n");
+ sprintf(buf, "%La", x.value);
+ fprintf(out, "fmt str: \"%%La\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Le", x.value);
+ fprintf(out, "fmt str: \"%%Le\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lf", x.value);
+ fprintf(out, "fmt str: \"%%Lf\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lg", x.value);
+ fprintf(out, "fmt str: \"%%Lg\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+ x.word[2] = 0x4004;
+ x.word[1] = 0x00000000;
+ x.word[0] = 0x00000000;
+ fprintf(out, "Pseudo-Zero\n");
+ sprintf(buf, "%La", x.value);
+ fprintf(out, "fmt str: \"%%La\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Le", x.value);
+ fprintf(out, "fmt str: \"%%Le\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lf", x.value);
+ fprintf(out, "fmt str: \"%%Lf\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lg", x.value);
+ fprintf(out, "fmt str: \"%%Lg\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+ x.word[2] = 0x0440;
+ x.word[1] = 0x60000006;
+ x.word[0] = 0x10000001;
+ fprintf(out, "Unnormalized number\n");
+ sprintf(buf, "%La", x.value);
+ fprintf(out, "fmt str: \"%%La\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Le", x.value);
+ fprintf(out, "fmt str: \"%%Le\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lf", x.value);
+ fprintf(out, "fmt str: \"%%Lf\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lg", x.value);
+ fprintf(out, "fmt str: \"%%Lg\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+ x.word[2] = 0x0000;
+ x.word[1] = 0x80000008;
+ x.word[0] = 0x10000001;
+ fprintf(out, "Pseudo-Denormal\n");
+ sprintf(buf, "%La", x.value);
+ fprintf(out, "fmt str: \"%%La\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Le", x.value);
+ fprintf(out, "fmt str: \"%%Le\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lf", x.value);
+ fprintf(out, "fmt str: \"%%Lf\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+ sprintf(buf, "%Lg", x.value);
+ fprintf(out, "fmt str: \"%%Lg\" exp: %#.4x manthi: %#.8x mantlo: %#.8x\n"
+ "Shall return: \"nan\" returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+
+
+ fprintf(out, "Testing asprintf.\n");
+ fprintf(out, "Code line: strlng = asprintf(&strbuf, \"Pi = %%.15Lf\", 3.1415926535897932384626433832795L);\n");
+ strlng = asprintf(&strbuf, "Pi = %.15Lf", 3.1415926535897932384626433832795L);
+ fprintf(out, "Result: strbuf: \"%s\" strlng: %d\n", strbuf, strlng);
+ free(strbuf);
+
+ fprintf(out, "Testing asnprintf.\n");
+ strbuf = NULL;
+ fprintf(out, "Code line: strlng = asnprintf(&strbuf, 0, \"Pi = %%.15Lf\", 3.1415926535897932384626433832795L);\n");
+ strlng = asnprintf(&strbuf, 0, "Pi = %.15Lf", 3.1415926535897932384626433832795L);
+ fprintf(out, "Result: strbuf: %s strlng: %d\n", strbuf, strlng);
+ fprintf(out, "Code line: strlng = asnprintf(&strbuf, 10, \"Pi = %%.15Lf\", 3.1415926535897932384626433832795L);\n");
+ strlng = asnprintf(&strbuf, 10, "Pi = %.15Lf", 3.1415926535897932384626433832795L);
+ fprintf(out, "Result: strbuf: 0x%p strlng: %d\n", strbuf, strlng);
+ fprintf(out, " strbuf: \"%s\" mallocated buffer length is %zd chars long plus 1 nul char\n\n", strbuf, strlen(strbuf));
+ free(strbuf);
+
+ fprintf(out, "Testing flags in combination with Infinity and NaN.\n");
+ fprintf(out, "Code line: sprintf(buf, \"%%0*Lf\", 10, 1.0L / 0.0L);\n");
+ sprintf(buf, "%0*Lf", 10, 1.0L / 0.0L);
+ asprintf(&strbuf, "%*s", (int)strlen(buf), "inf");
+ fprintf(out, "Shall return: <%s> returns: <%s> %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+ free(strbuf);
+ fprintf(out, "Code line: sprintf(buf, \"%%+*Lf\", 10, 1.0L / 0.0L);\n");
+ sprintf(buf, "%+*Lf", 10, 1.0L / 0.0L);
+ asprintf(&strbuf, "%*s", (int)strlen(buf), "+inf");
+ fprintf(out, "Shall return: <%s> returns: <%s> %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+ free(strbuf);
+ fprintf(out, "Code line: sprintf(buf, \"%%-*Lf\", 10, 1.0L / 0.0L);\n");
+ sprintf(buf, "%-*Lf", 10, 1.0L / 0.0L);
+ asprintf(&strbuf, "%*s", (int)strlen(buf), "inf ");
+ fprintf(out, "Shall return: <%s> returns: <%s> %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+ free(strbuf);
+ fprintf(out, "Code line: sprintf(buf, \"%% *Lf\", 10, 1.0L / 0.0L);\n");
+ sprintf(buf, "% *Lf", 10, 1.0L / 0.0L);
+ asprintf(&strbuf, "%*s", (int)strlen(buf), "inf");
+ fprintf(out, "Shall return: <%s> returns: <%s> %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+ free(strbuf);
+ fprintf(out, "Code line: sprintf(buf, \"%%#*Lf\", 10, 1.0L / 0.0L);\n");
+ sprintf(buf, "%#*Lf", 10, 1.0L / 0.0L);
+ asprintf(&strbuf, "%*s", (int)strlen(buf), "inf");
+ fprintf(out, "Shall return: <%s> returns: <%s> %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+ free(strbuf);
+ fprintf(out, "Code line: sprintf(buf, \"%%0*Lf\", 10, 0.0L / 0.0L);\n");
+ sprintf(buf, "%0*Lf", 10, 0.0L / 0.0L);
+ asprintf(&strbuf, "%*s", (int)strlen(buf), "nan");
+ fprintf(out, "Shall return: <%s> returns: <%s> %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+ free(strbuf);
+ fprintf(out, "Code line: sprintf(buf, \"%%+*Lf\", 10, 0.0L / 0.0L);\n");
+ sprintf(buf, "%+*Lf", 10, 0.0L / 0.0L);
+ asprintf(&strbuf, "%*s", (int)strlen(buf), "nan");
+ fprintf(out, "Shall return: <%s> returns: <%s> %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+ free(strbuf);
+ fprintf(out, "Code line: sprintf(buf, \"%%-*Lf\", 10, 0.0L / 0.0L);\n");
+ sprintf(buf, "%-*Lf", 10, 0.0L / 0.0L);
+ asprintf(&strbuf, "%*s", (int)strlen(buf), "nan ");
+ fprintf(out, "Shall return: <%s> returns: <%s> %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+ free(strbuf);
+ fprintf(out, "Code line: sprintf(buf, \"%% *Lf\", 10, 0.0L / 0.0L);\n");
+ sprintf(buf, "% *Lf", 10, 0.0L / 0.0L);
+ asprintf(&strbuf, "%*s", (int)strlen(buf), "nan");
+ fprintf(out, "Shall return: <%s> returns: <%s> %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+ free(strbuf);
+ fprintf(out, "Code line: sprintf(buf, \"%%#*Lf\", 10, 0.0L / 0.0L);\n");
+ sprintf(buf, "%#*Lf", 10, 0.0L / 0.0L);
+ asprintf(&strbuf, "%*s", (int)strlen(buf), "nan");
+ fprintf(out, "Shall return: <%s> returns: <%s> %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+ free(strbuf);
+}
+
+
+int main(void)
+{
+ FILE *out;
+
+ out = fopen("printf5.txt", "w");
+ if (out == NULL)
+ {
+ printf("Can not open test.txt. Test failed.\n");
+ return 1;
+ }
+
+ printf("Testing:\n"
+ " printf family of functions...\n");
+ flags_test(out);
+ length_modifiers_test(out);
+ numeric_conversion_specifiers_test(out);
+ printf_test(out);
+ fclose(out);
+
+ printf("The test output is in printf5.txt\n");
+ return 0;
+}
- Raw text -