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