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