OSDN Git Service

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