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