]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Stdio/vfwprintf.c
Add Socket Libraries.
[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
1006 (wchar_t)GETARG(wint_t), &mbs);\r
1007 if (mbseqlen == (size_t)-1) {\r
1008 fp->_flags |= __SERR;\r
1009 goto error;\r
1010 }\r
1011 size = (int)mbseqlen;\r
1012 } else {\r
1013 *buf = (char)(GETARG(int));\r
1014 size = 1;\r
1015 }\r
1016#else\r
1017 if (flags & LONGINT)\r
1018 *buf = (wchar_t)GETARG(wint_t);\r
1019 else\r
1020 *buf = (wchar_t)btowc(GETARG(int));\r
1021 size = 1;\r
1022#endif\r
1023 result = buf;\r
1024 sign = '\0';\r
1025 break;\r
1026 case 'D':\r
1027 flags |= LONGINT;\r
1028 /*FALLTHROUGH*/\r
1029 case 'd':\r
1030 case 'i':\r
1031 if (flags & INTMAX_SIZE) {\r
1032 ujval = SJARG();\r
1033 if ((intmax_t)ujval < 0) {\r
1034 ujval = (uintmax_t)(-((intmax_t)ujval));\r
1035 sign = '-';\r
1036 }\r
1037 } else {\r
1038 ulval = SARG();\r
1039 if ((long)ulval < 0) {\r
1040 ulval = (u_long)(-((long)ulval));\r
1041 sign = '-';\r
1042 }\r
1043 }\r
1044 base = 10;\r
1045 goto number;\r
1046#ifndef NO_FLOATING_POINT\r
1047#ifdef WIDE_DOUBLE\r
1048 case 'a':\r
1049 case 'A':\r
1050 if (ch == 'a') {\r
1051 ox[1] = 'x';\r
1052 xdigs = xdigs_lower;\r
1053 expchar = 'p';\r
1054 } else {\r
1055 ox[1] = 'X';\r
1056 xdigs = xdigs_upper;\r
1057 expchar = 'P';\r
1058 }\r
2aa62f2b 1059 if (flags & LONGDBL) {\r
1060 fparg.ldbl = GETARG(long double);\r
1061 dtoaresult =\r
1062 __hldtoa(fparg.ldbl, xdigs, prec,\r
1063 &expt, &signflag, &dtoaend);\r
1064 } else {\r
1065 fparg.dbl = GETARG(double);\r
1066 dtoaresult =\r
1067 __hdtoa(fparg.dbl, xdigs, prec,\r
1068 &expt, &signflag, &dtoaend);\r
1069 }\r
1070 if (dtoaresult == NULL)\r
1071 goto oomem;\r
1072\r
1073 if (prec < 0)\r
1074 prec = dtoaend - dtoaresult;\r
1075 if (expt == INT_MAX)\r
1076 ox[1] = '\0';\r
1077 ndig = dtoaend - dtoaresult;\r
1078 if (convbuf != NULL)\r
1079 free(convbuf);\r
1080#ifndef NARROW\r
1081 result = convbuf = __mbsconv(dtoaresult, -1);\r
1082#else\r
1083 /*XXX inefficient*/\r
1084 result = convbuf = strdup(dtoaresult);\r
1085#endif\r
1086 if (result == NULL)\r
1087 goto oomem;\r
1088 __freedtoa(dtoaresult);\r
1089 goto fp_common;\r
1090 case 'e':\r
1091 case 'E':\r
1092 expchar = ch;\r
d7ce7006 1093 if (prec < 0)\r
1094 prec = DEFPREC;\r
2aa62f2b 1095 goto fp_begin;\r
1096 case 'f':\r
1097 case 'F':\r
1098 expchar = '\0';\r
1099 goto fp_begin;\r
1100 case 'g':\r
1101 case 'G':\r
1102 expchar = ch - ('g' - 'e');\r
1103 if (prec == 0)\r
1104 prec = 1;\r
1105fp_begin:\r
1106 if (prec < 0)\r
1107 prec = DEFPREC;\r
1108 if (flags & LONGDBL) {\r
1109 fparg.ldbl = GETARG(long double);\r
1110 dtoaresult =\r
1111 __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,\r
1112 &expt, &signflag, &dtoaend);\r
1113 } else {\r
1114 fparg.dbl = GETARG(double);\r
1115 dtoaresult =\r
1116 __dtoa(fparg.dbl, expchar ? 2 : 3, prec,\r
1117 &expt, &signflag, &dtoaend);\r
1118 if (expt == 9999)\r
1119 expt = INT_MAX;\r
1120 }\r
1121 if (dtoaresult == NULL)\r
1122 goto oomem;\r
1123 ndig = dtoaend - dtoaresult;\r
1124 if (convbuf != NULL)\r
1125 free(convbuf);\r
1126#ifndef NARROW\r
1127 result = convbuf = __mbsconv(dtoaresult, -1);\r
1128#else\r
1129 /*XXX inefficient*/\r
1130 result = convbuf = strdup(dtoaresult);\r
1131#endif\r
1132 if (result == NULL)\r
1133 goto oomem;\r
1134 __freedtoa(dtoaresult);\r
1135fp_common:\r
1136 if (signflag)\r
1137 sign = '-';\r
1138 if (expt == INT_MAX) { /* inf or nan */\r
1139 if (*result == 'N') {\r
1140 result = (ch >= 'a') ? STRCONST("nan") :\r
1141 STRCONST("NAN");\r
1142 sign = '\0';\r
1143 } else\r
1144 result = (ch >= 'a') ? STRCONST("inf") :\r
1145 STRCONST("INF");\r
1146 size = 3;\r
1147 break;\r
1148 }\r
1149#else\r
1150 //case 'e':\r
1151 //case 'E':\r
1152 //case 'f':\r
1153 //case 'F':\r
1154 //case 'g':\r
1155 //case 'G':\r
1156 // if (prec == -1) {\r
1157 // prec = DEFPREC;\r
1158 // } else if ((ch == 'g' || ch == 'G') && prec == 0) {\r
1159 // prec = 1;\r
1160 // }\r
1161 case 'e':\r
1162 case 'E':\r
1163 expchar = ch;\r
d7ce7006 1164 if (prec < 0)\r
1165 prec = DEFPREC;\r
2aa62f2b 1166 goto fp_begin;\r
1167 case 'f':\r
1168 case 'F':\r
1169 expchar = '\0';\r
1170 goto fp_begin;\r
1171 case 'g':\r
1172 case 'G':\r
1173 expchar = ch - ('g' - 'e');\r
1174 if (prec == 0)\r
1175 prec = 1;\r
1176fp_begin:\r
1177 if (prec < 0)\r
1178 prec = DEFPREC;\r
1179\r
1180 if (flags & LONGDBL) {\r
1181 _double = (double) GETARG(long double);\r
1182 } else {\r
1183 _double = GETARG(double);\r
1184 }\r
1185\r
1186 /* do this before tricky precision changes */\r
1187 if (isinf(_double)) {\r
1188 if (_double < 0)\r
1189 sign = '-';\r
1190 if (ch == 'E' || ch == 'F' || ch == 'G')\r
1191 result = STRCONST("INF");\r
1192 else\r
1193 result = STRCONST("inf");\r
1194 size = 3;\r
1195 break;\r
1196 }\r
1197 if (isnan(_double)) {\r
1198 if (ch == 'E' || ch == 'F' || ch == 'G')\r
1199 result = STRCONST("NAN");\r
1200 else\r
1201 result = STRCONST("nan");\r
1202 size = 3;\r
1203 break;\r
1204 }\r
1205\r
1206 flags |= FPT;\r
1207 dtoaresult = cvt(_double, prec, flags, &softsign, &expt, ch, &ndig);\r
1208 if (dtoaresult == NULL)\r
1209 goto oomem;\r
1210 if (convbuf != NULL)\r
1211 free(convbuf);\r
1212#ifndef NARROW\r
1213 result = convbuf = __mbsconv(dtoaresult, -1);\r
1214#else\r
1215 /*XXX inefficient*/\r
1216 result = convbuf = strdup(dtoaresult);\r
1217#endif\r
1218 if (result == NULL)\r
1219 goto oomem;\r
1220 __freedtoa(dtoaresult);\r
1221 if (softsign)\r
1222 sign = '-';\r
1223#endif\r
1224 flags |= FPT;\r
1225 if (ch == 'g' || ch == 'G') {\r
1226 if (expt > -4 && expt <= prec) {\r
1227 /* Make %[gG] smell like %[fF] */\r
1228 expchar = '\0';\r
1229 if (flags & ALT)\r
1230 prec -= expt;\r
1231 else\r
1232 prec = ndig - expt;\r
1233 if (prec < 0)\r
1234 prec = 0;\r
1235 } else {\r
1236 /*\r
1237 * Make %[gG] smell like %[eE], but\r
1238 * trim trailing zeroes if no # flag.\r
d7ce7006 1239 *\r
1240 * Note: The precision field used with [gG] is the number significant\r
1241 * digits to print. When converting to [eE] the digit before the\r
1242 * decimal must not be included in the precision value.\r
2aa62f2b 1243 */\r
1244 if (!(flags & ALT))\r
d7ce7006 1245 prec = ndig - 1;\r
2aa62f2b 1246 }\r
1247 }\r
1248 if (expchar) {\r
d7ce7006 1249 dprec = prec; /* In some cases dprec will not be set. Make sure it is set now */\r
2aa62f2b 1250 expsize = exponent(expstr, expt - 1, expchar);\r
d7ce7006 1251 size = expsize + prec + 1; /* Leading digit + exponent string + precision */\r
1252 if (prec >= 1 || flags & ALT)\r
1253 ++size; /* Decimal point is added to character count */\r
2aa62f2b 1254 } else {\r
1255 /* space for digits before decimal point */\r
1256 if (expt > 0)\r
1257 size = expt;\r
1258 else /* "0" */\r
1259 size = 1;\r
1260 /* space for decimal pt and following digits */\r
1261 if (prec || flags & ALT)\r
1262 size += prec + 1;\r
1263 if (grouping && expt > 0) {\r
1264 /* space for thousands' grouping */\r
1265 nseps = nrepeats = 0;\r
1266 lead = expt;\r
1267 while (*grouping != CHAR_MAX) {\r
1268 if (lead <= *grouping)\r
1269 break;\r
1270 lead -= *grouping;\r
1271 if (*(grouping+1)) {\r
1272 nseps++;\r
1273 grouping++;\r
1274 } else\r
1275 nrepeats++;\r
1276 }\r
1277 size += nseps + nrepeats;\r
1278 } else\r
1279 lead = expt;\r
1280 }\r
1281 break;\r
1282#endif /* !NO_FLOATING_POINT */\r
1283 case 'n':\r
1284 /*\r
1285 * Assignment-like behavior is specified if the\r
1286 * value overflows or is otherwise unrepresentable.\r
1287 * C99 says to use `signed char' for %hhn conversions.\r
1288 */\r
1289 if (flags & LLONGINT)\r
1290 *GETARG(long long *) = ret;\r
1291 else if (flags & SIZET)\r
1292 *GETARG(ssize_t *) = (ssize_t)ret;\r
1293 else if (flags & PTRDIFFT)\r
1294 *GETARG(ptrdiff_t *) = ret;\r
1295 else if (flags & INTMAXT)\r
1296 *GETARG(intmax_t *) = ret;\r
1297 else if (flags & LONGINT)\r
1298 *GETARG(long *) = ret;\r
1299 else if (flags & SHORTINT)\r
1300 *GETARG(short *) = ret;\r
1301 else if (flags & CHARINT)\r
1302 *GETARG(signed char *) = ret;\r
1303 else\r
1304 *GETARG(int *) = ret;\r
1305 continue; /* no output */\r
1306 case 'O':\r
1307 flags |= LONGINT;\r
1308 /*FALLTHROUGH*/\r
1309 case 'o':\r
1310 if (flags & INTMAX_SIZE)\r
1311 ujval = UJARG();\r
1312 else\r
1313 ulval = UARG();\r
1314 base = 8;\r
1315 goto nosign;\r
1316 case 'p':\r
1317 /*-\r
1318 * ``The argument shall be a pointer to void. The\r
1319 * value of the pointer is converted to a sequence\r
1320 * of printable characters, in an implementation-\r
1321 * defined manner.''\r
1322 * -- ANSI X3J11\r
1323 */\r
d7ce7006 1324 ujval = (uintmax_t) (UINTN) GETARG(void *);\r
2aa62f2b 1325 base = 16;\r
1326 xdigs = xdigs_lower;\r
1327 flags = flags | INTMAXT;\r
1328 ox[1] = 'x';\r
1329 goto nosign;\r
1330 case 'S':\r
1331 flags |= LONGINT;\r
1332 /*FALLTHROUGH*/\r
1333 case 's':\r
d7ce7006 1334 if (((flags & LONGINT) ? 1:0) != MULTI) {\r
2aa62f2b 1335 if ((result = GETARG(CHAR_T *)) == NULL)\r
1336 result = STRCONST("(null)");\r
1337 } else {\r
1338 MCHAR_T *mc;\r
1339\r
1340 if (convbuf != NULL)\r
1341 free(convbuf);\r
1342 if ((mc = GETARG(MCHAR_T *)) == NULL)\r
1343 result = STRCONST("(null)");\r
1344 else {\r
1345 convbuf = SCONV(mc, prec);\r
1346 if (convbuf == NULL) {\r
1347 fp->_flags |= __SERR;\r
1348 goto error;\r
1349 }\r
1350 result = convbuf;\r
1351 }\r
1352 }\r
1353\r
1354 if (prec >= 0) {\r
1355 /*\r
1356 * can't use STRLEN; can only look for the\r
1357 * NUL in the first `prec' characters, and\r
1358 * STRLEN() will go further.\r
1359 */\r
1360 CHAR_T *p = MEMCHR(result, 0, (size_t)prec);\r
1361\r
1362 if (p != NULL) {\r
1363 size = p - result;\r
1364 if (size > prec)\r
1365 size = prec;\r
1366 } else\r
1367 size = prec;\r
1368 } else\r
1369 size = (int)STRLEN(result);\r
1370 sign = '\0';\r
1371 break;\r
1372 case 'U':\r
1373 flags |= LONGINT;\r
1374 /*FALLTHROUGH*/\r
1375 case 'u':\r
1376 if (flags & INTMAX_SIZE)\r
1377 ujval = UJARG();\r
1378 else\r
1379 ulval = UARG();\r
1380 base = 10;\r
1381 goto nosign;\r
1382 case 'X':\r
1383 xdigs = xdigs_upper;\r
1384 goto hex;\r
1385 case 'x':\r
1386 xdigs = xdigs_lower;\r
1387hex:\r
1388 if (flags & INTMAX_SIZE)\r
1389 ujval = UJARG();\r
1390 else\r
1391 ulval = UARG();\r
1392 base = 16;\r
1393 /* leading 0x/X only if non-zero */\r
1394 if (flags & ALT &&\r
1395 (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))\r
1396 ox[1] = ch;\r
1397\r
1398 flags &= ~GROUPING;\r
1399 /* unsigned conversions */\r
1400nosign: sign = '\0';\r
1401 /*-\r
1402 * ``... diouXx conversions ... if a precision is\r
1403 * specified, the 0 flag will be ignored.''\r
1404 * -- ANSI X3J11\r
1405 */\r
1406number: if ((dprec = prec) >= 0)\r
1407 flags &= ~ZEROPAD;\r
1408\r
1409 /*-\r
1410 * ``The result of converting a zero value with an\r
1411 * explicit precision of zero is no characters.''\r
1412 * -- ANSI X3J11\r
1413 *\r
1414 * ``The C Standard is clear enough as is. The call\r
1415 * printf("%#.0o", 0) should print 0.''\r
1416 * -- Defect Report #151\r
1417 */\r
1418 result = cp = buf + BUF;\r
1419 if (flags & INTMAX_SIZE) {\r
1420 if (ujval != 0 || prec != 0 ||\r
1421 (flags & ALT && base == 8))\r
1422 {\r
1423 result = __ujtoa(ujval, cp, base,\r
1424 flags & ALT, xdigs,\r
1425 flags & GROUPING, thousands_sep,\r
1426 grouping);\r
1427 }\r
1428 } else {\r
1429 if (ulval != 0 || prec != 0 ||\r
1430 (flags & ALT && base == 8))\r
1431 result = __ultoa(ulval, cp, base,\r
1432 flags & ALT, xdigs,\r
1433 flags & GROUPING, thousands_sep,\r
1434 grouping);\r
1435 }\r
1436 size = buf + BUF - result;\r
1437 if (size > BUF) /* should never happen */\r
1438 abort();\r
1439 break;\r
1440 default: /* "%?" prints ?, unless ? is NUL */\r
1441 if (ch == '\0')\r
1442 goto done;\r
1443 /* pretend it was %c with argument ch */\r
1444 *buf = ch;\r
1445 result = buf;\r
1446 size = 1;\r
1447 sign = '\0';\r
1448 break;\r
1449 }\r
1450\r
1451 /*\r
1452 * All reasonable formats wind up here. At this point, `result'\r
1453 * points to a string which (if not flags&LADJUST) should be\r
1454 * padded out to `width' places. If flags&ZEROPAD, it should\r
1455 * first be prefixed by any sign or other prefix; otherwise,\r
1456 * it should be blank padded before the prefix is emitted.\r
1457 * After any left-hand padding and prefixing, emit zeroes\r
1458 * required by a decimal [diouxX] precision, then print the\r
1459 * string proper, then emit zeroes required by any leftover\r
1460 * floating precision; finally, if LADJUST, pad with blanks.\r
1461 *\r
1462 * Compute actual size, so we know how much to pad.\r
1463 * size excludes decimal prec; realsz includes it.\r
1464 */\r
1465 realsz = dprec > size ? dprec : size;\r
1466 if (sign)\r
1467 realsz++;\r
1468 if (ox[1])\r
1469 realsz += 2;\r
1470\r
1471 prsize = width > realsz ? width : realsz;\r
1472 if ((unsigned)ret + prsize > INT_MAX) {\r
1473 ret = END_OF_FILE;\r
1474 goto error;\r
1475 }\r
1476\r
1477 /* right-adjusting blank padding */\r
1478 if ((flags & (LADJUST|ZEROPAD)) == 0)\r
1479 PAD(width - realsz, blanks);\r
1480\r
1481 /* prefix */\r
1482 if (sign)\r
1483 PRINT(&sign, 1);\r
1484\r
1485 if (ox[1]) { /* ox[1] is either x, X, or \0 */\r
1486 ox[0] = '0';\r
1487 PRINT(ox, 2);\r
1488 }\r
1489\r
1490 /* right-adjusting zero padding */\r
1491 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)\r
1492 PAD(width - realsz, zeroes);\r
1493\r
1494 /* leading zeroes from decimal precision */\r
1495 PAD(dprec - size, zeroes);\r
1496\r
1497 /* the string or number proper */\r
1498#ifndef NO_FLOATING_POINT\r
1499 if ((flags & FPT) == 0) {\r
1500 PRINT(result, size);\r
1501 } else { /* glue together f_p fragments */\r
1502 if (!expchar) { /* %[fF] or sufficiently short %[gG] */\r
1503 if (expt <= 0) {\r
1504 PRINT(zeroes, 1);\r
1505 if (prec || flags & ALT)\r
1506 PRINT(decimal_point, 1);\r
1507 PAD(-expt, zeroes);\r
1508 /* already handled initial 0's */\r
1509 prec += expt;\r
1510 } else {\r
1511 PRINTANDPAD(result, convbuf + ndig,\r
1512 lead, zeroes);\r
1513 result += lead;\r
1514 if (grouping) {\r
1515 while (nseps>0 || nrepeats>0) {\r
1516 if (nrepeats > 0)\r
1517 nrepeats--;\r
1518 else {\r
1519 grouping--;\r
1520 nseps--;\r
1521 }\r
1522 PRINT(&thousands_sep,\r
1523 1);\r
1524 PRINTANDPAD(result,\r
1525 convbuf + ndig,\r
1526 *grouping, zeroes);\r
1527 result += *grouping;\r
1528 }\r
1529 if (result > convbuf + ndig)\r
1530 result = convbuf + ndig;\r
1531 }\r
1532 if (prec || flags & ALT) {\r
1533 buf[0] = *decimal_point;\r
1534 PRINT(buf, 1);\r
1535 }\r
1536 }\r
1537 PRINTANDPAD(result, convbuf + ndig, prec,\r
1538 zeroes);\r
1539 } else { /* %[eE] or sufficiently long %[gG] */\r
d7ce7006 1540 if (prec >= 1 || flags & ALT) {\r
2aa62f2b 1541 buf[0] = *result++;\r
1542 buf[1] = *decimal_point;\r
1543 PRINT(buf, 2);\r
1544 PRINT(result, ndig-1);\r
1545 PAD(prec - ndig, zeroes);\r
1546 } else /* XeYYY */\r
1547 PRINT(result, 1);\r
1548 PRINT(expstr, expsize);\r
1549 }\r
1550 }\r
1551#else\r
1552 PRINT(result, size);\r
1553#endif\r
1554 /* left-adjusting padding (always blank) */\r
1555 if (flags & LADJUST)\r
1556 PAD(width - realsz, blanks);\r
1557\r
1558 /* finally, adjust ret */\r
1559 ret += prsize;\r
1560 FLUSH();\r
1561 }\r
1562done:\r
1563 FLUSH();\r
1564error:\r
1565 va_end(orgap);\r
1566 if (convbuf != NULL)\r
1567 free(convbuf);\r
1568 if (__sferror(fp))\r
1569 ret = END_OF_FILE;\r
1570 if ((argtable != NULL) && (argtable != statargtable))\r
1571 free (argtable);\r
1572 return (ret);\r
1573 /* NOTREACHED */\r
1574oomem:\r
1575 errno = ENOMEM;\r
1576 ret = END_OF_FILE;\r
1577 goto error;\r
1578}\r
1579\r
1580/*\r
1581 * Find all arguments when a positional parameter is encountered. Returns a\r
1582 * table, indexed by argument number, of pointers to each arguments. The\r
1583 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.\r
1584 * It will be replaces with a malloc-ed one if it overflows.\r
1585 */\r
1586static int\r
1587__find_arguments(const CHAR_T *fmt0, va_list ap, union arg **argtable)\r
1588{\r
1589 CHAR_T *fmt; /* format string */\r
1590 int ch; /* character from fmt */\r
1591 int n, n2; /* handy integer (short term usage) */\r
1592 CHAR_T *cp; /* handy char pointer (short term usage) */\r
1593 int flags; /* flags as above */\r
1594 enum typeid *typetable; /* table of types */\r
1595 enum typeid stattypetable [STATIC_ARG_TBL_SIZE];\r
1596 int tablesize; /* current size of type table */\r
1597 int tablemax; /* largest used index in table */\r
1598 int nextarg; /* 1-based argument index */\r
1599\r
1600 /*\r
1601 * Add an argument type to the table, expanding if necessary.\r
1602 */\r
1603#define ADDTYPE(type) \\r
1604 do { \\r
1605 if (nextarg >= tablesize) \\r
1606 if (__grow_type_table(nextarg, &typetable, \\r
1607 &tablesize) == -1) \\r
1608 return -1; \\r
1609 if (nextarg > tablemax) \\r
1610 tablemax = nextarg; \\r
1611 typetable[nextarg++] = type; \\r
1612 } while (/*CONSTCOND*/0)\r
1613\r
1614#define ADDSARG() \\r
1615 do { \\r
1616 if (flags & INTMAXT) \\r
1617 ADDTYPE(T_INTMAXT); \\r
1618 else if (flags & SIZET) \\r
1619 ADDTYPE(T_SIZET); \\r
1620 else if (flags & PTRDIFFT) \\r
1621 ADDTYPE(T_PTRDIFFT); \\r
1622 else if (flags & LLONGINT) \\r
1623 ADDTYPE(T_LLONG); \\r
1624 else if (flags & LONGINT) \\r
1625 ADDTYPE(T_LONG); \\r
1626 else \\r
1627 ADDTYPE(T_INT); \\r
1628 } while (/*CONSTCOND*/0)\r
1629\r
1630#define ADDUARG() \\r
1631 do { \\r
1632 if (flags & INTMAXT) \\r
1633 ADDTYPE(T_UINTMAXT); \\r
1634 else if (flags & SIZET) \\r
1635 ADDTYPE(T_SIZET); \\r
1636 else if (flags & PTRDIFFT) \\r
1637 ADDTYPE(T_PTRDIFFT); \\r
1638 else if (flags & LLONGINT) \\r
1639 ADDTYPE(T_U_LLONG); \\r
1640 else if (flags & LONGINT) \\r
1641 ADDTYPE(T_U_LONG); \\r
1642 else \\r
1643 ADDTYPE(T_U_INT); \\r
1644 } while (/*CONSTCOND*/0)\r
1645 /*\r
1646 * Add * arguments to the type array.\r
1647 */\r
1648#define ADDASTER() \\r
1649 n2 = 0; \\r
1650 cp = fmt; \\r
1651 while (is_digit(*cp)) { \\r
1652 n2 = 10 * n2 + to_digit(*cp); \\r
1653 cp++; \\r
1654 } \\r
1655 if (*cp == '$') { \\r
1656 int hold = nextarg; \\r
1657 nextarg = n2; \\r
1658 ADDTYPE(T_INT); \\r
1659 nextarg = hold; \\r
1660 fmt = ++cp; \\r
1661 } else { \\r
1662 ADDTYPE(T_INT); \\r
1663 }\r
1664 fmt = (CHAR_T *)__UNCONST(fmt0);\r
1665 typetable = stattypetable;\r
1666 tablesize = STATIC_ARG_TBL_SIZE;\r
1667 tablemax = 0;\r
1668 nextarg = 1;\r
1669 for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)\r
1670 typetable[n] = T_UNUSED;\r
1671\r
1672 /*\r
1673 * Scan the format for conversions (`%' character).\r
1674 */\r
1675 for (;;) {\r
1676 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)\r
1677 /* void */;\r
1678 if (ch == '\0')\r
1679 goto done;\r
1680 fmt++; /* skip over '%' */\r
1681\r
1682 flags = 0;\r
1683\r
1684rflag: ch = *fmt++;\r
1685reswitch: switch (ch) {\r
1686 case ' ':\r
1687 case '#':\r
1688 goto rflag;\r
1689 case '*':\r
1690 ADDASTER ();\r
1691 goto rflag;\r
1692 case '-':\r
1693 case '+':\r
1694 case '\'':\r
1695 goto rflag;\r
1696 case '.':\r
1697 if ((ch = *fmt++) == '*') {\r
1698 ADDASTER ();\r
1699 goto rflag;\r
1700 }\r
1701 while (is_digit(ch)) {\r
1702 ch = *fmt++;\r
1703 }\r
1704 goto reswitch;\r
1705 case '0':\r
1706 goto rflag;\r
1707 case '1': case '2': case '3': case '4':\r
1708 case '5': case '6': case '7': case '8': case '9':\r
1709 n = 0;\r
1710 do {\r
1711 n = 10 * n + to_digit(ch);\r
1712 ch = *fmt++;\r
1713 } while (is_digit(ch));\r
1714 if (ch == '$') {\r
1715 nextarg = n;\r
1716 goto rflag;\r
1717 }\r
1718 goto reswitch;\r
1719#ifndef NO_FLOATING_POINT\r
1720 case 'L':\r
1721 flags |= LONGDBL;\r
1722 goto rflag;\r
1723#endif\r
1724 case 'h':\r
1725 if (flags & SHORTINT) {\r
1726 flags &= ~SHORTINT;\r
1727 flags |= CHARINT;\r
1728 } else\r
1729 flags |= SHORTINT;\r
1730 goto rflag;\r
1731 case 'j':\r
1732 flags |= INTMAXT;\r
1733 goto rflag;\r
1734 case 'l':\r
1735 if (flags & LONGINT) {\r
1736 flags &= ~LONGINT;\r
1737 flags |= LLONGINT;\r
1738 } else\r
1739 flags |= LONGINT;\r
1740 goto rflag;\r
1741 case 'q':\r
1742 flags |= LLONGINT; /* not necessarily */\r
1743 goto rflag;\r
1744 case 't':\r
1745 flags |= PTRDIFFT;\r
1746 goto rflag;\r
1747 case 'z':\r
1748 flags |= SIZET;\r
1749 goto rflag;\r
1750 case 'C':\r
1751 flags |= LONGINT;\r
1752 /*FALLTHROUGH*/\r
1753 case 'c':\r
1754 if (flags & LONGINT)\r
1755 ADDTYPE(T_WINT);\r
1756 else\r
1757 ADDTYPE(T_INT);\r
1758 break;\r
1759 case 'D':\r
1760 flags |= LONGINT;\r
1761 /*FALLTHROUGH*/\r
1762 case 'd':\r
1763 case 'i':\r
1764 ADDSARG();\r
1765 break;\r
1766#ifndef NO_FLOATING_POINT\r
1767 case 'a':\r
1768 case 'A':\r
1769 case 'e':\r
1770 case 'E':\r
1771 case 'f':\r
1772 case 'g':\r
1773 case 'G':\r
1774 if (flags & LONGDBL)\r
1775 ADDTYPE(T_LONG_DOUBLE);\r
1776 else\r
1777 ADDTYPE(T_DOUBLE);\r
1778 break;\r
1779#endif /* !NO_FLOATING_POINT */\r
1780 case 'n':\r
1781 if (flags & INTMAXT)\r
1782 ADDTYPE(TP_INTMAXT);\r
1783 else if (flags & PTRDIFFT)\r
1784 ADDTYPE(TP_PTRDIFFT);\r
1785 else if (flags & SIZET)\r
1786 ADDTYPE(TP_SIZET);\r
1787 else if (flags & LLONGINT)\r
1788 ADDTYPE(TP_LLONG);\r
1789 else if (flags & LONGINT)\r
1790 ADDTYPE(TP_LONG);\r
1791 else if (flags & SHORTINT)\r
1792 ADDTYPE(TP_SHORT);\r
1793 else if (flags & CHARINT)\r
1794 ADDTYPE(TP_SCHAR);\r
1795 else\r
1796 ADDTYPE(TP_INT);\r
1797 continue; /* no output */\r
1798 case 'O':\r
1799 flags |= LONGINT;\r
1800 /*FALLTHROUGH*/\r
1801 case 'o':\r
1802 ADDUARG();\r
1803 break;\r
1804 case 'p':\r
1805 ADDTYPE(TP_VOID);\r
1806 break;\r
1807 case 'S':\r
1808 flags |= LONGINT;\r
1809 /*FALLTHROUGH*/\r
1810 case 's':\r
1811 if (flags & LONGINT)\r
1812 ADDTYPE(TP_WCHAR);\r
1813 else\r
1814 ADDTYPE(TP_CHAR);\r
1815 break;\r
1816 case 'U':\r
1817 flags |= LONGINT;\r
1818 /*FALLTHROUGH*/\r
1819 case 'u':\r
1820 case 'X':\r
1821 case 'x':\r
1822 ADDUARG();\r
1823 break;\r
1824 default: /* "%?" prints ?, unless ? is NUL */\r
1825 if (ch == '\0')\r
1826 goto done;\r
1827 break;\r
1828 }\r
1829 }\r
1830done:\r
1831 /*\r
1832 * Build the argument table.\r
1833 */\r
1834 if (tablemax >= STATIC_ARG_TBL_SIZE) {\r
1835 *argtable = (union arg *)\r
1836 malloc (sizeof (union arg) * (tablemax + 1));\r
1837 if (*argtable == NULL)\r
1838 return -1;\r
1839 }\r
1840\r
1841 (*argtable) [0].intarg = 0;\r
1842 for (n = 1; n <= tablemax; n++) {\r
1843 switch (typetable [n]) {\r
1844 case T_UNUSED: /* whoops! */\r
1845 (*argtable) [n].intarg = va_arg (ap, int);\r
1846 break;\r
1847 case TP_SCHAR:\r
1848 (*argtable) [n].pschararg = va_arg (ap, signed char *);\r
1849 break;\r
1850 case TP_SHORT:\r
1851 (*argtable) [n].pshortarg = va_arg (ap, short *);\r
1852 break;\r
1853 case T_INT:\r
1854 (*argtable) [n].intarg = va_arg (ap, int);\r
1855 break;\r
1856 case T_U_INT:\r
1857 (*argtable) [n].uintarg = va_arg (ap, unsigned int);\r
1858 break;\r
1859 case TP_INT:\r
1860 (*argtable) [n].pintarg = va_arg (ap, int *);\r
1861 break;\r
1862 case T_LONG:\r
1863 (*argtable) [n].longarg = va_arg (ap, long);\r
1864 break;\r
1865 case T_U_LONG:\r
1866 (*argtable) [n].ulongarg = va_arg (ap, unsigned long);\r
1867 break;\r
1868 case TP_LONG:\r
1869 (*argtable) [n].plongarg = va_arg (ap, long *);\r
1870 break;\r
1871 case T_LLONG:\r
1872 (*argtable) [n].longlongarg = va_arg (ap, long long);\r
1873 break;\r
1874 case T_U_LLONG:\r
1875 (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);\r
1876 break;\r
1877 case TP_LLONG:\r
1878 (*argtable) [n].plonglongarg = va_arg (ap, long long *);\r
1879 break;\r
1880 case T_PTRDIFFT:\r
1881 (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);\r
1882 break;\r
1883 case TP_PTRDIFFT:\r
1884 (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);\r
1885 break;\r
1886 case T_SIZET:\r
1887 (*argtable) [n].sizearg = va_arg (ap, size_t);\r
1888 break;\r
1889 case TP_SIZET:\r
1890 (*argtable) [n].psizearg = va_arg (ap, size_t *);\r
1891 break;\r
1892 case T_INTMAXT:\r
1893 (*argtable) [n].intmaxarg = va_arg (ap, intmax_t);\r
1894 break;\r
1895 case T_UINTMAXT:\r
1896 (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);\r
1897 break;\r
1898 case TP_INTMAXT:\r
1899 (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);\r
1900 break;\r
1901 case T_DOUBLE:\r
1902#ifndef NO_FLOATING_POINT\r
1903 (*argtable) [n].doublearg = va_arg (ap, double);\r
1904#endif\r
1905 break;\r
1906 case T_LONG_DOUBLE:\r
1907#ifndef NO_FLOATING_POINT\r
1908 (*argtable) [n].longdoublearg = va_arg (ap, long double);\r
1909#endif\r
1910 break;\r
1911 case TP_CHAR:\r
1912 (*argtable) [n].pchararg = va_arg (ap, char *);\r
1913 break;\r
1914 case TP_VOID:\r
1915 (*argtable) [n].pvoidarg = va_arg (ap, void *);\r
1916 break;\r
1917 case T_WINT:\r
1918 (*argtable) [n].wintarg = va_arg (ap, wint_t);\r
1919 break;\r
1920 case TP_WCHAR:\r
1921 (*argtable) [n].pwchararg = va_arg (ap, wchar_t *);\r
1922 break;\r
1923 }\r
1924 }\r
1925\r
1926 if ((typetable != NULL) && (typetable != stattypetable))\r
1927 free (typetable);\r
1928 return 0;\r
1929}\r
1930\r
1931/*\r
1932 * Increase the size of the type table.\r
1933 */\r
1934static int\r
1935__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize)\r
1936{\r
1937 enum typeid *const oldtable = *typetable;\r
1938 const int oldsize = *tablesize;\r
1939 enum typeid *newtable;\r
1940 int n, newsize = oldsize * 2;\r
1941\r
1942 if (newsize < nextarg + 1)\r
1943 newsize = nextarg + 1;\r
1944 if (oldsize == STATIC_ARG_TBL_SIZE) {\r
1945 if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)\r
1946 return -1;\r
1947 memcpy(newtable, oldtable, oldsize * sizeof(enum typeid));\r
1948 } else {\r
1949 newtable = realloc(oldtable, newsize * sizeof(enum typeid));\r
1950 if (newtable == NULL) {\r
1951 free(oldtable);\r
1952 return -1;\r
1953 }\r
1954 }\r
1955 for (n = oldsize; n < newsize; n++)\r
1956 newtable[n] = T_UNUSED;\r
1957\r
1958 *typetable = newtable;\r
1959 *tablesize = newsize;\r
1960 return 0;\r
1961}\r
1962\r
1963\r
1964#ifndef NO_FLOATING_POINT\r
1965#ifndef WIDE_DOUBLE\r
1966static char *\r
1967cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch,\r
1968 int *length)\r
1969{\r
1970 int mode, dsgn;\r
1971 char *digits, *bp, *rve;\r
1972\r
1973 _DIAGASSERT(decpt != NULL);\r
1974 _DIAGASSERT(length != NULL);\r
1975 _DIAGASSERT(sign != NULL);\r
1976\r
1977 if (ch == 'f') {\r
1978 mode = 3; /* ndigits after the decimal point */\r
1979 } else {\r
1980 /* To obtain ndigits after the decimal point for the 'e'\r
1981 * and 'E' formats, round to ndigits + 1 significant\r
1982 * figures.\r
1983 */\r
1984 if (ch == 'e' || ch == 'E') {\r
1985 ndigits++;\r
1986 }\r
1987 mode = 2; /* ndigits significant digits */\r
1988 }\r
1989\r
1990 digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);\r
1991 if (digits == NULL)\r
1992 return NULL;\r
1993 if (dsgn) {\r
1994 value = -value;\r
1995 *sign = '-';\r
1996 } else\r
1997 *sign = '\000';\r
1998 if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */\r
1999 bp = digits + ndigits;\r
2000 if (ch == 'f') {\r
2001 if (*digits == '0' && value)\r
2002 *decpt = -ndigits + 1;\r
2003 bp += *decpt;\r
2004 }\r
2aa62f2b 2005 while (rve < bp)\r
2006 *rve++ = '0';\r
2007 }\r
2008 *length = rve - digits;\r
2009 return digits;\r
2010}\r
2011#endif\r
2012\r
2013static int\r
2014exponent(CHAR_T *p0, int expo, int fmtch)\r
2015{\r
2016 CHAR_T *p, *t;\r
2017 CHAR_T expbuf[MAXEXPDIG];\r
2018\r
2019 p = p0;\r
2020 *p++ = fmtch;\r
2021 if (expo < 0) {\r
2022 expo = -expo;\r
2023 *p++ = '-';\r
2024 }\r
2025 else\r
2026 *p++ = '+';\r
2027 t = expbuf + MAXEXPDIG;\r
2028 if (expo > 9) {\r
2029 do {\r
2030 *--t = to_char(expo % 10);\r
2031 } while ((expo /= 10) > 9);\r
2032 *--t = to_char(expo);\r
2033 for (; t < expbuf + MAXEXPDIG; *p++ = *t++);\r
2034 }\r
2035 else {\r
2036 /*\r
2037 * Exponents for decimal floating point conversions\r
2038 * (%[eEgG]) must be at least two characters long,\r
2039 * whereas exponents for hexadecimal conversions can\r
2040 * be only one character long.\r
2041 */\r
2042 if (fmtch == 'e' || fmtch == 'E')\r
2043 *p++ = '0';\r
2044 *p++ = to_char(expo);\r
2045 }\r
2046 return (p - p0);\r
2047}\r
2048#endif /* !NO_FLOATING_POINT */\r