]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Stdio/vfwprintf.c
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / StdLib / LibC / Stdio / vfwprintf.c
CommitLineData
2aa62f2b 1/** @file\r
2 Implementation of internals for printf and wprintf.\r
3\r
4 Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials are licensed and made available\r
6 under the terms and conditions of the BSD License that accompanies this\r
7 distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13 Copyright (c) 1990, 1993\r
14 The Regents of the University of California. All rights reserved.\r
15\r
16 This code is derived from software contributed to Berkeley by\r
17 Chris Torek.\r
18\r
19 Redistribution and use in source and binary forms, with or without\r
20 modification, are permitted provided that the following conditions\r
21 are met:\r
22 - Redistributions of source code must retain the above copyright\r
23 notice, this list of conditions and the following disclaimer.\r
24 - Redistributions in binary form must reproduce the above copyright\r
25 notice, this list of conditions and the following disclaimer in the\r
26 documentation and/or other materials provided with the distribution.\r
27 - Neither the name of the University nor the names of its contributors\r
28 may be used to endorse or promote products derived from this software\r
29 without specific prior written permission.\r
30\r
31 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
32 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
33 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
34 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE\r
35 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
36 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
37 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
38 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
39 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
40 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
41 POSSIBILITY OF SUCH DAMAGE.\r
42\r
43 NetBSD: vfwprintf.c,v 1.9.2.1.4.1 2008/04/08 21:10:55 jdc Exp\r
44 vfprintf.c 8.1 (Berkeley) 6/4/93\r
45**/\r
46#include <LibConfig.h>\r
47\r
48#include "namespace.h"\r
49#include <sys/types.h>\r
50\r
51#include <assert.h>\r
52#include <ctype.h>\r
53#include <limits.h>\r
54#include <locale.h>\r
55#include <stdarg.h>\r
56#include <stddef.h>\r
57#include <stdint.h>\r
58#include <stdio.h>\r
59#include <stdlib.h>\r
60#include <string.h>\r
61#include <errno.h>\r
62#include <wchar.h>\r
63#include <wctype.h>\r
64\r
65#include "reentrant.h"\r
66#include "local.h"\r
67#include "extern.h"\r
68#include "fvwrite.h"\r
69\r
70#ifdef _MSC_VER\r
71 // Keep compiler quiet about conversions from larger to smaller types.\r
72 #pragma warning ( disable : 4244 )\r
73#endif\r
74\r
75#ifndef NARROW\r
76#define MCHAR_T char\r
77#define CHAR_T wchar_t\r
78#define STRLEN(a) wcslen(a)\r
79#define MEMCHR(a, b, c) wmemchr(a, b, c)\r
80#define SCONV(a, b) __mbsconv(a, b)\r
81#define STRCONST(a) L ## a\r
82#define WDECL(a, b) a ## w ## b\r
83#define END_OF_FILE WEOF\r
84#define MULTI 0\r
85#else\r
86#define MCHAR_T wchar_t\r
87#define CHAR_T char\r
88#define STRLEN(a) strlen(a)\r
89#define MEMCHR(a, b, c) memchr(a, b, c)\r
90#define SCONV(a, b) __wcsconv(a, b)\r
91#define STRCONST(a) a\r
92#define WDECL(a, b) a ## b\r
93#define END_OF_FILE EOF\r
94#define MULTI 1\r
95#endif\r
96\r
97union arg {\r
98 int intarg;\r
99 u_int uintarg;\r
100 long longarg;\r
101 unsigned long ulongarg;\r
102 long long longlongarg;\r
103 unsigned long long ulonglongarg;\r
104 ptrdiff_t ptrdiffarg;\r
105 size_t sizearg;\r
106 intmax_t intmaxarg;\r
107 uintmax_t uintmaxarg;\r
108 void *pvoidarg;\r
109 char *pchararg;\r
110 signed char *pschararg;\r
111 short *pshortarg;\r
112 int *pintarg;\r
113 long *plongarg;\r
114 long long *plonglongarg;\r
115 ptrdiff_t *pptrdiffarg;\r
116 size_t *psizearg;\r
117 intmax_t *pintmaxarg;\r
118#ifndef NO_FLOATING_POINT\r
119 double doublearg;\r
120 long double longdoublearg;\r
121#endif\r
122 wint_t wintarg;\r
123 wchar_t *pwchararg;\r
124};\r
125\r
126/*\r
127 * Type ids for argument type table.\r
128 */\r
129enum typeid {\r
130 T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,\r
131 T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG,\r
132 TP_LLONG, T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET,\r
133 T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR,\r
134 TP_SCHAR, T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR\r
135};\r
136\r
137static int __sbprintf(FILE *, const CHAR_T *, va_list);\r
138static CHAR_T *__ujtoa(uintmax_t, CHAR_T *, int, int, const char *, int,\r
139 char, const char *);\r
140static CHAR_T *__ultoa(u_long, CHAR_T *, int, int, const char *, int,\r
141 char, const char *);\r
142#ifndef NARROW\r
143static CHAR_T *__mbsconv(char *, int);\r
144static wint_t __xfputwc(CHAR_T, FILE *);\r
145#else\r
146static char *__wcsconv(wchar_t *, int);\r
147static int __sprint(FILE *, struct __suio *);\r
148#endif\r
149static int __find_arguments(const CHAR_T *, va_list, union arg **);\r
150static int __grow_type_table(int, enum typeid **, int *);\r
151\r
152/*\r
153 * Helper function for `fprintf to unbuffered unix file': creates a\r
154 * temporary buffer. We only work on write-only files; this avoids\r
155 * worries about ungetc buffers and so forth.\r
156 */\r
157static int\r
158__sbprintf(FILE *fp, const CHAR_T *fmt, va_list ap)\r
159{\r
160 int ret;\r
161 FILE fake;\r
162 struct __sfileext fakeext;\r
163 unsigned char buf[BUFSIZ];\r
164\r
165 _DIAGASSERT(fp != NULL);\r
166 _DIAGASSERT(fmt != NULL);\r
53e1e5c6 167 if(fp == NULL) {\r
168 errno = EINVAL;\r
169 return (EOF);\r
170 }\r
2aa62f2b 171\r
172 _FILEEXT_SETUP(&fake, &fakeext);\r
173\r
174 /* copy the important variables */\r
175 fake._flags = fp->_flags & ~__SNBF;\r
176 fake._file = fp->_file;\r
177 fake._cookie = fp->_cookie;\r
178 fake._write = fp->_write;\r
179\r
180 /* set up the buffer */\r
181 fake._bf._base = fake._p = buf;\r
182 fake._bf._size = fake._w = sizeof(buf);\r
183 fake._lbfsize = 0; /* not actually used, but Just In Case */\r
184\r
185 /* do the work, then copy any error status */\r
186 ret = WDECL(__vf,printf_unlocked)(&fake, fmt, ap);\r
187 if (ret >= 0 && fflush(&fake))\r
188 ret = END_OF_FILE;\r
189 if (fake._flags & __SERR)\r
190 fp->_flags |= __SERR;\r
191 return (ret);\r
192}\r
193\r
194#ifndef NARROW\r
195/*\r
196 * Like __fputwc, but handles fake string (__SSTR) files properly.\r
197 * File must already be locked.\r
198 */\r
199static wint_t\r
200__xfputwc(wchar_t wc, FILE *fp)\r
201{\r
202 static const mbstate_t initial = { 0 };\r
203 mbstate_t mbs;\r
204 char buf[MB_LEN_MAX];\r
205 struct __suio uio;\r
206 struct __siov iov;\r
207 size_t len;\r
208\r
209 if ((fp->_flags & __SSTR) == 0)\r
210 return (__fputwc_unlock(wc, fp));\r
211\r
212 mbs = initial;\r
213 if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) {\r
214 fp->_flags |= __SERR;\r
215 return (END_OF_FILE);\r
216 }\r
217 uio.uio_iov = &iov;\r
218 uio.uio_resid = (int)len;\r
219 uio.uio_iovcnt = 1;\r
220 iov.iov_base = buf;\r
221 iov.iov_len = len;\r
222 return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : END_OF_FILE);\r
223}\r
224#else\r
225/*\r
226 * Flush out all the vectors defined by the given uio,\r
227 * then reset it so that it can be reused.\r
228 */\r
229static int\r
230__sprint(FILE *fp, struct __suio *uio)\r
231{\r
232 int err;\r
233\r
234 _DIAGASSERT(fp != NULL);\r
235 _DIAGASSERT(uio != NULL);\r
53e1e5c6 236 if(fp == NULL) {\r
237 errno = EINVAL;\r
238 return (EOF);\r
239 }\r
2aa62f2b 240\r
241 if (uio->uio_resid == 0) {\r
242 uio->uio_iovcnt = 0;\r
243 return (0);\r
244 }\r
245 err = __sfvwrite(fp, uio);\r
246 uio->uio_resid = 0;\r
247 uio->uio_iovcnt = 0;\r
248 return (err);\r
249}\r
250#endif\r
251\r
252/*\r
253 * Macros for converting digits to letters and vice versa\r
254 */\r
255#define to_digit(c) ((c) - '0')\r
256#define is_digit(c) ((unsigned)to_digit(c) <= 9)\r
257#define to_char(n) (CHAR_T)((n) + '0')\r
258\r
259/*\r
260 * Convert an unsigned long to ASCII for printf purposes, returning\r
261 * a pointer to the first character of the string representation.\r
262 * Octal numbers can be forced to have a leading zero; hex numbers\r
263 * use the given digits.\r
264 */\r
265static CHAR_T *\r
266__ultoa(u_long val, CHAR_T *endp, int base, int octzero, const char *xdigs,\r
267 int needgrp, char thousep, const char *grp)\r
268{\r
269 CHAR_T *cp = endp;\r
270 LONGN sval;\r
271 int ndig;\r
272\r
273 /*\r
274 * Handle the three cases separately, in the hope of getting\r
275 * better/faster code.\r
276 */\r
277 switch (base) {\r
278 case 10:\r
279 if (val < 10) { /* many numbers are 1 digit */\r
280 *--cp = to_char(val);\r
281 return (cp);\r
282 }\r
283 ndig = 0;\r
284 /*\r
285 * On many machines, unsigned arithmetic is harder than\r
286 * signed arithmetic, so we do at most one unsigned mod and\r
287 * divide; this is sufficient to reduce the range of\r
288 * the incoming value to where signed arithmetic works.\r
289 */\r
290 if (val > LONG_MAX) {\r
291 *--cp = to_char(val % 10);\r
292 ndig++;\r
293 sval = (LONGN)(val / 10);\r
294 } else\r
295 sval = (LONGN)val;\r
296 do {\r
297 *--cp = to_char(sval % 10);\r
298 ndig++;\r
299 /*\r
300 * If (*grp == CHAR_MAX) then no more grouping\r
301 * should be performed.\r
302 */\r
303 if (needgrp && ndig == *grp && *grp != CHAR_MAX\r
304 && sval > 9) {\r
305 *--cp = thousep;\r
306 ndig = 0;\r
307 /*\r
308 * If (*(grp+1) == '\0') then we have to\r
309 * use *grp character (last grouping rule)\r
310 * for all next cases\r
311 */\r
312 if (*(grp+1) != '\0')\r
313 grp++;\r
314 }\r
315 sval /= 10;\r
316 } while (sval != 0);\r
317 break;\r
318\r
319 case 8:\r
320 do {\r
321 *--cp = to_char(val & 7);\r
322 val >>= 3;\r
323 } while (val);\r
324 if (octzero && *cp != '0')\r
325 *--cp = '0';\r
326 break;\r
327\r
328 case 16:\r
329 do {\r
330 *--cp = xdigs[(size_t)val & 15];\r
331 val >>= 4;\r
332 } while (val);\r
333 break;\r
334\r
335 default: /* oops */\r
336 abort();\r
337 }\r
338 return (cp);\r
339}\r
340\r
341/* Identical to __ultoa, but for intmax_t. */\r
342static CHAR_T *\r
343__ujtoa(uintmax_t val, CHAR_T *endp, int base, int octzero,\r
344 const char *xdigs, int needgrp, char thousep, const char *grp)\r
345{\r
346 CHAR_T *cp = endp;\r
347 intmax_t sval;\r
348 int ndig;\r
349\r
350 /* quick test for small values; __ultoa is typically much faster */\r
351 /* (perhaps instead we should run until small, then call __ultoa?) */\r
352 if (val <= ULONG_MAX)\r
353 return (__ultoa((u_long)val, endp, base, octzero, xdigs,\r
354 needgrp, thousep, grp));\r
355 switch (base) {\r
356 case 10:\r
357 if (val < 10) {\r
358 *--cp = to_char(val % 10);\r
359 return (cp);\r
360 }\r
361 ndig = 0;\r
362 if (val > INTMAX_MAX) {\r
363 *--cp = to_char(val % 10);\r
364 ndig++;\r
365 sval = val / 10;\r
366 } else\r
367 sval = val;\r
368 do {\r
369 *--cp = to_char(sval % 10);\r
370 ndig++;\r
371 /*\r
372 * If (*grp == CHAR_MAX) then no more grouping\r
373 * should be performed.\r
374 */\r
375 if (needgrp && *grp != CHAR_MAX && ndig == *grp\r
376 && sval > 9) {\r
377 *--cp = thousep;\r
378 ndig = 0;\r
379 /*\r
380 * If (*(grp+1) == '\0') then we have to\r
381 * use *grp character (last grouping rule)\r
382 * for all next cases\r
383 */\r
384 if (*(grp+1) != '\0')\r
385 grp++;\r
386 }\r
387 sval /= 10;\r
388 } while (sval != 0);\r
389 break;\r
390\r
391 case 8:\r
392 do {\r
393 *--cp = to_char(val & 7);\r
394 val >>= 3;\r
395 } while (val);\r
396 if (octzero && *cp != '0')\r
397 *--cp = '0';\r
398 break;\r
399\r
400 case 16:\r
401 do {\r
402 *--cp = xdigs[(size_t)val & 15];\r
403 val >>= 4;\r
404 } while (val);\r
405 break;\r
406\r
407 default:\r
408 abort();\r
409 }\r
410 return (cp);\r
411}\r
412\r
413#ifndef NARROW\r
414/*\r
415 * Convert a multibyte character string argument for the %s format to a wide\r
416 * string representation. ``prec'' specifies the maximum number of bytes\r
417 * to output. If ``prec'' is greater than or equal to zero, we can't assume\r
418 * that the multibyte char. string ends in a null character.\r
419 */\r
420static wchar_t *\r
421__mbsconv(char *mbsarg, int prec)\r
422{\r
423 static const mbstate_t initial = { 0 };\r
424 mbstate_t mbs;\r
425 wchar_t *convbuf, *wcp;\r
426 const char *p;\r
427 size_t insize, nchars, nconv;\r
428\r
429 if (mbsarg == NULL)\r
430 return (NULL);\r
431\r
432 /*\r
433 * Supplied argument is a multibyte string; convert it to wide\r
434 * characters first.\r
435 */\r
436 if (prec >= 0) {\r
437 /*\r
438 * String is not guaranteed to be NUL-terminated. Find the\r
439 * number of characters to print.\r
440 */\r
441 p = mbsarg;\r
442 insize = nchars = nconv = 0;\r
443 mbs = initial;\r
444 while (nchars != (size_t)prec) {\r
445 nconv = mbrlen(p, MB_CUR_MAX, &mbs);\r
446 if (nconv == 0 || nconv == (size_t)-1 ||\r
447 nconv == (size_t)-2)\r
448 break;\r
449 p += nconv;\r
450 nchars++;\r
451 insize += nconv;\r
452 }\r
453 if (nconv == (size_t)-1 || nconv == (size_t)-2)\r
454 return (NULL);\r
455 } else\r
456 insize = strlen(mbsarg);\r
457\r
458 /*\r
459 * Allocate buffer for the result and perform the conversion,\r
460 * converting at most `size' bytes of the input multibyte string to\r
461 * wide characters for printing.\r
462 */\r
463 convbuf = malloc((insize + 1) * sizeof(*convbuf));\r
464 if (convbuf == NULL)\r
465 return (NULL);\r
466 wcp = convbuf;\r
467 p = mbsarg;\r
468 mbs = initial;\r
469 nconv = 0;\r
470 while (insize != 0) {\r
471 nconv = mbrtowc(wcp, p, insize, &mbs);\r
472 if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2)\r
473 break;\r
474 wcp++;\r
475 p += nconv;\r
476 insize -= nconv;\r
477 }\r
478 if (nconv == (size_t)-1 || nconv == (size_t)-2) {\r
479 free(convbuf);\r
480 return (NULL);\r
481 }\r
482 *wcp = L'\0';\r
483\r
484 return (convbuf);\r
485}\r
486#else\r
487/*\r
488 * Convert a wide character string argument for the %ls format to a multibyte\r
489 * string representation. If not -1, prec specifies the maximum number of\r
490 * bytes to output, and also means that we can't assume that the wide char.\r
491 * string ends is null-terminated.\r
492 */\r
493static char *\r
494__wcsconv(wchar_t *wcsarg, int prec)\r
495{\r
496 static const mbstate_t initial = { 0 };\r
497 mbstate_t mbs;\r
498 char buf[MB_LEN_MAX];\r
499 wchar_t *p;\r
500 char *convbuf;\r
501 size_t clen, nbytes;\r
502\r
503 /* Allocate space for the maximum number of bytes we could output. */\r
504 if (prec < 0) {\r
505 p = wcsarg;\r
506 mbs = initial;\r
507 nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);\r
508 if (nbytes == (size_t)-1)\r
509 return (NULL);\r
510 } else {\r
511 /*\r
512 * Optimisation: if the output precision is small enough,\r
513 * just allocate enough memory for the maximum instead of\r
514 * scanning the string.\r
515 */\r
516 if (prec < 128)\r
517 nbytes = prec;\r
518 else {\r
519 nbytes = 0;\r
520 p = wcsarg;\r
521 mbs = initial;\r
522 for (;;) {\r
523 clen = wcrtomb(buf, *p++, &mbs);\r
524 if (clen == 0 || clen == (size_t)-1 ||\r
525 nbytes + clen > (size_t)prec)\r
526 break;\r
527 nbytes += clen;\r
528 }\r
529 }\r
530 }\r
531 if ((convbuf = malloc(nbytes + 1)) == NULL)\r
532 return (NULL);\r
533\r
534 /* Fill the output buffer. */\r
535 p = wcsarg;\r
536 mbs = initial;\r
537 if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,\r
538 nbytes, &mbs)) == (size_t)-1) {\r
539 free(convbuf);\r
540 return (NULL);\r
541 }\r
542 convbuf[nbytes] = '\0';\r
543 return (convbuf);\r
544}\r
545#endif\r
546\r
547/*\r
548 * MT-safe version\r
549 */\r
550int\r
551WDECL(vf,printf)(FILE * __restrict fp, const CHAR_T * __restrict fmt0, va_list ap)\r
552{\r
553 int ret;\r
554\r
53e1e5c6 555 if(fp == NULL) {\r
556 errno = EINVAL;\r
557 return (EOF);\r
558 }\r
2aa62f2b 559 FLOCKFILE(fp);\r
560 ret = WDECL(__vf,printf_unlocked)(fp, fmt0, ap);\r
561 FUNLOCKFILE(fp);\r
562 return (ret);\r
563}\r
564\r
565#ifndef NO_FLOATING_POINT\r
566\r
567#include <float.h>\r
568#include <math.h>\r
569#include "floatio.h"\r
570\r
571#define DEFPREC 6\r
572\r
573static int exponent(CHAR_T *, int, int);\r
574#ifndef WIDE_DOUBLE\r
575static char *cvt(double, int, int, char *, int *, int, int *);\r
576#endif\r
577\r
578#endif /* !NO_FLOATING_POINT */\r
579\r
580/*\r
581 * The size of the buffer we use as scratch space for integer\r
582 * conversions, among other things. Technically, we would need the\r
583 * most space for base 10 conversions with thousands' grouping\r
584 * characters between each pair of digits. 100 bytes is a\r
585 * conservative overestimate even for a 128-bit uintmax_t.\r
586 */\r
587#define BUF 100\r
588\r
589#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */\r
590\r
591/*\r
592 * Flags used during conversion.\r
593 */\r
594#define ALT 0x001 /* alternate form */\r
595#define LADJUST 0x004 /* left adjustment */\r
596#define LONGDBL 0x008 /* long double */\r
597#define LONGINT 0x010 /* long integer */\r
598#define LLONGINT 0x020 /* long long integer */\r
599#define SHORTINT 0x040 /* short integer */\r
600#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */\r
601#define FPT 0x100 /* Floating point number */\r
602#define GROUPING 0x200 /* use grouping ("'" flag) */\r
603 /* C99 additional size modifiers: */\r
604#define SIZET 0x400 /* size_t */\r
605#define PTRDIFFT 0x800 /* ptrdiff_t */\r
606#define INTMAXT 0x1000 /* intmax_t */\r
607#define CHARINT 0x2000 /* print char using int format */\r
608\r
609/*\r
610 * Non-MT-safe version\r
611 */\r
612int\r
613WDECL(__vf,printf_unlocked)(FILE *fp, const CHAR_T *fmt0, va_list ap)\r
614{\r
615 CHAR_T *fmt; /* format string */\r
616 int ch; /* character from fmt */\r
617 int n, n2; /* handy integer (short term usage) */\r
618 CHAR_T *cp; /* handy char pointer (short term usage) */\r
619 int flags; /* flags as above */\r
620 int ret; /* return value accumulator (number of items converted)*/\r
621 int width; /* width from format (%8d), or 0 */\r
622 int prec; /* precision from format; <0 for N/A */\r
623 CHAR_T sign; /* sign prefix (' ', '+', '-', or \0) */\r
624 char thousands_sep; /* locale specific thousands separator */\r
625 const char *grouping; /* locale specific numeric grouping rules */\r
626#ifndef NO_FLOATING_POINT\r
627 /*\r
628 * We can decompose the printed representation of floating\r
629 * point numbers into several parts, some of which may be empty:\r
630 *\r
631 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ\r
632 * A B ---C--- D E F\r
633 *\r
634 * A: 'sign' holds this value if present; '\0' otherwise\r
635 * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal\r
636 * C: cp points to the string MMMNNN. Leading and trailing\r
637 * zeros are not in the string and must be added.\r
638 * D: expchar holds this character; '\0' if no exponent, e.g. %f\r
639 * F: at least two digits for decimal, at least one digit for hex\r
640 */\r
641 char *decimal_point; /* locale specific decimal point */\r
642#ifdef WIDE_DOUBLE\r
643 int signflag; /* true if float is negative */\r
644 union { /* floating point arguments %[aAeEfFgG] */\r
645 double dbl;\r
646 long double ldbl;\r
647 } fparg;\r
648 char *dtoaend; /* pointer to end of converted digits */\r
649#else\r
650 double _double; /* double precision arguments %[eEfgG] */\r
651 char softsign; /* temporary negative sign for floats */\r
652#endif\r
653 char *dtoaresult; /* buffer allocated by dtoa */\r
654 int expt = 0; /* integer value of exponent */\r
655 char expchar; /* exponent character: [eEpP\0] */\r
656 int expsize; /* character count for expstr */\r
657 int lead; /* sig figs before decimal or group sep */\r
658 int ndig; /* actual number of digits returned by dtoa */\r
659 CHAR_T expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */\r
660 int nseps; /* number of group separators with ' */\r
661 int nrepeats; /* number of repeats of the last group */\r
662#endif\r
663 u_long ulval; /* integer arguments %[diouxX] */\r
664 uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */\r
665 int base; /* base for [diouxX] conversion */\r
666 int dprec; /* a copy of prec if [diouxX], 0 otherwise */\r
667 int realsz; /* field size expanded by dprec, sign, etc */\r
668 int size; /* size of converted field or string */\r
669 int prsize; /* max size of printed field */\r
670 const char *xdigs; /* digits for %[xX] conversion */\r
671#ifdef NARROW\r
672#define NIOV 8\r
673 struct __siov *iovp; /* for PRINT macro */\r
674 struct __suio uio; /* output information: summary */\r
675 struct __siov iov[NIOV];/* ... and individual io vectors */\r
676#else\r
677 int n3;\r
678#endif\r
679 CHAR_T buf[BUF]; /* buffer with space for digits of uintmax_t */\r
680 CHAR_T ox[2]; /* space for 0x hex-prefix */\r
681 union arg *argtable; /* args, built due to positional arg */\r
682 union arg statargtable [STATIC_ARG_TBL_SIZE];\r
683 int nextarg; /* 1-based argument index */\r
684 va_list orgap; /* original argument pointer */\r
685 CHAR_T *convbuf; /* multibyte to wide conversion result */\r
686\r
687 /*\r
688 * Choose PADSIZE to trade efficiency vs. size. If larger printf\r
689 * fields occur frequently, increase PADSIZE and make the initialisers\r
690 * below longer.\r
691 */\r
692#define PADSIZE 16 /* pad chunk size */\r
693 static CHAR_T blanks[PADSIZE] =\r
694 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};\r
695 static CHAR_T zeroes[PADSIZE] =\r
696 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};\r
697\r
698 static const char xdigs_lower[17] = "0123456789abcdef";\r
699 static const char xdigs_upper[17] = "0123456789ABCDEF";\r
700\r
701 /*\r
702 * BEWARE, these `goto error' on error, PRINT uses `n2' and\r
703 * PAD uses `n'.\r
704 */\r
705#ifndef NARROW\r
706#define PRINT(ptr, len) do { \\r
707 for (n3 = 0; n3 < (len); n3++) \\r
708 __xfputwc((ptr)[n3], fp); \\r
709} while (/*CONSTCOND*/0)\r
710#define FLUSH()\r
711#else\r
712#define PRINT(ptr, len) do { \\r
713 iovp->iov_base = __UNCONST(ptr); \\r
714 iovp->iov_len = (len); \\r
715 uio.uio_resid += (len); \\r
716 iovp++; \\r
717 if (++uio.uio_iovcnt >= NIOV) { \\r
718 if (__sprint(fp, &uio)) \\r
719 goto error; \\r
720 iovp = iov; \\r
721 } \\r
722} while (/*CONSTCOND*/0)\r
723#define FLUSH() do { \\r
724 if (uio.uio_resid && __sprint(fp, &uio)) \\r
725 goto error; \\r
726 uio.uio_iovcnt = 0; \\r
727 iovp = iov; \\r
728} while (/*CONSTCOND*/0)\r
729#endif /* NARROW */\r
730\r
731#define PAD(howmany, with) do { \\r
732 if ((n = (howmany)) > 0) { \\r
733 while (n > PADSIZE) { \\r
734 PRINT(with, PADSIZE); \\r
735 n -= PADSIZE; \\r
736 } \\r
737 PRINT(with, n); \\r
738 } \\r
739} while (/*CONSTCOND*/0)\r
740#define PRINTANDPAD(p, ep, len, with) do { \\r
741 n2 = (ep) - (p); \\r
742 if (n2 > (len)) \\r
743 n2 = (len); \\r
744 if (n2 > 0) \\r
745 PRINT((p), n2); \\r
746 PAD((len) - (n2 > 0 ? n2 : 0), (with)); \\r
747} while(/*CONSTCOND*/0)\r
748\r
749 /*\r
750 * Get the argument indexed by nextarg. If the argument table is\r
751 * built, use it to get the argument. If its not, get the next\r
752 * argument (and arguments must be gotten sequentially).\r
753 */\r
754#define GETARG(type) \\r
755 ((/*CONSTCOND*/argtable != NULL) ? *((type*)(void*)(&argtable[nextarg++])) : \\r
756 (nextarg++, va_arg(ap, type)))\r
757\r
758 /*\r
759 * To extend shorts properly, we need both signed and unsigned\r
760 * argument extraction methods.\r
761 */\r
762#define SARG() \\r
763 ((long)(flags&LONGINT ? GETARG(long) : \\r
764 flags&SHORTINT ? (short)GETARG(int) : \\r
765 flags&CHARINT ? (signed char)GETARG(int) : \\r
766 GETARG(int)))\r
767\r
768#define UARG() \\r
769 ((u_long)(flags&LONGINT ? GETARG(u_long) : \\r
770 flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \\r
771 flags&CHARINT ? (u_long)(u_char)GETARG(int) : \\r
772 (u_long)GETARG(u_int)))\r
773\r
774#define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT)\r
775\r
776#define SJARG() \\r
777 (flags&INTMAXT ? GETARG(intmax_t) : \\r
778 flags&SIZET ? (intmax_t)GETARG(size_t) : \\r
779 flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \\r
780 (intmax_t)GETARG(long long))\r
781\r
782#define UJARG() \\r
783 (flags&INTMAXT ? GETARG(uintmax_t) : \\r
784 flags&SIZET ? (uintmax_t)GETARG(size_t) : \\r
785 flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \\r
786 (uintmax_t)GETARG(unsigned long long))\r
787\r
788 /*\r
789 * Get * arguments, including the form *nn$. Preserve the nextarg\r
790 * that the argument can be gotten once the type is determined.\r
791 */\r
792#define GETASTER(val) \\r
793 n2 = 0; \\r
794 cp = fmt; \\r
795 while (is_digit(*cp)) { \\r
796 n2 = 10 * n2 + to_digit(*cp); \\r
797 cp++; \\r
798 } \\r
799 if (*cp == '$') { \\r
800 int hold = nextarg; \\r
801 if (argtable == NULL) { \\r
802 argtable = statargtable; \\r
803 if (__find_arguments(fmt0, orgap, &argtable) == -1) \\r
804 goto oomem; \\r
805 } \\r
806 nextarg = n2; \\r
807 val = GETARG (int); \\r
808 nextarg = hold; \\r
809 fmt = ++cp; \\r
810 } else { \\r
811 val = GETARG (int); \\r
812 }\r
813\r
814 _DIAGASSERT(fp != NULL);\r
815 _DIAGASSERT(fmt0 != NULL);\r
53e1e5c6 816 if(fp == NULL) {\r
817 errno = EINVAL;\r
818 return (EOF);\r
819 }\r
2aa62f2b 820\r
821 _SET_ORIENTATION(fp, -1);\r
822\r
823 ndig = -1; /* XXX gcc */\r
824\r
825 thousands_sep = '\0';\r
826 grouping = NULL;\r
827#ifndef NO_FLOATING_POINT\r
828 decimal_point = localeconv()->decimal_point;\r
829 expsize = 0; /* XXXGCC -Wuninitialized [sh3,m68000] */\r
830#endif\r
831 convbuf = NULL;\r
832 /* sorry, f{w,}printf(read_only_file, L"") returns {W,}EOF, not 0 */\r
833 if (cantwrite(fp)) {\r
834 errno = EBADF;\r
835 return (END_OF_FILE);\r
836 }\r
837\r
838 /* optimise fprintf(stderr) (and other unbuffered Unix files) */\r
839 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&\r
840 fp->_file >= 0)\r
841 return (__sbprintf(fp, fmt0, ap));\r
842\r
843 fmt = (CHAR_T *)__UNCONST(fmt0);\r
844 argtable = NULL;\r
845 nextarg = 1;\r
846 va_copy(orgap, ap);\r
847#ifdef NARROW\r
848 uio.uio_iov = iovp = iov;\r
849 uio.uio_resid = 0;\r
850 uio.uio_iovcnt = 0;\r
851#endif\r
852 ret = 0;\r
853\r
854 /*\r
855 * Scan the format for conversions (`%' character).\r
856 */\r
857 for (;;)\r
858 {\r
859 const CHAR_T *result;\r
860\r
861 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)\r
862 continue;\r
863 if ((n = (int)(fmt - cp)) != 0) {\r
864 if ((unsigned)ret + n > INT_MAX) {\r
865 ret = END_OF_FILE;\r
866 goto error;\r
867 }\r
868 PRINT(cp, n);\r
869 ret += n;\r
870 }\r
871 if (ch == '\0')\r
872 goto done;\r
873 fmt++; /* skip over '%' */\r
874\r
875 flags = 0;\r
876 dprec = 0;\r
877 width = 0;\r
878 prec = -1;\r
879 sign = '\0';\r
880 ox[1] = '\0';\r
881 expchar = '\0';\r
882 lead = 0;\r
883 nseps = nrepeats = 0;\r
884 ulval = 0;\r
885 ujval = 0;\r
886 xdigs = NULL;\r
887\r
888rflag: ch = *fmt++;\r
889reswitch: switch (ch) {\r
890 case ' ':\r
891 /*-\r
892 * ``If the space and + flags both appear, the space\r
893 * flag will be ignored.''\r
894 * -- ANSI X3J11\r
895 */\r
896 if (!sign)\r
897 sign = ' ';\r
898 goto rflag;\r
899 case '#':\r
900 flags |= ALT;\r
901 goto rflag;\r
902 case '*':\r
903 /*-\r
904 * ``A negative field width argument is taken as a\r
905 * - flag followed by a positive field width.''\r
906 * -- ANSI X3J11\r
907 * They don't exclude field widths read from args.\r
908 */\r
909 GETASTER (width);\r
910 if (width >= 0)\r
911 goto rflag;\r
912 width = -width;\r
913 /* FALLTHROUGH */\r
914 case '-':\r
915 flags |= LADJUST;\r
916 goto rflag;\r
917 case '+':\r
918 sign = '+';\r
919 goto rflag;\r
920 case '\'':\r
921 flags |= GROUPING;\r
922 thousands_sep = *(localeconv()->thousands_sep);\r
923 grouping = localeconv()->grouping;\r
924 goto rflag;\r
925 case '.':\r
926 if ((ch = *fmt++) == '*') {\r
927 GETASTER (prec);\r
928 goto rflag;\r
929 }\r
930 prec = 0;\r
931 while (is_digit(ch)) {\r
932 prec = 10 * prec + to_digit(ch);\r
933 ch = *fmt++;\r
934 }\r
935 goto reswitch;\r
936 case '0':\r
937 /*-\r
938 * ``Note that 0 is taken as a flag, not as the\r
939 * beginning of a field width.''\r
940 * -- ANSI X3J11\r
941 */\r
942 flags |= ZEROPAD;\r
943 goto rflag;\r
944 case '1': case '2': case '3': case '4':\r
945 case '5': case '6': case '7': case '8': case '9':\r
946 n = 0;\r
947 do {\r
948 n = 10 * n + to_digit(ch);\r
949 ch = *fmt++;\r
950 } while (is_digit(ch));\r
951 if (ch == '$') {\r
952 nextarg = n;\r
953 if (argtable == NULL) {\r
954 argtable = statargtable;\r
955 if (__find_arguments(fmt0, orgap,\r
956 &argtable) == -1)\r
957 goto oomem;\r
958 }\r
959 goto rflag;\r
960 }\r
961 width = n;\r
962 goto reswitch;\r
963#ifndef NO_FLOATING_POINT\r
964 case 'L':\r
965 flags |= LONGDBL;\r
966 goto rflag;\r
967#endif\r
968 case 'h':\r
969 if (flags & SHORTINT) {\r
970 flags &= ~SHORTINT;\r
971 flags |= CHARINT;\r
972 } else\r
973 flags |= SHORTINT;\r
974 goto rflag;\r
975 case 'j':\r
976 flags |= INTMAXT;\r
977 goto rflag;\r
978 case 'l':\r
979 if (flags & LONGINT) {\r
980 flags &= ~LONGINT;\r
981 flags |= LLONGINT;\r
982 } else\r
983 flags |= LONGINT;\r
984 goto rflag;\r
985 case 'q':\r
986 flags |= LLONGINT; /* not necessarily */\r
987 goto rflag;\r
988 case 't':\r
989 flags |= PTRDIFFT;\r
990 goto rflag;\r
991 case 'z':\r
992 flags |= SIZET;\r
993 goto rflag;\r
994 case 'C':\r
995 flags |= LONGINT;\r
996 /*FALLTHROUGH*/\r
997 case 'c':\r
998#ifdef NARROW\r
999 if (flags & LONGINT) {\r
1000 static const mbstate_t initial = { 0 };\r
1001 mbstate_t mbs;\r
1002 size_t mbseqlen;\r
1003\r
1004 mbs = initial;\r
1005 mbseqlen = wcrtomb(buf,\r
5244f47e 1006 /* The compiler "knows" that wint_t may be smaller than an int so\r
1007 it warns about it when used as the type argument to va_arg().\r
1008 Since any type of parameter smaller than an int is promoted to an int on a\r
1009 function call, we must call GETARG with type int instead of wint_t.\r
1010 */\r
1011 (wchar_t)GETARG(int), &mbs);\r
2aa62f2b 1012 if (mbseqlen == (size_t)-1) {\r
1013 fp->_flags |= __SERR;\r
1014 goto error;\r
1015 }\r
1016 size = (int)mbseqlen;\r
1017 } else {\r
1018 *buf = (char)(GETARG(int));\r
1019 size = 1;\r
1020 }\r
1021#else\r
1022 if (flags & LONGINT)\r
5244f47e 1023 *buf = (wchar_t)GETARG(int);\r
2aa62f2b 1024 else\r
1025 *buf = (wchar_t)btowc(GETARG(int));\r
1026 size = 1;\r
1027#endif\r
1028 result = buf;\r
1029 sign = '\0';\r
1030 break;\r
1031 case 'D':\r
1032 flags |= LONGINT;\r
1033 /*FALLTHROUGH*/\r
1034 case 'd':\r
1035 case 'i':\r
1036 if (flags & INTMAX_SIZE) {\r
1037 ujval = SJARG();\r
1038 if ((intmax_t)ujval < 0) {\r
1039 ujval = (uintmax_t)(-((intmax_t)ujval));\r
1040 sign = '-';\r
1041 }\r
1042 } else {\r
1043 ulval = SARG();\r
1044 if ((long)ulval < 0) {\r
1045 ulval = (u_long)(-((long)ulval));\r
1046 sign = '-';\r
1047 }\r
1048 }\r
1049 base = 10;\r
1050 goto number;\r
1051#ifndef NO_FLOATING_POINT\r
1052#ifdef WIDE_DOUBLE\r
1053 case 'a':\r
1054 case 'A':\r
1055 if (ch == 'a') {\r
1056 ox[1] = 'x';\r
1057 xdigs = xdigs_lower;\r
1058 expchar = 'p';\r
1059 } else {\r
1060 ox[1] = 'X';\r
1061 xdigs = xdigs_upper;\r
1062 expchar = 'P';\r
1063 }\r
2aa62f2b 1064 if (flags & LONGDBL) {\r
1065 fparg.ldbl = GETARG(long double);\r
1066 dtoaresult =\r
1067 __hldtoa(fparg.ldbl, xdigs, prec,\r
1068 &expt, &signflag, &dtoaend);\r
1069 } else {\r
1070 fparg.dbl = GETARG(double);\r
1071 dtoaresult =\r
1072 __hdtoa(fparg.dbl, xdigs, prec,\r
1073 &expt, &signflag, &dtoaend);\r
1074 }\r
1075 if (dtoaresult == NULL)\r
1076 goto oomem;\r
1077\r
1078 if (prec < 0)\r
1079 prec = dtoaend - dtoaresult;\r
1080 if (expt == INT_MAX)\r
1081 ox[1] = '\0';\r
1082 ndig = dtoaend - dtoaresult;\r
1083 if (convbuf != NULL)\r
1084 free(convbuf);\r
1085#ifndef NARROW\r
1086 result = convbuf = __mbsconv(dtoaresult, -1);\r
1087#else\r
1088 /*XXX inefficient*/\r
1089 result = convbuf = strdup(dtoaresult);\r
1090#endif\r
1091 if (result == NULL)\r
1092 goto oomem;\r
1093 __freedtoa(dtoaresult);\r
1094 goto fp_common;\r
1095 case 'e':\r
1096 case 'E':\r
1097 expchar = ch;\r
d7ce7006 1098 if (prec < 0)\r
1099 prec = DEFPREC;\r
2aa62f2b 1100 goto fp_begin;\r
1101 case 'f':\r
1102 case 'F':\r
1103 expchar = '\0';\r
1104 goto fp_begin;\r
1105 case 'g':\r
1106 case 'G':\r
1107 expchar = ch - ('g' - 'e');\r
1108 if (prec == 0)\r
1109 prec = 1;\r
1110fp_begin:\r
1111 if (prec < 0)\r
1112 prec = DEFPREC;\r
1113 if (flags & LONGDBL) {\r
1114 fparg.ldbl = GETARG(long double);\r
1115 dtoaresult =\r
1116 __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,\r
1117 &expt, &signflag, &dtoaend);\r
1118 } else {\r
1119 fparg.dbl = GETARG(double);\r
1120 dtoaresult =\r
1121 __dtoa(fparg.dbl, expchar ? 2 : 3, prec,\r
1122 &expt, &signflag, &dtoaend);\r
1123 if (expt == 9999)\r
1124 expt = INT_MAX;\r
1125 }\r
1126 if (dtoaresult == NULL)\r
1127 goto oomem;\r
1128 ndig = dtoaend - dtoaresult;\r
1129 if (convbuf != NULL)\r
1130 free(convbuf);\r
1131#ifndef NARROW\r
1132 result = convbuf = __mbsconv(dtoaresult, -1);\r
1133#else\r
1134 /*XXX inefficient*/\r
1135 result = convbuf = strdup(dtoaresult);\r
1136#endif\r
1137 if (result == NULL)\r
1138 goto oomem;\r
1139 __freedtoa(dtoaresult);\r
1140fp_common:\r
1141 if (signflag)\r
1142 sign = '-';\r
1143 if (expt == INT_MAX) { /* inf or nan */\r
1144 if (*result == 'N') {\r
1145 result = (ch >= 'a') ? STRCONST("nan") :\r
1146 STRCONST("NAN");\r
1147 sign = '\0';\r
1148 } else\r
1149 result = (ch >= 'a') ? STRCONST("inf") :\r
1150 STRCONST("INF");\r
1151 size = 3;\r
1152 break;\r
1153 }\r
1154#else\r
1155 //case 'e':\r
1156 //case 'E':\r
1157 //case 'f':\r
1158 //case 'F':\r
1159 //case 'g':\r
1160 //case 'G':\r
1161 // if (prec == -1) {\r
1162 // prec = DEFPREC;\r
1163 // } else if ((ch == 'g' || ch == 'G') && prec == 0) {\r
1164 // prec = 1;\r
1165 // }\r
1166 case 'e':\r
1167 case 'E':\r
1168 expchar = ch;\r
d7ce7006 1169 if (prec < 0)\r
1170 prec = DEFPREC;\r
2aa62f2b 1171 goto fp_begin;\r
1172 case 'f':\r
1173 case 'F':\r
1174 expchar = '\0';\r
1175 goto fp_begin;\r
1176 case 'g':\r
1177 case 'G':\r
1178 expchar = ch - ('g' - 'e');\r
1179 if (prec == 0)\r
1180 prec = 1;\r
1181fp_begin:\r
1182 if (prec < 0)\r
1183 prec = DEFPREC;\r
1184\r
1185 if (flags & LONGDBL) {\r
1186 _double = (double) GETARG(long double);\r
1187 } else {\r
1188 _double = GETARG(double);\r
1189 }\r
1190\r
1191 /* do this before tricky precision changes */\r
1192 if (isinf(_double)) {\r
1193 if (_double < 0)\r
1194 sign = '-';\r
1195 if (ch == 'E' || ch == 'F' || ch == 'G')\r
1196 result = STRCONST("INF");\r
1197 else\r
1198 result = STRCONST("inf");\r
1199 size = 3;\r
1200 break;\r
1201 }\r
1202 if (isnan(_double)) {\r
1203 if (ch == 'E' || ch == 'F' || ch == 'G')\r
1204 result = STRCONST("NAN");\r
1205 else\r
1206 result = STRCONST("nan");\r
1207 size = 3;\r
1208 break;\r
1209 }\r
1210\r
1211 flags |= FPT;\r
1212 dtoaresult = cvt(_double, prec, flags, &softsign, &expt, ch, &ndig);\r
1213 if (dtoaresult == NULL)\r
1214 goto oomem;\r
1215 if (convbuf != NULL)\r
1216 free(convbuf);\r
1217#ifndef NARROW\r
1218 result = convbuf = __mbsconv(dtoaresult, -1);\r
1219#else\r
1220 /*XXX inefficient*/\r
1221 result = convbuf = strdup(dtoaresult);\r
1222#endif\r
1223 if (result == NULL)\r
1224 goto oomem;\r
1225 __freedtoa(dtoaresult);\r
1226 if (softsign)\r
1227 sign = '-';\r
1228#endif\r
1229 flags |= FPT;\r
1230 if (ch == 'g' || ch == 'G') {\r
1231 if (expt > -4 && expt <= prec) {\r
1232 /* Make %[gG] smell like %[fF] */\r
1233 expchar = '\0';\r
1234 if (flags & ALT)\r
1235 prec -= expt;\r
1236 else\r
1237 prec = ndig - expt;\r
1238 if (prec < 0)\r
1239 prec = 0;\r
1240 } else {\r
1241 /*\r
1242 * Make %[gG] smell like %[eE], but\r
1243 * trim trailing zeroes if no # flag.\r
d7ce7006 1244 *\r
1245 * Note: The precision field used with [gG] is the number significant\r
1246 * digits to print. When converting to [eE] the digit before the\r
1247 * decimal must not be included in the precision value.\r
2aa62f2b 1248 */\r
1249 if (!(flags & ALT))\r
d7ce7006 1250 prec = ndig - 1;\r
2aa62f2b 1251 }\r
1252 }\r
1253 if (expchar) {\r
d7ce7006 1254 dprec = prec; /* In some cases dprec will not be set. Make sure it is set now */\r
2aa62f2b 1255 expsize = exponent(expstr, expt - 1, expchar);\r
d7ce7006 1256 size = expsize + prec + 1; /* Leading digit + exponent string + precision */\r
1257 if (prec >= 1 || flags & ALT)\r
1258 ++size; /* Decimal point is added to character count */\r
2aa62f2b 1259 } else {\r
1260 /* space for digits before decimal point */\r
1261 if (expt > 0)\r
1262 size = expt;\r
1263 else /* "0" */\r
1264 size = 1;\r
1265 /* space for decimal pt and following digits */\r
1266 if (prec || flags & ALT)\r
1267 size += prec + 1;\r
1268 if (grouping && expt > 0) {\r
1269 /* space for thousands' grouping */\r
1270 nseps = nrepeats = 0;\r
1271 lead = expt;\r
1272 while (*grouping != CHAR_MAX) {\r
1273 if (lead <= *grouping)\r
1274 break;\r
1275 lead -= *grouping;\r
1276 if (*(grouping+1)) {\r
1277 nseps++;\r
1278 grouping++;\r
1279 } else\r
1280 nrepeats++;\r
1281 }\r
1282 size += nseps + nrepeats;\r
1283 } else\r
1284 lead = expt;\r
1285 }\r
1286 break;\r
1287#endif /* !NO_FLOATING_POINT */\r
1288 case 'n':\r
1289 /*\r
1290 * Assignment-like behavior is specified if the\r
1291 * value overflows or is otherwise unrepresentable.\r
1292 * C99 says to use `signed char' for %hhn conversions.\r
1293 */\r
1294 if (flags & LLONGINT)\r
1295 *GETARG(long long *) = ret;\r
1296 else if (flags & SIZET)\r
1297 *GETARG(ssize_t *) = (ssize_t)ret;\r
1298 else if (flags & PTRDIFFT)\r
1299 *GETARG(ptrdiff_t *) = ret;\r
1300 else if (flags & INTMAXT)\r
1301 *GETARG(intmax_t *) = ret;\r
1302 else if (flags & LONGINT)\r
1303 *GETARG(long *) = ret;\r
1304 else if (flags & SHORTINT)\r
1305 *GETARG(short *) = ret;\r
1306 else if (flags & CHARINT)\r
1307 *GETARG(signed char *) = ret;\r
1308 else\r
1309 *GETARG(int *) = ret;\r
1310 continue; /* no output */\r
1311 case 'O':\r
1312 flags |= LONGINT;\r
1313 /*FALLTHROUGH*/\r
1314 case 'o':\r
1315 if (flags & INTMAX_SIZE)\r
1316 ujval = UJARG();\r
1317 else\r
1318 ulval = UARG();\r
1319 base = 8;\r
1320 goto nosign;\r
1321 case 'p':\r
1322 /*-\r
1323 * ``The argument shall be a pointer to void. The\r
1324 * value of the pointer is converted to a sequence\r
1325 * of printable characters, in an implementation-\r
1326 * defined manner.''\r
1327 * -- ANSI X3J11\r
1328 */\r
d7ce7006 1329 ujval = (uintmax_t) (UINTN) GETARG(void *);\r
2aa62f2b 1330 base = 16;\r
1331 xdigs = xdigs_lower;\r
1332 flags = flags | INTMAXT;\r
1333 ox[1] = 'x';\r
1334 goto nosign;\r
1335 case 'S':\r
1336 flags |= LONGINT;\r
1337 /*FALLTHROUGH*/\r
1338 case 's':\r
d7ce7006 1339 if (((flags & LONGINT) ? 1:0) != MULTI) {\r
2aa62f2b 1340 if ((result = GETARG(CHAR_T *)) == NULL)\r
1341 result = STRCONST("(null)");\r
1342 } else {\r
1343 MCHAR_T *mc;\r
1344\r
1345 if (convbuf != NULL)\r
1346 free(convbuf);\r
1347 if ((mc = GETARG(MCHAR_T *)) == NULL)\r
1348 result = STRCONST("(null)");\r
1349 else {\r
1350 convbuf = SCONV(mc, prec);\r
1351 if (convbuf == NULL) {\r
1352 fp->_flags |= __SERR;\r
1353 goto error;\r
1354 }\r
1355 result = convbuf;\r
1356 }\r
1357 }\r
1358\r
1359 if (prec >= 0) {\r
1360 /*\r
1361 * can't use STRLEN; can only look for the\r
1362 * NUL in the first `prec' characters, and\r
1363 * STRLEN() will go further.\r
1364 */\r
1365 CHAR_T *p = MEMCHR(result, 0, (size_t)prec);\r
1366\r
1367 if (p != NULL) {\r
1368 size = p - result;\r
1369 if (size > prec)\r
1370 size = prec;\r
1371 } else\r
1372 size = prec;\r
1373 } else\r
1374 size = (int)STRLEN(result);\r
1375 sign = '\0';\r
1376 break;\r
1377 case 'U':\r
1378 flags |= LONGINT;\r
1379 /*FALLTHROUGH*/\r
1380 case 'u':\r
1381 if (flags & INTMAX_SIZE)\r
1382 ujval = UJARG();\r
1383 else\r
1384 ulval = UARG();\r
1385 base = 10;\r
1386 goto nosign;\r
1387 case 'X':\r
1388 xdigs = xdigs_upper;\r
1389 goto hex;\r
1390 case 'x':\r
1391 xdigs = xdigs_lower;\r
1392hex:\r
1393 if (flags & INTMAX_SIZE)\r
1394 ujval = UJARG();\r
1395 else\r
1396 ulval = UARG();\r
1397 base = 16;\r
1398 /* leading 0x/X only if non-zero */\r
1399 if (flags & ALT &&\r
1400 (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))\r
1401 ox[1] = ch;\r
1402\r
1403 flags &= ~GROUPING;\r
1404 /* unsigned conversions */\r
1405nosign: sign = '\0';\r
1406 /*-\r
1407 * ``... diouXx conversions ... if a precision is\r
1408 * specified, the 0 flag will be ignored.''\r
1409 * -- ANSI X3J11\r
1410 */\r
1411number: if ((dprec = prec) >= 0)\r
1412 flags &= ~ZEROPAD;\r
1413\r
1414 /*-\r
1415 * ``The result of converting a zero value with an\r
1416 * explicit precision of zero is no characters.''\r
1417 * -- ANSI X3J11\r
1418 *\r
1419 * ``The C Standard is clear enough as is. The call\r
1420 * printf("%#.0o", 0) should print 0.''\r
1421 * -- Defect Report #151\r
1422 */\r
1423 result = cp = buf + BUF;\r
1424 if (flags & INTMAX_SIZE) {\r
1425 if (ujval != 0 || prec != 0 ||\r
1426 (flags & ALT && base == 8))\r
1427 {\r
1428 result = __ujtoa(ujval, cp, base,\r
1429 flags & ALT, xdigs,\r
1430 flags & GROUPING, thousands_sep,\r
1431 grouping);\r
1432 }\r
1433 } else {\r
1434 if (ulval != 0 || prec != 0 ||\r
1435 (flags & ALT && base == 8))\r
1436 result = __ultoa(ulval, cp, base,\r
1437 flags & ALT, xdigs,\r
1438 flags & GROUPING, thousands_sep,\r
1439 grouping);\r
1440 }\r
1441 size = buf + BUF - result;\r
1442 if (size > BUF) /* should never happen */\r
1443 abort();\r
1444 break;\r
1445 default: /* "%?" prints ?, unless ? is NUL */\r
1446 if (ch == '\0')\r
1447 goto done;\r
1448 /* pretend it was %c with argument ch */\r
1449 *buf = ch;\r
1450 result = buf;\r
1451 size = 1;\r
1452 sign = '\0';\r
1453 break;\r
1454 }\r
1455\r
1456 /*\r
1457 * All reasonable formats wind up here. At this point, `result'\r
1458 * points to a string which (if not flags&LADJUST) should be\r
1459 * padded out to `width' places. If flags&ZEROPAD, it should\r
1460 * first be prefixed by any sign or other prefix; otherwise,\r
1461 * it should be blank padded before the prefix is emitted.\r
1462 * After any left-hand padding and prefixing, emit zeroes\r
1463 * required by a decimal [diouxX] precision, then print the\r
1464 * string proper, then emit zeroes required by any leftover\r
1465 * floating precision; finally, if LADJUST, pad with blanks.\r
1466 *\r
1467 * Compute actual size, so we know how much to pad.\r
1468 * size excludes decimal prec; realsz includes it.\r
1469 */\r
1470 realsz = dprec > size ? dprec : size;\r
1471 if (sign)\r
1472 realsz++;\r
1473 if (ox[1])\r
1474 realsz += 2;\r
1475\r
1476 prsize = width > realsz ? width : realsz;\r
1477 if ((unsigned)ret + prsize > INT_MAX) {\r
1478 ret = END_OF_FILE;\r
1479 goto error;\r
1480 }\r
1481\r
1482 /* right-adjusting blank padding */\r
1483 if ((flags & (LADJUST|ZEROPAD)) == 0)\r
1484 PAD(width - realsz, blanks);\r
1485\r
1486 /* prefix */\r
1487 if (sign)\r
1488 PRINT(&sign, 1);\r
1489\r
1490 if (ox[1]) { /* ox[1] is either x, X, or \0 */\r
1491 ox[0] = '0';\r
1492 PRINT(ox, 2);\r
1493 }\r
1494\r
1495 /* right-adjusting zero padding */\r
1496 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)\r
1497 PAD(width - realsz, zeroes);\r
1498\r
1499 /* leading zeroes from decimal precision */\r
1500 PAD(dprec - size, zeroes);\r
1501\r
1502 /* the string or number proper */\r
1503#ifndef NO_FLOATING_POINT\r
1504 if ((flags & FPT) == 0) {\r
1505 PRINT(result, size);\r
1506 } else { /* glue together f_p fragments */\r
1507 if (!expchar) { /* %[fF] or sufficiently short %[gG] */\r
1508 if (expt <= 0) {\r
1509 PRINT(zeroes, 1);\r
1510 if (prec || flags & ALT)\r
1511 PRINT(decimal_point, 1);\r
1512 PAD(-expt, zeroes);\r
1513 /* already handled initial 0's */\r
1514 prec += expt;\r
1515 } else {\r
1516 PRINTANDPAD(result, convbuf + ndig,\r
1517 lead, zeroes);\r
1518 result += lead;\r
1519 if (grouping) {\r
1520 while (nseps>0 || nrepeats>0) {\r
1521 if (nrepeats > 0)\r
1522 nrepeats--;\r
1523 else {\r
1524 grouping--;\r
1525 nseps--;\r
1526 }\r
1527 PRINT(&thousands_sep,\r
1528 1);\r
1529 PRINTANDPAD(result,\r
1530 convbuf + ndig,\r
1531 *grouping, zeroes);\r
1532 result += *grouping;\r
1533 }\r
1534 if (result > convbuf + ndig)\r
1535 result = convbuf + ndig;\r
1536 }\r
1537 if (prec || flags & ALT) {\r
1538 buf[0] = *decimal_point;\r
1539 PRINT(buf, 1);\r
1540 }\r
1541 }\r
1542 PRINTANDPAD(result, convbuf + ndig, prec,\r
1543 zeroes);\r
1544 } else { /* %[eE] or sufficiently long %[gG] */\r
d7ce7006 1545 if (prec >= 1 || flags & ALT) {\r
2aa62f2b 1546 buf[0] = *result++;\r
1547 buf[1] = *decimal_point;\r
1548 PRINT(buf, 2);\r
1549 PRINT(result, ndig-1);\r
1550 PAD(prec - ndig, zeroes);\r
1551 } else /* XeYYY */\r
1552 PRINT(result, 1);\r
1553 PRINT(expstr, expsize);\r
1554 }\r
1555 }\r
1556#else\r
1557 PRINT(result, size);\r
1558#endif\r
1559 /* left-adjusting padding (always blank) */\r
1560 if (flags & LADJUST)\r
1561 PAD(width - realsz, blanks);\r
1562\r
1563 /* finally, adjust ret */\r
1564 ret += prsize;\r
1565 FLUSH();\r
1566 }\r
1567done:\r
1568 FLUSH();\r
1569error:\r
1570 va_end(orgap);\r
1571 if (convbuf != NULL)\r
1572 free(convbuf);\r
1573 if (__sferror(fp))\r
1574 ret = END_OF_FILE;\r
1575 if ((argtable != NULL) && (argtable != statargtable))\r
1576 free (argtable);\r
1577 return (ret);\r
1578 /* NOTREACHED */\r
1579oomem:\r
1580 errno = ENOMEM;\r
1581 ret = END_OF_FILE;\r
1582 goto error;\r
1583}\r
1584\r
1585/*\r
1586 * Find all arguments when a positional parameter is encountered. Returns a\r
1587 * table, indexed by argument number, of pointers to each arguments. The\r
1588 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.\r
1589 * It will be replaces with a malloc-ed one if it overflows.\r
1590 */\r
1591static int\r
1592__find_arguments(const CHAR_T *fmt0, va_list ap, union arg **argtable)\r
1593{\r
1594 CHAR_T *fmt; /* format string */\r
1595 int ch; /* character from fmt */\r
1596 int n, n2; /* handy integer (short term usage) */\r
1597 CHAR_T *cp; /* handy char pointer (short term usage) */\r
1598 int flags; /* flags as above */\r
1599 enum typeid *typetable; /* table of types */\r
1600 enum typeid stattypetable [STATIC_ARG_TBL_SIZE];\r
1601 int tablesize; /* current size of type table */\r
1602 int tablemax; /* largest used index in table */\r
1603 int nextarg; /* 1-based argument index */\r
1604\r
1605 /*\r
1606 * Add an argument type to the table, expanding if necessary.\r
1607 */\r
1608#define ADDTYPE(type) \\r
1609 do { \\r
1610 if (nextarg >= tablesize) \\r
1611 if (__grow_type_table(nextarg, &typetable, \\r
1612 &tablesize) == -1) \\r
1613 return -1; \\r
1614 if (nextarg > tablemax) \\r
1615 tablemax = nextarg; \\r
1616 typetable[nextarg++] = type; \\r
1617 } while (/*CONSTCOND*/0)\r
1618\r
1619#define ADDSARG() \\r
1620 do { \\r
1621 if (flags & INTMAXT) \\r
1622 ADDTYPE(T_INTMAXT); \\r
1623 else if (flags & SIZET) \\r
1624 ADDTYPE(T_SIZET); \\r
1625 else if (flags & PTRDIFFT) \\r
1626 ADDTYPE(T_PTRDIFFT); \\r
1627 else if (flags & LLONGINT) \\r
1628 ADDTYPE(T_LLONG); \\r
1629 else if (flags & LONGINT) \\r
1630 ADDTYPE(T_LONG); \\r
1631 else \\r
1632 ADDTYPE(T_INT); \\r
1633 } while (/*CONSTCOND*/0)\r
1634\r
1635#define ADDUARG() \\r
1636 do { \\r
1637 if (flags & INTMAXT) \\r
1638 ADDTYPE(T_UINTMAXT); \\r
1639 else if (flags & SIZET) \\r
1640 ADDTYPE(T_SIZET); \\r
1641 else if (flags & PTRDIFFT) \\r
1642 ADDTYPE(T_PTRDIFFT); \\r
1643 else if (flags & LLONGINT) \\r
1644 ADDTYPE(T_U_LLONG); \\r
1645 else if (flags & LONGINT) \\r
1646 ADDTYPE(T_U_LONG); \\r
1647 else \\r
1648 ADDTYPE(T_U_INT); \\r
1649 } while (/*CONSTCOND*/0)\r
1650 /*\r
1651 * Add * arguments to the type array.\r
1652 */\r
1653#define ADDASTER() \\r
1654 n2 = 0; \\r
1655 cp = fmt; \\r
1656 while (is_digit(*cp)) { \\r
1657 n2 = 10 * n2 + to_digit(*cp); \\r
1658 cp++; \\r
1659 } \\r
1660 if (*cp == '$') { \\r
1661 int hold = nextarg; \\r
1662 nextarg = n2; \\r
1663 ADDTYPE(T_INT); \\r
1664 nextarg = hold; \\r
1665 fmt = ++cp; \\r
1666 } else { \\r
1667 ADDTYPE(T_INT); \\r
1668 }\r
1669 fmt = (CHAR_T *)__UNCONST(fmt0);\r
1670 typetable = stattypetable;\r
1671 tablesize = STATIC_ARG_TBL_SIZE;\r
1672 tablemax = 0;\r
1673 nextarg = 1;\r
1674 for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)\r
1675 typetable[n] = T_UNUSED;\r
1676\r
1677 /*\r
1678 * Scan the format for conversions (`%' character).\r
1679 */\r
1680 for (;;) {\r
1681 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)\r
1682 /* void */;\r
1683 if (ch == '\0')\r
1684 goto done;\r
1685 fmt++; /* skip over '%' */\r
1686\r
1687 flags = 0;\r
1688\r
1689rflag: ch = *fmt++;\r
1690reswitch: switch (ch) {\r
1691 case ' ':\r
1692 case '#':\r
1693 goto rflag;\r
1694 case '*':\r
1695 ADDASTER ();\r
1696 goto rflag;\r
1697 case '-':\r
1698 case '+':\r
1699 case '\'':\r
1700 goto rflag;\r
1701 case '.':\r
1702 if ((ch = *fmt++) == '*') {\r
1703 ADDASTER ();\r
1704 goto rflag;\r
1705 }\r
1706 while (is_digit(ch)) {\r
1707 ch = *fmt++;\r
1708 }\r
1709 goto reswitch;\r
1710 case '0':\r
1711 goto rflag;\r
1712 case '1': case '2': case '3': case '4':\r
1713 case '5': case '6': case '7': case '8': case '9':\r
1714 n = 0;\r
1715 do {\r
1716 n = 10 * n + to_digit(ch);\r
1717 ch = *fmt++;\r
1718 } while (is_digit(ch));\r
1719 if (ch == '$') {\r
1720 nextarg = n;\r
1721 goto rflag;\r
1722 }\r
1723 goto reswitch;\r
1724#ifndef NO_FLOATING_POINT\r
1725 case 'L':\r
1726 flags |= LONGDBL;\r
1727 goto rflag;\r
1728#endif\r
1729 case 'h':\r
1730 if (flags & SHORTINT) {\r
1731 flags &= ~SHORTINT;\r
1732 flags |= CHARINT;\r
1733 } else\r
1734 flags |= SHORTINT;\r
1735 goto rflag;\r
1736 case 'j':\r
1737 flags |= INTMAXT;\r
1738 goto rflag;\r
1739 case 'l':\r
1740 if (flags & LONGINT) {\r
1741 flags &= ~LONGINT;\r
1742 flags |= LLONGINT;\r
1743 } else\r
1744 flags |= LONGINT;\r
1745 goto rflag;\r
1746 case 'q':\r
1747 flags |= LLONGINT; /* not necessarily */\r
1748 goto rflag;\r
1749 case 't':\r
1750 flags |= PTRDIFFT;\r
1751 goto rflag;\r
1752 case 'z':\r
1753 flags |= SIZET;\r
1754 goto rflag;\r
1755 case 'C':\r
1756 flags |= LONGINT;\r
1757 /*FALLTHROUGH*/\r
1758 case 'c':\r
1759 if (flags & LONGINT)\r
1760 ADDTYPE(T_WINT);\r
1761 else\r
1762 ADDTYPE(T_INT);\r
1763 break;\r
1764 case 'D':\r
1765 flags |= LONGINT;\r
1766 /*FALLTHROUGH*/\r
1767 case 'd':\r
1768 case 'i':\r
1769 ADDSARG();\r
1770 break;\r
1771#ifndef NO_FLOATING_POINT\r
1772 case 'a':\r
1773 case 'A':\r
1774 case 'e':\r
1775 case 'E':\r
1776 case 'f':\r
1777 case 'g':\r
1778 case 'G':\r
1779 if (flags & LONGDBL)\r
1780 ADDTYPE(T_LONG_DOUBLE);\r
1781 else\r
1782 ADDTYPE(T_DOUBLE);\r
1783 break;\r
1784#endif /* !NO_FLOATING_POINT */\r
1785 case 'n':\r
1786 if (flags & INTMAXT)\r
1787 ADDTYPE(TP_INTMAXT);\r
1788 else if (flags & PTRDIFFT)\r
1789 ADDTYPE(TP_PTRDIFFT);\r
1790 else if (flags & SIZET)\r
1791 ADDTYPE(TP_SIZET);\r
1792 else if (flags & LLONGINT)\r
1793 ADDTYPE(TP_LLONG);\r
1794 else if (flags & LONGINT)\r
1795 ADDTYPE(TP_LONG);\r
1796 else if (flags & SHORTINT)\r
1797 ADDTYPE(TP_SHORT);\r
1798 else if (flags & CHARINT)\r
1799 ADDTYPE(TP_SCHAR);\r
1800 else\r
1801 ADDTYPE(TP_INT);\r
1802 continue; /* no output */\r
1803 case 'O':\r
1804 flags |= LONGINT;\r
1805 /*FALLTHROUGH*/\r
1806 case 'o':\r
1807 ADDUARG();\r
1808 break;\r
1809 case 'p':\r
1810 ADDTYPE(TP_VOID);\r
1811 break;\r
1812 case 'S':\r
1813 flags |= LONGINT;\r
1814 /*FALLTHROUGH*/\r
1815 case 's':\r
1816 if (flags & LONGINT)\r
1817 ADDTYPE(TP_WCHAR);\r
1818 else\r
1819 ADDTYPE(TP_CHAR);\r
1820 break;\r
1821 case 'U':\r
1822 flags |= LONGINT;\r
1823 /*FALLTHROUGH*/\r
1824 case 'u':\r
1825 case 'X':\r
1826 case 'x':\r
1827 ADDUARG();\r
1828 break;\r
1829 default: /* "%?" prints ?, unless ? is NUL */\r
1830 if (ch == '\0')\r
1831 goto done;\r
1832 break;\r
1833 }\r
1834 }\r
1835done:\r
1836 /*\r
1837 * Build the argument table.\r
1838 */\r
1839 if (tablemax >= STATIC_ARG_TBL_SIZE) {\r
1840 *argtable = (union arg *)\r
1841 malloc (sizeof (union arg) * (tablemax + 1));\r
1842 if (*argtable == NULL)\r
1843 return -1;\r
1844 }\r
1845\r
1846 (*argtable) [0].intarg = 0;\r
1847 for (n = 1; n <= tablemax; n++) {\r
1848 switch (typetable [n]) {\r
1849 case T_UNUSED: /* whoops! */\r
1850 (*argtable) [n].intarg = va_arg (ap, int);\r
1851 break;\r
1852 case TP_SCHAR:\r
1853 (*argtable) [n].pschararg = va_arg (ap, signed char *);\r
1854 break;\r
1855 case TP_SHORT:\r
1856 (*argtable) [n].pshortarg = va_arg (ap, short *);\r
1857 break;\r
1858 case T_INT:\r
1859 (*argtable) [n].intarg = va_arg (ap, int);\r
1860 break;\r
1861 case T_U_INT:\r
1862 (*argtable) [n].uintarg = va_arg (ap, unsigned int);\r
1863 break;\r
1864 case TP_INT:\r
1865 (*argtable) [n].pintarg = va_arg (ap, int *);\r
1866 break;\r
1867 case T_LONG:\r
1868 (*argtable) [n].longarg = va_arg (ap, long);\r
1869 break;\r
1870 case T_U_LONG:\r
1871 (*argtable) [n].ulongarg = va_arg (ap, unsigned long);\r
1872 break;\r
1873 case TP_LONG:\r
1874 (*argtable) [n].plongarg = va_arg (ap, long *);\r
1875 break;\r
1876 case T_LLONG:\r
1877 (*argtable) [n].longlongarg = va_arg (ap, long long);\r
1878 break;\r
1879 case T_U_LLONG:\r
1880 (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);\r
1881 break;\r
1882 case TP_LLONG:\r
1883 (*argtable) [n].plonglongarg = va_arg (ap, long long *);\r
1884 break;\r
1885 case T_PTRDIFFT:\r
1886 (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);\r
1887 break;\r
1888 case TP_PTRDIFFT:\r
1889 (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);\r
1890 break;\r
1891 case T_SIZET:\r
1892 (*argtable) [n].sizearg = va_arg (ap, size_t);\r
1893 break;\r
1894 case TP_SIZET:\r
1895 (*argtable) [n].psizearg = va_arg (ap, size_t *);\r
1896 break;\r
1897 case T_INTMAXT:\r
1898 (*argtable) [n].intmaxarg = va_arg (ap, intmax_t);\r
1899 break;\r
1900 case T_UINTMAXT:\r
1901 (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);\r
1902 break;\r
1903 case TP_INTMAXT:\r
1904 (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);\r
1905 break;\r
1906 case T_DOUBLE:\r
1907#ifndef NO_FLOATING_POINT\r
1908 (*argtable) [n].doublearg = va_arg (ap, double);\r
1909#endif\r
1910 break;\r
1911 case T_LONG_DOUBLE:\r
1912#ifndef NO_FLOATING_POINT\r
1913 (*argtable) [n].longdoublearg = va_arg (ap, long double);\r
1914#endif\r
1915 break;\r
1916 case TP_CHAR:\r
1917 (*argtable) [n].pchararg = va_arg (ap, char *);\r
1918 break;\r
1919 case TP_VOID:\r
1920 (*argtable) [n].pvoidarg = va_arg (ap, void *);\r
1921 break;\r
1922 case T_WINT:\r
5244f47e 1923 (*argtable) [n].wintarg = va_arg (ap, int);\r
2aa62f2b 1924 break;\r
1925 case TP_WCHAR:\r
1926 (*argtable) [n].pwchararg = va_arg (ap, wchar_t *);\r
1927 break;\r
1928 }\r
1929 }\r
1930\r
1931 if ((typetable != NULL) && (typetable != stattypetable))\r
1932 free (typetable);\r
1933 return 0;\r
1934}\r
1935\r
1936/*\r
1937 * Increase the size of the type table.\r
1938 */\r
1939static int\r
1940__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize)\r
1941{\r
1942 enum typeid *const oldtable = *typetable;\r
1943 const int oldsize = *tablesize;\r
1944 enum typeid *newtable;\r
1945 int n, newsize = oldsize * 2;\r
1946\r
1947 if (newsize < nextarg + 1)\r
1948 newsize = nextarg + 1;\r
1949 if (oldsize == STATIC_ARG_TBL_SIZE) {\r
1950 if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)\r
1951 return -1;\r
1952 memcpy(newtable, oldtable, oldsize * sizeof(enum typeid));\r
1953 } else {\r
1954 newtable = realloc(oldtable, newsize * sizeof(enum typeid));\r
1955 if (newtable == NULL) {\r
1956 free(oldtable);\r
1957 return -1;\r
1958 }\r
1959 }\r
1960 for (n = oldsize; n < newsize; n++)\r
1961 newtable[n] = T_UNUSED;\r
1962\r
1963 *typetable = newtable;\r
1964 *tablesize = newsize;\r
1965 return 0;\r
1966}\r
1967\r
1968\r
1969#ifndef NO_FLOATING_POINT\r
1970#ifndef WIDE_DOUBLE\r
1971static char *\r
1972cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch,\r
1973 int *length)\r
1974{\r
1975 int mode, dsgn;\r
1976 char *digits, *bp, *rve;\r
1977\r
1978 _DIAGASSERT(decpt != NULL);\r
1979 _DIAGASSERT(length != NULL);\r
1980 _DIAGASSERT(sign != NULL);\r
1981\r
1982 if (ch == 'f') {\r
1983 mode = 3; /* ndigits after the decimal point */\r
1984 } else {\r
1985 /* To obtain ndigits after the decimal point for the 'e'\r
1986 * and 'E' formats, round to ndigits + 1 significant\r
1987 * figures.\r
1988 */\r
1989 if (ch == 'e' || ch == 'E') {\r
1990 ndigits++;\r
1991 }\r
1992 mode = 2; /* ndigits significant digits */\r
1993 }\r
1994\r
1995 digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);\r
1996 if (digits == NULL)\r
1997 return NULL;\r
1998 if (dsgn) {\r
1999 value = -value;\r
2000 *sign = '-';\r
2001 } else\r
2002 *sign = '\000';\r
2003 if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */\r
2004 bp = digits + ndigits;\r
2005 if (ch == 'f') {\r
2006 if (*digits == '0' && value)\r
2007 *decpt = -ndigits + 1;\r
2008 bp += *decpt;\r
2009 }\r
2aa62f2b 2010 while (rve < bp)\r
2011 *rve++ = '0';\r
2012 }\r
2013 *length = rve - digits;\r
2014 return digits;\r
2015}\r
2016#endif\r
2017\r
2018static int\r
2019exponent(CHAR_T *p0, int expo, int fmtch)\r
2020{\r
2021 CHAR_T *p, *t;\r
2022 CHAR_T expbuf[MAXEXPDIG];\r
2023\r
2024 p = p0;\r
2025 *p++ = fmtch;\r
2026 if (expo < 0) {\r
2027 expo = -expo;\r
2028 *p++ = '-';\r
2029 }\r
2030 else\r
2031 *p++ = '+';\r
2032 t = expbuf + MAXEXPDIG;\r
2033 if (expo > 9) {\r
2034 do {\r
2035 *--t = to_char(expo % 10);\r
2036 } while ((expo /= 10) > 9);\r
2037 *--t = to_char(expo);\r
2038 for (; t < expbuf + MAXEXPDIG; *p++ = *t++);\r
2039 }\r
2040 else {\r
2041 /*\r
2042 * Exponents for decimal floating point conversions\r
2043 * (%[eEgG]) must be at least two characters long,\r
2044 * whereas exponents for hexadecimal conversions can\r
2045 * be only one character long.\r
2046 */\r
2047 if (fmtch == 'e' || fmtch == 'E')\r
2048 *p++ = '0';\r
2049 *p++ = to_char(expo);\r
2050 }\r
2051 return (p - p0);\r
2052}\r
2053#endif /* !NO_FLOATING_POINT */\r