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