source: trunk/libs/newlib/src/newlib/libc/stdio/vfwprintf.c @ 543

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

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

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