summaryrefslogtreecommitdiff
path: root/libc/stdio-common/vfprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/stdio-common/vfprintf.c')
-rw-r--r--libc/stdio-common/vfprintf.c162
1 files changed, 153 insertions, 9 deletions
diff --git a/libc/stdio-common/vfprintf.c b/libc/stdio-common/vfprintf.c
index d1dc1aaf5..0c87be989 100644
--- a/libc/stdio-common/vfprintf.c
+++ b/libc/stdio-common/vfprintf.c
@@ -31,6 +31,12 @@
#include "_itoa.h"
#include <locale/localeinfo.h>
#include <stdio.h>
+#ifdef __STDC_DEC_FP__
+#include <printf_dfp.h>
+#define IFDEF__STDC_DEC_FP__(...) __VA_ARGS__
+#else
+#define IFDEF__STDC_DEC_FP__(...)
+#endif
/* This code is shared between the standard stdio implementation found
in GNU C library and the libio implementation originally found in
@@ -236,8 +242,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
/* '8' */ 8, /* '9' */ 8, 0, 0,
0, 0, 0, 0,
0, /* 'A' */ 26, 0, /* 'C' */ 25,
+#ifdef __STDC_DEC_FP__
+ /* 'D' */ 31, /* 'E' */ 19, /* F */ 19, /* 'G' */ 19,
+ /* 'H' */ 30, /* 'I' */ 29, 0, 0,
+#else
0, /* 'E' */ 19, /* F */ 19, /* 'G' */ 19,
0, /* 'I' */ 29, 0, 0,
+#endif
/* 'L' */ 12, 0, 0, 0,
0, 0, 0, /* 'S' */ 21,
0, 0, 0, 0,
@@ -285,7 +296,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
#define STEP0_3_TABLE \
/* Step 0: at the beginning. */ \
- static JUMP_TABLE_TYPE step0_jumps[30] = \
+ static JUMP_TABLE_TYPE step0_jumps[] = \
{ \
REF (form_unknown), \
REF (flag_space), /* for ' ' */ \
@@ -316,10 +327,14 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
REF (form_floathex), /* for 'A', 'a' */ \
REF (mod_ptrdiff_t), /* for 't' */ \
REF (mod_intmax_t), /* for 'j' */ \
- REF (flag_i18n), /* for 'I' */ \
+ REF (flag_i18n) /* for 'I' */ \
+IFDEF__STDC_DEC_FP__(, \
+ REF (mod_decimal_half), /* for 'H' */ \
+ REF (mod_decimal) /* for 'D' */ \
+) \
}; \
/* Step 1: after processing width. */ \
- static JUMP_TABLE_TYPE step1_jumps[30] = \
+ static JUMP_TABLE_TYPE step1_jumps[] = \
{ \
REF (form_unknown), \
REF (form_unknown), /* for ' ' */ \
@@ -351,9 +366,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
REF (mod_ptrdiff_t), /* for 't' */ \
REF (mod_intmax_t), /* for 'j' */ \
REF (form_unknown) /* for 'I' */ \
+IFDEF__STDC_DEC_FP__(, \
+ REF (mod_decimal_half), /* for 'H' */ \
+ REF (mod_decimal), /* for 'D' */ \
+) \
}; \
/* Step 2: after processing precision. */ \
- static JUMP_TABLE_TYPE step2_jumps[30] = \
+ static JUMP_TABLE_TYPE step2_jumps[] = \
{ \
REF (form_unknown), \
REF (form_unknown), /* for ' ' */ \
@@ -385,9 +404,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
REF (mod_ptrdiff_t), /* for 't' */ \
REF (mod_intmax_t), /* for 'j' */ \
REF (form_unknown) /* for 'I' */ \
+IFDEF__STDC_DEC_FP__(, \
+ REF (mod_decimal_half), /* for 'H' */ \
+ REF (mod_decimal) /* for 'D' */ \
+) \
}; \
/* Step 3a: after processing first 'h' modifier. */ \
- static JUMP_TABLE_TYPE step3a_jumps[30] = \
+ static JUMP_TABLE_TYPE step3a_jumps[] = \
{ \
REF (form_unknown), \
REF (form_unknown), /* for ' ' */ \
@@ -419,9 +442,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
REF (form_unknown), /* for 't' */ \
REF (form_unknown), /* for 'j' */ \
REF (form_unknown) /* for 'I' */ \
+IFDEF__STDC_DEC_FP__(, \
+ REF (form_unknown), /* for 'H' */ \
+ REF (form_unknown) /* for 'D' */ \
+) \
}; \
/* Step 3b: after processing first 'l' modifier. */ \
- static JUMP_TABLE_TYPE step3b_jumps[30] = \
+ static JUMP_TABLE_TYPE step3b_jumps[] = \
{ \
REF (form_unknown), \
REF (form_unknown), /* for ' ' */ \
@@ -453,11 +480,52 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
REF (form_unknown), /* for 't' */ \
REF (form_unknown), /* for 'j' */ \
REF (form_unknown) /* for 'I' */ \
+IFDEF__STDC_DEC_FP__(, \
+ REF (form_unknown), /* for 'H' */ \
+ REF (form_unknown) /* for 'D' */ \
+ }; \
+ /* Some format codes should not be allowed for decimal-float. */ \
+ /* Step 3c: after processing first 'D' modifier. */ \
+ static JUMP_TABLE_TYPE step3c_jumps[] = \
+ { \
+ REF (form_unknown), \
+ REF (form_unknown), /* for ' ' */ \
+ REF (form_unknown), /* for '+' */ \
+ REF (form_unknown), /* for '-' */ \
+ REF (form_unknown), /* for '<hash>' */ \
+ REF (form_unknown), /* for '0' */ \
+ REF (form_unknown), /* for '\'' */ \
+ REF (form_unknown), /* for '*' */ \
+ REF (form_unknown), /* for '1'...'9' */ \
+ REF (form_unknown), /* for '.' */ \
+ REF (form_unknown), /* for 'h' */ \
+ REF (form_unknown), /* for 'l' */ \
+ REF (form_unknown), /* for 'L', 'q' */ \
+ REF (form_unknown), /* for 'z', 'Z' */ \
+ REF (form_percent), /* for '%' */ \
+ REF (form_integer), /* for 'd', 'i' */ \
+ REF (form_unsigned), /* for 'u' */ \
+ REF (form_octal), /* for 'o' */ \
+ REF (form_hexa), /* for 'X', 'x' */ \
+ REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \
+ REF (form_character), /* for 'c' */ \
+ REF (form_string), /* for 's', 'S' */ \
+ REF (form_pointer), /* for 'p' */ \
+ REF (form_number), /* for 'n' */ \
+ REF (form_strerror), /* for 'm' */ \
+ REF (form_wcharacter), /* for 'C' */ \
+ REF (form_floathex), /* for 'A', 'a' */ \
+ REF (form_unknown), /* for 't' */ \
+ REF (form_unknown), /* for 'j' */ \
+ REF (form_unknown), /* for 'I' */ \
+ REF (form_unknown), /* for 'H' */ \
+ REF (mod_decimal_long) /* for 'D' */ \
+) \
}
#define STEP4_TABLE \
/* Step 4: processing format specifier. */ \
- static JUMP_TABLE_TYPE step4_jumps[30] = \
+ static JUMP_TABLE_TYPE step4_jumps[] = \
{ \
REF (form_unknown), \
REF (form_unknown), /* for ' ' */ \
@@ -489,6 +557,10 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
REF (form_unknown), /* for 't' */ \
REF (form_unknown), /* for 'j' */ \
REF (form_unknown) /* for 'I' */ \
+IFDEF__STDC_DEC_FP__(, \
+ REF (form_unknown), /* for 'H' */ \
+ REF (form_unknown) /* for 'D' */ \
+) \
}
@@ -782,14 +854,30 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
.pad = pad, \
.extra = 0, \
.i18n = use_outdigits, \
+IFDEF__STDC_DEC_FP__( .is_decimal = is_decimal, ) \
.wide = sizeof (CHAR_T) != 1 }; \
\
- if (is_long_double) \
+ if (is_long_double IFDEF__STDC_DEC_FP__(&& !is_decimal)) \
the_arg.pa_long_double = va_arg (ap, long double); \
+IFDEF__STDC_DEC_FP__( \
+ else if (is_long_double && is_decimal) \
+ the_arg.pa_decimal128 = va_arg (ap, _Decimal128); \
+ else if (is_short && is_decimal) \
+ /* The specification indicates that _Decimal32 should */ \
+ /* NOT be promoted to _Decimal64 for DFP types. */ \
+ the_arg.pa_decimal32 = va_arg (ap, _Decimal32); \
+ else if (is_decimal && !is_long_double && !is_short) \
+ the_arg.pa_decimal64 = va_arg (ap, _Decimal64); \
+) \
else \
the_arg.pa_double = va_arg (ap, double); \
ptr = (const void *) &the_arg; \
\
+IFDEF__STDC_DEC_FP__( \
+ if (is_decimal) \
+ function_done = __printf_dfp (s, &info, &ptr); \
+ else \
+) \
function_done = __printf_fp (s, &info, &ptr); \
} \
else \
@@ -839,14 +927,28 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
.group = group, \
.pad = pad, \
.extra = 0, \
+IFDEF__STDC_DEC_FP__( .is_decimal = is_decimal, ) \
.wide = sizeof (CHAR_T) != 1 }; \
\
- if (is_long_double) \
+ if (is_long_double IFDEF__STDC_DEC_FP__(&& !is_decimal)) \
the_arg.pa_long_double = va_arg (ap, long double); \
+IFDEF__STDC_DEC_FP__( \
+ else if (is_long_double && is_decimal) \
+ the_arg.pa_decimal128 = va_arg (ap, _Decimal128); \
+ else if (is_short && is_decimal) \
+ the_arg.pa_decimal32 = va_arg (ap, _Decimal32); \
+ else if (is_decimal && !is_long_double && !is_short) \
+ the_arg.pa_decimal64 = va_arg (ap, _Decimal64); \
+) \
else \
the_arg.pa_double = va_arg (ap, double); \
ptr = (const void *) &the_arg; \
\
+IFDEF__STDC_DEC_FP__( \
+ if (is_decimal) \
+ function_done = __printf_dfphex (s, &info, &ptr); \
+ else \
+) \
function_done = __printf_fphex (s, &info, &ptr); \
} \
else \
@@ -855,6 +957,12 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
if (__ldbl_is_dbl) \
fspec->info.is_long_double = 0; \
\
+IFDEF__STDC_DEC_FP__( \
+ /* FIX ME */ \
+ if (is_decimal) \
+ function_done = __printf_dfphex (s, &fspec->info, &ptr); \
+ else \
+) \
function_done = __printf_fphex (s, &fspec->info, &ptr); \
} \
\
@@ -1336,6 +1444,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
int is_short = 0; /* Argument is short int. */
int is_long = 0; /* Argument is long int. */
int is_char = 0; /* Argument is promoted (unsigned) char. */
+#ifdef __STDC_DEC_FP__
+ int is_decimal = 0; /* Argument is decimal floating point. */
+#endif
int width = 0; /* Width of output; 0 means none specified. */
int prec = -1; /* Precision of output; -1 means none specified. */
/* This flag is set by the 'I' modifier and selects the use of the
@@ -1553,6 +1664,31 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
is_long = sizeof (intmax_t) > sizeof (unsigned int);
JUMP (*++f, step4_jumps);
+#ifdef __STDC_DEC_FP__
+ /* Process 'H' modifier. No other modifier is allowed to follow. */
+ LABEL (mod_decimal_half):
+ is_decimal = 1;
+ is_short = 1;
+ JUMP (*++f, step4_jumps);
+
+ /* Process 'D' modifier. There might be another 'D' following. */
+ LABEL (mod_decimal):
+ is_decimal = 1;
+ is_short = 0;
+ is_long = 0;
+ JUMP (*++f, step3c_jumps);
+
+ /* Process 'DD' modifier. */
+ LABEL (mod_decimal_long):
+ /* is_decimal = 0; */
+ is_decimal = 1;
+ is_long_double = 1;
+ JUMP (*++f, step4_jumps);
+
+ /* The previous step3c_jumps or step4_jumps will jump directly
+ * to the LABELs defined in the process_arg macro. */
+#endif
+
/* Process current format. */
while (1)
{
@@ -1730,6 +1866,11 @@ do_positional:
T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
T (PA_FLOAT, pa_double, double); /* Promoted. */
T (PA_DOUBLE, pa_double, double);
+#ifdef __STDC_DEC_FP__
+ T (PA_DECIMAL, pa_decimal32, _Decimal32);
+ T (PA_DECIMAL|PA_FLAG_SHORT, pa_decimal64, _Decimal64);
+ T (PA_DECIMAL|PA_FLAG_LONG_DOUBLE, pa_decimal128, _Decimal128);
+#endif
case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
if (__ldbl_is_dbl)
{
@@ -1792,6 +1933,9 @@ do_positional:
int width = specs[nspecs_done].info.width;
int prec = specs[nspecs_done].info.prec;
int use_outdigits = specs[nspecs_done].info.i18n;
+#ifdef __STDC_DEC_FP__
+ int is_decimal = specs[nspecs_done].info.is_decimal;
+#endif
char pad = specs[nspecs_done].info.pad;
CHAR_T spec = specs[nspecs_done].info.spec;