Back to index

glibc  2.9
vfprintf.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991-2002, 2003, 2004, 2005, 2006, 2007, 2008
00002    Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <ctype.h>
00021 #include <limits.h>
00022 #include <printf.h>
00023 #include <stdarg.h>
00024 #include <stdint.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <errno.h>
00028 #include <wchar.h>
00029 #include <bits/libc-lock.h>
00030 #include <sys/param.h>
00031 #include "_itoa.h"
00032 #include <locale/localeinfo.h>
00033 #include <stdio.h>
00034 
00035 /* This code is shared between the standard stdio implementation found
00036    in GNU C library and the libio implementation originally found in
00037    GNU libg++.
00038 
00039    Beside this it is also shared between the normal and wide character
00040    implementation as defined in ISO/IEC 9899:1990/Amendment 1:1995.  */
00041 
00042 
00043 #include <libioP.h>
00044 #define FILE         _IO_FILE
00045 #undef va_list
00046 #define va_list      _IO_va_list
00047 #undef BUFSIZ
00048 #define BUFSIZ              _IO_BUFSIZ
00049 #define ARGCHECK(S, Format) \
00050   do                                                                 \
00051     {                                                                \
00052       /* Check file argument for consistence.  */                           \
00053       CHECK_FILE (S, -1);                                            \
00054       if (S->_flags & _IO_NO_WRITES)                                        \
00055        {                                                             \
00056          __set_errno (EBADF);                                               \
00057          return -1;                                                  \
00058        }                                                             \
00059       if (Format == NULL)                                            \
00060        {                                                             \
00061          MAYBE_SET_EINVAL;                                           \
00062          return -1;                                                  \
00063        }                                                             \
00064     } while (0)
00065 #define UNBUFFERED_P(S) ((S)->_IO_file_flags & _IO_UNBUFFERED)
00066 
00067 #define done_add(val) \
00068   do {                                                               \
00069     unsigned int _val = val;                                                \
00070     assert ((unsigned int) done < (unsigned int) INT_MAX);                  \
00071     if (__builtin_expect ((unsigned int) INT_MAX - (unsigned int) done             \
00072                        < _val, 0))                                   \
00073       {                                                                     \
00074        done = -1;                                                    \
00075        goto all_done;                                                       \
00076       }                                                                     \
00077     done += _val;                                                    \
00078   } while (0)
00079 
00080 #ifndef COMPILE_WPRINTF
00081 # define vfprintf    _IO_vfprintf_internal
00082 # define CHAR_T             char
00083 # define UCHAR_T     unsigned char
00084 # define INT_T              int
00085 # define L_(Str)     Str
00086 # define ISDIGIT(Ch) ((unsigned int) ((Ch) - '0') < 10)
00087 # define STR_LEN(Str)       strlen (Str)
00088 
00089 # define PUT(F, S, N)       _IO_sputn ((F), (S), (N))
00090 # define PAD(Padchar) \
00091   if (width > 0)                                                     \
00092     done_add (INTUSE(_IO_padn) (s, (Padchar), width))
00093 # define PUTC(C, F)  _IO_putc_unlocked (C, F)
00094 # define ORIENT             if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
00095                        return -1
00096 #else
00097 # define vfprintf    _IO_vfwprintf
00098 # define CHAR_T             wchar_t
00099 /* This is a hack!!!  There should be a type uwchar_t.  */
00100 # define UCHAR_T     unsigned int /* uwchar_t */
00101 # define INT_T              wint_t
00102 # define L_(Str)     L##Str
00103 # define ISDIGIT(Ch) ((unsigned int) ((Ch) - L'0') < 10)
00104 # define STR_LEN(Str)       __wcslen (Str)
00105 
00106 # include "_itowa.h"
00107 
00108 # define PUT(F, S, N)       _IO_sputn ((F), (S), (N))
00109 # define PAD(Padchar) \
00110   if (width > 0)                                                     \
00111     done_add (_IO_wpadn (s, (Padchar), width))
00112 # define PUTC(C, F)  _IO_putwc_unlocked (C, F)
00113 # define ORIENT             if (_IO_fwide (s, 1) != 1) return -1
00114 
00115 # undef _itoa
00116 # define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case)
00117 # define _itoa_word(Val, Buf, Base, Case) _itowa_word (Val, Buf, Base, Case)
00118 # undef EOF
00119 # define EOF WEOF
00120 #endif
00121 
00122 #include "_i18n_number.h"
00123 
00124 /* Include the shared code for parsing the format string.  */
00125 #include "printf-parse.h"
00126 
00127 
00128 #define       outchar(Ch)                                                   \
00129   do                                                                 \
00130     {                                                                \
00131       register const INT_T outc = (Ch);                                     \
00132       if (PUTC (outc, s) == EOF || done == INT_MAX)                         \
00133        {                                                             \
00134          done = -1;                                                  \
00135          goto all_done;                                              \
00136        }                                                             \
00137       ++done;                                                        \
00138     }                                                                \
00139   while (0)
00140 
00141 #define outstring(String, Len)                                              \
00142   do                                                                 \
00143     {                                                                \
00144       assert ((size_t) done <= (size_t) INT_MAX);                           \
00145       if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len)               \
00146          || (size_t) INT_MAX - (size_t) done < (size_t) (Len))              \
00147        {                                                             \
00148          done = -1;                                                  \
00149          goto all_done;                                              \
00150        }                                                             \
00151       done += (Len);                                                 \
00152     }                                                                \
00153   while (0)
00154 
00155 /* For handling long_double and longlong we use the same flag.  If
00156    `long' and `long long' are effectively the same type define it to
00157    zero.  */
00158 #if LONG_MAX == LONG_LONG_MAX
00159 # define is_longlong 0
00160 #else
00161 # define is_longlong is_long_double
00162 #endif
00163 
00164 /* If `long' and `int' is effectively the same type we don't have to
00165    handle `long separately.  */
00166 #if INT_MAX == LONG_MAX
00167 # define is_long_num 0
00168 #else
00169 # define is_long_num is_long
00170 #endif
00171 
00172 
00173 /* Global variables.  */
00174 static const CHAR_T null[] = L_("(null)");
00175 
00176 
00177 /* Helper function to provide temporary buffering for unbuffered streams.  */
00178 static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
00179      __THROW __attribute__ ((noinline)) internal_function;
00180 
00181 /* Handle unknown format specifier.  */
00182 static int printf_unknown (FILE *, const struct printf_info *,
00183                         const void *const *) __THROW;
00184 
00185 /* Group digits of number string.  */
00186 #ifdef COMPILE_WPRINTF
00187 static CHAR_T *group_number (CHAR_T *, CHAR_T *, const char *, wchar_t)
00188      __THROW internal_function;
00189 #else
00190 static CHAR_T *group_number (CHAR_T *, CHAR_T *, const char *, const char *)
00191      __THROW internal_function;
00192 #endif
00193 
00194 
00195 /* The function itself.  */
00196 int
00197 vfprintf (FILE *s, const CHAR_T *format, va_list ap)
00198 {
00199   /* The character used as thousands separator.  */
00200 #ifdef COMPILE_WPRINTF
00201   wchar_t thousands_sep = L'\0';
00202 #else
00203   const char *thousands_sep = NULL;
00204 #endif
00205 
00206   /* The string describing the size of groups of digits.  */
00207   const char *grouping;
00208 
00209   /* Place to accumulate the result.  */
00210   int done;
00211 
00212   /* Current character in format string.  */
00213   const UCHAR_T *f;
00214 
00215   /* End of leading constant string.  */
00216   const UCHAR_T *lead_str_end;
00217 
00218   /* Points to next format specifier.  */
00219   const UCHAR_T *end_of_spec;
00220 
00221   /* Buffer intermediate results.  */
00222   CHAR_T work_buffer[1000];
00223   CHAR_T *workstart = NULL;
00224   CHAR_T *workend;
00225 
00226   /* We have to save the original argument pointer.  */
00227   va_list ap_save;
00228 
00229   /* Count number of specifiers we already processed.  */
00230   int nspecs_done;
00231 
00232   /* For the %m format we may need the current `errno' value.  */
00233   int save_errno = errno;
00234 
00235   /* 1 if format is in read-only memory, -1 if it is in writable memory,
00236      0 if unknown.  */
00237   int readonly_format = 0;
00238 
00239   /* This table maps a character into a number representing a
00240      class.  In each step there is a destination label for each
00241      class.  */
00242   static const int jump_table[] =
00243   {
00244     /* ' ' */  1,            0,            0, /* '#' */  4,
00245               0, /* '%' */ 14,            0, /* '\''*/  6,
00246               0,            0, /* '*' */  7, /* '+' */  2,
00247               0, /* '-' */  3, /* '.' */  9,            0,
00248     /* '0' */  5, /* '1' */  8, /* '2' */  8, /* '3' */  8,
00249     /* '4' */  8, /* '5' */  8, /* '6' */  8, /* '7' */  8,
00250     /* '8' */  8, /* '9' */  8,            0,            0,
00251               0,            0,            0,            0,
00252               0, /* 'A' */ 26,            0, /* 'C' */ 25,
00253               0, /* 'E' */ 19, /* F */   19, /* 'G' */ 19,
00254               0, /* 'I' */ 29,            0,            0,
00255     /* 'L' */ 12,            0,            0,            0,
00256               0,            0,            0, /* 'S' */ 21,
00257               0,            0,            0,            0,
00258     /* 'X' */ 18,            0, /* 'Z' */ 13,            0,
00259               0,            0,            0,            0,
00260               0, /* 'a' */ 26,            0, /* 'c' */ 20,
00261     /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19,
00262     /* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28,            0,
00263     /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17,
00264     /* 'p' */ 22, /* 'q' */ 12,            0, /* 's' */ 21,
00265     /* 't' */ 27, /* 'u' */ 16,            0,            0,
00266     /* 'x' */ 18,            0, /* 'z' */ 13
00267   };
00268 
00269 #define NOT_IN_JUMP_RANGE(Ch) ((Ch) < L_(' ') || (Ch) > L_('z'))
00270 #define CHAR_CLASS(Ch) (jump_table[(INT_T) (Ch) - L_(' ')])
00271 #ifdef SHARED
00272   /* 'int' is enough and it saves some space on 64 bit systems.  */
00273 # define JUMP_TABLE_TYPE const int
00274 # define JUMP(ChExpr, table)                                                \
00275       do                                                             \
00276        {                                                             \
00277          int offset;                                                 \
00278          void *__unbounded ptr;                                      \
00279          spec = (ChExpr);                                            \
00280          offset = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown)             \
00281            : table[CHAR_CLASS (spec)];                                      \
00282          ptr = &&do_form_unknown + offset;                                  \
00283          goto *ptr;                                                  \
00284        }                                                             \
00285       while (0)
00286 #else
00287 # define JUMP_TABLE_TYPE const void *const
00288 # define JUMP(ChExpr, table)                                                \
00289       do                                                             \
00290        {                                                             \
00291          const void *__unbounded ptr;                                       \
00292          spec = (ChExpr);                                            \
00293          ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown)                \
00294            : table[CHAR_CLASS (spec)];                                      \
00295          goto *ptr;                                                  \
00296        }                                                             \
00297       while (0)
00298 #endif
00299 
00300 #define STEP0_3_TABLE                                                       \
00301     /* Step 0: at the beginning.  */                                        \
00302     static JUMP_TABLE_TYPE step0_jumps[30] =                                \
00303     {                                                                \
00304       REF (form_unknown),                                            \
00305       REF (flag_space),            /* for ' ' */                            \
00306       REF (flag_plus),             /* for '+' */                            \
00307       REF (flag_minus),            /* for '-' */                            \
00308       REF (flag_hash),             /* for '<hash>' */                       \
00309       REF (flag_zero),             /* for '0' */                            \
00310       REF (flag_quote),            /* for '\'' */                                  \
00311       REF (width_asterics), /* for '*' */                            \
00312       REF (width),          /* for '1'...'9' */                      \
00313       REF (precision),             /* for '.' */                            \
00314       REF (mod_half),              /* for 'h' */                            \
00315       REF (mod_long),              /* for 'l' */                            \
00316       REF (mod_longlong),   /* for 'L', 'q' */                       \
00317       REF (mod_size_t),            /* for 'z', 'Z' */                       \
00318       REF (form_percent),   /* for '%' */                            \
00319       REF (form_integer),   /* for 'd', 'i' */                       \
00320       REF (form_unsigned),  /* for 'u' */                            \
00321       REF (form_octal),            /* for 'o' */                            \
00322       REF (form_hexa),             /* for 'X', 'x' */                       \
00323       REF (form_float),            /* for 'E', 'e', 'F', 'f', 'G', 'g' */          \
00324       REF (form_character), /* for 'c' */                            \
00325       REF (form_string),    /* for 's', 'S' */                       \
00326       REF (form_pointer),   /* for 'p' */                            \
00327       REF (form_number),    /* for 'n' */                            \
00328       REF (form_strerror),  /* for 'm' */                            \
00329       REF (form_wcharacter),       /* for 'C' */                            \
00330       REF (form_floathex),  /* for 'A', 'a' */                       \
00331       REF (mod_ptrdiff_t),      /* for 't' */                               \
00332       REF (mod_intmax_t),       /* for 'j' */                               \
00333       REF (flag_i18n),              /* for 'I' */                                  \
00334     };                                                               \
00335     /* Step 1: after processing width.  */                                  \
00336     static JUMP_TABLE_TYPE step1_jumps[30] =                                \
00337     {                                                                \
00338       REF (form_unknown),                                            \
00339       REF (form_unknown),   /* for ' ' */                            \
00340       REF (form_unknown),   /* for '+' */                            \
00341       REF (form_unknown),   /* for '-' */                            \
00342       REF (form_unknown),   /* for '<hash>' */                       \
00343       REF (form_unknown),   /* for '0' */                            \
00344       REF (form_unknown),   /* for '\'' */                                  \
00345       REF (form_unknown),   /* for '*' */                            \
00346       REF (form_unknown),   /* for '1'...'9' */                      \
00347       REF (precision),             /* for '.' */                            \
00348       REF (mod_half),              /* for 'h' */                            \
00349       REF (mod_long),              /* for 'l' */                            \
00350       REF (mod_longlong),   /* for 'L', 'q' */                       \
00351       REF (mod_size_t),            /* for 'z', 'Z' */                       \
00352       REF (form_percent),   /* for '%' */                            \
00353       REF (form_integer),   /* for 'd', 'i' */                       \
00354       REF (form_unsigned),  /* for 'u' */                            \
00355       REF (form_octal),            /* for 'o' */                            \
00356       REF (form_hexa),             /* for 'X', 'x' */                       \
00357       REF (form_float),            /* for 'E', 'e', 'F', 'f', 'G', 'g' */          \
00358       REF (form_character), /* for 'c' */                            \
00359       REF (form_string),    /* for 's', 'S' */                       \
00360       REF (form_pointer),   /* for 'p' */                            \
00361       REF (form_number),    /* for 'n' */                            \
00362       REF (form_strerror),  /* for 'm' */                            \
00363       REF (form_wcharacter),       /* for 'C' */                            \
00364       REF (form_floathex),  /* for 'A', 'a' */                       \
00365       REF (mod_ptrdiff_t),      /* for 't' */                               \
00366       REF (mod_intmax_t),       /* for 'j' */                               \
00367       REF (form_unknown)        /* for 'I' */                               \
00368     };                                                               \
00369     /* Step 2: after processing precision.  */                              \
00370     static JUMP_TABLE_TYPE step2_jumps[30] =                                \
00371     {                                                                \
00372       REF (form_unknown),                                            \
00373       REF (form_unknown),   /* for ' ' */                            \
00374       REF (form_unknown),   /* for '+' */                            \
00375       REF (form_unknown),   /* for '-' */                            \
00376       REF (form_unknown),   /* for '<hash>' */                       \
00377       REF (form_unknown),   /* for '0' */                            \
00378       REF (form_unknown),   /* for '\'' */                                  \
00379       REF (form_unknown),   /* for '*' */                            \
00380       REF (form_unknown),   /* for '1'...'9' */                      \
00381       REF (form_unknown),   /* for '.' */                            \
00382       REF (mod_half),              /* for 'h' */                            \
00383       REF (mod_long),              /* for 'l' */                            \
00384       REF (mod_longlong),   /* for 'L', 'q' */                       \
00385       REF (mod_size_t),            /* for 'z', 'Z' */                       \
00386       REF (form_percent),   /* for '%' */                            \
00387       REF (form_integer),   /* for 'd', 'i' */                       \
00388       REF (form_unsigned),  /* for 'u' */                            \
00389       REF (form_octal),            /* for 'o' */                            \
00390       REF (form_hexa),             /* for 'X', 'x' */                       \
00391       REF (form_float),            /* for 'E', 'e', 'F', 'f', 'G', 'g' */          \
00392       REF (form_character), /* for 'c' */                            \
00393       REF (form_string),    /* for 's', 'S' */                       \
00394       REF (form_pointer),   /* for 'p' */                            \
00395       REF (form_number),    /* for 'n' */                            \
00396       REF (form_strerror),  /* for 'm' */                            \
00397       REF (form_wcharacter),       /* for 'C' */                            \
00398       REF (form_floathex),  /* for 'A', 'a' */                       \
00399       REF (mod_ptrdiff_t),      /* for 't' */                               \
00400       REF (mod_intmax_t),       /* for 'j' */                               \
00401       REF (form_unknown)        /* for 'I' */                               \
00402     };                                                               \
00403     /* Step 3a: after processing first 'h' modifier.  */                    \
00404     static JUMP_TABLE_TYPE step3a_jumps[30] =                               \
00405     {                                                                \
00406       REF (form_unknown),                                            \
00407       REF (form_unknown),   /* for ' ' */                            \
00408       REF (form_unknown),   /* for '+' */                            \
00409       REF (form_unknown),   /* for '-' */                            \
00410       REF (form_unknown),   /* for '<hash>' */                       \
00411       REF (form_unknown),   /* for '0' */                            \
00412       REF (form_unknown),   /* for '\'' */                                  \
00413       REF (form_unknown),   /* for '*' */                            \
00414       REF (form_unknown),   /* for '1'...'9' */                      \
00415       REF (form_unknown),   /* for '.' */                            \
00416       REF (mod_halfhalf),   /* for 'h' */                            \
00417       REF (form_unknown),   /* for 'l' */                            \
00418       REF (form_unknown),   /* for 'L', 'q' */                       \
00419       REF (form_unknown),   /* for 'z', 'Z' */                       \
00420       REF (form_percent),   /* for '%' */                            \
00421       REF (form_integer),   /* for 'd', 'i' */                       \
00422       REF (form_unsigned),  /* for 'u' */                            \
00423       REF (form_octal),            /* for 'o' */                            \
00424       REF (form_hexa),             /* for 'X', 'x' */                       \
00425       REF (form_unknown),   /* for 'E', 'e', 'F', 'f', 'G', 'g' */          \
00426       REF (form_unknown),   /* for 'c' */                            \
00427       REF (form_unknown),   /* for 's', 'S' */                       \
00428       REF (form_unknown),   /* for 'p' */                            \
00429       REF (form_number),    /* for 'n' */                            \
00430       REF (form_unknown),   /* for 'm' */                            \
00431       REF (form_unknown),   /* for 'C' */                            \
00432       REF (form_unknown),   /* for 'A', 'a' */                       \
00433       REF (form_unknown),       /* for 't' */                               \
00434       REF (form_unknown),       /* for 'j' */                               \
00435       REF (form_unknown)        /* for 'I' */                               \
00436     };                                                               \
00437     /* Step 3b: after processing first 'l' modifier.  */                    \
00438     static JUMP_TABLE_TYPE step3b_jumps[30] =                               \
00439     {                                                                \
00440       REF (form_unknown),                                            \
00441       REF (form_unknown),   /* for ' ' */                            \
00442       REF (form_unknown),   /* for '+' */                            \
00443       REF (form_unknown),   /* for '-' */                            \
00444       REF (form_unknown),   /* for '<hash>' */                       \
00445       REF (form_unknown),   /* for '0' */                            \
00446       REF (form_unknown),   /* for '\'' */                                  \
00447       REF (form_unknown),   /* for '*' */                            \
00448       REF (form_unknown),   /* for '1'...'9' */                      \
00449       REF (form_unknown),   /* for '.' */                            \
00450       REF (form_unknown),   /* for 'h' */                            \
00451       REF (mod_longlong),   /* for 'l' */                            \
00452       REF (form_unknown),   /* for 'L', 'q' */                       \
00453       REF (form_unknown),   /* for 'z', 'Z' */                       \
00454       REF (form_percent),   /* for '%' */                            \
00455       REF (form_integer),   /* for 'd', 'i' */                       \
00456       REF (form_unsigned),  /* for 'u' */                            \
00457       REF (form_octal),            /* for 'o' */                            \
00458       REF (form_hexa),             /* for 'X', 'x' */                       \
00459       REF (form_float),            /* for 'E', 'e', 'F', 'f', 'G', 'g' */          \
00460       REF (form_character), /* for 'c' */                            \
00461       REF (form_string),    /* for 's', 'S' */                       \
00462       REF (form_pointer),   /* for 'p' */                            \
00463       REF (form_number),    /* for 'n' */                            \
00464       REF (form_strerror),  /* for 'm' */                            \
00465       REF (form_wcharacter),       /* for 'C' */                            \
00466       REF (form_floathex),  /* for 'A', 'a' */                       \
00467       REF (form_unknown),       /* for 't' */                               \
00468       REF (form_unknown),       /* for 'j' */                               \
00469       REF (form_unknown)        /* for 'I' */                               \
00470     }
00471 
00472 #define STEP4_TABLE                                                  \
00473     /* Step 4: processing format specifier.  */                             \
00474     static JUMP_TABLE_TYPE step4_jumps[30] =                                \
00475     {                                                                \
00476       REF (form_unknown),                                            \
00477       REF (form_unknown),   /* for ' ' */                            \
00478       REF (form_unknown),   /* for '+' */                            \
00479       REF (form_unknown),   /* for '-' */                            \
00480       REF (form_unknown),   /* for '<hash>' */                       \
00481       REF (form_unknown),   /* for '0' */                            \
00482       REF (form_unknown),   /* for '\'' */                                  \
00483       REF (form_unknown),   /* for '*' */                            \
00484       REF (form_unknown),   /* for '1'...'9' */                      \
00485       REF (form_unknown),   /* for '.' */                            \
00486       REF (form_unknown),   /* for 'h' */                            \
00487       REF (form_unknown),   /* for 'l' */                            \
00488       REF (form_unknown),   /* for 'L', 'q' */                       \
00489       REF (form_unknown),   /* for 'z', 'Z' */                       \
00490       REF (form_percent),   /* for '%' */                            \
00491       REF (form_integer),   /* for 'd', 'i' */                       \
00492       REF (form_unsigned),  /* for 'u' */                            \
00493       REF (form_octal),            /* for 'o' */                            \
00494       REF (form_hexa),             /* for 'X', 'x' */                       \
00495       REF (form_float),            /* for 'E', 'e', 'F', 'f', 'G', 'g' */          \
00496       REF (form_character), /* for 'c' */                            \
00497       REF (form_string),    /* for 's', 'S' */                       \
00498       REF (form_pointer),   /* for 'p' */                            \
00499       REF (form_number),    /* for 'n' */                            \
00500       REF (form_strerror),  /* for 'm' */                            \
00501       REF (form_wcharacter),       /* for 'C' */                            \
00502       REF (form_floathex),  /* for 'A', 'a' */                       \
00503       REF (form_unknown),       /* for 't' */                               \
00504       REF (form_unknown),       /* for 'j' */                               \
00505       REF (form_unknown)        /* for 'I' */                               \
00506     }
00507 
00508 
00509 #define process_arg(fspec)                                           \
00510       /* Start real work.  We know about all flags and modifiers and        \
00511         now process the wanted format specifier.  */                        \
00512     LABEL (form_percent):                                            \
00513       /* Write a literal "%".  */                                    \
00514       outchar (L_('%'));                                             \
00515       break;                                                         \
00516                                                                      \
00517     LABEL (form_integer):                                            \
00518       /* Signed decimal integer.  */                                        \
00519       base = 10;                                                     \
00520                                                                      \
00521       if (is_longlong)                                                      \
00522        {                                                             \
00523          long long int signed_number;                                       \
00524                                                                      \
00525          if (fspec == NULL)                                          \
00526            signed_number = va_arg (ap, long long int);                      \
00527          else                                                        \
00528            signed_number = args_value[fspec->data_arg].pa_long_long_int;     \
00529                                                                      \
00530          is_negative = signed_number < 0;                            \
00531          number.longlong = is_negative ? (- signed_number) : signed_number;  \
00532                                                                      \
00533          goto LABEL (longlong_number);                                      \
00534        }                                                             \
00535       else                                                           \
00536        {                                                             \
00537          long int signed_number;                                     \
00538                                                                      \
00539          if (fspec == NULL)                                          \
00540            {                                                         \
00541              if (is_long_num)                                               \
00542               signed_number = va_arg (ap, long int);                        \
00543              else if (is_char)                                              \
00544                signed_number = (signed char) va_arg (ap, unsigned int);      \
00545              else if (!is_short)                                     \
00546               signed_number = va_arg (ap, int);                      \
00547              else                                                    \
00548               signed_number = (short int) va_arg (ap, unsigned int);        \
00549            }                                                         \
00550          else                                                        \
00551            if (is_long_num)                                          \
00552              signed_number = args_value[fspec->data_arg].pa_long_int;       \
00553            else if (is_char)                                                \
00554              signed_number = (signed char)                                  \
00555               args_value[fspec->data_arg].pa_u_int;                         \
00556            else if (!is_short)                                              \
00557              signed_number = args_value[fspec->data_arg].pa_int;            \
00558            else                                                      \
00559              signed_number = (short int)                             \
00560               args_value[fspec->data_arg].pa_u_int;                         \
00561                                                                      \
00562          is_negative = signed_number < 0;                            \
00563          number.word = is_negative ? (- signed_number) : signed_number;      \
00564                                                                      \
00565          goto LABEL (number);                                               \
00566        }                                                             \
00567       /* NOTREACHED */                                                      \
00568                                                                      \
00569     LABEL (form_unsigned):                                           \
00570       /* Unsigned decimal integer.  */                                      \
00571       base = 10;                                                     \
00572       goto LABEL (unsigned_number);                                         \
00573       /* NOTREACHED */                                                      \
00574                                                                      \
00575     LABEL (form_octal):                                                     \
00576       /* Unsigned octal integer.  */                                        \
00577       base = 8;                                                             \
00578       goto LABEL (unsigned_number);                                         \
00579       /* NOTREACHED */                                                      \
00580                                                                      \
00581     LABEL (form_hexa):                                                      \
00582       /* Unsigned hexadecimal integer.  */                                  \
00583       base = 16;                                                     \
00584                                                                      \
00585     LABEL (unsigned_number):         /* Unsigned number of base BASE.  */          \
00586                                                                      \
00587       /* ISO specifies the `+' and ` ' flags only for signed                \
00588         conversions.  */                                             \
00589       is_negative = 0;                                                      \
00590       showsign = 0;                                                  \
00591       space = 0;                                                     \
00592                                                                      \
00593       if (is_longlong)                                                      \
00594        {                                                             \
00595          if (fspec == NULL)                                          \
00596            number.longlong = va_arg (ap, unsigned long long int);           \
00597          else                                                        \
00598            number.longlong = args_value[fspec->data_arg].pa_u_long_long_int; \
00599                                                                      \
00600        LABEL (longlong_number):                                      \
00601          if (prec < 0)                                                      \
00602            /* Supply a default precision if none was given.  */             \
00603            prec = 1;                                                 \
00604          else                                                        \
00605            /* We have to take care for the '0' flag.  If a precision        \
00606               is given it must be ignored.  */                              \
00607            pad = L_(' ');                                            \
00608                                                                      \
00609          /* If the precision is 0 and the number is 0 nothing has to        \
00610             be written for the number, except for the 'o' format in         \
00611             alternate form.  */                                      \
00612          if (prec == 0 && number.longlong == 0)                      \
00613            {                                                         \
00614              string = workend;                                              \
00615              if (base == 8 && alt)                                   \
00616               *--string = L_('0');                                   \
00617            }                                                         \
00618          else                                                        \
00619            {                                                         \
00620              /* Put the number in WORK.  */                                 \
00621              string = _itoa (number.longlong, workend, base,                \
00622                            spec == L_('X'));                                \
00623              if (group && grouping)                                         \
00624               string = group_number (string, workend, grouping,             \
00625                                    thousands_sep);                          \
00626                                                                      \
00627              if (use_outdigits && base == 10)                               \
00628               string = _i18n_number_rewrite (string, workend, workend);     \
00629            }                                                         \
00630          /* Simplify further test for num != 0.  */                         \
00631          number.word = number.longlong != 0;                                \
00632        }                                                             \
00633       else                                                           \
00634        {                                                             \
00635          if (fspec == NULL)                                          \
00636            {                                                         \
00637              if (is_long_num)                                               \
00638               number.word = va_arg (ap, unsigned long int);                 \
00639              else if (is_char)                                              \
00640                number.word = (unsigned char) va_arg (ap, unsigned int);      \
00641              else if (!is_short)                                     \
00642               number.word = va_arg (ap, unsigned int);               \
00643              else                                                    \
00644               number.word = (unsigned short int) va_arg (ap, unsigned int); \
00645            }                                                         \
00646          else                                                        \
00647            if (is_long_num)                                          \
00648              number.word = args_value[fspec->data_arg].pa_u_long_int;       \
00649            else if (is_char)                                                \
00650              number.word = (unsigned char)                                  \
00651               args_value[fspec->data_arg].pa_u_int;                         \
00652            else if (!is_short)                                              \
00653              number.word = args_value[fspec->data_arg].pa_u_int;            \
00654            else                                                      \
00655              number.word = (unsigned short int)                      \
00656               args_value[fspec->data_arg].pa_u_int;                         \
00657                                                                      \
00658        LABEL (number):                                                      \
00659          if (prec < 0)                                                      \
00660            /* Supply a default precision if none was given.  */             \
00661            prec = 1;                                                 \
00662          else                                                        \
00663            /* We have to take care for the '0' flag.  If a precision        \
00664               is given it must be ignored.  */                              \
00665            pad = L_(' ');                                            \
00666                                                                      \
00667          /* If the precision is 0 and the number is 0 nothing has to        \
00668             be written for the number, except for the 'o' format in         \
00669             alternate form.  */                                      \
00670          if (prec == 0 && number.word == 0)                                 \
00671            {                                                         \
00672              string = workend;                                              \
00673              if (base == 8 && alt)                                   \
00674               *--string = L_('0');                                   \
00675            }                                                         \
00676          else                                                        \
00677            {                                                         \
00678              /* Put the number in WORK.  */                                 \
00679              string = _itoa_word (number.word, workend, base,               \
00680                                spec == L_('X'));                     \
00681              if (group && grouping)                                         \
00682               string = group_number (string, workend, grouping,             \
00683                                    thousands_sep);                          \
00684                                                                      \
00685              if (use_outdigits && base == 10)                               \
00686               string = _i18n_number_rewrite (string, workend, workend);     \
00687            }                                                         \
00688        }                                                             \
00689                                                                      \
00690       if (prec <= workend - string && number.word != 0 && alt && base == 8)   \
00691        /* Add octal marker.  */                                      \
00692        *--string = L_('0');                                          \
00693                                                                      \
00694       prec = MAX (0, prec - (workend - string));                     \
00695                                                                      \
00696       if (!left)                                                     \
00697        {                                                             \
00698          width -= workend - string + prec;                                  \
00699                                                                      \
00700          if (number.word != 0 && alt && base == 16)                         \
00701            /* Account for 0X hex marker.  */                                \
00702            width -= 2;                                                      \
00703                                                                      \
00704          if (is_negative || showsign || space)                              \
00705            --width;                                                  \
00706                                                                      \
00707          if (pad == L_(' '))                                                \
00708            {                                                         \
00709              PAD (L_(' '));                                          \
00710              width = 0;                                              \
00711            }                                                         \
00712                                                                      \
00713          if (is_negative)                                            \
00714            outchar (L_('-'));                                               \
00715          else if (showsign)                                          \
00716            outchar (L_('+'));                                               \
00717          else if (space)                                             \
00718            outchar (L_(' '));                                               \
00719                                                                      \
00720          if (number.word != 0 && alt && base == 16)                         \
00721            {                                                         \
00722              outchar (L_('0'));                                      \
00723              outchar (spec);                                                \
00724            }                                                         \
00725                                                                      \
00726          width += prec;                                              \
00727          PAD (L_('0'));                                              \
00728                                                                      \
00729          outstring (string, workend - string);                              \
00730                                                                      \
00731          break;                                                      \
00732        }                                                             \
00733       else                                                           \
00734        {                                                             \
00735          if (is_negative)                                            \
00736            {                                                         \
00737              outchar (L_('-'));                                      \
00738              --width;                                                       \
00739            }                                                         \
00740          else if (showsign)                                          \
00741            {                                                         \
00742              outchar (L_('+'));                                      \
00743              --width;                                                       \
00744            }                                                         \
00745          else if (space)                                             \
00746            {                                                         \
00747              outchar (L_(' '));                                      \
00748              --width;                                                       \
00749            }                                                         \
00750                                                                      \
00751          if (number.word != 0 && alt && base == 16)                         \
00752            {                                                         \
00753              outchar (L_('0'));                                      \
00754              outchar (spec);                                                \
00755              width -= 2;                                             \
00756            }                                                         \
00757                                                                      \
00758          width -= workend - string + prec;                                  \
00759                                                                      \
00760          if (prec > 0)                                                      \
00761            {                                                         \
00762              int temp = width;                                              \
00763              width = prec;                                           \
00764              PAD (L_('0'));                                          \
00765              width = temp;                                           \
00766            }                                                         \
00767                                                                      \
00768          outstring (string, workend - string);                              \
00769                                                                      \
00770          PAD (L_(' '));                                              \
00771          break;                                                      \
00772        }                                                             \
00773                                                                      \
00774     LABEL (form_float):                                                     \
00775       {                                                                     \
00776        /* Floating-point number.  This is handled by printf_fp.c.  */       \
00777        const void *ptr;                                              \
00778        int function_done;                                            \
00779                                                                      \
00780        if (fspec == NULL)                                            \
00781          {                                                           \
00782            if (__ldbl_is_dbl)                                               \
00783              is_long_double = 0;                                     \
00784                                                                      \
00785            struct printf_info info = { .prec = prec,                        \
00786                                    .width = width,                          \
00787                                    .spec = spec,                     \
00788                                    .is_long_double = is_long_double,     \
00789                                    .is_short = is_short,                    \
00790                                    .is_long = is_long,               \
00791                                    .alt = alt,                       \
00792                                    .space = space,                          \
00793                                    .left = left,                     \
00794                                    .showsign = showsign,                    \
00795                                    .group = group,                          \
00796                                    .pad = pad,                       \
00797                                    .extra = 0,                       \
00798                                    .i18n = use_outdigits,                   \
00799                                    .wide = sizeof (CHAR_T) != 1 };          \
00800                                                                      \
00801            if (is_long_double)                                              \
00802              the_arg.pa_long_double = va_arg (ap, long double);             \
00803            else                                                      \
00804              the_arg.pa_double = va_arg (ap, double);                       \
00805            ptr = (const void *) &the_arg;                            \
00806                                                                      \
00807            function_done = __printf_fp (s, &info, &ptr);                    \
00808          }                                                           \
00809        else                                                          \
00810          {                                                           \
00811            ptr = (const void *) &args_value[fspec->data_arg];               \
00812            if (__ldbl_is_dbl)                                               \
00813              {                                                              \
00814               fspec->data_arg_type = PA_DOUBLE;                      \
00815               fspec->info.is_long_double = 0;                               \
00816              }                                                              \
00817                                                                      \
00818            function_done = __printf_fp (s, &fspec->info, &ptr);             \
00819          }                                                           \
00820                                                                      \
00821        if (function_done < 0)                                               \
00822          {                                                           \
00823            /* Error in print handler.  */                            \
00824            done = -1;                                                       \
00825            goto all_done;                                            \
00826          }                                                           \
00827                                                                      \
00828        done_add (function_done);                                     \
00829       }                                                                     \
00830       break;                                                         \
00831                                                                      \
00832     LABEL (form_floathex):                                           \
00833       {                                                                     \
00834         /* Floating point number printed as hexadecimal number.  */         \
00835        const void *ptr;                                              \
00836        int function_done;                                            \
00837                                                                      \
00838        if (fspec == NULL)                                            \
00839          {                                                           \
00840            if (__ldbl_is_dbl)                                               \
00841              is_long_double = 0;                                     \
00842                                                                      \
00843            struct printf_info info = { .prec = prec,                        \
00844                                    .width = width,                          \
00845                                    .spec = spec,                     \
00846                                    .is_long_double = is_long_double,     \
00847                                    .is_short = is_short,                    \
00848                                    .is_long = is_long,               \
00849                                    .alt = alt,                       \
00850                                    .space = space,                          \
00851                                    .left = left,                     \
00852                                    .showsign = showsign,                    \
00853                                    .group = group,                          \
00854                                    .pad = pad,                       \
00855                                    .extra = 0,                       \
00856                                    .wide = sizeof (CHAR_T) != 1 };          \
00857                                                                      \
00858            if (is_long_double)                                              \
00859              the_arg.pa_long_double = va_arg (ap, long double);             \
00860            else                                                      \
00861              the_arg.pa_double = va_arg (ap, double);                       \
00862            ptr = (const void *) &the_arg;                            \
00863                                                                      \
00864            function_done = __printf_fphex (s, &info, &ptr);                 \
00865          }                                                           \
00866        else                                                          \
00867          {                                                           \
00868            ptr = (const void *) &args_value[fspec->data_arg];               \
00869            if (__ldbl_is_dbl)                                               \
00870              fspec->info.is_long_double = 0;                                \
00871                                                                      \
00872            function_done = __printf_fphex (s, &fspec->info, &ptr);          \
00873          }                                                           \
00874                                                                      \
00875        if (function_done < 0)                                               \
00876          {                                                           \
00877            /* Error in print handler.  */                            \
00878            done = -1;                                                       \
00879            goto all_done;                                            \
00880          }                                                           \
00881                                                                      \
00882        done_add (function_done);                                     \
00883       }                                                                     \
00884       break;                                                         \
00885                                                                      \
00886     LABEL (form_pointer):                                            \
00887       /* Generic pointer.  */                                               \
00888       {                                                                     \
00889        const void *ptr;                                              \
00890        if (fspec == NULL)                                            \
00891          ptr = va_arg (ap, void *);                                         \
00892        else                                                          \
00893          ptr = args_value[fspec->data_arg].pa_pointer;                      \
00894        if (ptr != NULL)                                              \
00895          {                                                           \
00896            /* If the pointer is not NULL, write it as a %#x spec.  */       \
00897            base = 16;                                                       \
00898            number.word = (unsigned long int) ptr;                           \
00899            is_negative = 0;                                          \
00900            alt = 1;                                                  \
00901            group = 0;                                                       \
00902            spec = L_('x');                                           \
00903            goto LABEL (number);                                      \
00904          }                                                           \
00905        else                                                          \
00906          {                                                           \
00907            /* Write "(nil)" for a nil pointer.  */                          \
00908            string = (CHAR_T *) L_("(nil)");                                 \
00909            /* Make sure the full string "(nil)" is printed.  */             \
00910            if (prec < 5)                                             \
00911              prec = 5;                                                      \
00912            is_long = 0;     /* This is no wide-char string.  */             \
00913            goto LABEL (print_string);                                       \
00914          }                                                           \
00915       }                                                                     \
00916       /* NOTREACHED */                                                      \
00917                                                                      \
00918     LABEL (form_number):                                             \
00919       if (s->_flags2 & _IO_FLAGS2_FORTIFY)                                  \
00920        {                                                             \
00921          if (! readonly_format)                                      \
00922            {                                                         \
00923              extern int __readonly_area (const void *, size_t)              \
00924               attribute_hidden;                                      \
00925              readonly_format                                                \
00926               = __readonly_area (format, ((STR_LEN (format) + 1)            \
00927                                        * sizeof (CHAR_T)));          \
00928            }                                                         \
00929          if (readonly_format < 0)                                    \
00930            __libc_fatal ("*** %n in writable segment detected ***\n");             \
00931        }                                                             \
00932       /* Answer the count of characters written.  */                        \
00933       if (fspec == NULL)                                             \
00934        {                                                             \
00935          if (is_longlong)                                            \
00936            *(long long int *) va_arg (ap, void *) = done;                   \
00937          else if (is_long_num)                                              \
00938            *(long int *) va_arg (ap, void *) = done;                        \
00939          else if (is_char)                                           \
00940            *(char *) va_arg (ap, void *) = done;                     \
00941          else if (!is_short)                                                \
00942            *(int *) va_arg (ap, void *) = done;                      \
00943          else                                                        \
00944            *(short int *) va_arg (ap, void *) = done;                       \
00945        }                                                             \
00946       else                                                           \
00947        if (is_longlong)                                              \
00948          *(long long int *) args_value[fspec->data_arg].pa_pointer = done;   \
00949        else if (is_long_num)                                                \
00950          *(long int *) args_value[fspec->data_arg].pa_pointer = done;       \
00951        else if (is_char)                                             \
00952          *(char *) args_value[fspec->data_arg].pa_pointer = done;           \
00953        else if (!is_short)                                           \
00954          *(int *) args_value[fspec->data_arg].pa_pointer = done;            \
00955        else                                                          \
00956          *(short int *) args_value[fspec->data_arg].pa_pointer = done;             \
00957       break;                                                         \
00958                                                                      \
00959     LABEL (form_strerror):                                           \
00960       /* Print description of error ERRNO.  */                              \
00961       string =                                                              \
00962        (CHAR_T *) __strerror_r (save_errno, (char *) work_buffer,           \
00963                              sizeof work_buffer);                           \
00964       is_long = 0;          /* This is no wide-char string.  */             \
00965       goto LABEL (print_string)
00966 
00967 #ifdef COMPILE_WPRINTF
00968 # define process_string_arg(fspec) \
00969     LABEL (form_character):                                          \
00970       /* Character.  */                                                     \
00971       if (is_long)                                                   \
00972        goto LABEL (form_wcharacter);                                        \
00973       --width;       /* Account for the character itself.  */               \
00974       if (!left)                                                     \
00975        PAD (L' ');                                                   \
00976       if (fspec == NULL)                                             \
00977        outchar (__btowc ((unsigned char) va_arg (ap, int))); /* Promoted. */ \
00978       else                                                           \
00979        outchar (__btowc ((unsigned char)                             \
00980                        args_value[fspec->data_arg].pa_int));                \
00981       if (left)                                                             \
00982        PAD (L' ');                                                   \
00983       break;                                                         \
00984                                                                      \
00985     LABEL (form_wcharacter):                                                \
00986       {                                                                     \
00987        /* Wide character.  */                                               \
00988        --width;                                                      \
00989        if (!left)                                                    \
00990          PAD (L' ');                                                 \
00991         if (fspec == NULL)                                           \
00992          outchar (va_arg (ap, wchar_t));                             \
00993        else                                                          \
00994          outchar (args_value[fspec->data_arg].pa_wchar);                    \
00995        if (left)                                                     \
00996          PAD (L' ');                                                 \
00997       }                                                                     \
00998       break;                                                         \
00999                                                                      \
01000     LABEL (form_string):                                             \
01001       {                                                                     \
01002        size_t len;                                                   \
01003        int string_malloced;                                          \
01004                                                                      \
01005        /* The string argument could in fact be `char *' or `wchar_t *'.      \
01006           But this should not make a difference here.  */                   \
01007        if (fspec == NULL)                                            \
01008          string = (CHAR_T *) va_arg (ap, const wchar_t *);                  \
01009        else                                                          \
01010          string = (CHAR_T *) args_value[fspec->data_arg].pa_wstring;        \
01011                                                                      \
01012        /* Entry point for printing other strings.  */                       \
01013       LABEL (print_string):                                          \
01014                                                                      \
01015        string_malloced = 0;                                          \
01016        if (string == NULL)                                           \
01017          {                                                           \
01018            /* Write "(null)" if there's space.  */                          \
01019            if (prec == -1                                            \
01020               || prec >= (int) (sizeof (null) / sizeof (null[0])) - 1)      \
01021              {                                                              \
01022               string = (CHAR_T *) null;                              \
01023               len = (sizeof (null) / sizeof (null[0])) - 1;                 \
01024              }                                                              \
01025            else                                                      \
01026              {                                                              \
01027               string = (CHAR_T *) L"";                               \
01028               len = 0;                                               \
01029              }                                                              \
01030          }                                                           \
01031        else if (!is_long && spec != L_('S'))                                \
01032          {                                                           \
01033            /* This is complicated.  We have to transform the multibyte             \
01034               string into a wide character string.  */                      \
01035            const char *mbs = (const char *) string;                         \
01036            mbstate_t mbstate;                                               \
01037                                                                      \
01038            len = prec != -1 ? __strnlen (mbs, (size_t) prec) : strlen (mbs); \
01039                                                                      \
01040            /* Allocate dynamically an array which definitely is long        \
01041               enough for the wide character version.  Each byte in the             \
01042               multi-byte string can produce at most one wide character.  */  \
01043            if (__libc_use_alloca (len * sizeof (wchar_t)))                  \
01044              string = (CHAR_T *) alloca (len * sizeof (wchar_t));           \
01045            else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t)))    \
01046                    == NULL)                                          \
01047              {                                                              \
01048               done = -1;                                             \
01049               goto all_done;                                                \
01050              }                                                              \
01051            else                                                      \
01052              string_malloced = 1;                                    \
01053                                                                      \
01054            memset (&mbstate, '\0', sizeof (mbstate_t));              \
01055            len = __mbsrtowcs (string, &mbs, len, &mbstate);                 \
01056            if (len == (size_t) -1)                                   \
01057              {                                                              \
01058               /* Illegal multibyte character.  */                           \
01059               done = -1;                                             \
01060               goto all_done;                                                \
01061              }                                                              \
01062          }                                                           \
01063        else                                                          \
01064          {                                                           \
01065            if (prec != -1)                                           \
01066              /* Search for the end of the string, but don't search past      \
01067                the length specified by the precision.  */                   \
01068              len = __wcsnlen (string, prec);                                \
01069            else                                                      \
01070              len = __wcslen (string);                                       \
01071          }                                                           \
01072                                                                      \
01073        if ((width -= len) < 0)                                              \
01074          {                                                           \
01075            outstring (string, len);                                         \
01076            break;                                                    \
01077          }                                                           \
01078                                                                      \
01079        if (!left)                                                    \
01080          PAD (L' ');                                                 \
01081        outstring (string, len);                                      \
01082        if (left)                                                     \
01083          PAD (L' ');                                                 \
01084        if (__builtin_expect (string_malloced, 0))                           \
01085          free (string);                                              \
01086       }                                                                     \
01087       break;
01088 #else
01089 # define process_string_arg(fspec) \
01090     LABEL (form_character):                                          \
01091       /* Character.  */                                                     \
01092       if (is_long)                                                   \
01093        goto LABEL (form_wcharacter);                                        \
01094       --width;       /* Account for the character itself.  */               \
01095       if (!left)                                                     \
01096        PAD (' ');                                                    \
01097       if (fspec == NULL)                                             \
01098        outchar ((unsigned char) va_arg (ap, int)); /* Promoted.  */         \
01099       else                                                           \
01100        outchar ((unsigned char) args_value[fspec->data_arg].pa_int);        \
01101       if (left)                                                             \
01102        PAD (' ');                                                    \
01103       break;                                                         \
01104                                                                      \
01105     LABEL (form_wcharacter):                                                \
01106       {                                                                     \
01107        /* Wide character.  */                                               \
01108        char buf[MB_CUR_MAX];                                                \
01109        mbstate_t mbstate;                                            \
01110        size_t len;                                                   \
01111                                                                      \
01112        memset (&mbstate, '\0', sizeof (mbstate_t));                         \
01113        len = __wcrtomb (buf, (fspec == NULL ? va_arg (ap, wchar_t)          \
01114                             : args_value[fspec->data_arg].pa_wchar),        \
01115                       &mbstate);                                     \
01116        if (len == (size_t) -1)                                              \
01117          {                                                           \
01118            /* Something went wron gduring the conversion.  Bail out.  */     \
01119            done = -1;                                                       \
01120            goto all_done;                                            \
01121          }                                                           \
01122        width -= len;                                                 \
01123        if (!left)                                                    \
01124          PAD (' ');                                                  \
01125        outstring (buf, len);                                                \
01126        if (left)                                                     \
01127          PAD (' ');                                                  \
01128       }                                                                     \
01129       break;                                                         \
01130                                                                      \
01131     LABEL (form_string):                                             \
01132       {                                                                     \
01133        size_t len;                                                   \
01134        int string_malloced;                                          \
01135                                                                      \
01136        /* The string argument could in fact be `char *' or `wchar_t *'.      \
01137           But this should not make a difference here.  */                   \
01138        if (fspec == NULL)                                            \
01139          string = (char *) va_arg (ap, const char *);                       \
01140        else                                                          \
01141          string = (char *) args_value[fspec->data_arg].pa_string;           \
01142                                                                      \
01143        /* Entry point for printing other strings.  */                       \
01144       LABEL (print_string):                                          \
01145                                                                      \
01146        string_malloced = 0;                                          \
01147        if (string == NULL)                                           \
01148          {                                                           \
01149            /* Write "(null)" if there's space.  */                          \
01150            if (prec == -1 || prec >= (int) sizeof (null) - 1)               \
01151              {                                                              \
01152               string = (char *) null;                                       \
01153               len = sizeof (null) - 1;                               \
01154              }                                                              \
01155            else                                                      \
01156              {                                                              \
01157               string = (char *) "";                                         \
01158               len = 0;                                               \
01159              }                                                              \
01160          }                                                           \
01161        else if (!is_long && spec != L_('S'))                                \
01162          {                                                           \
01163            if (prec != -1)                                           \
01164              {                                                              \
01165               /* Search for the end of the string, but don't search past    \
01166                  the length (in bytes) specified by the precision.  Also    \
01167                  don't use incomplete characters.  */                       \
01168               if (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MB_CUR_MAX) == 1)   \
01169                 len = __strnlen (string, prec);                      \
01170               else                                                   \
01171                 {                                                    \
01172                   /* In case we have a multibyte character set the          \
01173                      situation is more complicated.  We must not copy       \
01174                      bytes at the end which form an incomplete character. */\
01175                   size_t ignore_size = (unsigned) prec > 1024 ? 1024 : prec;\
01176                   wchar_t ignore[ignore_size];                       \
01177                   const char *str2 = string;                                \
01178                   const char *strend = string + prec;                       \
01179                   if (strend < string)                               \
01180                     strend = (const char *) UINTPTR_MAX;                    \
01181                                                                      \
01182                   mbstate_t ps;                                      \
01183                   memset (&ps, '\0', sizeof (ps));                          \
01184                                                                      \
01185                   while (str2 != NULL && str2 < strend)              \
01186                     if (__mbsnrtowcs (ignore, &str2, strend - str2,         \
01187                                    ignore_size, &ps) == (size_t) -1)     \
01188                      {                                               \
01189                        done = -1;                                    \
01190                        goto all_done;                                \
01191                      }                                               \
01192                                                                      \
01193                   if (str2 == NULL)                                         \
01194                     len = strlen (string);                                  \
01195                   else                                               \
01196                     len = str2 - string - (ps.__count & 7);                 \
01197                 }                                                    \
01198              }                                                              \
01199            else                                                      \
01200              len = strlen (string);                                         \
01201          }                                                           \
01202        else                                                          \
01203          {                                                           \
01204            const wchar_t *s2 = (const wchar_t *) string;                    \
01205            mbstate_t mbstate;                                               \
01206                                                                      \
01207            memset (&mbstate, '\0', sizeof (mbstate_t));              \
01208                                                                      \
01209            if (prec >= 0)                                            \
01210              {                                                              \
01211               /* The string `s2' might not be NUL terminated.  */           \
01212               if (__libc_use_alloca (prec))                                 \
01213                 string = (char *) alloca (prec);                     \
01214               else if ((string = (char *) malloc (prec)) == NULL)           \
01215                 {                                                    \
01216                   done = -1;                                                \
01217                   goto all_done;                                     \
01218                 }                                                    \
01219               else                                                   \
01220                 string_malloced = 1;                                        \
01221               len = __wcsrtombs (string, &s2, prec, &mbstate);       \
01222              }                                                              \
01223            else                                                      \
01224              {                                                              \
01225               len = __wcsrtombs (NULL, &s2, 0, &mbstate);                   \
01226               if (len != (size_t) -1)                                       \
01227                 {                                                    \
01228                   assert (__mbsinit (&mbstate));                     \
01229                   s2 = (const wchar_t *) string;                     \
01230                   if (__libc_use_alloca (len + 1))                          \
01231                     string = (char *) alloca (len + 1);              \
01232                   else if ((string = (char *) malloc (len + 1)) == NULL)    \
01233                     {                                                       \
01234                      done = -1;                                      \
01235                      goto all_done;                                         \
01236                     }                                                       \
01237                   else                                               \
01238                     string_malloced = 1;                             \
01239                   (void) __wcsrtombs (string, &s2, len + 1, &mbstate);      \
01240                 }                                                    \
01241              }                                                              \
01242                                                                      \
01243            if (len == (size_t) -1)                                   \
01244              {                                                              \
01245                /* Illegal wide-character string.  */                        \
01246               done = -1;                                             \
01247               goto all_done;                                                \
01248              }                                                              \
01249          }                                                           \
01250                                                                      \
01251        if ((width -= len) < 0)                                              \
01252          {                                                           \
01253            outstring (string, len);                                         \
01254            break;                                                    \
01255          }                                                           \
01256                                                                      \
01257        if (!left)                                                    \
01258          PAD (' ');                                                  \
01259        outstring (string, len);                                      \
01260        if (left)                                                     \
01261          PAD (' ');                                                  \
01262        if (__builtin_expect (string_malloced, 0))                           \
01263          free (string);                                              \
01264       }                                                                     \
01265       break;
01266 #endif
01267 
01268   /* Orient the stream.  */
01269 #ifdef ORIENT
01270   ORIENT;
01271 #endif
01272 
01273   /* Sanity check of arguments.  */
01274   ARGCHECK (s, format);
01275 
01276 #ifdef ORIENT
01277   /* Check for correct orientation.  */
01278   if (_IO_vtable_offset (s) == 0 &&
01279       _IO_fwide (s, sizeof (CHAR_T) == 1 ? -1 : 1)
01280       != (sizeof (CHAR_T) == 1 ? -1 : 1))
01281     /* The stream is already oriented otherwise.  */
01282     return EOF;
01283 #endif
01284 
01285   if (UNBUFFERED_P (s))
01286     /* Use a helper function which will allocate a local temporary buffer
01287        for the stream and then call us again.  */
01288     return buffered_vfprintf (s, format, ap);
01289 
01290   /* Initialize local variables.  */
01291   done = 0;
01292   grouping = (const char *) -1;
01293 #ifdef __va_copy
01294   /* This macro will be available soon in gcc's <stdarg.h>.  We need it
01295      since on some systems `va_list' is not an integral type.  */
01296   __va_copy (ap_save, ap);
01297 #else
01298   ap_save = ap;
01299 #endif
01300   nspecs_done = 0;
01301 
01302 #ifdef COMPILE_WPRINTF
01303   /* Find the first format specifier.  */
01304   f = lead_str_end = __find_specwc ((const UCHAR_T *) format);
01305 #else
01306   /* Find the first format specifier.  */
01307   f = lead_str_end = __find_specmb ((const UCHAR_T *) format);
01308 #endif
01309 
01310   /* Lock stream.  */
01311   _IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);
01312   _IO_flockfile (s);
01313 
01314   /* Write the literal text before the first format.  */
01315   outstring ((const UCHAR_T *) format,
01316             lead_str_end - (const UCHAR_T *) format);
01317 
01318   /* If we only have to print a simple string, return now.  */
01319   if (*f == L_('\0'))
01320     goto all_done;
01321 
01322   /* Process whole format string.  */
01323   do
01324     {
01325 #ifdef SHARED
01326 # define REF(Name) &&do_##Name - &&do_form_unknown
01327 #else
01328 # define REF(Name) &&do_##Name
01329 #endif
01330 #define LABEL(Name) do_##Name
01331       STEP0_3_TABLE;
01332       STEP4_TABLE;
01333 
01334       union printf_arg *args_value;       /* This is not used here but ... */
01335       int is_negative;      /* Flag for negative number.  */
01336       union
01337       {
01338        unsigned long long int longlong;
01339        unsigned long int word;
01340       } number;
01341       int base;
01342       union printf_arg the_arg;
01343       CHAR_T *string;       /* Pointer to argument string.  */
01344       int alt = 0;   /* Alternate format.  */
01345       int space = 0; /* Use space prefix if no sign is needed.  */
01346       int left = 0;  /* Left-justify output.  */
01347       int showsign = 0;     /* Always begin with plus or minus sign.  */
01348       int group = 0; /* Print numbers according grouping rules.  */
01349       int is_long_double = 0; /* Argument is long double/ long long int.  */
01350       int is_short = 0;     /* Argument is short int.  */
01351       int is_long = 0;      /* Argument is long int.  */
01352       int is_char = 0;      /* Argument is promoted (unsigned) char.  */
01353       int width = 0; /* Width of output; 0 means none specified.  */
01354       int prec = -1; /* Precision of output; -1 means none specified.  */
01355       /* This flag is set by the 'I' modifier and selects the use of the
01356         `outdigits' as determined by the current locale.  */
01357       int use_outdigits = 0;
01358       UCHAR_T pad = L_(' ');/* Padding character.  */
01359       CHAR_T spec;
01360 
01361       workstart = NULL;
01362       workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
01363 
01364       /* Get current character in format string.  */
01365       JUMP (*++f, step0_jumps);
01366 
01367       /* ' ' flag.  */
01368     LABEL (flag_space):
01369       space = 1;
01370       JUMP (*++f, step0_jumps);
01371 
01372       /* '+' flag.  */
01373     LABEL (flag_plus):
01374       showsign = 1;
01375       JUMP (*++f, step0_jumps);
01376 
01377       /* The '-' flag.  */
01378     LABEL (flag_minus):
01379       left = 1;
01380       pad = L_(' ');
01381       JUMP (*++f, step0_jumps);
01382 
01383       /* The '#' flag.  */
01384     LABEL (flag_hash):
01385       alt = 1;
01386       JUMP (*++f, step0_jumps);
01387 
01388       /* The '0' flag.  */
01389     LABEL (flag_zero):
01390       if (!left)
01391        pad = L_('0');
01392       JUMP (*++f, step0_jumps);
01393 
01394       /* The '\'' flag.  */
01395     LABEL (flag_quote):
01396       group = 1;
01397 
01398       if (grouping == (const char *) -1)
01399        {
01400 #ifdef COMPILE_WPRINTF
01401          thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
01402                                        _NL_NUMERIC_THOUSANDS_SEP_WC);
01403 #else
01404          thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
01405 #endif
01406 
01407          grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
01408          if (*grouping == '\0' || *grouping == CHAR_MAX
01409 #ifdef COMPILE_WPRINTF
01410              || thousands_sep == L'\0'
01411 #else
01412              || *thousands_sep == '\0'
01413 #endif
01414              )
01415            grouping = NULL;
01416        }
01417       JUMP (*++f, step0_jumps);
01418 
01419     LABEL (flag_i18n):
01420       use_outdigits = 1;
01421       JUMP (*++f, step0_jumps);
01422 
01423       /* Get width from argument.  */
01424     LABEL (width_asterics):
01425       {
01426        const UCHAR_T *tmp;  /* Temporary value.  */
01427 
01428        tmp = ++f;
01429        if (ISDIGIT (*tmp) && read_int (&tmp) && *tmp == L_('$'))
01430          /* The width comes from a positional parameter.  */
01431          goto do_positional;
01432 
01433        width = va_arg (ap, int);
01434 
01435        /* Negative width means left justified.  */
01436        if (width < 0)
01437          {
01438            width = -width;
01439            pad = L_(' ');
01440            left = 1;
01441          }
01442 
01443        if (width + 32 >= (int) (sizeof (work_buffer)
01444                              / sizeof (work_buffer[0])))
01445          {
01446            /* We have to use a special buffer.  The "32" is just a safe
01447               bet for all the output which is not counted in the width.  */
01448            if (__libc_use_alloca ((width + 32) * sizeof (CHAR_T)))
01449              workend = ((CHAR_T *) alloca ((width + 32) * sizeof (CHAR_T))
01450                       + (width + 32));
01451            else
01452              {
01453               workstart = (CHAR_T *) malloc ((width + 32) * sizeof (CHAR_T));
01454               if (workstart == NULL)
01455                 {
01456                   done = -1;
01457                   goto all_done;
01458                 }
01459               workend = workstart + (width + 32);
01460              }
01461          }
01462       }
01463       JUMP (*f, step1_jumps);
01464 
01465       /* Given width in format string.  */
01466     LABEL (width):
01467       width = read_int (&f);
01468 
01469       if (width + 32 >= (int) (sizeof (work_buffer) / sizeof (work_buffer[0])))
01470        {
01471          /* We have to use a special buffer.  The "32" is just a safe
01472             bet for all the output which is not counted in the width.  */
01473          if (__libc_use_alloca ((width + 32) * sizeof (CHAR_T)))
01474            workend = ((CHAR_T *) alloca ((width + 32) * sizeof (CHAR_T))
01475                      + (width + 32));
01476          else
01477            {
01478              workstart = (CHAR_T *) malloc ((width + 32) * sizeof (CHAR_T));
01479              if (workstart == NULL)
01480               {
01481                 done = -1;
01482                 goto all_done;
01483               }
01484              workend = workstart + (width + 32);
01485            }
01486        }
01487       if (*f == L_('$'))
01488        /* Oh, oh.  The argument comes from a positional parameter.  */
01489        goto do_positional;
01490       JUMP (*f, step1_jumps);
01491 
01492     LABEL (precision):
01493       ++f;
01494       if (*f == L_('*'))
01495        {
01496          const UCHAR_T *tmp;       /* Temporary value.  */
01497 
01498          tmp = ++f;
01499          if (ISDIGIT (*tmp) && read_int (&tmp) > 0 && *tmp == L_('$'))
01500            /* The precision comes from a positional parameter.  */
01501            goto do_positional;
01502 
01503          prec = va_arg (ap, int);
01504 
01505          /* If the precision is negative the precision is omitted.  */
01506          if (prec < 0)
01507            prec = -1;
01508        }
01509       else if (ISDIGIT (*f))
01510        prec = read_int (&f);
01511       else
01512        prec = 0;
01513       if (prec > width
01514          && prec + 32 > (int)(sizeof (work_buffer) / sizeof (work_buffer[0])))
01515        {
01516          if (__builtin_expect (prec > ~((size_t) 0) / sizeof (CHAR_T) - 31,
01517                             0))
01518            {
01519              done = -1;
01520              goto all_done;
01521            }
01522          size_t needed = ((size_t) prec + 32) * sizeof (CHAR_T);
01523 
01524          if (__libc_use_alloca (needed))
01525            workend = (((CHAR_T *) alloca (needed)) + ((size_t) prec + 32));
01526          else
01527            {
01528              workstart = (CHAR_T *) malloc (needed);
01529              if (workstart == NULL)
01530               {
01531                 done = -1;
01532                 goto all_done;
01533               }
01534              workend = workstart + ((size_t) prec + 32);
01535            }
01536        }
01537       JUMP (*f, step2_jumps);
01538 
01539       /* Process 'h' modifier.  There might another 'h' following.  */
01540     LABEL (mod_half):
01541       is_short = 1;
01542       JUMP (*++f, step3a_jumps);
01543 
01544       /* Process 'hh' modifier.  */
01545     LABEL (mod_halfhalf):
01546       is_short = 0;
01547       is_char = 1;
01548       JUMP (*++f, step4_jumps);
01549 
01550       /* Process 'l' modifier.  There might another 'l' following.  */
01551     LABEL (mod_long):
01552       is_long = 1;
01553       JUMP (*++f, step3b_jumps);
01554 
01555       /* Process 'L', 'q', or 'll' modifier.  No other modifier is
01556         allowed to follow.  */
01557     LABEL (mod_longlong):
01558       is_long_double = 1;
01559       is_long = 1;
01560       JUMP (*++f, step4_jumps);
01561 
01562     LABEL (mod_size_t):
01563       is_long_double = sizeof (size_t) > sizeof (unsigned long int);
01564       is_long = sizeof (size_t) > sizeof (unsigned int);
01565       JUMP (*++f, step4_jumps);
01566 
01567     LABEL (mod_ptrdiff_t):
01568       is_long_double = sizeof (ptrdiff_t) > sizeof (unsigned long int);
01569       is_long = sizeof (ptrdiff_t) > sizeof (unsigned int);
01570       JUMP (*++f, step4_jumps);
01571 
01572     LABEL (mod_intmax_t):
01573       is_long_double = sizeof (intmax_t) > sizeof (unsigned long int);
01574       is_long = sizeof (intmax_t) > sizeof (unsigned int);
01575       JUMP (*++f, step4_jumps);
01576 
01577       /* Process current format.  */
01578       while (1)
01579        {
01580          process_arg (((struct printf_spec *) NULL));
01581          process_string_arg (((struct printf_spec *) NULL));
01582 
01583        LABEL (form_unknown):
01584          if (spec == L_('\0'))
01585            {
01586              /* The format string ended before the specifier is complete.  */
01587              done = -1;
01588              goto all_done;
01589            }
01590 
01591          /* If we are in the fast loop force entering the complicated
01592             one.  */
01593          goto do_positional;
01594        }
01595 
01596       /* The format is correctly handled.  */
01597       ++nspecs_done;
01598 
01599       if (__builtin_expect (workstart != NULL, 0))
01600        free (workstart);
01601       workstart = NULL;
01602 
01603       /* Look for next format specifier.  */
01604 #ifdef COMPILE_WPRINTF
01605       f = __find_specwc ((end_of_spec = ++f));
01606 #else
01607       f = __find_specmb ((end_of_spec = ++f));
01608 #endif
01609 
01610       /* Write the following constant string.  */
01611       outstring (end_of_spec, f - end_of_spec);
01612     }
01613   while (*f != L_('\0'));
01614 
01615   /* Unlock stream and return.  */
01616   goto all_done;
01617 
01618   /* Here starts the more complex loop to handle positional parameters.  */
01619 do_positional:
01620   {
01621     /* Array with information about the needed arguments.  This has to
01622        be dynamically extensible.  */
01623     size_t nspecs = 0;
01624     size_t nspecs_max = 32; /* A more or less arbitrary start value.  */
01625     struct printf_spec *specs
01626       = alloca (nspecs_max * sizeof (struct printf_spec));
01627 
01628     /* The number of arguments the format string requests.  This will
01629        determine the size of the array needed to store the argument
01630        attributes.  */
01631     size_t nargs = 0;
01632     int *args_type;
01633     union printf_arg *args_value = NULL;
01634 
01635     /* Positional parameters refer to arguments directly.  This could
01636        also determine the maximum number of arguments.  Track the
01637        maximum number.  */
01638     size_t max_ref_arg = 0;
01639 
01640     /* Just a counter.  */
01641     size_t cnt;
01642 
01643     free (workstart);
01644     workstart = NULL;
01645 
01646     if (grouping == (const char *) -1)
01647       {
01648 #ifdef COMPILE_WPRINTF
01649        thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
01650                                      _NL_NUMERIC_THOUSANDS_SEP_WC);
01651 #else
01652        thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
01653 #endif
01654 
01655        grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
01656        if (*grouping == '\0' || *grouping == CHAR_MAX)
01657          grouping = NULL;
01658       }
01659 
01660     for (f = lead_str_end; *f != L_('\0'); f = specs[nspecs++].next_fmt)
01661       {
01662        if (nspecs >= nspecs_max)
01663          {
01664            /* Extend the array of format specifiers.  */
01665            struct printf_spec *old = specs;
01666 
01667            nspecs_max *= 2;
01668            specs = alloca (nspecs_max * sizeof (struct printf_spec));
01669 
01670            if (specs == &old[nspecs])
01671              /* Stack grows up, OLD was the last thing allocated;
01672                extend it.  */
01673              nspecs_max += nspecs_max / 2;
01674            else
01675              {
01676               /* Copy the old array's elements to the new space.  */
01677               memcpy (specs, old, nspecs * sizeof (struct printf_spec));
01678               if (old == &specs[nspecs])
01679                 /* Stack grows down, OLD was just below the new
01680                    SPECS.  We can use that space when the new space
01681                    runs out.  */
01682                 nspecs_max += nspecs_max / 2;
01683              }
01684          }
01685 
01686        /* Parse the format specifier.  */
01687 #ifdef COMPILE_WPRINTF
01688        nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
01689 #else
01690        nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg);
01691 #endif
01692       }
01693 
01694     /* Determine the number of arguments the format string consumes.  */
01695     nargs = MAX (nargs, max_ref_arg);
01696 
01697     /* Allocate memory for the argument descriptions.  */
01698     args_type = alloca (nargs * sizeof (int));
01699     memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
01700            nargs * sizeof (int));
01701     args_value = alloca (nargs * sizeof (union printf_arg));
01702 
01703     /* XXX Could do sanity check here: If any element in ARGS_TYPE is
01704        still zero after this loop, format is invalid.  For now we
01705        simply use 0 as the value.  */
01706 
01707     /* Fill in the types of all the arguments.  */
01708     for (cnt = 0; cnt < nspecs; ++cnt)
01709       {
01710        /* If the width is determined by an argument this is an int.  */
01711        if (specs[cnt].width_arg != -1)
01712          args_type[specs[cnt].width_arg] = PA_INT;
01713 
01714        /* If the precision is determined by an argument this is an int.  */
01715        if (specs[cnt].prec_arg != -1)
01716          args_type[specs[cnt].prec_arg] = PA_INT;
01717 
01718        switch (specs[cnt].ndata_args)
01719          {
01720          case 0:            /* No arguments.  */
01721            break;
01722          case 1:            /* One argument; we already have the type.  */
01723            args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type;
01724            break;
01725          default:
01726            /* We have more than one argument for this format spec.
01727               We must call the arginfo function again to determine
01728               all the types.  */
01729            (void) (*__printf_arginfo_table[specs[cnt].info.spec])
01730              (&specs[cnt].info,
01731               specs[cnt].ndata_args, &args_type[specs[cnt].data_arg]);
01732            break;
01733          }
01734       }
01735 
01736     /* Now we know all the types and the order.  Fill in the argument
01737        values.  */
01738     for (cnt = 0; cnt < nargs; ++cnt)
01739       switch (args_type[cnt])
01740        {
01741 #define T(tag, mem, type)                                            \
01742        case tag:                                                     \
01743          args_value[cnt].mem = va_arg (ap_save, type);                      \
01744          break
01745 
01746        T (PA_CHAR, pa_int, int); /* Promoted.  */
01747        T (PA_WCHAR, pa_wchar, wint_t);
01748        T (PA_INT|PA_FLAG_SHORT, pa_int, int); /* Promoted.  */
01749        T (PA_INT, pa_int, int);
01750        T (PA_INT|PA_FLAG_LONG, pa_long_int, long int);
01751        T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
01752        T (PA_FLOAT, pa_double, double);   /* Promoted.  */
01753        T (PA_DOUBLE, pa_double, double);
01754        case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
01755          if (__ldbl_is_dbl)
01756            {
01757              args_value[cnt].pa_double = va_arg (ap_save, double);
01758              args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
01759            }
01760          else
01761            args_value[cnt].pa_long_double = va_arg (ap_save, long double);
01762          break;
01763        T (PA_STRING, pa_string, const char *);
01764        T (PA_WSTRING, pa_wstring, const wchar_t *);
01765        T (PA_POINTER, pa_pointer, void *);
01766 #undef T
01767        default:
01768          if ((args_type[cnt] & PA_FLAG_PTR) != 0)
01769            args_value[cnt].pa_pointer = va_arg (ap_save, void *);
01770          else
01771            args_value[cnt].pa_long_double = 0.0;
01772          break;
01773        case -1:
01774          /* Error case.  Not all parameters appear in N$ format
01775             strings.  We have no way to determine their type.  */
01776          assert (s->_flags2 & _IO_FLAGS2_FORTIFY);
01777          __libc_fatal ("*** invalid %N$ use detected ***\n");
01778        }
01779 
01780     /* Now walk through all format specifiers and process them.  */
01781     for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
01782       {
01783 #undef REF
01784 #ifdef SHARED
01785 # define REF(Name) &&do2_##Name - &&do_form_unknown
01786 #else
01787 # define REF(Name) &&do2_##Name
01788 #endif
01789 #undef LABEL
01790 #define LABEL(Name) do2_##Name
01791        STEP4_TABLE;
01792 
01793        int is_negative;
01794        union
01795        {
01796          unsigned long long int longlong;
01797          unsigned long int word;
01798        } number;
01799        int base;
01800        union printf_arg the_arg;
01801        CHAR_T *string;             /* Pointer to argument string.  */
01802 
01803        /* Fill variables from values in struct.  */
01804        int alt = specs[nspecs_done].info.alt;
01805        int space = specs[nspecs_done].info.space;
01806        int left = specs[nspecs_done].info.left;
01807        int showsign = specs[nspecs_done].info.showsign;
01808        int group = specs[nspecs_done].info.group;
01809        int is_long_double = specs[nspecs_done].info.is_long_double;
01810        int is_short = specs[nspecs_done].info.is_short;
01811        int is_char = specs[nspecs_done].info.is_char;
01812        int is_long = specs[nspecs_done].info.is_long;
01813        int width = specs[nspecs_done].info.width;
01814        int prec = specs[nspecs_done].info.prec;
01815        int use_outdigits = specs[nspecs_done].info.i18n;
01816        char pad = specs[nspecs_done].info.pad;
01817        CHAR_T spec = specs[nspecs_done].info.spec;
01818 
01819        workstart = NULL;
01820        workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
01821 
01822        /* Fill in last information.  */
01823        if (specs[nspecs_done].width_arg != -1)
01824          {
01825            /* Extract the field width from an argument.  */
01826            specs[nspecs_done].info.width =
01827              args_value[specs[nspecs_done].width_arg].pa_int;
01828 
01829            if (specs[nspecs_done].info.width < 0)
01830              /* If the width value is negative left justification is
01831                selected and the value is taken as being positive.  */
01832              {
01833               specs[nspecs_done].info.width *= -1;
01834               left = specs[nspecs_done].info.left = 1;
01835              }
01836            width = specs[nspecs_done].info.width;
01837          }
01838 
01839        if (specs[nspecs_done].prec_arg != -1)
01840          {
01841            /* Extract the precision from an argument.  */
01842            specs[nspecs_done].info.prec =
01843              args_value[specs[nspecs_done].prec_arg].pa_int;
01844 
01845            if (specs[nspecs_done].info.prec < 0)
01846              /* If the precision is negative the precision is
01847                omitted.  */
01848              specs[nspecs_done].info.prec = -1;
01849 
01850            prec = specs[nspecs_done].info.prec;
01851          }
01852 
01853        /* Maybe the buffer is too small.  */
01854        if (MAX (prec, width) + 32 > (int) (sizeof (work_buffer)
01855                                        / sizeof (CHAR_T)))
01856          {
01857            if (__libc_use_alloca ((MAX (prec, width) + 32)
01858                                * sizeof (CHAR_T)))
01859              workend = ((CHAR_T *) alloca ((MAX (prec, width) + 32)
01860                                        * sizeof (CHAR_T))
01861                       + (MAX (prec, width) + 32));
01862            else
01863              {
01864               workstart = (CHAR_T *) malloc ((MAX (prec, width) + 32)
01865                                           * sizeof (CHAR_T));
01866               workend = workstart + (MAX (prec, width) + 32);
01867              }
01868          }
01869 
01870        /* Process format specifiers.  */
01871        while (1)
01872          {
01873            JUMP (spec, step4_jumps);
01874 
01875            process_arg ((&specs[nspecs_done]));
01876            process_string_arg ((&specs[nspecs_done]));
01877 
01878          LABEL (form_unknown):
01879            {
01880              extern printf_function **__printf_function_table;
01881              int function_done;
01882              printf_function *function;
01883              unsigned int i;
01884              const void **ptr;
01885 
01886              function =
01887               (__printf_function_table == NULL ? NULL :
01888                __printf_function_table[specs[nspecs_done].info.spec]);
01889 
01890              if (function == NULL)
01891               function = &printf_unknown;
01892 
01893              ptr = alloca (specs[nspecs_done].ndata_args
01894                          * sizeof (const void *));
01895 
01896              /* Fill in an array of pointers to the argument values.  */
01897              for (i = 0; i < specs[nspecs_done].ndata_args; ++i)
01898               ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
01899 
01900              /* Call the function.  */
01901              function_done = (*function) (s, &specs[nspecs_done].info, ptr);
01902 
01903              /* If an error occurred we don't have information about #
01904                of chars.  */
01905              if (function_done < 0)
01906               {
01907                 done = -1;
01908                 goto all_done;
01909               }
01910 
01911              done_add (function_done);
01912            }
01913            break;
01914          }
01915 
01916        free (workstart);
01917        workstart = NULL;
01918 
01919        /* Write the following constant string.  */
01920        outstring (specs[nspecs_done].end_of_fmt,
01921                  specs[nspecs_done].next_fmt
01922                  - specs[nspecs_done].end_of_fmt);
01923       }
01924   }
01925 
01926 all_done:
01927   if (__builtin_expect (workstart != NULL, 0))
01928     free (workstart);
01929   /* Unlock the stream.  */
01930   _IO_funlockfile (s);
01931   _IO_cleanup_region_end (0);
01932 
01933   return done;
01934 }
01935 
01936 /* Handle an unknown format specifier.  This prints out a canonicalized
01937    representation of the format spec itself.  */
01938 static int
01939 printf_unknown (FILE *s, const struct printf_info *info,
01940               const void *const *args)
01941 
01942 {
01943   int done = 0;
01944   CHAR_T work_buffer[MAX (sizeof (info->width), sizeof (info->prec)) * 3];
01945   CHAR_T *const workend
01946     = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
01947   register CHAR_T *w;
01948 
01949   outchar (L_('%'));
01950 
01951   if (info->alt)
01952     outchar (L_('#'));
01953   if (info->group)
01954     outchar (L_('\''));
01955   if (info->showsign)
01956     outchar (L_('+'));
01957   else if (info->space)
01958     outchar (L_(' '));
01959   if (info->left)
01960     outchar (L_('-'));
01961   if (info->pad == L_('0'))
01962     outchar (L_('0'));
01963   if (info->i18n)
01964     outchar (L_('I'));
01965 
01966   if (info->width != 0)
01967     {
01968       w = _itoa_word (info->width, workend, 10, 0);
01969       while (w < workend)
01970        outchar (*w++);
01971     }
01972 
01973   if (info->prec != -1)
01974     {
01975       outchar (L_('.'));
01976       w = _itoa_word (info->prec, workend, 10, 0);
01977       while (w < workend)
01978        outchar (*w++);
01979     }
01980 
01981   if (info->spec != L_('\0'))
01982     outchar (info->spec);
01983 
01984  all_done:
01985   return done;
01986 }
01987 
01988 /* Group the digits according to the grouping rules of the current locale.
01989    The interpretation of GROUPING is as in `struct lconv' from <locale.h>.  */
01990 static CHAR_T *
01991 internal_function
01992 group_number (CHAR_T *w, CHAR_T *rear_ptr, const char *grouping,
01993 #ifdef COMPILE_WPRINTF
01994              wchar_t thousands_sep
01995 #else
01996              const char *thousands_sep
01997 #endif
01998              )
01999 {
02000   int len;
02001   CHAR_T *src, *s;
02002 #ifndef COMPILE_WPRINTF
02003   int tlen = strlen (thousands_sep);
02004 #endif
02005 
02006   /* We treat all negative values like CHAR_MAX.  */
02007 
02008   if (*grouping == CHAR_MAX || *grouping <= 0)
02009     /* No grouping should be done.  */
02010     return w;
02011 
02012   len = *grouping++;
02013 
02014   /* Copy existing string so that nothing gets overwritten.  */
02015   src = (CHAR_T *) alloca ((rear_ptr - w) * sizeof (CHAR_T));
02016   s = (CHAR_T *) __mempcpy (src, w,
02017                          (rear_ptr - w) * sizeof (CHAR_T));
02018   w = rear_ptr;
02019 
02020   /* Process all characters in the string.  */
02021   while (s > src)
02022     {
02023       *--w = *--s;
02024 
02025       if (--len == 0 && s > src)
02026        {
02027          /* A new group begins.  */
02028 #ifdef COMPILE_WPRINTF
02029          *--w = thousands_sep;
02030 #else
02031          int cnt = tlen;
02032          do
02033            *--w = thousands_sep[--cnt];
02034          while (cnt > 0);
02035 #endif
02036 
02037          if (*grouping == CHAR_MAX
02038 #if CHAR_MIN < 0
02039                  || *grouping < 0
02040 #endif
02041                  )
02042            {
02043              /* No further grouping to be done.
02044                Copy the rest of the number.  */
02045              do
02046               *--w = *--s;
02047              while (s > src);
02048              break;
02049            }
02050          else if (*grouping != '\0')
02051            /* The previous grouping repeats ad infinitum.  */
02052            len = *grouping++;
02053          else
02054            len = grouping[-1];
02055        }
02056     }
02057   return w;
02058 }
02059 
02060 /* Helper "class" for `fprintf to unbuffered': creates a temporary buffer.  */
02061 struct helper_file
02062   {
02063     struct _IO_FILE_plus _f;
02064 #ifdef COMPILE_WPRINTF
02065     struct _IO_wide_data _wide_data;
02066 #endif
02067     _IO_FILE *_put_stream;
02068 #ifdef _IO_MTSAFE_IO
02069     _IO_lock_t lock;
02070 #endif
02071   };
02072 
02073 static int
02074 _IO_helper_overflow (_IO_FILE *s, int c)
02075 {
02076   _IO_FILE *target = ((struct helper_file*) s)->_put_stream;
02077 #ifdef COMPILE_WPRINTF
02078   int used = s->_wide_data->_IO_write_ptr - s->_wide_data->_IO_write_base;
02079   if (used)
02080     {
02081       _IO_size_t written = _IO_sputn (target, s->_wide_data->_IO_write_base,
02082                                   used);
02083       if (written == 0 || written == WEOF)
02084        return WEOF;
02085       __wmemmove (s->_wide_data->_IO_write_base,
02086                 s->_wide_data->_IO_write_base + written,
02087                 used - written);
02088       s->_wide_data->_IO_write_ptr -= written;
02089     }
02090 #else
02091   int used = s->_IO_write_ptr - s->_IO_write_base;
02092   if (used)
02093     {
02094       _IO_size_t written = _IO_sputn (target, s->_IO_write_base, used);
02095       if (written == 0 || written == EOF)
02096        return EOF;
02097       memmove (s->_IO_write_base, s->_IO_write_base + written,
02098               used - written);
02099       s->_IO_write_ptr -= written;
02100     }
02101 #endif
02102   return PUTC (c, s);
02103 }
02104 
02105 #ifdef COMPILE_WPRINTF
02106 static const struct _IO_jump_t _IO_helper_jumps =
02107 {
02108   JUMP_INIT_DUMMY,
02109   JUMP_INIT (finish, INTUSE(_IO_wdefault_finish)),
02110   JUMP_INIT (overflow, _IO_helper_overflow),
02111   JUMP_INIT (underflow, _IO_default_underflow),
02112   JUMP_INIT (uflow, INTUSE(_IO_default_uflow)),
02113   JUMP_INIT (pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
02114   JUMP_INIT (xsputn, INTUSE(_IO_wdefault_xsputn)),
02115   JUMP_INIT (xsgetn, INTUSE(_IO_wdefault_xsgetn)),
02116   JUMP_INIT (seekoff, _IO_default_seekoff),
02117   JUMP_INIT (seekpos, _IO_default_seekpos),
02118   JUMP_INIT (setbuf, _IO_default_setbuf),
02119   JUMP_INIT (sync, _IO_default_sync),
02120   JUMP_INIT (doallocate, INTUSE(_IO_wdefault_doallocate)),
02121   JUMP_INIT (read, _IO_default_read),
02122   JUMP_INIT (write, _IO_default_write),
02123   JUMP_INIT (seek, _IO_default_seek),
02124   JUMP_INIT (close, _IO_default_close),
02125   JUMP_INIT (stat, _IO_default_stat)
02126 };
02127 #else
02128 static const struct _IO_jump_t _IO_helper_jumps =
02129 {
02130   JUMP_INIT_DUMMY,
02131   JUMP_INIT (finish, INTUSE(_IO_default_finish)),
02132   JUMP_INIT (overflow, _IO_helper_overflow),
02133   JUMP_INIT (underflow, _IO_default_underflow),
02134   JUMP_INIT (uflow, INTUSE(_IO_default_uflow)),
02135   JUMP_INIT (pbackfail, INTUSE(_IO_default_pbackfail)),
02136   JUMP_INIT (xsputn, INTUSE(_IO_default_xsputn)),
02137   JUMP_INIT (xsgetn, INTUSE(_IO_default_xsgetn)),
02138   JUMP_INIT (seekoff, _IO_default_seekoff),
02139   JUMP_INIT (seekpos, _IO_default_seekpos),
02140   JUMP_INIT (setbuf, _IO_default_setbuf),
02141   JUMP_INIT (sync, _IO_default_sync),
02142   JUMP_INIT (doallocate, INTUSE(_IO_default_doallocate)),
02143   JUMP_INIT (read, _IO_default_read),
02144   JUMP_INIT (write, _IO_default_write),
02145   JUMP_INIT (seek, _IO_default_seek),
02146   JUMP_INIT (close, _IO_default_close),
02147   JUMP_INIT (stat, _IO_default_stat)
02148 };
02149 #endif
02150 
02151 static int
02152 internal_function
02153 buffered_vfprintf (register _IO_FILE *s, const CHAR_T *format,
02154                  _IO_va_list args)
02155 {
02156   CHAR_T buf[_IO_BUFSIZ];
02157   struct helper_file helper;
02158   register _IO_FILE *hp = (_IO_FILE *) &helper._f;
02159   int result, to_flush;
02160 
02161   /* Orient the stream.  */
02162 #ifdef ORIENT
02163   ORIENT;
02164 #endif
02165 
02166   /* Initialize helper.  */
02167   helper._put_stream = s;
02168 #ifdef COMPILE_WPRINTF
02169   hp->_wide_data = &helper._wide_data;
02170   _IO_wsetp (hp, buf, buf + sizeof buf / sizeof (CHAR_T));
02171   hp->_mode = 1;
02172 #else
02173   _IO_setp (hp, buf, buf + sizeof buf);
02174   hp->_mode = -1;
02175 #endif
02176   hp->_IO_file_flags = _IO_MAGIC|_IO_NO_READS|_IO_USER_LOCK;
02177 #if _IO_JUMPS_OFFSET
02178   hp->_vtable_offset = 0;
02179 #endif
02180 #ifdef _IO_MTSAFE_IO
02181   hp->_lock = NULL;
02182 #endif
02183   hp->_flags2 = s->_flags2;
02184   _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
02185 
02186   /* Now print to helper instead.  */
02187 #ifndef COMPILE_WPRINTF
02188   result = INTUSE(_IO_vfprintf) (hp, format, args);
02189 #else
02190   result = vfprintf (hp, format, args);
02191 #endif
02192 
02193   /* Lock stream.  */
02194   __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
02195   _IO_flockfile (s);
02196 
02197   /* Now flush anything from the helper to the S. */
02198 #ifdef COMPILE_WPRINTF
02199   if ((to_flush = (hp->_wide_data->_IO_write_ptr
02200                  - hp->_wide_data->_IO_write_base)) > 0)
02201     {
02202       if ((int) _IO_sputn (s, hp->_wide_data->_IO_write_base, to_flush)
02203          != to_flush)
02204        result = -1;
02205     }
02206 #else
02207   if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
02208     {
02209       if ((int) _IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
02210        result = -1;
02211     }
02212 #endif
02213 
02214   /* Unlock the stream.  */
02215   _IO_funlockfile (s);
02216   __libc_cleanup_region_end (0);
02217 
02218   return result;
02219 }
02220 
02221 #undef vfprintf
02222 #ifdef COMPILE_WPRINTF
02223 strong_alias (_IO_vfwprintf, __vfwprintf);
02224 ldbl_weak_alias (_IO_vfwprintf, vfwprintf);
02225 #else
02226 ldbl_strong_alias (_IO_vfprintf_internal, vfprintf);
02227 ldbl_hidden_def (_IO_vfprintf_internal, vfprintf)
02228 ldbl_strong_alias (_IO_vfprintf_internal, _IO_vfprintf);
02229 #endif