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