]>
Commit | Line | Data |
---|---|---|
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 | /* |
34 | FUNCTION | |
391b530a | 35 | <<vfprintf>>, <<vprintf>>, <<vsprintf>>, <<vsnprintf>>, <<vasprintf>>, <<vasnprintf>>---format argument list |
8a0efa53 | 36 | |
8a0efa53 CF |
37 | INDEX |
38 | vfprintf | |
1dc1ccd4 JJ |
39 | INDEX |
40 | _vfprintf_r | |
391b530a EB |
41 | INDEX |
42 | vprintf | |
1dc1ccd4 JJ |
43 | INDEX |
44 | _vprintf_r | |
8a0efa53 CF |
45 | INDEX |
46 | vsprintf | |
1dc1ccd4 JJ |
47 | INDEX |
48 | _vsprintf_r | |
8a0efa53 CF |
49 | INDEX |
50 | vsnprintf | |
1dc1ccd4 JJ |
51 | INDEX |
52 | _vsnprintf_r | |
b9db5292 EB |
53 | INDEX |
54 | vasprintf | |
1dc1ccd4 JJ |
55 | INDEX |
56 | _vasprintf_r | |
b9db5292 EB |
57 | INDEX |
58 | vasnprintf | |
1dc1ccd4 JJ |
59 | INDEX |
60 | _vasnprintf_r | |
8a0efa53 | 61 | |
c7ef9668 | 62 | SYNOPSIS |
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 | |
87 | DESCRIPTION | |
b9db5292 EB |
88 | <<vprintf>>, <<vfprintf>>, <<vasprintf>>, <<vsprintf>>, <<vsnprintf>>, |
89 | and <<vasnprintf>> are (respectively) variants of <<printf>>, | |
90 | <<fprintf>>, <<asprintf>>, <<sprintf>>, <<snprintf>>, and | |
91 | <<asnprintf>>. They differ only in allowing their caller to pass the | |
92 | variable argument list as a <<va_list>> object (initialized by | |
93 | <<va_start>>) rather than directly accepting a variable number of | |
94 | arguments. The caller is responsible for calling <<va_end>>. | |
95 | ||
96 | <<_vprintf_r>>, <<_vfprintf_r>>, <<_vasprintf_r>>, <<_vsprintf_r>>, | |
97 | <<_vsnprintf_r>>, and <<_vasnprintf_r>> are reentrant versions of the | |
98 | above. | |
8a0efa53 CF |
99 | |
100 | RETURNS | |
b9db5292 | 101 | The return values are consistent with the corresponding functions. |
8a0efa53 CF |
102 | |
103 | PORTABILITY | |
b9db5292 EB |
104 | ANSI C requires <<vprintf>>, <<vfprintf>>, <<vsprintf>>, and |
105 | <<vsnprintf>>. The remaining functions are newlib extensions. | |
8a0efa53 CF |
106 | |
107 | Supporting 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";*/ | |
113 | static char *rcsid = "$Id$"; | |
114 | #endif /* LIBC_SCCS and not lint */ | |
115 | ||
116 | /* | |
117 | * Actual printf innards. | |
118 | * | |
119 | * This code is large and complicated... | |
120 | */ | |
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 |
258 | extern 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 |
267 | extern char *_ldtoa_r (struct _reent *, _LONG_DOUBLE, int, |
268 | int, int *, int *, char **); | |
8a0efa53 | 269 | |
70ee6b17 | 270 | extern 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 |
277 | static char *cvt(struct _reent *, _PRINTF_FLOAT_TYPE, int, int, char *, int *, |
278 | int, int *, char *); | |
8a0efa53 | 279 | |
34507ce0 | 280 | static 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 | ||
315 | typedef quad_t * quad_ptr_t; | |
e6321aa6 | 316 | typedef void *void_ptr_t; |
037240a2 JJ |
317 | typedef char * char_ptr_t; |
318 | typedef long * long_ptr_t; | |
319 | typedef int * int_ptr_t; | |
320 | typedef 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 | |
329 | union 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 | 349 | static union arg_val * |
70ee6b17 | 350 | get_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 | 389 | int _VFPRINTF_R (struct _reent *, FILE *, const char *, va_list); |
037240a2 | 390 | |
eabd7de0 | 391 | #ifndef STRING_ONLY |
f77a1a88 | 392 | int |
90871638 | 393 | VFPRINTF (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 | 403 | int |
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 | |
701 | rflag: ch = *fmt++; | |
702 | reswitch: 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 |
1188 | string: | |
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 | 1293 | hex: _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 */ |
1306 | nosign: sign = '\0'; | |
1307 | /* | |
1308 | * ``... diouXx conversions ... if a precision is | |
1309 | * specified, the 0 flag will be ignored.'' | |
1310 | * -- ANSI X3J11 | |
1311 | */ | |
1312 | number: 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 | } |
1530 | done: | |
05b31577 | 1531 | FLUSH (); |
8a0efa53 | 1532 | error: |
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 | 1551 | static char * |
34507ce0 EB |
1552 | cvt(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 | ||
1645 | static int | |
34507ce0 | 1646 | exponent(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 | 1720 | const __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 | 1755 | const __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 | 1770 | const __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 */ |
1788 | static union arg_val * | |
90871638 | 1789 | get_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 */ |