]> rtime.felk.cvut.cz Git - fpga/lx-cpu1/newlib-tumbl.git/blob - newlib/libc/stdio/vfprintf.c
* libc/include/sys/features.h (__GNUC_PREREQ): Define. Use
[fpga/lx-cpu1/newlib-tumbl.git] / newlib / libc / stdio / vfprintf.c
1 /*
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Chris Torek.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 /*
38 FUNCTION
39 <<vfprintf>>, <<vprintf>>, <<vsprintf>>, <<vsnprintf>>, <<vasprintf>>, <<vasnprintf>>---format argument list
40
41 INDEX
42         vfprintf
43 INDEX
44         _vfprintf_r
45 INDEX
46         vprintf
47 INDEX
48         _vprintf_r
49 INDEX
50         vsprintf
51 INDEX
52         _vsprintf_r
53 INDEX
54         vsnprintf
55 INDEX
56         _vsnprintf_r
57 INDEX
58         vasprintf
59 INDEX
60         _vasprintf_r
61 INDEX
62         vasnprintf
63 INDEX
64         _vasnprintf_r
65
66 ANSI_SYNOPSIS
67         #include <stdio.h>
68         #include <stdarg.h>
69         int vprintf(const char *<[fmt]>, va_list <[list]>);
70         int vfprintf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
71         int vsprintf(char *<[str]>, const char *<[fmt]>, va_list <[list]>);
72         int vsnprintf(char *<[str]>, size_t <[size]>, const char *<[fmt]>,
73                       va_list <[list]>);
74         int vasprintf(char **<[strp]>, const char *<[fmt]>, va_list <[list]>);
75         char *vasnprintf(char *<[str]>, size_t *<[size]>, const char *<[fmt]>,
76                          va_list <[list]>);
77
78         int _vprintf_r(struct _reent *<[reent]>, const char *<[fmt]>,
79                         va_list <[list]>);
80         int _vfprintf_r(struct _reent *<[reent]>, FILE *<[fp]>,
81                         const char *<[fmt]>, va_list <[list]>);
82         int _vsprintf_r(struct _reent *<[reent]>, char *<[str]>,
83                         const char *<[fmt]>, va_list <[list]>);
84         int _vasprintf_r(struct _reent *<[reent]>, char **<[str]>,
85                          const char *<[fmt]>, va_list <[list]>);
86         int _vsnprintf_r(struct _reent *<[reent]>, char *<[str]>,
87                          size_t <[size]>, const char *<[fmt]>, va_list <[list]>);
88         char *_vasnprintf_r(struct _reent *<[reent]>, char *<[str]>,
89                             size_t *<[size]>, const char *<[fmt]>, va_list <[list]>);
90
91 DESCRIPTION
92 <<vprintf>>, <<vfprintf>>, <<vasprintf>>, <<vsprintf>>, <<vsnprintf>>,
93 and <<vasnprintf>> are (respectively) variants of <<printf>>,
94 <<fprintf>>, <<asprintf>>, <<sprintf>>, <<snprintf>>, and
95 <<asnprintf>>.  They differ only in allowing their caller to pass the
96 variable argument list as a <<va_list>> object (initialized by
97 <<va_start>>) rather than directly accepting a variable number of
98 arguments.  The caller is responsible for calling <<va_end>>.
99
100 <<_vprintf_r>>, <<_vfprintf_r>>, <<_vasprintf_r>>, <<_vsprintf_r>>,
101 <<_vsnprintf_r>>, and <<_vasnprintf_r>> are reentrant versions of the
102 above.
103
104 RETURNS
105 The return values are consistent with the corresponding functions.
106
107 PORTABILITY
108 ANSI C requires <<vprintf>>, <<vfprintf>>, <<vsprintf>>, and
109 <<vsnprintf>>.  The remaining functions are newlib extensions.
110
111 Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
112 <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
113 */
114
115 #if defined(LIBC_SCCS) && !defined(lint)
116 /*static char *sccsid = "from: @(#)vfprintf.c   5.50 (Berkeley) 12/16/92";*/
117 static char *rcsid = "$Id$";
118 #endif /* LIBC_SCCS and not lint */
119
120 /*
121  * Actual printf innards.
122  *
123  * This code is large and complicated...
124  */
125 #include <newlib.h>
126
127 #ifdef INTEGER_ONLY
128 # define VFPRINTF vfiprintf
129 # ifdef STRING_ONLY
130 #   define _VFPRINTF_R _svfiprintf_r
131 # else
132 #   define _VFPRINTF_R _vfiprintf_r
133 # endif
134 #else
135 # define VFPRINTF vfprintf
136 # ifdef STRING_ONLY
137 #   define _VFPRINTF_R _svfprintf_r
138 # else
139 #   define _VFPRINTF_R _vfprintf_r
140 # endif
141 # ifndef NO_FLOATING_POINT
142 #  define FLOATING_POINT
143 # endif
144 #endif
145
146 #define _NO_POS_ARGS
147 #ifdef _WANT_IO_POS_ARGS
148 # undef _NO_POS_ARGS
149 #endif
150
151 #include <_ansi.h>
152 #include <reent.h>
153 #include <stdio.h>
154 #include <stdlib.h>
155 #include <string.h>
156 #include <limits.h>
157 #include <stdint.h>
158 #include <wchar.h>
159 #include <sys/lock.h>
160 #include <stdarg.h>
161 #include "local.h"
162 #include "../stdlib/local.h"
163 #include "fvwrite.h"
164 #include "vfieeefp.h"
165
166 /* Currently a test is made to see if long double processing is warranted.
167    This could be changed in the future should the _ldtoa_r code be
168    preferred over _dtoa_r.  */
169 #define _NO_LONGDBL
170 #if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
171 #undef _NO_LONGDBL
172 #endif
173
174 #define _NO_LONGLONG
175 #if defined _WANT_IO_LONG_LONG \
176         && (defined __GNUC__ || __STDC_VERSION__ >= 199901L)
177 # undef _NO_LONGLONG
178 #endif
179
180 #ifdef STRING_ONLY
181 #define __SPRINT __ssprint_r
182 #else
183 #define __SPRINT __sprint_r
184 #endif
185
186 /* The __sprint_r/__ssprint_r functions are shared between all versions of
187    vfprintf and vfwprintf.  They must only be defined once, which we do in
188    the INTEGER_ONLY versions here. */
189 #ifdef STRING_ONLY
190 #ifdef INTEGER_ONLY
191 int
192 _DEFUN(__ssprint_r, (ptr, fp, uio),
193        struct _reent *ptr _AND
194        FILE *fp _AND
195        register struct __suio *uio)
196 {
197         register size_t len;
198         register int w;
199         register struct __siov *iov;
200         register _CONST char *p = NULL;
201
202         iov = uio->uio_iov;
203         len = 0;
204
205         if (uio->uio_resid == 0) {
206                 uio->uio_iovcnt = 0;
207                 return (0);
208         }
209
210         do {
211                 while (len == 0) {
212                         p = iov->iov_base;
213                         len = iov->iov_len;
214                         iov++;
215                 }
216                 w = fp->_w;
217                 if (len >= w && fp->_flags & (__SMBF | __SOPT)) {
218                         /* must be asprintf family */
219                         unsigned char *str;
220                         int curpos = (fp->_p - fp->_bf._base);
221                         /* Choose a geometric growth factor to avoid
222                          * quadratic realloc behavior, but use a rate less
223                          * than (1+sqrt(5))/2 to accomodate malloc
224                          * overhead. asprintf EXPECTS us to overallocate, so
225                          * that it can add a trailing \0 without
226                          * reallocating.  The new allocation should thus be
227                          * max(prev_size*1.5, curpos+len+1). */
228                         int newsize = fp->_bf._size * 3 / 2;
229                         if (newsize < curpos + len + 1)
230                                 newsize = curpos + len + 1;
231                         if (fp->_flags & __SOPT)
232                         {
233                                 /* asnprintf leaves original buffer alone.  */
234                                 str = (unsigned char *)_malloc_r (ptr, newsize);
235                                 if (!str)
236                                 {
237                                         ptr->_errno = ENOMEM;
238                                         goto err;
239                                 }
240                                 memcpy (str, fp->_bf._base, curpos);
241                                 fp->_flags = (fp->_flags & ~__SOPT) | __SMBF;
242                         }
243                         else
244                         {
245                                 str = (unsigned char *)_realloc_r (ptr, fp->_bf._base,
246                                                 newsize);
247                                 if (!str) {
248                                         /* Free unneeded buffer.  */
249                                         _free_r (ptr, fp->_bf._base);
250                                         /* Ensure correct errno, even if free
251                                          * changed it.  */
252                                         ptr->_errno = ENOMEM;
253                                         goto err;
254                                 }
255                         }
256                         fp->_bf._base = str;
257                         fp->_p = str + curpos;
258                         fp->_bf._size = newsize;
259                         w = len;
260                         fp->_w = newsize - curpos;
261                 }
262                 if (len < w)
263                         w = len;
264                 (void)memmove ((_PTR) fp->_p, (_PTR) p, (size_t) (w));
265                 fp->_w -= w;
266                 fp->_p += w;
267                 w = len;          /* pretend we copied all */
268                 p += w;
269                 len -= w;
270         } while ((uio->uio_resid -= w) != 0);
271
272         uio->uio_resid = 0;
273         uio->uio_iovcnt = 0;
274         return 0;
275
276 err:
277   fp->_flags |= __SERR;
278   uio->uio_resid = 0;
279   uio->uio_iovcnt = 0;
280   return EOF;
281 }
282 #else /* !INTEGER_ONLY */
283 int __ssprint_r (struct _reent *, FILE *, register struct __suio *);
284 #endif /* !INTEGER_ONLY */
285
286 #else /* !STRING_ONLY */
287 #ifdef INTEGER_ONLY
288 /*
289  * Flush out all the vectors defined by the given uio,
290  * then reset it so that it can be reused.
291  */
292 int
293 _DEFUN(__sprint_r, (ptr, fp, uio),
294        struct _reent *ptr _AND
295        FILE *fp _AND
296        register struct __suio *uio)
297 {
298         register int err = 0;
299
300         if (uio->uio_resid == 0) {
301                 uio->uio_iovcnt = 0;
302                 return (0);
303         }
304         if (fp->_flags2 & __SWID) {
305                 struct __siov *iov;
306                 wchar_t *p;
307                 int i, len;
308
309                 iov = uio->uio_iov;
310                 for (; uio->uio_resid != 0;
311                      uio->uio_resid -= len * sizeof (wchar_t), iov++) {
312                         p = (wchar_t *) iov->iov_base;
313                         len = iov->iov_len / sizeof (wchar_t);
314                         for (i = 0; i < len; i++) {
315                                 if (_fputwc_r (ptr, p[i], fp) == WEOF) {
316                                         err = -1;
317                                         goto out;
318                                 }
319                         }
320                 }
321         } else
322                 err = __sfvwrite_r(ptr, fp, uio);
323 out:
324         uio->uio_resid = 0;
325         uio->uio_iovcnt = 0;
326         return (err);
327 }
328 #else /* !INTEGER_ONLY */
329 int __sprint_r (struct _reent *, FILE *, register struct __suio *);
330 #endif /* !INTEGER_ONLY */
331
332 /*
333  * Helper function for `fprintf to unbuffered unix file': creates a
334  * temporary buffer.  We only work on write-only files; this avoids
335  * worries about ungetc buffers and so forth.
336  *
337  * Make sure to avoid inlining when optimizing for size.
338  */
339 _NOINLINE_STATIC int
340 _DEFUN(__sbprintf, (rptr, fp, fmt, ap),
341        struct _reent *rptr _AND
342        register FILE *fp   _AND
343        _CONST char *fmt  _AND
344        va_list ap)
345 {
346         int ret;
347         FILE fake;
348         unsigned char buf[BUFSIZ];
349
350         /* copy the important variables */
351         fake._flags = fp->_flags & ~__SNBF;
352         fake._flags2 = fp->_flags2;
353         fake._file = fp->_file;
354         fake._cookie = fp->_cookie;
355         fake._write = fp->_write;
356
357         /* set up the buffer */
358         fake._bf._base = fake._p = buf;
359         fake._bf._size = fake._w = sizeof (buf);
360         fake._lbfsize = 0;      /* not actually used, but Just In Case */
361 #ifndef __SINGLE_THREAD__
362         __lock_init_recursive (fake._lock);
363 #endif
364
365         /* do the work, then copy any error status */
366         ret = _VFPRINTF_R (rptr, &fake, fmt, ap);
367         if (ret >= 0 && _fflush_r (rptr, &fake))
368                 ret = EOF;
369         if (fake._flags & __SERR)
370                 fp->_flags |= __SERR;
371
372 #ifndef __SINGLE_THREAD__
373         __lock_close_recursive (fake._lock);
374 #endif
375         return (ret);
376 }
377 #endif /* !STRING_ONLY */
378
379
380 #if defined (FLOATING_POINT) || defined (_WANT_IO_C99_FORMATS)
381 # include <locale.h>
382 #endif
383 #ifdef FLOATING_POINT
384 # include <math.h>
385
386 /* For %La, an exponent of 15 bits occupies the exponent character, a
387    sign, and up to 5 digits.  */
388 # define MAXEXPLEN              7
389 # define DEFPREC                6
390
391 # ifdef _NO_LONGDBL
392
393 extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
394                               int, int *, int *, char **));
395
396 #  define _PRINTF_FLOAT_TYPE double
397 #  define _DTOA_R _dtoa_r
398 #  define FREXP frexp
399
400 # else /* !_NO_LONGDBL */
401
402 extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
403                               int, int *, int *, char **));
404
405 extern int _EXFUN(_ldcheck,(_LONG_DOUBLE *));
406
407 #  define _PRINTF_FLOAT_TYPE _LONG_DOUBLE
408 #  define _DTOA_R _ldtoa_r
409 /* FIXME - frexpl is not yet supported; and cvt infloops if (double)f
410    converts a finite value into infinity.  */
411 /* #  define FREXP frexpl */
412 #  define FREXP(f,e) ((_LONG_DOUBLE) frexp ((double)f, e))
413 # endif /* !_NO_LONGDBL */
414
415 static char *cvt(struct _reent *, _PRINTF_FLOAT_TYPE, int, int, char *, int *,
416                  int, int *, char *);
417
418 static int exponent(char *, int, int);
419
420 #endif /* FLOATING_POINT */
421
422 /* BUF must be big enough for the maximum %#llo (assuming long long is
423    at most 64 bits, this would be 23 characters), the maximum
424    multibyte character %C, and the maximum default precision of %La
425    (assuming long double is at most 128 bits with 113 bits of
426    mantissa, this would be 29 characters).  %e, %f, and %g use
427    reentrant storage shared with mprec.  All other formats that use
428    buf get by with fewer characters.  Making BUF slightly bigger
429    reduces the need for malloc in %.*a and %S, when large precision or
430    long strings are processed.
431    The bigger size of 100 bytes is used on systems which allow number
432    strings using the locale's grouping character.  Since that's a multibyte
433    value, we should use a conservative value.
434    */
435 #ifdef _WANT_IO_C99_FORMATS
436 #define BUF             100
437 #else
438 #define BUF             40
439 #endif
440 #if defined _MB_CAPABLE && MB_LEN_MAX > BUF
441 # undef BUF
442 # define BUF MB_LEN_MAX
443 #endif
444
445 #ifndef _NO_LONGLONG
446 # define quad_t long long
447 # define u_quad_t unsigned long long
448 #else
449 # define quad_t long
450 # define u_quad_t unsigned long
451 #endif
452
453 typedef quad_t * quad_ptr_t;
454 typedef _PTR     void_ptr_t;
455 typedef char *   char_ptr_t;
456 typedef long *   long_ptr_t;
457 typedef int  *   int_ptr_t;
458 typedef short *  short_ptr_t;
459
460 #ifndef _NO_POS_ARGS
461 # ifdef NL_ARGMAX
462 #  define MAX_POS_ARGS NL_ARGMAX
463 # else
464 #  define MAX_POS_ARGS 32
465 # endif
466
467 union arg_val
468 {
469   int val_int;
470   u_int val_u_int;
471   long val_long;
472   u_long val_u_long;
473   float val_float;
474   double val_double;
475   _LONG_DOUBLE val__LONG_DOUBLE;
476   int_ptr_t val_int_ptr_t;
477   short_ptr_t val_short_ptr_t;
478   long_ptr_t val_long_ptr_t;
479   char_ptr_t val_char_ptr_t;
480   quad_ptr_t val_quad_ptr_t;
481   void_ptr_t val_void_ptr_t;
482   quad_t val_quad_t;
483   u_quad_t val_u_quad_t;
484   wint_t val_wint_t;
485 };
486
487 static union arg_val *
488 _EXFUN(get_arg, (struct _reent *data, int n, char *fmt,
489                  va_list *ap, int *numargs, union arg_val *args,
490                  int *arg_type, char **last_fmt));
491 #endif /* !_NO_POS_ARGS */
492
493 /*
494  * Macros for converting digits to letters and vice versa
495  */
496 #define to_digit(c)     ((c) - '0')
497 #define is_digit(c)     ((unsigned)to_digit (c) <= 9)
498 #define to_char(n)      ((n) + '0')
499
500 /*
501  * Flags used during conversion.
502  */
503 #define ALT             0x001           /* alternate form */
504 #define HEXPREFIX       0x002           /* add 0x or 0X prefix */
505 #define LADJUST         0x004           /* left adjustment */
506 #define LONGDBL         0x008           /* long double */
507 #define LONGINT         0x010           /* long integer */
508 #ifndef _NO_LONGLONG
509 # define QUADINT        0x020           /* quad integer */
510 #else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
511          that %lld behaves the same as %ld, not as %d, as expected if:
512          sizeof (long long) = sizeof long > sizeof int  */
513 # define QUADINT        LONGINT
514 #endif
515 #define SHORTINT        0x040           /* short integer */
516 #define ZEROPAD         0x080           /* zero (as opposed to blank) pad */
517 #define FPT             0x100           /* Floating point number */
518 #ifdef _WANT_IO_C99_FORMATS
519 # define CHARINT        0x200           /* char as integer */
520 #else /* define as 0, to make SARG and UARG occupy fewer instructions  */
521 # define CHARINT        0
522 #endif
523 #ifdef _WANT_IO_C99_FORMATS
524 # define GROUPING       0x400           /* use grouping ("'" flag) */
525 #endif
526
527 int _EXFUN(_VFPRINTF_R, (struct _reent *, FILE *, _CONST char *, va_list));
528
529 #ifndef STRING_ONLY
530 int
531 _DEFUN(VFPRINTF, (fp, fmt0, ap),
532        FILE * fp         _AND
533        _CONST char *fmt0 _AND
534        va_list ap)
535 {
536   int result;
537   result = _VFPRINTF_R (_REENT, fp, fmt0, ap);
538   return result;
539 }
540 #endif /* STRING_ONLY */
541
542 int
543 _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
544        struct _reent *data _AND
545        FILE * fp           _AND
546        _CONST char *fmt0   _AND
547        va_list ap)
548 {
549         register char *fmt;     /* format string */
550         register int ch;        /* character from fmt */
551         register int n, m;      /* handy integers (short term usage) */
552         register char *cp;      /* handy char pointer (short term usage) */
553         register struct __siov *iovp;/* for PRINT macro */
554         register int flags;     /* flags as above */
555         char *fmt_anchor;       /* current format spec being processed */
556 #ifndef _NO_POS_ARGS
557         int N;                  /* arg number */
558         int arg_index;          /* index into args processed directly */
559         int numargs;            /* number of varargs read */
560         char *saved_fmt;        /* saved fmt pointer */
561         union arg_val args[MAX_POS_ARGS];
562         int arg_type[MAX_POS_ARGS];
563         int is_pos_arg;         /* is current format positional? */
564         int old_is_pos_arg;     /* is current format positional? */
565 #endif
566         int ret;                /* return value accumulator */
567         int width;              /* width from format (%8d), or 0 */
568         int prec;               /* precision from format (%.3d), or -1 */
569         char sign;              /* sign prefix (' ', '+', '-', or \0) */
570 #ifdef _WANT_IO_C99_FORMATS
571                                 /* locale specific numeric grouping */
572         char *thousands_sep = NULL;
573         size_t thsnd_len = 0;
574         const char *grouping = NULL;
575 #endif
576 #ifdef FLOATING_POINT
577         char *decimal_point = _localeconv_r (data)->decimal_point;
578         size_t decp_len = strlen (decimal_point);
579         char softsign;          /* temporary negative sign for floats */
580         union { int i; _PRINTF_FLOAT_TYPE fp; } _double_ = {0};
581 # define _fpvalue (_double_.fp)
582         int expt;               /* integer value of exponent */
583         int expsize = 0;        /* character count for expstr */
584         char expstr[MAXEXPLEN]; /* buffer for exponent string */
585         int lead;               /* sig figs before decimal or group sep */
586 #endif /* FLOATING_POINT */
587 #if defined (FLOATING_POINT) || defined (_WANT_IO_C99_FORMATS)
588         int ndig = 0;           /* actual number of digits returned by cvt */
589 #endif
590 #if defined (FLOATING_POINT) && defined (_WANT_IO_C99_FORMATS)
591         int nseps;              /* number of group separators with ' */
592         int nrepeats;           /* number of repeats of the last group */
593 #endif
594         u_quad_t _uquad;        /* integer arguments %[diouxX] */
595         enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
596         int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
597         int realsz;             /* field size expanded by dprec */
598         int size;               /* size of converted field or string */
599         char *xdigs = NULL;     /* digits for [xX] conversion */
600 #define NIOV 8
601         struct __suio uio;      /* output information: summary */
602         struct __siov iov[NIOV];/* ... and individual io vectors */
603         char buf[BUF];          /* space for %c, %S, %[diouxX], %[aA] */
604         char ox[2];             /* space for 0x hex-prefix */
605 #ifdef _MB_CAPABLE
606         wchar_t wc;
607         mbstate_t state;        /* mbtowc calls from library must not change state */
608 #endif
609         char *malloc_buf = NULL;/* handy pointer for malloced buffers */
610
611         /*
612          * Choose PADSIZE to trade efficiency vs. size.  If larger printf
613          * fields occur frequently, increase PADSIZE and make the initialisers
614          * below longer.
615          */
616 #define PADSIZE 16              /* pad chunk size */
617         static _CONST char blanks[PADSIZE] =
618          {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
619         static _CONST char zeroes[PADSIZE] =
620          {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
621
622 #ifdef _MB_CAPABLE
623         memset (&state, '\0', sizeof (state));
624 #endif
625         /*
626          * BEWARE, these `goto error' on error, and PAD uses `n'.
627          */
628 #define PRINT(ptr, len) { \
629         iovp->iov_base = (ptr); \
630         iovp->iov_len = (len); \
631         uio.uio_resid += (len); \
632         iovp++; \
633         if (++uio.uio_iovcnt >= NIOV) { \
634                 if (__SPRINT(data, fp, &uio)) \
635                         goto error; \
636                 iovp = iov; \
637         } \
638 }
639 #define PAD(howmany, with) { \
640         if ((n = (howmany)) > 0) { \
641                 while (n > PADSIZE) { \
642                         PRINT (with, PADSIZE); \
643                         n -= PADSIZE; \
644                 } \
645                 PRINT (with, n); \
646         } \
647 }
648 #define PRINTANDPAD(p, ep, len, with) { \
649         int n = (ep) - (p); \
650         if (n > (len)) \
651                 n = (len); \
652         if (n > 0) \
653                 PRINT((p), n); \
654         PAD((len) - (n > 0 ? n : 0), (with)); \
655 }
656 #define FLUSH() { \
657         if (uio.uio_resid && __SPRINT(data, fp, &uio)) \
658                 goto error; \
659         uio.uio_iovcnt = 0; \
660         iovp = iov; \
661 }
662
663         /* Macros to support positional arguments */
664 #ifndef _NO_POS_ARGS
665 # define GET_ARG(n, ap, type)                                           \
666         (is_pos_arg                                                     \
667          ? (n < numargs                                                 \
668             ? args[n].val_##type                                        \
669             : get_arg (data, n, fmt_anchor, &ap, &numargs, args,        \
670                        arg_type, &saved_fmt)->val_##type)               \
671          : (arg_index++ < numargs                                       \
672             ? args[n].val_##type                                        \
673             : (numargs < MAX_POS_ARGS                                   \
674                ? args[numargs++].val_##type = va_arg (ap, type)         \
675                : va_arg (ap, type))))
676 #else
677 # define GET_ARG(n, ap, type) (va_arg (ap, type))
678 #endif
679
680         /*
681          * To extend shorts properly, we need both signed and unsigned
682          * argument extraction methods.
683          */
684 #ifndef _NO_LONGLONG
685 #define SARG() \
686         (flags&QUADINT ? GET_ARG (N, ap, quad_t) : \
687             flags&LONGINT ? GET_ARG (N, ap, long) : \
688             flags&SHORTINT ? (long)(short)GET_ARG (N, ap, int) : \
689             flags&CHARINT ? (long)(signed char)GET_ARG (N, ap, int) : \
690             (long)GET_ARG (N, ap, int))
691 #define UARG() \
692         (flags&QUADINT ? GET_ARG (N, ap, u_quad_t) : \
693             flags&LONGINT ? GET_ARG (N, ap, u_long) : \
694             flags&SHORTINT ? (u_long)(u_short)GET_ARG (N, ap, int) : \
695             flags&CHARINT ? (u_long)(unsigned char)GET_ARG (N, ap, int) : \
696             (u_long)GET_ARG (N, ap, u_int))
697 #else
698 #define SARG() \
699         (flags&LONGINT ? GET_ARG (N, ap, long) : \
700             flags&SHORTINT ? (long)(short)GET_ARG (N, ap, int) : \
701             flags&CHARINT ? (long)(signed char)GET_ARG (N, ap, int) : \
702             (long)GET_ARG (N, ap, int))
703 #define UARG() \
704         (flags&LONGINT ? GET_ARG (N, ap, u_long) : \
705             flags&SHORTINT ? (u_long)(u_short)GET_ARG (N, ap, int) : \
706             flags&CHARINT ? (u_long)(unsigned char)GET_ARG (N, ap, int) : \
707             (u_long)GET_ARG (N, ap, u_int))
708 #endif
709
710 #ifndef STRING_ONLY
711         /* Initialize std streams if not dealing with sprintf family.  */
712         CHECK_INIT (data, fp);
713         _newlib_flockfile_start (fp);
714
715         ORIENT(fp, -1);
716
717         /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
718         if (cantwrite (data, fp)) {
719                 _newlib_flockfile_exit (fp);
720                 return (EOF);
721         }
722
723         /* optimise fprintf(stderr) (and other unbuffered Unix files) */
724         if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
725             fp->_file >= 0) {
726                 _newlib_flockfile_exit (fp);
727                 return (__sbprintf (data, fp, fmt0, ap));
728         }
729 #else /* STRING_ONLY */
730         /* Create initial buffer if we are called by asprintf family.  */
731         if (fp->_flags & __SMBF && !fp->_bf._base)
732         {
733                 fp->_bf._base = fp->_p = _malloc_r (data, 64);
734                 if (!fp->_p)
735                 {
736                         data->_errno = ENOMEM;
737                         return EOF;
738                 }
739                 fp->_bf._size = 64;
740         }
741 #endif /* STRING_ONLY */
742
743         fmt = (char *)fmt0;
744         uio.uio_iov = iovp = iov;
745         uio.uio_resid = 0;
746         uio.uio_iovcnt = 0;
747         ret = 0;
748 #ifndef _NO_POS_ARGS
749         arg_index = 0;
750         saved_fmt = NULL;
751         arg_type[0] = -1;
752         numargs = 0;
753         is_pos_arg = 0;
754 #endif
755
756         /*
757          * Scan the format for conversions (`%' character).
758          */
759         for (;;) {
760                 cp = fmt;
761 #ifdef _MB_CAPABLE
762                 while ((n = __mbtowc (data, &wc, fmt, MB_CUR_MAX,
763                                       __locale_charset (), &state)) != 0) {
764                     if (n < 0) {
765                         /* Wave invalid chars through. */
766                         memset (&state, 0, sizeof state);
767                         n = 1;
768                     }
769                     else if (wc == '%')
770                         break;
771                     fmt += n;
772                 }
773 #else
774                 while (*fmt != '\0' && *fmt != '%')
775                     fmt += 1;
776 #endif
777                 if ((m = fmt - cp) != 0) {
778                         PRINT (cp, m);
779                         ret += m;
780                 }
781 #ifdef _MB_CAPABLE
782                 if (n <= 0)
783                     goto done;
784 #else
785                 if (*fmt == '\0')
786                     goto done;
787 #endif
788                 fmt_anchor = fmt;
789                 fmt++;          /* skip over '%' */
790
791                 flags = 0;
792                 dprec = 0;
793                 width = 0;
794                 prec = -1;
795                 sign = '\0';
796 #ifdef FLOATING_POINT
797                 lead = 0;
798 #ifdef _WANT_IO_C99_FORMATS
799                 nseps = nrepeats = 0;
800 #endif
801 #endif
802 #ifndef _NO_POS_ARGS
803                 N = arg_index;
804                 is_pos_arg = 0;
805 #endif
806
807 rflag:          ch = *fmt++;
808 reswitch:       switch (ch) {
809 #ifdef _WANT_IO_C99_FORMATS
810                 case '\'':
811                         thousands_sep = _localeconv_r (data)->thousands_sep;
812                         thsnd_len = strlen (thousands_sep);
813                         grouping = _localeconv_r (data)->grouping;
814                         if (thsnd_len > 0 && grouping && *grouping)
815                           flags |= GROUPING;
816                         goto rflag;
817 #endif
818                 case ' ':
819                         /*
820                          * ``If the space and + flags both appear, the space
821                          * flag will be ignored.''
822                          *      -- ANSI X3J11
823                          */
824                         if (!sign)
825                                 sign = ' ';
826                         goto rflag;
827                 case '#':
828                         flags |= ALT;
829                         goto rflag;
830                 case '*':
831 #ifndef _NO_POS_ARGS
832                         /* we must check for positional arg used for dynamic width */
833                         n = N;
834                         old_is_pos_arg = is_pos_arg;
835                         is_pos_arg = 0;
836                         if (is_digit (*fmt)) {
837                                 char *old_fmt = fmt;
838
839                                 n = 0;
840                                 ch = *fmt++;
841                                 do {
842                                         n = 10 * n + to_digit (ch);
843                                         ch = *fmt++;
844                                 } while (is_digit (ch));
845
846                                 if (ch == '$') {
847                                         if (n <= MAX_POS_ARGS) {
848                                                 n -= 1;
849                                                 is_pos_arg = 1;
850                                         }
851                                         else
852                                                 goto error;
853                                 }
854                                 else {
855                                         fmt = old_fmt;
856                                         goto rflag;
857                                 }
858                         }
859 #endif /* !_NO_POS_ARGS */
860
861                         /*
862                          * ``A negative field width argument is taken as a
863                          * - flag followed by a positive field width.''
864                          *      -- ANSI X3J11
865                          * They don't exclude field widths read from args.
866                          */
867                         width = GET_ARG (n, ap, int);
868 #ifndef _NO_POS_ARGS
869                         is_pos_arg = old_is_pos_arg;
870 #endif
871                         if (width >= 0)
872                                 goto rflag;
873                         width = -width;
874                         /* FALLTHROUGH */
875                 case '-':
876                         flags |= LADJUST;
877                         goto rflag;
878                 case '+':
879                         sign = '+';
880                         goto rflag;
881                 case '.':
882                         if ((ch = *fmt++) == '*') {
883 #ifndef _NO_POS_ARGS
884                                 /* we must check for positional arg used for dynamic width */
885                                 n = N;
886                                 old_is_pos_arg = is_pos_arg;
887                                 is_pos_arg = 0;
888                                 if (is_digit (*fmt)) {
889                                         char *old_fmt = fmt;
890
891                                         n = 0;
892                                         ch = *fmt++;
893                                         do {
894                                                 n = 10 * n + to_digit (ch);
895                                                 ch = *fmt++;
896                                         } while (is_digit (ch));
897
898                                         if (ch == '$') {
899                                                 if (n <= MAX_POS_ARGS) {
900                                                         n -= 1;
901                                                         is_pos_arg = 1;
902                                                 }
903                                                 else
904                                                         goto error;
905                                         }
906                                         else {
907                                                 fmt = old_fmt;
908                                                 goto rflag;
909                                         }
910                                 }
911 #endif /* !_NO_POS_ARGS */
912                                 prec = GET_ARG (n, ap, int);
913 #ifndef _NO_POS_ARGS
914                                 is_pos_arg = old_is_pos_arg;
915 #endif
916                                 if (prec < 0)
917                                         prec = -1;
918                                 goto rflag;
919                         }
920                         n = 0;
921                         while (is_digit (ch)) {
922                                 n = 10 * n + to_digit (ch);
923                                 ch = *fmt++;
924                         }
925                         prec = n < 0 ? -1 : n;
926                         goto reswitch;
927                 case '0':
928                         /*
929                          * ``Note that 0 is taken as a flag, not as the
930                          * beginning of a field width.''
931                          *      -- ANSI X3J11
932                          */
933                         flags |= ZEROPAD;
934                         goto rflag;
935                 case '1': case '2': case '3': case '4':
936                 case '5': case '6': case '7': case '8': case '9':
937                         n = 0;
938                         do {
939                                 n = 10 * n + to_digit (ch);
940                                 ch = *fmt++;
941                         } while (is_digit (ch));
942 #ifndef _NO_POS_ARGS
943                         if (ch == '$') {
944                                 if (n <= MAX_POS_ARGS) {
945                                         N = n - 1;
946                                         is_pos_arg = 1;
947                                         goto rflag;
948                                 }
949                                 else
950                                         goto error;
951                         }
952 #endif /* !_NO_POS_ARGS */
953                         width = n;
954                         goto reswitch;
955 #ifdef FLOATING_POINT
956                 case 'L':
957                         flags |= LONGDBL;
958                         goto rflag;
959 #endif
960                 case 'h':
961 #ifdef _WANT_IO_C99_FORMATS
962                         if (*fmt == 'h') {
963                                 fmt++;
964                                 flags |= CHARINT;
965                         } else
966 #endif
967                                 flags |= SHORTINT;
968                         goto rflag;
969                 case 'l':
970 #if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
971                         if (*fmt == 'l') {
972                                 fmt++;
973                                 flags |= QUADINT;
974                         } else
975 #endif
976                                 flags |= LONGINT;
977                         goto rflag;
978                 case 'q': /* extension */
979                         flags |= QUADINT;
980                         goto rflag;
981 #ifdef _WANT_IO_C99_FORMATS
982                 case 'j':
983                   if (sizeof (intmax_t) == sizeof (long))
984                     flags |= LONGINT;
985                   else
986                     flags |= QUADINT;
987                   goto rflag;
988                 case 'z':
989                   if (sizeof (size_t) < sizeof (int))
990                     /* POSIX states size_t is 16 or more bits, as is short.  */
991                     flags |= SHORTINT;
992                   else if (sizeof (size_t) == sizeof (int))
993                     /* no flag needed */;
994                   else if (sizeof (size_t) <= sizeof (long))
995                     flags |= LONGINT;
996                   else
997                     /* POSIX states that at least one programming
998                        environment must support size_t no wider than
999                        long, but that means other environments can
1000                        have size_t as wide as long long.  */
1001                     flags |= QUADINT;
1002                   goto rflag;
1003                 case 't':
1004                   if (sizeof (ptrdiff_t) < sizeof (int))
1005                     /* POSIX states ptrdiff_t is 16 or more bits, as
1006                        is short.  */
1007                     flags |= SHORTINT;
1008                   else if (sizeof (ptrdiff_t) == sizeof (int))
1009                     /* no flag needed */;
1010                   else if (sizeof (ptrdiff_t) <= sizeof (long))
1011                     flags |= LONGINT;
1012                   else
1013                     /* POSIX states that at least one programming
1014                        environment must support ptrdiff_t no wider than
1015                        long, but that means other environments can
1016                        have ptrdiff_t as wide as long long.  */
1017                     flags |= QUADINT;
1018                   goto rflag;
1019                 case 'C':
1020 #endif /* _WANT_IO_C99_FORMATS */
1021                 case 'c':
1022                         cp = buf;
1023 #ifdef _MB_CAPABLE
1024                         if (ch == 'C' || (flags & LONGINT)) {
1025                                 mbstate_t ps;
1026
1027                                 memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
1028                                 if ((size = (int)_wcrtomb_r (data, cp,
1029                                                (wchar_t)GET_ARG (N, ap, wint_t),
1030                                                 &ps)) == -1) {
1031                                         fp->_flags |= __SERR;
1032                                         goto error;
1033                                 }
1034                         }
1035                         else
1036 #endif /* _MB_CAPABLE */
1037                         {
1038                                 *cp = GET_ARG (N, ap, int);
1039                                 size = 1;
1040                         }
1041                         sign = '\0';
1042                         break;
1043                 case 'D':  /* extension */
1044                         flags |= LONGINT;
1045                         /*FALLTHROUGH*/
1046                 case 'd':
1047                 case 'i':
1048                         _uquad = SARG ();
1049 #ifndef _NO_LONGLONG
1050                         if ((quad_t)_uquad < 0)
1051 #else
1052                         if ((long) _uquad < 0)
1053 #endif
1054                         {
1055
1056                                 _uquad = -_uquad;
1057                                 sign = '-';
1058                         }
1059                         base = DEC;
1060                         goto number;
1061 #ifdef FLOATING_POINT
1062 # ifdef _WANT_IO_C99_FORMATS
1063                 case 'a':
1064                 case 'A':
1065                 case 'F':
1066 # endif
1067                 case 'e':
1068                 case 'E':
1069                 case 'f':
1070                 case 'g':
1071                 case 'G':
1072 # ifdef _NO_LONGDBL
1073                         if (flags & LONGDBL) {
1074                                 _fpvalue = (double) GET_ARG (N, ap, _LONG_DOUBLE);
1075                         } else {
1076                                 _fpvalue = GET_ARG (N, ap, double);
1077                         }
1078
1079                         /* do this before tricky precision changes
1080
1081                            If the output is infinite or NaN, leading
1082                            zeros are not permitted.  Otherwise, scanf
1083                            could not read what printf wrote.
1084                          */
1085                         if (isinf (_fpvalue)) {
1086                                 if (_fpvalue < 0)
1087                                         sign = '-';
1088                                 if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */
1089                                         cp = "INF";
1090                                 else
1091                                         cp = "inf";
1092                                 size = 3;
1093                                 flags &= ~ZEROPAD;
1094                                 break;
1095                         }
1096                         if (isnan (_fpvalue)) {
1097                                 if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */
1098                                         cp = "NAN";
1099                                 else
1100                                         cp = "nan";
1101                                 size = 3;
1102                                 flags &= ~ZEROPAD;
1103                                 break;
1104                         }
1105
1106 # else /* !_NO_LONGDBL */
1107
1108                         if (flags & LONGDBL) {
1109                                 _fpvalue = GET_ARG (N, ap, _LONG_DOUBLE);
1110                         } else {
1111                                 _fpvalue = (_LONG_DOUBLE)GET_ARG (N, ap, double);
1112                         }
1113
1114                         /* do this before tricky precision changes */
1115                         expt = _ldcheck (&_fpvalue);
1116                         if (expt == 2) {
1117                                 if (_fpvalue < 0)
1118                                         sign = '-';
1119                                 if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */
1120                                         cp = "INF";
1121                                 else
1122                                         cp = "inf";
1123                                 size = 3;
1124                                 flags &= ~ZEROPAD;
1125                                 break;
1126                         }
1127                         if (expt == 1) {
1128                                 if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */
1129                                         cp = "NAN";
1130                                 else
1131                                         cp = "nan";
1132                                 size = 3;
1133                                 flags &= ~ZEROPAD;
1134                                 break;
1135                         }
1136 # endif /* !_NO_LONGDBL */
1137
1138 # ifdef _WANT_IO_C99_FORMATS
1139                         if (ch == 'a' || ch == 'A') {
1140                                 ox[0] = '0';
1141                                 ox[1] = ch == 'a' ? 'x' : 'X';
1142                                 flags |= HEXPREFIX;
1143                                 if (prec >= BUF)
1144                                   {
1145                                     if ((malloc_buf =
1146                                          (char *)_malloc_r (data, prec + 1))
1147                                         == NULL)
1148                                       {
1149                                         fp->_flags |= __SERR;
1150                                         goto error;
1151                                       }
1152                                     cp = malloc_buf;
1153                                   }
1154                                 else
1155                                   cp = buf;
1156                         } else
1157 # endif /* _WANT_IO_C99_FORMATS */
1158                         if (prec == -1) {
1159                                 prec = DEFPREC;
1160                         } else if ((ch == 'g' || ch == 'G') && prec == 0) {
1161                                 prec = 1;
1162                         }
1163
1164                         flags |= FPT;
1165
1166                         cp = cvt (data, _fpvalue, prec, flags, &softsign,
1167                                   &expt, ch, &ndig, cp);
1168
1169                         if (ch == 'g' || ch == 'G') {
1170                                 if (expt <= -4 || expt > prec)
1171                                         ch -= 2; /* 'e' or 'E' */
1172                                 else
1173                                         ch = 'g';
1174                         }
1175 # ifdef _WANT_IO_C99_FORMATS
1176                         else if (ch == 'F')
1177                                 ch = 'f';
1178 # endif
1179                         if (ch <= 'e') {        /* 'a', 'A', 'e', or 'E' fmt */
1180                                 --expt;
1181                                 expsize = exponent (expstr, expt, ch);
1182                                 size = expsize + ndig;
1183                                 if (ndig > 1 || flags & ALT)
1184                                         ++size;
1185 # ifdef _WANT_IO_C99_FORMATS
1186                                 flags &= ~GROUPING;
1187 # endif
1188                         } else {
1189                                 if (ch == 'f') {                /* f fmt */
1190                                         if (expt > 0) {
1191                                                 size = expt;
1192                                                 if (prec || flags & ALT)
1193                                                         size += prec + 1;
1194                                         } else  /* "0.X" */
1195                                                 size = (prec || flags & ALT)
1196                                                           ? prec + 2
1197                                                           : 1;
1198                                 } else if (expt >= ndig) { /* fixed g fmt */
1199                                         size = expt;
1200                                         if (flags & ALT)
1201                                                 ++size;
1202                                 } else
1203                                         size = ndig + (expt > 0 ?
1204                                                 1 : 2 - expt);
1205 # ifdef _WANT_IO_C99_FORMATS
1206                                 if ((flags & GROUPING) && expt > 0) {
1207                                         /* space for thousands' grouping */
1208                                         nseps = nrepeats = 0;
1209                                         lead = expt;
1210                                         while (*grouping != CHAR_MAX) {
1211                                                 if (lead <= *grouping)
1212                                                         break;
1213                                                 lead -= *grouping;
1214                                                 if (grouping[1]) {
1215                                                         nseps++;
1216                                                         grouping++;
1217                                                 } else
1218                                                         nrepeats++;
1219                                         }
1220                                         size += (nseps + nrepeats) * thsnd_len;
1221                                 } else
1222 # endif
1223                                         lead = expt;
1224                         }
1225
1226                         if (softsign)
1227                                 sign = '-';
1228                         break;
1229 #endif /* FLOATING_POINT */
1230 #ifdef _GLIBC_EXTENSION
1231                 case 'm':  /* extension */
1232                         {
1233                                 int dummy;
1234                                 cp = _strerror_r (data, data->_errno, 1, &dummy);
1235                         }
1236                         flags &= ~LONGINT;
1237                         goto string;
1238 #endif
1239                 case 'n':
1240 #ifndef _NO_LONGLONG
1241                         if (flags & QUADINT)
1242                                 *GET_ARG (N, ap, quad_ptr_t) = ret;
1243                         else
1244 #endif
1245                         if (flags & LONGINT)
1246                                 *GET_ARG (N, ap, long_ptr_t) = ret;
1247                         else if (flags & SHORTINT)
1248                                 *GET_ARG (N, ap, short_ptr_t) = ret;
1249 #ifdef _WANT_IO_C99_FORMATS
1250                         else if (flags & CHARINT)
1251                                 *GET_ARG (N, ap, char_ptr_t) = ret;
1252 #endif
1253                         else
1254                                 *GET_ARG (N, ap, int_ptr_t) = ret;
1255                         continue;       /* no output */
1256                 case 'O': /* extension */
1257                         flags |= LONGINT;
1258                         /*FALLTHROUGH*/
1259                 case 'o':
1260                         _uquad = UARG ();
1261                         base = OCT;
1262 #ifdef _WANT_IO_C99_FORMATS
1263                         flags &= ~GROUPING;
1264 #endif
1265                         goto nosign;
1266                 case 'p':
1267                         /*
1268                          * ``The argument shall be a pointer to void.  The
1269                          * value of the pointer is converted to a sequence
1270                          * of printable characters, in an implementation-
1271                          * defined manner.''
1272                          *      -- ANSI X3J11
1273                          */
1274                         /* NOSTRICT */
1275                         _uquad = (uintptr_t) GET_ARG (N, ap, void_ptr_t);
1276                         base = HEX;
1277                         xdigs = "0123456789abcdef";
1278                         flags |= HEXPREFIX;
1279                         ox[0] = '0';
1280                         ox[1] = ch = 'x';
1281                         goto nosign;
1282                 case 's':
1283 #ifdef _WANT_IO_C99_FORMATS
1284                 case 'S':
1285 #endif
1286                         cp = GET_ARG (N, ap, char_ptr_t);
1287 #ifdef _GLIBC_EXTENSION
1288 string:
1289 #endif
1290                         sign = '\0';
1291 #ifndef __OPTIMIZE_SIZE__
1292                         /* Behavior is undefined if the user passed a
1293                            NULL string when precision is not 0.
1294                            However, if we are not optimizing for size,
1295                            we might as well mirror glibc behavior.  */
1296                         if (cp == NULL) {
1297                                 cp = "(null)";
1298                                 size = ((unsigned) prec > 6U) ? 6 : prec;
1299                         }
1300                         else
1301 #endif /* __OPTIMIZE_SIZE__ */
1302 #ifdef _MB_CAPABLE
1303                         if (ch == 'S' || (flags & LONGINT)) {
1304                                 mbstate_t ps;
1305                                 _CONST wchar_t *wcp;
1306
1307                                 wcp = (_CONST wchar_t *)cp;
1308                                 size = m = 0;
1309                                 memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
1310
1311                                 /* Count number of bytes needed for multibyte
1312                                    string that will be produced from widechar
1313                                    string.  */
1314                                 if (prec >= 0) {
1315                                         while (1) {
1316                                                 if (wcp[m] == L'\0')
1317                                                         break;
1318                                                 if ((n = (int)_wcrtomb_r (data,
1319                                                      buf, wcp[m], &ps)) == -1) {
1320                                                         fp->_flags |= __SERR;
1321                                                         goto error;
1322                                                 }
1323                                                 if (n + size > prec)
1324                                                         break;
1325                                                 m += 1;
1326                                                 size += n;
1327                                                 if (size == prec)
1328                                                         break;
1329                                         }
1330                                 }
1331                                 else {
1332                                         if ((size = (int)_wcsrtombs_r (data,
1333                                                    NULL, &wcp, 0, &ps)) == -1) {
1334                                                 fp->_flags |= __SERR;
1335                                                 goto error;
1336                                         }
1337                                         wcp = (_CONST wchar_t *)cp;
1338                                 }
1339
1340                                 if (size == 0)
1341                                         break;
1342
1343                                 if (size >= BUF) {
1344                                         if ((malloc_buf =
1345                                              (char *)_malloc_r (data, size + 1))
1346                                             == NULL) {
1347                                                 fp->_flags |= __SERR;
1348                                                 goto error;
1349                                         }
1350                                         cp = malloc_buf;
1351                                 } else
1352                                         cp = buf;
1353
1354                                 /* Convert widechar string to multibyte string. */
1355                                 memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
1356                                 if (_wcsrtombs_r (data, cp, &wcp, size, &ps)
1357                                     != size) {
1358                                         fp->_flags |= __SERR;
1359                                         goto error;
1360                                 }
1361                                 cp[size] = '\0';
1362                         }
1363                         else
1364 #endif /* _MB_CAPABLE */
1365                         if (prec >= 0) {
1366                                 /*
1367                                  * can't use strlen; can only look for the
1368                                  * NUL in the first `prec' characters, and
1369                                  * strlen () will go further.
1370                                  */
1371                                 char *p = memchr (cp, 0, prec);
1372
1373                                 if (p != NULL) {
1374                                         size = p - cp;
1375                                         if (size > prec)
1376                                                 size = prec;
1377                                 } else
1378                                         size = prec;
1379                         } else
1380                                 size = strlen (cp);
1381
1382                         break;
1383                 case 'U': /* extension */
1384                         flags |= LONGINT;
1385                         /*FALLTHROUGH*/
1386                 case 'u':
1387                         _uquad = UARG ();
1388                         base = DEC;
1389                         goto nosign;
1390                 case 'X':
1391                         xdigs = "0123456789ABCDEF";
1392                         goto hex;
1393                 case 'x':
1394                         xdigs = "0123456789abcdef";
1395 hex:                    _uquad = UARG ();
1396                         base = HEX;
1397                         /* leading 0x/X only if non-zero */
1398                         if (flags & ALT && _uquad != 0) {
1399                                 ox[0] = '0';
1400                                 ox[1] = ch;
1401                                 flags |= HEXPREFIX;
1402                         }
1403
1404 #ifdef _WANT_IO_C99_FORMATS
1405                         flags &= ~GROUPING;
1406 #endif
1407                         /* unsigned conversions */
1408 nosign:                 sign = '\0';
1409                         /*
1410                          * ``... diouXx conversions ... if a precision is
1411                          * specified, the 0 flag will be ignored.''
1412                          *      -- ANSI X3J11
1413                          */
1414 number:                 if ((dprec = prec) >= 0)
1415                                 flags &= ~ZEROPAD;
1416
1417                         /*
1418                          * ``The result of converting a zero value with an
1419                          * explicit precision of zero is no characters.''
1420                          *      -- ANSI X3J11
1421                          */
1422                         cp = buf + BUF;
1423                         if (_uquad != 0 || prec != 0) {
1424                                 /*
1425                                  * Unsigned mod is hard, and unsigned mod
1426                                  * by a constant is easier than that by
1427                                  * a variable; hence this switch.
1428                                  */
1429                                 switch (base) {
1430                                 case OCT:
1431                                         do {
1432                                                 *--cp = to_char (_uquad & 7);
1433                                                 _uquad >>= 3;
1434                                         } while (_uquad);
1435                                         /* handle octal leading 0 */
1436                                         if (flags & ALT && *cp != '0')
1437                                                 *--cp = '0';
1438                                         break;
1439
1440                                 case DEC:
1441                                         /* many numbers are 1 digit */
1442                                         if (_uquad < 10) {
1443                                                 *--cp = to_char(_uquad);
1444                                                 break;
1445                                         }
1446 #ifdef _WANT_IO_C99_FORMATS
1447                                         ndig = 0;
1448 #endif
1449                                         do {
1450                                           *--cp = to_char (_uquad % 10);
1451 #ifdef _WANT_IO_C99_FORMATS
1452                                           ndig++;
1453                                           /* If (*grouping == CHAR_MAX) then no
1454                                              more grouping */
1455                                           if ((flags & GROUPING)
1456                                               && ndig == *grouping
1457                                               && *grouping != CHAR_MAX
1458                                               && _uquad > 9) {
1459                                             cp -= thsnd_len;
1460                                             strncpy (cp, thousands_sep,
1461                                                      thsnd_len);
1462                                             ndig = 0;
1463                                             /* If (grouping[1] == '\0') then we
1464                                                have to use *grouping character
1465                                                (last grouping rule) for all
1466                                                next cases. */
1467                                             if (grouping[1] != '\0')
1468                                               grouping++;
1469                                           }
1470 #endif
1471                                           _uquad /= 10;
1472                                         } while (_uquad != 0);
1473                                         break;
1474
1475                                 case HEX:
1476                                         do {
1477                                                 *--cp = xdigs[_uquad & 15];
1478                                                 _uquad >>= 4;
1479                                         } while (_uquad);
1480                                         break;
1481
1482                                 default:
1483                                         cp = "bug in vfprintf: bad base";
1484                                         size = strlen (cp);
1485                                         goto skipsize;
1486                                 }
1487                         }
1488                        /*
1489                         * ...result is to be converted to an 'alternate form'.
1490                         * For o conversion, it increases the precision to force
1491                         * the first digit of the result to be a zero."
1492                         *     -- ANSI X3J11
1493                         *
1494                         * To demonstrate this case, compile and run:
1495                         *    printf ("%#.0o",0);
1496                         */
1497                        else if (base == OCT && (flags & ALT))
1498                          *--cp = '0';
1499
1500                         size = buf + BUF - cp;
1501                 skipsize:
1502                         break;
1503                 default:        /* "%?" prints ?, unless ? is NUL */
1504                         if (ch == '\0')
1505                                 goto done;
1506                         /* pretend it was %c with argument ch */
1507                         cp = buf;
1508                         *cp = ch;
1509                         size = 1;
1510                         sign = '\0';
1511                         break;
1512                 }
1513
1514                 /*
1515                  * All reasonable formats wind up here.  At this point, `cp'
1516                  * points to a string which (if not flags&LADJUST) should be
1517                  * padded out to `width' places.  If flags&ZEROPAD, it should
1518                  * first be prefixed by any sign or other prefix; otherwise,
1519                  * it should be blank padded before the prefix is emitted.
1520                  * After any left-hand padding and prefixing, emit zeroes
1521                  * required by a decimal [diouxX] precision, then print the
1522                  * string proper, then emit zeroes required by any leftover
1523                  * floating precision; finally, if LADJUST, pad with blanks.
1524                  * If flags&FPT, ch must be in [aAeEfg].
1525                  *
1526                  * Compute actual size, so we know how much to pad.
1527                  * size excludes decimal prec; realsz includes it.
1528                  */
1529                 realsz = dprec > size ? dprec : size;
1530                 if (sign)
1531                         realsz++;
1532                 if (flags & HEXPREFIX)
1533                         realsz+= 2;
1534
1535                 /* right-adjusting blank padding */
1536                 if ((flags & (LADJUST|ZEROPAD)) == 0)
1537                         PAD (width - realsz, blanks);
1538
1539                 /* prefix */
1540                 if (sign)
1541                         PRINT (&sign, 1);
1542                 if (flags & HEXPREFIX)
1543                         PRINT (ox, 2);
1544
1545                 /* right-adjusting zero padding */
1546                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
1547                         PAD (width - realsz, zeroes);
1548
1549                 /* leading zeroes from decimal precision */
1550                 PAD (dprec - size, zeroes);
1551
1552                 /* the string or number proper */
1553 #ifdef FLOATING_POINT
1554                 if ((flags & FPT) == 0) {
1555                         PRINT (cp, size);
1556                 } else {        /* glue together f_p fragments */
1557                         if (ch >= 'f') {        /* 'f' or 'g' */
1558                                 if (_fpvalue == 0) {
1559                                         /* kludge for __dtoa irregularity */
1560                                         PRINT ("0", 1);
1561                                         if (expt < ndig || flags & ALT) {
1562                                                 PRINT (decimal_point, decp_len);
1563                                                 PAD (ndig - 1, zeroes);
1564                                         }
1565                                 } else if (expt <= 0) {
1566                                         PRINT ("0", 1);
1567                                         if (expt || ndig || flags & ALT) {
1568                                                 PRINT (decimal_point, decp_len);
1569                                                 PAD (-expt, zeroes);
1570                                                 PRINT (cp, ndig);
1571                                         }
1572                                 } else {
1573                                         char *convbuf = cp;
1574                                         PRINTANDPAD(cp, convbuf + ndig,
1575                                                     lead, zeroes);
1576                                         cp += lead;
1577 #ifdef _WANT_IO_C99_FORMATS
1578                                         if (flags & GROUPING) {
1579                                             while (nseps > 0 || nrepeats > 0) {
1580                                                 if (nrepeats > 0)
1581                                                     nrepeats--;
1582                                                 else {
1583                                                     grouping--;
1584                                                     nseps--;
1585                                                 }
1586                                                 PRINT(thousands_sep, thsnd_len);
1587                                                 PRINTANDPAD (cp, convbuf + ndig,
1588                                                              *grouping, zeroes);
1589                                                 cp += *grouping;
1590                                             }
1591                                             if (cp > convbuf + ndig)
1592                                                 cp = convbuf + ndig;
1593                                         }
1594 #endif
1595                                         if (expt < ndig || flags & ALT)
1596                                             PRINT (decimal_point, decp_len);
1597                                         PRINTANDPAD (cp, convbuf + ndig,
1598                                                      ndig - expt, zeroes);
1599                                 }
1600                         } else {        /* 'a', 'A', 'e', or 'E' */
1601                                 if (ndig > 1 || flags & ALT) {
1602                                         PRINT (cp, 1);
1603                                         cp++;
1604                                         PRINT (decimal_point, decp_len);
1605                                         if (_fpvalue) {
1606                                                 PRINT (cp, ndig - 1);
1607                                         } else  /* 0.[0..] */
1608                                                 /* __dtoa irregularity */
1609                                                 PAD (ndig - 1, zeroes);
1610                                 } else  /* XeYYY */
1611                                         PRINT (cp, 1);
1612                                 PRINT (expstr, expsize);
1613                         }
1614                 }
1615 #else /* !FLOATING_POINT */
1616                 PRINT (cp, size);
1617 #endif
1618                 /* left-adjusting padding (always blank) */
1619                 if (flags & LADJUST)
1620                         PAD (width - realsz, blanks);
1621
1622                 /* finally, adjust ret */
1623                 ret += width > realsz ? width : realsz;
1624
1625                 FLUSH ();       /* copy out the I/O vectors */
1626
1627                 if (malloc_buf != NULL) {
1628                         _free_r (data, malloc_buf);
1629                         malloc_buf = NULL;
1630                 }
1631         }
1632 done:
1633         FLUSH ();
1634 error:
1635         if (malloc_buf != NULL)
1636                 _free_r (data, malloc_buf);
1637 #ifndef STRING_ONLY
1638         _newlib_flockfile_end (fp);
1639 #endif
1640         return (__sferror (fp) ? EOF : ret);
1641         /* NOTREACHED */
1642 }
1643
1644 #ifdef FLOATING_POINT
1645
1646 /* Using reentrant DATA, convert finite VALUE into a string of digits
1647    with no decimal point, using NDIGITS precision and FLAGS as guides
1648    to whether trailing zeros must be included.  Set *SIGN to nonzero
1649    if VALUE was negative.  Set *DECPT to the exponent plus one.  Set
1650    *LENGTH to the length of the returned string.  CH must be one of
1651    [aAeEfFgG]; if it is [aA], then the return string lives in BUF,
1652    otherwise the return value shares the mprec reentrant storage.  */
1653 static char *
1654 cvt(struct _reent *data, _PRINTF_FLOAT_TYPE value, int ndigits, int flags,
1655     char *sign, int *decpt, int ch, int *length, char *buf)
1656 {
1657         int mode, dsgn;
1658         char *digits, *bp, *rve;
1659 # ifdef _NO_LONGDBL
1660         union double_union tmp;
1661
1662         tmp.d = value;
1663         if (word0 (tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
1664                 value = -value;
1665                 *sign = '-';
1666         } else
1667                 *sign = '\000';
1668 # else /* !_NO_LONGDBL */
1669         union
1670         {
1671           struct ldieee ieee;
1672           _LONG_DOUBLE val;
1673         } ld;
1674
1675         ld.val = value;
1676         if (ld.ieee.sign) { /* this will check for < 0 and -0.0 */
1677                 value = -value;
1678                 *sign = '-';
1679         } else
1680                 *sign = '\000';
1681 # endif /* !_NO_LONGDBL */
1682
1683 # ifdef _WANT_IO_C99_FORMATS
1684         if (ch == 'a' || ch == 'A') {
1685                 /* This code assumes FLT_RADIX is a power of 2.  The initial
1686                    division ensures the digit before the decimal will be less
1687                    than FLT_RADIX (unless it is rounded later).  There is no
1688                    loss of precision in these calculations.  */
1689                 value = FREXP (value, decpt) / 8;
1690                 if (!value)
1691                         *decpt = 1;
1692                 digits = ch == 'a' ? "0123456789abcdef" : "0123456789ABCDEF";
1693                 bp = buf;
1694                 do {
1695                         value *= 16;
1696                         mode = (int) value;
1697                         value -= mode;
1698                         *bp++ = digits[mode];
1699                 } while (ndigits-- && value);
1700                 if (value > 0.5 || (value == 0.5 && mode & 1)) {
1701                         /* round to even */
1702                         rve = bp;
1703                         while (*--rve == digits[0xf]) {
1704                                 *rve = '0';
1705                         }
1706                         *rve = *rve == '9' ? digits[0xa] : *rve + 1;
1707                 } else {
1708                         while (ndigits-- >= 0) {
1709                                 *bp++ = '0';
1710                         }
1711                 }
1712                 *length = bp - buf;
1713                 return buf;
1714         }
1715 # endif /* _WANT_IO_C99_FORMATS */
1716         if (ch == 'f' || ch == 'F') {
1717                 mode = 3;               /* ndigits after the decimal point */
1718         } else {
1719                 /* To obtain ndigits after the decimal point for the 'e'
1720                  * and 'E' formats, round to ndigits + 1 significant
1721                  * figures.
1722                  */
1723                 if (ch == 'e' || ch == 'E') {
1724                         ndigits++;
1725                 }
1726                 mode = 2;               /* ndigits significant digits */
1727         }
1728
1729         digits = _DTOA_R (data, value, mode, ndigits, decpt, &dsgn, &rve);
1730
1731         if ((ch != 'g' && ch != 'G') || flags & ALT) {  /* Print trailing zeros */
1732                 bp = digits + ndigits;
1733                 if (ch == 'f' || ch == 'F') {
1734                         if (*digits == '0' && value)
1735                                 *decpt = -ndigits + 1;
1736                         bp += *decpt;
1737                 }
1738                 if (value == 0) /* kludge for __dtoa irregularity */
1739                         rve = bp;
1740                 while (rve < bp)
1741                         *rve++ = '0';
1742         }
1743         *length = rve - digits;
1744         return (digits);
1745 }
1746
1747 static int
1748 exponent(char *p0, int exp, int fmtch)
1749 {
1750         register char *p, *t;
1751         char expbuf[MAXEXPLEN];
1752 # ifdef _WANT_IO_C99_FORMATS
1753         int isa = fmtch == 'a' || fmtch == 'A';
1754 # else
1755 #  define isa 0
1756 # endif
1757
1758         p = p0;
1759         *p++ = isa ? 'p' - 'a' + fmtch : fmtch;
1760         if (exp < 0) {
1761                 exp = -exp;
1762                 *p++ = '-';
1763         }
1764         else
1765                 *p++ = '+';
1766         t = expbuf + MAXEXPLEN;
1767         if (exp > 9) {
1768                 do {
1769                         *--t = to_char (exp % 10);
1770                 } while ((exp /= 10) > 9);
1771                 *--t = to_char (exp);
1772                 for (; t < expbuf + MAXEXPLEN; *p++ = *t++);
1773         }
1774         else {
1775                 if (!isa)
1776                         *p++ = '0';
1777                 *p++ = to_char (exp);
1778         }
1779         return (p - p0);
1780 }
1781 #endif /* FLOATING_POINT */
1782
1783
1784 #ifndef _NO_POS_ARGS
1785
1786 /* Positional argument support.
1787    Written by Jeff Johnston
1788
1789    Copyright (c) 2002 Red Hat Incorporated.
1790    All rights reserved.
1791
1792    Redistribution and use in source and binary forms, with or without
1793    modification, are permitted provided that the following conditions are met:
1794
1795       Redistributions of source code must retain the above copyright
1796       notice, this list of conditions and the following disclaimer.
1797
1798       Redistributions in binary form must reproduce the above copyright
1799       notice, this list of conditions and the following disclaimer in the
1800       documentation and/or other materials provided with the distribution.
1801
1802       The name of Red Hat Incorporated may not be used to endorse
1803       or promote products derived from this software without specific
1804       prior written permission.
1805
1806    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1807    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1808    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1809    DISCLAIMED.  IN NO EVENT SHALL RED HAT INCORPORATED BE LIABLE FOR ANY
1810    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1811    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1812    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1813    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1814    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1815    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
1816
1817 /* The below constant state tables are shared between all versions of
1818    vfprintf and vfwprintf.  They must only be defined once, which we do in
1819    the STRING_ONLY/INTEGER_ONLY versions here. */
1820 #if defined (STRING_ONLY) && defined(INTEGER_ONLY)
1821
1822 _CONST __CH_CLASS __chclass[256] = {
1823   /* 00-07 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1824   /* 08-0f */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1825   /* 10-17 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1826   /* 18-1f */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1827   /* 20-27 */  FLAG,    OTHER,   OTHER,   FLAG,    DOLLAR,  OTHER,   OTHER,   FLAG,
1828   /* 28-2f */  OTHER,   OTHER,   STAR,    FLAG,    OTHER,   FLAG,    DOT,     OTHER,
1829   /* 30-37 */  ZERO,    DIGIT,   DIGIT,   DIGIT,   DIGIT,   DIGIT,   DIGIT,   DIGIT,
1830   /* 38-3f */  DIGIT,   DIGIT,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1831   /* 40-47 */  OTHER,   SPEC,    OTHER,   SPEC,    SPEC,    SPEC,    SPEC,    SPEC,
1832   /* 48-4f */  OTHER,   OTHER,   OTHER,   OTHER,   MODFR,   OTHER,   OTHER,   SPEC,
1833   /* 50-57 */  OTHER,   OTHER,   OTHER,   SPEC,    OTHER,   SPEC,    OTHER,   OTHER,
1834   /* 58-5f */  SPEC,    OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1835   /* 60-67 */  OTHER,   SPEC,    OTHER,   SPEC,    SPEC,    SPEC,    SPEC,    SPEC,
1836   /* 68-6f */  MODFR,   SPEC,    MODFR,   OTHER,   MODFR,   OTHER,   SPEC,    SPEC,
1837   /* 70-77 */  SPEC,    MODFR,   OTHER,   SPEC,    MODFR,   SPEC,    OTHER,   OTHER,
1838   /* 78-7f */  SPEC,    OTHER,   MODFR,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1839   /* 80-87 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1840   /* 88-8f */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1841   /* 90-97 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1842   /* 98-9f */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1843   /* a0-a7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1844   /* a8-af */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1845   /* b0-b7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1846   /* b8-bf */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1847   /* c0-c7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1848   /* c8-cf */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1849   /* d0-d7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1850   /* d8-df */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1851   /* e0-e7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1852   /* e8-ef */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1853   /* f0-f7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1854   /* f8-ff */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
1855 };
1856
1857 _CONST __STATE __state_table[MAX_STATE][MAX_CH_CLASS] = {
1858   /*             '0'     '1-9'     '$'     MODFR    SPEC    '.'     '*'    FLAG    OTHER */
1859   /* START */  { SFLAG,   WDIG,    DONE,   SMOD,    DONE,   SDOT,  VARW,   SFLAG,  DONE },
1860   /* SFLAG */  { SFLAG,   WDIG,    DONE,   SMOD,    DONE,   SDOT,  VARW,   SFLAG,  DONE },
1861   /* WDIG  */  { DONE,    DONE,    WIDTH,  SMOD,    DONE,   SDOT,  DONE,   DONE,   DONE },
1862   /* WIDTH */  { DONE,    DONE,    DONE,   SMOD,    DONE,   SDOT,  DONE,   DONE,   DONE },
1863   /* SMOD  */  { DONE,    DONE,    DONE,   DONE,    DONE,   DONE,  DONE,   DONE,   DONE },
1864   /* SDOT  */  { SDOT,    PREC,    DONE,   SMOD,    DONE,   DONE,  VARP,   DONE,   DONE },
1865   /* VARW  */  { DONE,    VWDIG,   DONE,   SMOD,    DONE,   SDOT,  DONE,   DONE,   DONE },
1866   /* VARP  */  { DONE,    VPDIG,   DONE,   SMOD,    DONE,   DONE,  DONE,   DONE,   DONE },
1867   /* PREC  */  { DONE,    DONE,    DONE,   SMOD,    DONE,   DONE,  DONE,   DONE,   DONE },
1868   /* VWDIG */  { DONE,    DONE,    WIDTH,  DONE,    DONE,   DONE,  DONE,   DONE,   DONE },
1869   /* VPDIG */  { DONE,    DONE,    PREC,   DONE,    DONE,   DONE,  DONE,   DONE,   DONE },
1870 };
1871
1872 _CONST __ACTION __action_table[MAX_STATE][MAX_CH_CLASS] = {
1873   /*             '0'     '1-9'     '$'     MODFR    SPEC    '.'     '*'    FLAG    OTHER */
1874   /* START */  { NOOP,    NUMBER,  NOOP,   GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
1875   /* SFLAG */  { NOOP,    NUMBER,  NOOP,   GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
1876   /* WDIG  */  { NOOP,    NOOP,    GETPOS, GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
1877   /* WIDTH */  { NOOP,    NOOP,    NOOP,   GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
1878   /* SMOD  */  { NOOP,    NOOP,    NOOP,   NOOP,    GETARG, NOOP,  NOOP,   NOOP,   NOOP },
1879   /* SDOT  */  { NOOP,    SKIPNUM, NOOP,   GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
1880   /* VARW  */  { NOOP,    NUMBER,  NOOP,   GETPW,   GETPWB, GETPW, NOOP,   NOOP,   NOOP },
1881   /* VARP  */  { NOOP,    NUMBER,  NOOP,   GETPW,   GETPWB, NOOP,  NOOP,   NOOP,   NOOP },
1882   /* PREC  */  { NOOP,    NOOP,    NOOP,   GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
1883   /* VWDIG */  { NOOP,    NOOP,    PWPOS,  NOOP,    NOOP,   NOOP,  NOOP,   NOOP,   NOOP },
1884   /* VPDIG */  { NOOP,    NOOP,    PWPOS,  NOOP,    NOOP,   NOOP,  NOOP,   NOOP,   NOOP },
1885 };
1886
1887 #endif /* STRING_ONLY && INTEGER_ONLY */
1888
1889 /* function to get positional parameter N where n = N - 1 */
1890 static union arg_val *
1891 _DEFUN(get_arg, (data, n, fmt, ap, numargs_p, args, arg_type, last_fmt),
1892        struct _reent *data _AND
1893        int n               _AND
1894        char *fmt           _AND
1895        va_list *ap         _AND
1896        int *numargs_p      _AND
1897        union arg_val *args _AND
1898        int *arg_type       _AND
1899        char **last_fmt)
1900 {
1901   int ch;
1902   int number, flags;
1903   int spec_type;
1904   int numargs = *numargs_p;
1905   __CH_CLASS chtype;
1906   __STATE state, next_state;
1907   __ACTION action;
1908   int pos, last_arg;
1909   int max_pos_arg = n;
1910   /* Only need types that can be reached via vararg promotions.  */
1911   enum types { INT, LONG_INT, QUAD_INT, CHAR_PTR, DOUBLE, LONG_DOUBLE, WIDE_CHAR };
1912 # ifdef _MB_CAPABLE
1913   wchar_t wc;
1914   mbstate_t wc_state;
1915   int nbytes;
1916 # endif
1917
1918   /* if this isn't the first call, pick up where we left off last time */
1919   if (*last_fmt != NULL)
1920     fmt = *last_fmt;
1921
1922 # ifdef _MB_CAPABLE
1923   memset (&wc_state, '\0', sizeof (wc_state));
1924 # endif
1925
1926   /* we need to process either to end of fmt string or until we have actually
1927      read the desired parameter from the vararg list. */
1928   while (*fmt && n >= numargs)
1929     {
1930 # ifdef _MB_CAPABLE
1931       while ((nbytes = __mbtowc (data, &wc, fmt, MB_CUR_MAX,
1932                                  __locale_charset (), &wc_state)) > 0)
1933         {
1934           fmt += nbytes;
1935           if (wc == '%')
1936             break;
1937         }
1938
1939       if (nbytes <= 0)
1940         break;
1941 # else
1942       while (*fmt != '\0' && *fmt != '%')
1943         fmt += 1;
1944
1945       if (*fmt == '\0')
1946         break;
1947 # endif /* ! _MB_CAPABLE */
1948       state = START;
1949       flags = 0;
1950       pos = -1;
1951       number = 0;
1952       spec_type = INT;
1953
1954       /* Use state/action table to process format specifiers.  We ignore invalid
1955          formats and we are only interested in information that tells us how to
1956          read the vararg list. */
1957       while (state != DONE)
1958         {
1959           ch = *fmt++;
1960           chtype = __chclass[ch];
1961           next_state = __state_table[state][chtype];
1962           action = __action_table[state][chtype];
1963           state = next_state;
1964
1965           switch (action)
1966             {
1967             case GETMOD:  /* we have format modifier */
1968               switch (ch)
1969                 {
1970                 case 'h':
1971                   /* No flag needed, since short and char promote to int.  */
1972                   break;
1973                 case 'L':
1974                   flags |= LONGDBL;
1975                   break;
1976                 case 'q':
1977                   flags |= QUADINT;
1978                   break;
1979 # ifdef _WANT_IO_C99_FORMATS
1980                 case 'j':
1981                   if (sizeof (intmax_t) == sizeof (long))
1982                     flags |= LONGINT;
1983                   else
1984                     flags |= QUADINT;
1985                   break;
1986                 case 'z':
1987                   if (sizeof (size_t) <= sizeof (int))
1988                     /* no flag needed */;
1989                   else if (sizeof (size_t) <= sizeof (long))
1990                     flags |= LONGINT;
1991                   else
1992                     /* POSIX states that at least one programming
1993                        environment must support size_t no wider than
1994                        long, but that means other environments can
1995                        have size_t as wide as long long.  */
1996                     flags |= QUADINT;
1997                   break;
1998                 case 't':
1999                   if (sizeof (ptrdiff_t) <= sizeof (int))
2000                     /* no flag needed */;
2001                   else if (sizeof (ptrdiff_t) <= sizeof (long))
2002                     flags |= LONGINT;
2003                   else
2004                     /* POSIX states that at least one programming
2005                        environment must support ptrdiff_t no wider than
2006                        long, but that means other environments can
2007                        have ptrdiff_t as wide as long long.  */
2008                     flags |= QUADINT;
2009                   break;
2010 # endif /* _WANT_IO_C99_FORMATS */
2011                 case 'l':
2012                 default:
2013 # if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
2014                   if (*fmt == 'l')
2015                     {
2016                       flags |= QUADINT;
2017                       ++fmt;
2018                     }
2019                   else
2020 # endif
2021                     flags |= LONGINT;
2022                   break;
2023                 }
2024               break;
2025             case GETARG: /* we have format specifier */
2026               {
2027                 numargs &= (MAX_POS_ARGS - 1);
2028                 /* process the specifier and translate it to a type to fetch from varargs */
2029                 switch (ch)
2030                   {
2031                   case 'd':
2032                   case 'i':
2033                   case 'o':
2034                   case 'x':
2035                   case 'X':
2036                   case 'u':
2037                     if (flags & LONGINT)
2038                       spec_type = LONG_INT;
2039 # ifndef _NO_LONGLONG
2040                     else if (flags & QUADINT)
2041                       spec_type = QUAD_INT;
2042 # endif
2043                     else
2044                       spec_type = INT;
2045                     break;
2046                   case 'D':
2047                   case 'U':
2048                   case 'O':
2049                     spec_type = LONG_INT;
2050                     break;
2051 # ifdef _WANT_IO_C99_FORMATS
2052                   case 'a':
2053                   case 'A':
2054                   case 'F':
2055 # endif
2056                   case 'f':
2057                   case 'g':
2058                   case 'G':
2059                   case 'E':
2060                   case 'e':
2061 # ifndef _NO_LONGDBL
2062                     if (flags & LONGDBL)
2063                       spec_type = LONG_DOUBLE;
2064                     else
2065 # endif
2066                       spec_type = DOUBLE;
2067                     break;
2068                   case 's':
2069 # ifdef _WANT_IO_C99_FORMATS
2070                   case 'S':
2071 # endif
2072                   case 'p':
2073                   case 'n':
2074                     spec_type = CHAR_PTR;
2075                     break;
2076                   case 'c':
2077 # ifdef _WANT_IO_C99_FORMATS
2078                     if (flags & LONGINT)
2079                       spec_type = WIDE_CHAR;
2080                     else
2081 # endif
2082                       spec_type = INT;
2083                     break;
2084 # ifdef _WANT_IO_C99_FORMATS
2085                   case 'C':
2086                     spec_type = WIDE_CHAR;
2087                     break;
2088 # endif
2089                   }
2090
2091                 /* if we have a positional parameter, just store the type, otherwise
2092                    fetch the parameter from the vararg list */
2093                 if (pos != -1)
2094                   arg_type[pos] = spec_type;
2095                 else
2096                   {
2097                     switch (spec_type)
2098                       {
2099                       case LONG_INT:
2100                         args[numargs++].val_long = va_arg (*ap, long);
2101                         break;
2102                       case QUAD_INT:
2103                         args[numargs++].val_quad_t = va_arg (*ap, quad_t);
2104                         break;
2105                       case WIDE_CHAR:
2106                         args[numargs++].val_wint_t = va_arg (*ap, wint_t);
2107                         break;
2108                       case INT:
2109                         args[numargs++].val_int = va_arg (*ap, int);
2110                         break;
2111                       case CHAR_PTR:
2112                         args[numargs++].val_char_ptr_t = va_arg (*ap, char *);
2113                         break;
2114                       case DOUBLE:
2115                         args[numargs++].val_double = va_arg (*ap, double);
2116                         break;
2117                       case LONG_DOUBLE:
2118                         args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE);
2119                         break;
2120                       }
2121                   }
2122               }
2123               break;
2124             case GETPOS: /* we have positional specifier */
2125               if (arg_type[0] == -1)
2126                 memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS);
2127               pos = number - 1;
2128               max_pos_arg = (max_pos_arg > pos ? max_pos_arg : pos);
2129               break;
2130             case PWPOS:  /* we have positional specifier for width or precision */
2131               if (arg_type[0] == -1)
2132                 memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS);
2133               number -= 1;
2134               arg_type[number] = INT;
2135               max_pos_arg = (max_pos_arg > number ? max_pos_arg : number);
2136               break;
2137             case GETPWB: /* we require format pushback */
2138               --fmt;
2139               /* fallthrough */
2140             case GETPW:  /* we have a variable precision or width to acquire */
2141               args[numargs++].val_int = va_arg (*ap, int);
2142               break;
2143             case NUMBER: /* we have a number to process */
2144               number = (ch - '0');
2145               while ((ch = *fmt) != '\0' && is_digit (ch))
2146                 {
2147                   number = number * 10 + (ch - '0');
2148                   ++fmt;
2149                 }
2150               break;
2151             case SKIPNUM: /* we have a number to skip */
2152               while ((ch = *fmt) != '\0' && is_digit (ch))
2153                 ++fmt;
2154               break;
2155             case NOOP:
2156             default:
2157               break; /* do nothing */
2158             }
2159         }
2160     }
2161
2162   /* process all arguments up to at least the one we are looking for and if we
2163      have seen the end of the string, then process up to the max argument needed */
2164   if (*fmt == '\0')
2165     last_arg = max_pos_arg;
2166   else
2167     last_arg = n;
2168
2169   while (numargs <= last_arg)
2170     {
2171       switch (arg_type[numargs])
2172         {
2173         case LONG_INT:
2174           args[numargs++].val_long = va_arg (*ap, long);
2175           break;
2176         case QUAD_INT:
2177           args[numargs++].val_quad_t = va_arg (*ap, quad_t);
2178           break;
2179         case CHAR_PTR:
2180           args[numargs++].val_char_ptr_t = va_arg (*ap, char *);
2181           break;
2182         case DOUBLE:
2183           args[numargs++].val_double = va_arg (*ap, double);
2184           break;
2185         case LONG_DOUBLE:
2186           args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE);
2187           break;
2188         case WIDE_CHAR:
2189           args[numargs++].val_wint_t = va_arg (*ap, wint_t);
2190           break;
2191         case INT:
2192         default:
2193           args[numargs++].val_int = va_arg (*ap, int);
2194           break;
2195         }
2196     }
2197
2198   /* alter the global numargs value and keep a reference to the last bit of the fmt
2199      string we processed here because the caller will continue processing where we started */
2200   *numargs_p = numargs;
2201   *last_fmt = fmt;
2202   return &args[n];
2203 }
2204 #endif /* !_NO_POS_ARGS */