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