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