source: trunk/libs/newlib/src/newlib/libc/stdio/vfprintf.c

Last change on this file was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

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