]> git.saurik.com Git - apple/libc.git/blob - stdio/FreeBSD/vfprintf.c
Libc-1244.50.9.tar.gz
[apple/libc.git] / stdio / FreeBSD / vfprintf.c
1 /*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #define OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE 1
34
35 #if defined(LIBC_SCCS) && !defined(lint)
36 static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93";
37 #endif /* LIBC_SCCS and not lint */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.90 2009/02/28 06:06:57 das Exp $");
40
41 #include "xlocale_private.h"
42
43 /*
44 * Actual printf innards.
45 *
46 * This code is large and complicated...
47 */
48
49 #include "namespace.h"
50 #include <sys/types.h>
51
52 #include <ctype.h>
53 #include <limits.h>
54 #include <locale.h>
55 #include <stddef.h>
56 #include <stdint.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <wchar.h>
61 #if 0 // xprintf pending API review
62 #include <printf.h>
63 #endif
64 #include <errno.h>
65
66 #include <stdarg.h>
67 #include "un-namespace.h"
68
69 #include <os/assumes.h>
70 #include <mach-o/dyld_priv.h>
71 #include <mach/vm_region.h>
72
73 #include "libc_private.h"
74 #include "local.h"
75 #include "fvwrite.h"
76 #include "printflocal.h"
77
78 static int __sprint(FILE *, locale_t, struct __suio *);
79 #if 0
80 static int __sbprintf(FILE *, locale_t, const char *, va_list) __printflike(3, 0);
81 #endif
82 static char *__wcsconv(wchar_t *, int, locale_t);
83
84 __private_extern__ const char *__fix_nogrouping(const char *);
85
86 #define CHAR char
87 #include "printfcommon.h"
88
89 struct grouping_state {
90 char *thousands_sep; /* locale-specific thousands separator */
91 int thousep_len; /* length of thousands_sep */
92 const char *grouping; /* locale-specific numeric grouping rules */
93 int lead; /* sig figs before decimal or group sep */
94 int nseps; /* number of group separators with ' */
95 int nrepeats; /* number of repeats of the last group */
96 };
97
98 /*
99 * Initialize the thousands' grouping state in preparation to print a
100 * number with ndigits digits. This routine returns the total number
101 * of bytes that will be needed.
102 */
103 static int
104 grouping_init(struct grouping_state *gs, int ndigits, locale_t loc)
105 {
106 struct lconv *locale;
107
108 locale = localeconv_l(loc);
109 gs->grouping = __fix_nogrouping(locale->grouping);
110 gs->thousands_sep = locale->thousands_sep;
111 gs->thousep_len = strlen(gs->thousands_sep);
112
113 gs->nseps = gs->nrepeats = 0;
114 gs->lead = ndigits;
115 while (*gs->grouping != CHAR_MAX) {
116 if (gs->lead <= *gs->grouping)
117 break;
118 gs->lead -= *gs->grouping;
119 if (*(gs->grouping+1)) {
120 gs->nseps++;
121 gs->grouping++;
122 } else
123 gs->nrepeats++;
124 }
125 return ((gs->nseps + gs->nrepeats) * gs->thousep_len);
126 }
127
128 /*
129 * Print a number with thousands' separators.
130 */
131 static int
132 grouping_print(struct grouping_state *gs, struct io_state *iop,
133 const CHAR *cp, const CHAR *ep, locale_t loc)
134 {
135 const CHAR *cp0 = cp;
136
137 if (io_printandpad(iop, cp, ep, gs->lead, zeroes, loc))
138 return (-1);
139 cp += gs->lead;
140 while (gs->nseps > 0 || gs->nrepeats > 0) {
141 if (gs->nrepeats > 0)
142 gs->nrepeats--;
143 else {
144 gs->grouping--;
145 gs->nseps--;
146 }
147 if (io_print(iop, gs->thousands_sep, gs->thousep_len, loc))
148 return (-1);
149 if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, loc))
150 return (-1);
151 cp += *gs->grouping;
152 }
153 if (cp > ep)
154 cp = ep;
155 return (cp - cp0);
156 }
157
158 /*
159 * Flush out all the vectors defined by the given uio,
160 * then reset it so that it can be reused.
161 */
162 static int
163 __sprint(FILE *fp, locale_t loc __unused, struct __suio *uio)
164 {
165 int err;
166
167 if (uio->uio_resid == 0) {
168 uio->uio_iovcnt = 0;
169 return (0);
170 }
171 err = __sfvwrite(fp, uio);
172 uio->uio_resid = 0;
173 uio->uio_iovcnt = 0;
174 return (err);
175 }
176
177 #if 0
178 /*
179 * Helper function for `fprintf to unbuffered unix file': creates a
180 * temporary buffer. We only work on write-only files; this avoids
181 * worries about ungetc buffers and so forth.
182 */
183 static int
184 __sbprintf(FILE *fp, locale_t loc, const char *fmt, va_list ap)
185 {
186 int ret;
187 FILE fake;
188 unsigned char buf[BUFSIZ];
189 struct __sFILEX ext;
190 fake._extra = &ext;
191 INITEXTRA(&fake);
192
193 /* XXX This is probably not needed. */
194 if (prepwrite(fp) != 0)
195 return (EOF);
196
197 /* copy the important variables */
198 fake._flags = fp->_flags & ~__SNBF;
199 fake._file = fp->_file;
200 fake._cookie = fp->_cookie;
201 fake._write = fp->_write;
202 fake._orientation = fp->_orientation;
203 fake._mbstate = fp->_mbstate;
204
205 /* set up the buffer */
206 fake._bf._base = fake._p = buf;
207 fake._bf._size = fake._w = sizeof(buf);
208 fake._lbfsize = 0; /* not actually used, but Just In Case */
209
210 /* do the work, then copy any error status */
211 ret = __vfprintf(&fake, loc, fmt, ap);
212 if (ret >= 0 && __fflush(&fake))
213 ret = EOF;
214 if (fake._flags & __SERR)
215 fp->_flags |= __SERR;
216 return (ret);
217 }
218 #endif
219
220 /*
221 * Convert a wide character string argument for the %ls format to a multibyte
222 * string representation. If not -1, prec specifies the maximum number of
223 * bytes to output, and also means that we can't assume that the wide char.
224 * string ends is null-terminated.
225 */
226 static char *
227 __wcsconv(wchar_t *wcsarg, int prec, locale_t loc)
228 {
229 static const mbstate_t initial;
230 mbstate_t mbs;
231 char buf[MB_LEN_MAX];
232 wchar_t *p;
233 char *convbuf;
234 size_t clen, nbytes;
235
236 /* Allocate space for the maximum number of bytes we could output. */
237 if (prec < 0) {
238 p = wcsarg;
239 mbs = initial;
240 nbytes = wcsrtombs_l(NULL, (const wchar_t **)&p, 0, &mbs, loc);
241 if (nbytes == (size_t)-1)
242 return (NULL);
243 } else {
244 /*
245 * Optimisation: if the output precision is small enough,
246 * just allocate enough memory for the maximum instead of
247 * scanning the string.
248 */
249 if (prec < 128)
250 nbytes = prec;
251 else {
252 nbytes = 0;
253 p = wcsarg;
254 mbs = initial;
255 for (;;) {
256 clen = wcrtomb_l(buf, *p++, &mbs, loc);
257 if (clen == 0 || clen == (size_t)-1 ||
258 nbytes + clen > prec)
259 break;
260 nbytes += clen;
261 }
262 }
263 }
264 if ((convbuf = malloc(nbytes + 1)) == NULL)
265 return (NULL);
266
267 /* Fill the output buffer. */
268 p = wcsarg;
269 mbs = initial;
270 if ((nbytes = wcsrtombs_l(convbuf, (const wchar_t **)&p,
271 nbytes, &mbs, loc)) == (size_t)-1) {
272 free(convbuf);
273 return (NULL);
274 }
275 convbuf[nbytes] = '\0';
276 return (convbuf);
277 }
278
279 /*
280 * MT-safe version
281 */
282 int
283 vfprintf_l(FILE * __restrict fp, locale_t loc, const char * __restrict fmt0, va_list ap)
284
285 {
286 int ret;
287
288 FLOCKFILE(fp);
289 ret = __xvprintf(XPRINTF_PLAIN, NULL, fp, loc, fmt0, ap);
290 FUNLOCKFILE(fp);
291 return (ret);
292 }
293
294 int
295 vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
296
297 {
298 int ret;
299
300 FLOCKFILE(fp);
301 ret = __xvprintf(XPRINTF_PLAIN, NULL, fp, __current_locale(), fmt0, ap);
302 FUNLOCKFILE(fp);
303 return ret;
304 }
305
306 /*
307 * The size of the buffer we use as scratch space for integer
308 * conversions, among other things. We need enough space to
309 * write a uintmax_t in octal (plus one byte).
310 */
311 #if UINTMAX_MAX <= UINT64_MAX
312 #define BUF 32
313 #else
314 #error "BUF must be large enough to format a uintmax_t"
315 #endif
316
317 __private_extern__ bool
318 __printf_is_memory_read_only(void *addr, size_t __unused size)
319 {
320 vm_address_t address = addr;
321 vm_size_t vmsize = 0;
322 vm_region_basic_info_data_64_t info;
323 mach_msg_type_number_t info_cnt = VM_REGION_BASIC_INFO_COUNT_64;
324 memory_object_name_t object = MACH_PORT_NULL;
325 kern_return_t kr = KERN_SUCCESS;
326
327 kr = vm_region_64(mach_task_self(),
328 &address,
329 &vmsize,
330 VM_REGION_BASIC_INFO_64,
331 (vm_region_info_t) &info,
332 &info_cnt,
333 &object);
334 return (kr == KERN_SUCCESS) && !(info.protection & VM_PROT_WRITE);
335 }
336
337 /*
338 * Non-MT-safe version
339 */
340 __private_extern__ int
341 __vfprintf(FILE *fp, locale_t loc, const char *fmt0, va_list ap)
342 {
343 char *fmt; /* format string */
344 int ch; /* character from fmt */
345 ssize_t n, n2; /* handy integer (short term usage) */
346 char *cp; /* handy char pointer (short term usage) */
347 int flags; /* flags as above */
348 ssize_t ret; /* return value accumulator */
349 ssize_t width; /* width from format (%8d), or 0 */
350 ssize_t prec; /* precision from format; <0 for N/A */
351 char sign; /* sign prefix (' ', '+', '-', or \0) */
352 struct grouping_state gs; /* thousands' grouping info */
353
354 #ifndef ALLOW_DYNAMIC_PERCENT_N
355 bool static_format_checked = false;
356 #endif // ALLOW_DYNAMIC_PERCENT_N
357
358 #ifndef NO_FLOATING_POINT
359 /*
360 * We can decompose the printed representation of floating
361 * point numbers into several parts, some of which may be empty:
362 *
363 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
364 * A B ---C--- D E F
365 *
366 * A: 'sign' holds this value if present; '\0' otherwise
367 * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
368 * C: cp points to the string MMMNNN. Leading and trailing
369 * zeros are not in the string and must be added.
370 * D: expchar holds this character; '\0' if no exponent, e.g. %f
371 * F: at least two digits for decimal, at least one digit for hex
372 */
373 char *decimal_point; /* locale specific decimal point */
374 int decpt_len; /* length of decimal_point */
375 int signflag; /* true if float is negative */
376 union { /* floating point arguments %[aAeEfFgG] */
377 double dbl;
378 long double ldbl;
379 } fparg;
380 int expt; /* integer value of exponent */
381 char expchar; /* exponent character: [eEpP\0] */
382 char *dtoaend; /* pointer to end of converted digits */
383 int expsize; /* character count for expstr */
384 int ndig; /* actual number of digits returned by dtoa */
385 char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */
386 char *dtoaresult; /* buffer allocated by dtoa */
387 #endif
388 #ifdef VECTORS
389 union arg vval; /* Vector argument. */
390 char *pct; /* Pointer to '%' at beginning of specifier. */
391 char vsep; /* Vector separator character. */
392 #endif
393 u_long ulval; /* integer arguments %[diouxX] */
394 uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */
395 int base; /* base for [diouxX] conversion */
396 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
397 ssize_t realsz; /* field size expanded by dprec, sign, etc */
398 ssize_t size; /* size of converted field or string */
399 ssize_t prsize; /* max size of printed field */
400 const char *xdigs; /* digits for %[xX] conversion */
401 struct io_state io; /* I/O buffering state */
402 char buf[BUF]; /* buffer with space for digits of uintmax_t */
403 char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */
404 union arg *argtable; /* args, built due to positional arg */
405 union arg statargtable [STATIC_ARG_TBL_SIZE];
406 int nextarg; /* 1-based argument index */
407 va_list orgap; /* original argument pointer */
408 char *convbuf; /* wide to multibyte conversion result */
409
410 static const char xdigs_lower[16] = "0123456789abcdef";
411 static const char xdigs_upper[16] = "0123456789ABCDEF";
412
413 /* BEWARE, these `goto error' on error. */
414 #define PRINT(ptr, len) { \
415 if (io_print(&io, (ptr), (len), loc)) \
416 goto error; \
417 }
418 #define PAD(howmany, with) { \
419 if (io_pad(&io, (howmany), (with), loc)) \
420 goto error; \
421 }
422 #define PRINTANDPAD(p, ep, len, with) { \
423 if (io_printandpad(&io, (p), (ep), (len), (with), loc)) \
424 goto error; \
425 }
426 #define FLUSH() { \
427 if (io_flush(&io, loc)) \
428 goto error; \
429 }
430
431 /*
432 * Get the argument indexed by nextarg. If the argument table is
433 * built, use it to get the argument. If its not, get the next
434 * argument (and arguments must be gotten sequentially).
435 */
436 #define GETARG(type) \
437 ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
438 (nextarg++, va_arg(ap, type)))
439
440 /*
441 * To extend shorts properly, we need both signed and unsigned
442 * argument extraction methods.
443 */
444 #define SARG() \
445 (flags&LONGINT ? GETARG(long) : \
446 flags&SHORTINT ? (long)(short)GETARG(int) : \
447 flags&CHARINT ? (long)(signed char)GETARG(int) : \
448 (long)GETARG(int))
449 #define UARG() \
450 (flags&LONGINT ? GETARG(u_long) : \
451 flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
452 flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
453 (u_long)GETARG(u_int))
454 #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT)
455 #define SJARG() \
456 (flags&INTMAXT ? GETARG(intmax_t) : \
457 flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
458 flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
459 (intmax_t)GETARG(long long))
460 #define UJARG() \
461 (flags&INTMAXT ? GETARG(uintmax_t) : \
462 flags&SIZET ? (uintmax_t)GETARG(size_t) : \
463 flags&PTRDIFFT ? (uintmax_t)(unsigned long)GETARG(ptrdiff_t) : \
464 (uintmax_t)GETARG(unsigned long long))
465
466 /*
467 * Get * arguments, including the form *nn$. Preserve the nextarg
468 * that the argument can be gotten once the type is determined.
469 */
470 #define GETASTER(val) \
471 n2 = 0; \
472 cp = fmt; \
473 while (is_digit(*cp)) { \
474 n2 = 10 * n2 + to_digit(*cp); \
475 cp++; \
476 } \
477 if (*cp == '$') { \
478 int hold = nextarg; \
479 if (argtable == NULL) { \
480 argtable = statargtable; \
481 if (__find_arguments (fmt0, orgap, &argtable)) { \
482 ret = EOF; \
483 goto error; \
484 } \
485 } \
486 nextarg = n2; \
487 val = GETARG (int); \
488 nextarg = hold; \
489 fmt = ++cp; \
490 } else { \
491 val = GETARG (int); \
492 }
493
494 /* The following has been moved to __v2printf() */
495 #if 0
496 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
497 if (prepwrite(fp) != 0) {
498 errno = EBADF;
499 return (EOF);
500 }
501 ORIENT(fp, -1);
502 #endif
503
504 convbuf = NULL;
505 fmt = (char *)fmt0;
506 argtable = NULL;
507 nextarg = 1;
508 va_copy(orgap, ap);
509 io_init(&io, fp);
510 ret = 0;
511 #ifndef NO_FLOATING_POINT
512 dtoaresult = NULL;
513 decimal_point = localeconv_l(loc)->decimal_point;
514 /* The overwhelmingly common case is decpt_len == 1. */
515 decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point));
516 #endif
517
518 /*
519 * Scan the format for conversions (`%' character).
520 */
521 for (;;) {
522 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
523 /* void */;
524 if ((n = fmt - cp) != 0) {
525 if (ret + n >= INT_MAX) {
526 ret = EOF;
527 errno = EOVERFLOW;
528 goto error;
529 }
530 PRINT(cp, n);
531 ret += n;
532 }
533 if (ch == '\0')
534 goto done;
535 #ifdef VECTORS
536 pct = fmt;
537 #endif /* VECTORS */
538 fmt++; /* skip over '%' */
539
540 flags = 0;
541 dprec = 0;
542 width = 0;
543 prec = -1;
544 gs.grouping = NULL;
545 sign = '\0';
546 ox[1] = '\0';
547 #ifdef VECTORS
548 vsep = 'X'; /* Illegal value, changed to defaults later. */
549 #endif /* VECTORS */
550
551 rflag: ch = *fmt++;
552 reswitch: switch (ch) {
553 case ' ':
554 /*-
555 * ``If the space and + flags both appear, the space
556 * flag will be ignored.''
557 * -- ANSI X3J11
558 */
559 if (!sign)
560 sign = ' ';
561 goto rflag;
562 case '#':
563 flags |= ALT;
564 goto rflag;
565 #ifdef VECTORS
566 case ',': case ';': case ':': case '_':
567 vsep = ch;
568 goto rflag;
569 #endif /* VECTORS */
570 case '*':
571 /*-
572 * ``A negative field width argument is taken as a
573 * - flag followed by a positive field width.''
574 * -- ANSI X3J11
575 * They don't exclude field widths read from args.
576 */
577 GETASTER (width);
578 if (width >= 0)
579 goto rflag;
580 width = -width;
581 /* FALLTHROUGH */
582 case '-':
583 flags |= LADJUST;
584 goto rflag;
585 case '+':
586 sign = '+';
587 goto rflag;
588 case '\'':
589 flags |= GROUPING;
590 goto rflag;
591 case '.':
592 if ((ch = *fmt++) == '*') {
593 GETASTER (prec);
594 goto rflag;
595 }
596 prec = 0;
597 while (is_digit(ch)) {
598 prec = 10 * prec + to_digit(ch);
599 ch = *fmt++;
600 }
601 goto reswitch;
602 case '0':
603 /*-
604 * ``Note that 0 is taken as a flag, not as the
605 * beginning of a field width.''
606 * -- ANSI X3J11
607 */
608 flags |= ZEROPAD;
609 goto rflag;
610 case '1': case '2': case '3': case '4':
611 case '5': case '6': case '7': case '8': case '9':
612 n = 0;
613 do {
614 n = 10 * n + to_digit(ch);
615 ch = *fmt++;
616 } while (is_digit(ch));
617 if (ch == '$') {
618 nextarg = n;
619 if (argtable == NULL) {
620 argtable = statargtable;
621 if (__find_arguments (fmt0, orgap,
622 &argtable)) {
623 ret = EOF;
624 goto error;
625 }
626 }
627 goto rflag;
628 }
629 width = n;
630 goto reswitch;
631 #ifndef NO_FLOATING_POINT
632 case 'L':
633 flags |= LONGDBL;
634 goto rflag;
635 #endif
636 case 'h':
637 if (flags & SHORTINT) {
638 flags &= ~SHORTINT;
639 flags |= CHARINT;
640 } else
641 flags |= SHORTINT;
642 goto rflag;
643 case 'j':
644 flags |= INTMAXT;
645 goto rflag;
646 case 'l':
647 if (flags & LONGINT) {
648 flags &= ~LONGINT;
649 flags |= LLONGINT;
650 } else
651 flags |= LONGINT;
652 goto rflag;
653 case 'q':
654 flags |= LLONGINT; /* not necessarily */
655 goto rflag;
656 case 't':
657 flags |= PTRDIFFT;
658 goto rflag;
659 case 'z':
660 flags |= SIZET;
661 goto rflag;
662 case 'C':
663 flags |= LONGINT;
664 /*FALLTHROUGH*/
665 case 'c':
666 #ifdef VECTORS
667 if (flags & VECTOR)
668 break;
669 #endif /* VECTORS */
670 if (flags & LONGINT) {
671 static const mbstate_t initial;
672 mbstate_t mbs;
673 size_t mbseqlen;
674
675 mbs = initial;
676 mbseqlen = wcrtomb_l(cp = buf,
677 (wchar_t)GETARG(wint_t), &mbs, loc);
678 if (mbseqlen == (size_t)-1) {
679 fp->_flags |= __SERR;
680 goto error;
681 }
682 size = (int)mbseqlen;
683 } else {
684 *(cp = buf) = GETARG(int);
685 size = 1;
686 }
687 sign = '\0';
688 break;
689 case 'D':
690 flags |= LONGINT;
691 /*FALLTHROUGH*/
692 case 'd':
693 case 'i':
694 #ifdef VECTORS
695 if (flags & VECTOR)
696 break;
697 #endif /* VECTORS */
698 if (flags & INTMAX_SIZE) {
699 ujval = SJARG();
700 if ((intmax_t)ujval < 0) {
701 ujval = -ujval;
702 sign = '-';
703 }
704 } else {
705 ulval = SARG();
706 if ((long)ulval < 0) {
707 ulval = -ulval;
708 sign = '-';
709 }
710 }
711 base = 10;
712 goto number;
713 #ifndef NO_FLOATING_POINT
714 case 'a':
715 case 'A':
716 #ifdef VECTORS
717 if (flags & VECTOR) {
718 flags |= FPT;
719 break;
720 }
721 #endif /* VECTORS */
722 if (ch == 'a') {
723 ox[1] = 'x';
724 xdigs = xdigs_lower;
725 expchar = 'p';
726 } else {
727 ox[1] = 'X';
728 xdigs = xdigs_upper;
729 expchar = 'P';
730 }
731 if (prec >= 0)
732 prec++;
733 if (dtoaresult != NULL)
734 freedtoa(dtoaresult);
735 if (flags & LONGDBL) {
736 fparg.ldbl = GETARG(long double);
737 dtoaresult = cp =
738 __hldtoa(fparg.ldbl, xdigs, prec,
739 &expt, &signflag, &dtoaend);
740 } else {
741 fparg.dbl = GETARG(double);
742 dtoaresult = cp =
743 __hdtoa(fparg.dbl, xdigs, prec,
744 &expt, &signflag, &dtoaend);
745 }
746 if (prec < 0)
747 prec = dtoaend - cp;
748 if (expt == INT_MAX)
749 ox[1] = '\0';
750 goto fp_common;
751 case 'e':
752 case 'E':
753 #ifdef VECTORS
754 if (flags & VECTOR) {
755 flags |= FPT;
756 break;
757 }
758 #endif /* VECTORS */
759 expchar = ch;
760 if (prec < 0) /* account for digit before decpt */
761 prec = DEFPREC + 1;
762 else
763 prec++;
764 goto fp_begin;
765 case 'f':
766 case 'F':
767 #ifdef VECTORS
768 if (flags & VECTOR) {
769 flags |= FPT;
770 break;
771 }
772 #endif /* VECTORS */
773 expchar = '\0';
774 goto fp_begin;
775 case 'g':
776 case 'G':
777 #ifdef VECTORS
778 if (flags & VECTOR) {
779 flags |= FPT;
780 break;
781 }
782 #endif /* VECTORS */
783 expchar = ch - ('g' - 'e');
784 if (prec == 0)
785 prec = 1;
786 fp_begin:
787 if (prec < 0)
788 prec = DEFPREC;
789 if (dtoaresult != NULL)
790 freedtoa(dtoaresult);
791 if (flags & LONGDBL) {
792 fparg.ldbl = GETARG(long double);
793 dtoaresult = cp =
794 __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
795 &expt, &signflag, &dtoaend);
796 } else {
797 fparg.dbl = GETARG(double);
798 dtoaresult = cp =
799 dtoa(fparg.dbl, expchar ? 2 : 3, prec,
800 &expt, &signflag, &dtoaend);
801 if (expt == 9999)
802 expt = INT_MAX;
803 }
804 fp_common:
805 if (signflag)
806 sign = '-';
807 if (expt == INT_MAX) { /* inf or nan */
808 if (*cp == 'N') {
809 cp = (ch >= 'a') ? "nan" : "NAN";
810 sign = '\0';
811 } else
812 cp = (ch >= 'a') ? "inf" : "INF";
813 size = 3;
814 flags &= ~ZEROPAD;
815 break;
816 }
817 flags |= FPT;
818 ndig = dtoaend - cp;
819 if (ch == 'g' || ch == 'G') {
820 if (expt > -4 && expt <= prec) {
821 /* Make %[gG] smell like %[fF] */
822 expchar = '\0';
823 if (flags & ALT)
824 prec -= expt;
825 else
826 prec = ndig - expt;
827 if (prec < 0)
828 prec = 0;
829 } else {
830 /*
831 * Make %[gG] smell like %[eE], but
832 * trim trailing zeroes if no # flag.
833 */
834 if (!(flags & ALT))
835 prec = ndig;
836 }
837 }
838 if (expchar) {
839 expsize = exponent(expstr, expt - 1, expchar);
840 size = expsize + prec;
841 if (prec > 1 || flags & ALT)
842 size += decpt_len;
843 } else {
844 /* space for digits before decimal point */
845 if (expt > 0)
846 size = expt;
847 else /* "0" */
848 size = 1;
849 /* space for decimal pt and following digits */
850 if (prec || flags & ALT)
851 size += prec + decpt_len;
852 if ((flags & GROUPING) && expt > 0)
853 size += grouping_init(&gs, expt, loc);
854 }
855 break;
856 #endif /* !NO_FLOATING_POINT */
857 case 'n':
858 {
859 /*
860 * Assignment-like behavior is specified if the
861 * value overflows or is otherwise unrepresentable.
862 * C99 says to use `signed char' for %hhn conversions.
863 */
864 void *ptr = GETARG(void *);
865 if (ptr == NULL)
866 continue;
867
868 #ifndef ALLOW_DYNAMIC_PERCENT_N
869 if (!static_format_checked) {
870 static_format_checked = __printf_is_memory_read_only((void*)fmt0, strlen(fmt0));
871 }
872 if (!static_format_checked) {
873 os_crash("%%n used in a non-immutable format string: %s", fmt0);
874 }
875 #endif // ALLOW_DYNAMIC_PERCENT_N
876
877 if (flags & LLONGINT)
878 *(long long *)ptr = ret;
879 else if (flags & SIZET)
880 *(ssize_t *)ptr = (ssize_t)ret;
881 else if (flags & PTRDIFFT)
882 *(ptrdiff_t *)ptr = ret;
883 else if (flags & INTMAXT)
884 *(intmax_t *)ptr = ret;
885 else if (flags & LONGINT)
886 *(long *)ptr = ret;
887 else if (flags & SHORTINT)
888 *(short *)ptr = ret;
889 else if (flags & CHARINT)
890 *(signed char *)ptr = ret;
891 else
892 *(int *)ptr = ret;
893 continue; /* no output */
894 }
895 case 'O':
896 flags |= LONGINT;
897 /*FALLTHROUGH*/
898 case 'o':
899 #ifdef VECTORS
900 if (flags & VECTOR)
901 break;
902 #endif /* VECTORS */
903 if (flags & INTMAX_SIZE)
904 ujval = UJARG();
905 else
906 ulval = UARG();
907 base = 8;
908 goto nosign;
909 case 'p':
910 /*-
911 * ``The argument shall be a pointer to void. The
912 * value of the pointer is converted to a sequence
913 * of printable characters, in an implementation-
914 * defined manner.''
915 * -- ANSI X3J11
916 */
917 #ifdef VECTORS
918 if (flags & VECTOR)
919 break;
920 #endif /* VECTORS */
921 ujval = (uintmax_t)(uintptr_t)GETARG(void *);
922 base = 16;
923 xdigs = xdigs_lower;
924 flags = flags | INTMAXT;
925 ox[1] = 'x';
926 goto nosign;
927 case 'S':
928 flags |= LONGINT;
929 /*FALLTHROUGH*/
930 case 's':
931 if (flags & LONGINT) {
932 wchar_t *wcp;
933
934 free(convbuf);
935 if ((wcp = GETARG(wchar_t *)) == NULL) {
936 convbuf = NULL;
937 cp = "(null)";
938 } else {
939 convbuf = __wcsconv(wcp, prec, loc);
940 if (convbuf == NULL) {
941 fp->_flags |= __SERR;
942 goto error;
943 }
944 cp = convbuf;
945 }
946 } else if ((cp = GETARG(char *)) == NULL)
947 cp = "(null)";
948 {
949 size_t cp_len = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
950 if (cp_len < INT_MAX) {
951 size = cp_len;
952 } else {
953 ret = EOF;
954 goto error;
955 }
956 }
957 sign = '\0';
958 break;
959 case 'U':
960 flags |= LONGINT;
961 /*FALLTHROUGH*/
962 case 'u':
963 #ifdef VECTORS
964 if (flags & VECTOR)
965 break;
966 #endif /* VECTORS */
967 if (flags & INTMAX_SIZE)
968 ujval = UJARG();
969 else
970 ulval = UARG();
971 base = 10;
972 goto nosign;
973 case 'X':
974 xdigs = xdigs_upper;
975 goto hex;
976 case 'x':
977 xdigs = xdigs_lower;
978 hex:
979 #ifdef VECTORS
980 if (flags & VECTOR)
981 break;
982 #endif /* VECTORS */
983 if (flags & INTMAX_SIZE)
984 ujval = UJARG();
985 else
986 ulval = UARG();
987 base = 16;
988 /* leading 0x/X only if non-zero */
989 if (flags & ALT &&
990 (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
991 ox[1] = ch;
992
993 flags &= ~GROUPING;
994 /* unsigned conversions */
995 nosign: sign = '\0';
996 /*-
997 * ``... diouXx conversions ... if a precision is
998 * specified, the 0 flag will be ignored.''
999 * -- ANSI X3J11
1000 * except for %#.0o and zero value
1001 */
1002 number: if ((dprec = prec) >= 0)
1003 flags &= ~ZEROPAD;
1004
1005 /*-
1006 * ``The result of converting a zero value with an
1007 * explicit precision of zero is no characters.''
1008 * -- ANSI X3J11
1009 *
1010 * ``The C Standard is clear enough as is. The call
1011 * printf("%#.0o", 0) should print 0.''
1012 * -- Defect Report #151
1013 */
1014 cp = buf + BUF;
1015 if (flags & INTMAX_SIZE) {
1016 if (ujval != 0 || prec != 0 ||
1017 (flags & ALT && base == 8))
1018 cp = __ujtoa(ujval, cp, base,
1019 flags & ALT, xdigs);
1020 } else {
1021 if (ulval != 0 || prec != 0 ||
1022 (flags & ALT && base == 8))
1023 cp = __ultoa(ulval, cp, base,
1024 flags & ALT, xdigs);
1025 }
1026 size = buf + BUF - cp;
1027 if (size > BUF) /* should never happen */
1028 LIBC_ABORT("size (%zd) > BUF (%d)", size, BUF);
1029 if ((flags & GROUPING) && size != 0)
1030 size += grouping_init(&gs, size, loc);
1031 break;
1032 #ifdef VECTORS
1033 case 'v':
1034 flags |= VECTOR;
1035 goto rflag;
1036 #endif /* VECTORS */
1037 default: /* "%?" prints ?, unless ? is NUL */
1038 if (ch == '\0')
1039 goto done;
1040 /* pretend it was %c with argument ch */
1041 cp = buf;
1042 *cp = ch;
1043 size = 1;
1044 sign = '\0';
1045 break;
1046 }
1047
1048 #ifdef VECTORS
1049 if (flags & VECTOR) {
1050 /*
1051 * Do the minimum amount of work necessary to construct
1052 * a format specifier that can be used to recursively
1053 * call vfprintf() for each element in the vector.
1054 */
1055 int i, j; /* Counter. */
1056 int vcnt; /* Number of elements in vector. */
1057 char *vfmt; /* Pointer to format specifier. */
1058 #define EXTRAHH 2
1059 char vfmt_buf[32 + EXTRAHH]; /* Static buffer for format spec. */
1060 int vwidth = 0; /* Width specified via '*'. */
1061 int vprec = 0; /* Precision specified via '*'. */
1062 char *vstr; /* Used for asprintf(). */
1063 int vlen; /* Length returned by asprintf(). */
1064 enum {
1065 V_CHAR, V_SHORT, V_INT,
1066 V_PCHAR, V_PSHORT, V_PINT,
1067 V_FLOAT,
1068 #ifdef V64TYPE
1069 V_LONGLONG, V_PLONGLONG,
1070 V_DOUBLE,
1071 #endif /* V64TYPE */
1072 } vtype;
1073
1074 vval.vectorarg = GETARG(VECTORTYPE);
1075 /*
1076 * Set vfmt. If vfmt_buf may not be big enough,
1077 * malloc() space, taking care to free it later.
1078 * (EXTRAHH is for possible extra "hh")
1079 */
1080 if (&fmt[-1] - pct + EXTRAHH < sizeof(vfmt_buf))
1081 vfmt = vfmt_buf;
1082 else
1083 vfmt = (char *)malloc(&fmt[-1] - pct + EXTRAHH + 1);
1084
1085 /* Set the separator character, if not specified. */
1086 if (vsep == 'X') {
1087 if (ch == 'c')
1088 vsep = '\0';
1089 else
1090 vsep = ' ';
1091 }
1092
1093 /* Create the format specifier. */
1094 for (i = j = 0; i < &fmt[-1] - pct; i++) {
1095 switch (pct[i]) {
1096 case ',': case ';': case ':': case '_':
1097 case 'v': case 'h': case 'l':
1098 /* Ignore. */
1099 break;
1100 case '*':
1101 if (pct[i - 1] != '.')
1102 vwidth = 1;
1103 else
1104 vprec = 1;
1105 /* FALLTHROUGH */
1106 default:
1107 vfmt[j++] = pct[i];
1108 }
1109 }
1110
1111 /*
1112 * Determine the number of elements in the vector and
1113 * finish up the format specifier.
1114 */
1115 if (flags & SHORTINT) {
1116 switch (ch) {
1117 case 'c':
1118 vtype = V_SHORT;
1119 break;
1120 case 'p':
1121 vtype = V_PSHORT;
1122 break;
1123 default:
1124 vfmt[j++] = 'h';
1125 vtype = V_SHORT;
1126 break;
1127 }
1128 vcnt = 8;
1129 } else if (flags & LONGINT) {
1130 vcnt = 4;
1131 vtype = (ch == 'p') ? V_PINT : V_INT;
1132 #ifdef V64TYPE
1133 } else if (flags & LLONGINT) {
1134 switch (ch) {
1135 case 'a':
1136 case 'A':
1137 case 'e':
1138 case 'E':
1139 case 'f':
1140 case 'g':
1141 case 'G':
1142 vcnt = 2;
1143 vtype = V_DOUBLE;
1144 break;
1145 case 'd':
1146 case 'i':
1147 case 'u':
1148 case 'o':
1149 case 'p':
1150 case 'x':
1151 case 'X':
1152 vfmt[j++] = 'l';
1153 vfmt[j++] = 'l';
1154 vcnt = 2;
1155 vtype = (ch == 'p') ? V_PLONGLONG : V_LONGLONG;
1156 break;
1157 default:
1158 /*
1159 * The default case should never
1160 * happen.
1161 */
1162 case 'c':
1163 vcnt = 16;
1164 vtype = V_CHAR;
1165 }
1166 #endif /* V64TYPE */
1167 } else {
1168 switch (ch) {
1169 case 'a':
1170 case 'A':
1171 case 'e':
1172 case 'E':
1173 case 'f':
1174 case 'g':
1175 case 'G':
1176 vcnt = 4;
1177 vtype = V_FLOAT;
1178 break;
1179 default:
1180 /*
1181 * The default case should never
1182 * happen.
1183 */
1184 case 'd':
1185 case 'i':
1186 case 'u':
1187 case 'o':
1188 case 'x':
1189 case 'X':
1190 vfmt[j++] = 'h';
1191 vfmt[j++] = 'h';
1192 /* drop through */
1193 case 'p':
1194 case 'c':
1195 vcnt = 16;
1196 vtype = (ch == 'p') ? V_PCHAR : V_CHAR;
1197 }
1198 }
1199 vfmt[j++] = ch;
1200 vfmt[j++] = '\0';
1201
1202 /* Get a vector element. */
1203 #ifdef V64TYPE
1204 #define VPRINT(type, ind, args...) do { \
1205 switch (type) { \
1206 case V_CHAR: \
1207 vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vuchararg[ind]); \
1208 break; \
1209 case V_PCHAR: \
1210 vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vuchararg[ind]); \
1211 break; \
1212 case V_SHORT: \
1213 vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vushortarg[ind]); \
1214 break; \
1215 case V_PSHORT: \
1216 vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vushortarg[ind]); \
1217 break; \
1218 case V_INT: \
1219 vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vuintarg[ind]); \
1220 break; \
1221 case V_PINT: \
1222 vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vuintarg[ind]); \
1223 break; \
1224 case V_LONGLONG: \
1225 vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vulonglongarg[ind]); \
1226 break; \
1227 case V_PLONGLONG: \
1228 vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vulonglongarg[ind]); \
1229 break; \
1230 case V_FLOAT: \
1231 vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vfloatarg[ind]); \
1232 break; \
1233 case V_DOUBLE: \
1234 vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vdoublearg[ind]); \
1235 break; \
1236 } \
1237 ret += vlen; \
1238 PRINT(vstr, vlen); \
1239 FLUSH(); \
1240 free(vstr); \
1241 } while (0)
1242 #else /* !V64TYPE */
1243 #define VPRINT(type, ind, args...) do { \
1244 switch (type) { \
1245 case V_CHAR: \
1246 vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vuchararg[ind]); \
1247 break; \
1248 case V_PCHAR: \
1249 vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vuchararg[ind]); \
1250 break; \
1251 case V_SHORT: \
1252 vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vushortarg[ind]); \
1253 break; \
1254 case V_PSHORT: \
1255 vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vushortarg[ind]); \
1256 break; \
1257 case V_INT: \
1258 vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vuintarg[ind]); \
1259 break; \
1260 case V_PINT: \
1261 vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vuintarg[ind]); \
1262 break; \
1263 case V_FLOAT: \
1264 vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vfloatarg[ind]); \
1265 break; \
1266 } \
1267 ret += vlen; \
1268 PRINT(vstr, vlen); \
1269 FLUSH(); \
1270 free(vstr); \
1271 } while (0)
1272 #endif /* V64TYPE */
1273
1274 /* Actually print. */
1275 if (vwidth == 0) {
1276 if (vprec == 0) {
1277 /* First element. */
1278 VPRINT(vtype, 0);
1279 for (i = 1; i < vcnt; i++) {
1280 /* Separator. */
1281 if(vsep)
1282 PRINT(&vsep, 1);
1283
1284 /* Element. */
1285 VPRINT(vtype, i);
1286 }
1287 } else {
1288 /* First element. */
1289 VPRINT(vtype, 0, prec);
1290 for (i = 1; i < vcnt; i++) {
1291 /* Separator. */
1292 if(vsep)
1293 PRINT(&vsep, 1);
1294
1295 /* Element. */
1296 VPRINT(vtype, i, prec);
1297 }
1298 }
1299 } else {
1300 if (vprec == 0) {
1301 /* First element. */
1302 VPRINT(vtype, 0, width);
1303 for (i = 1; i < vcnt; i++) {
1304 /* Separator. */
1305 if(vsep)
1306 PRINT(&vsep, 1);
1307
1308 /* Element. */
1309 VPRINT(vtype, i, width);
1310 }
1311 } else {
1312 /* First element. */
1313 VPRINT(vtype, 0, width, prec);
1314 for (i = 1; i < vcnt; i++) {
1315 /* Separator. */
1316 if(vsep)
1317 PRINT(&vsep, 1);
1318
1319 /* Element. */
1320 VPRINT(vtype, i, width, prec);
1321 }
1322 }
1323 }
1324 #undef VPRINT
1325
1326 if (vfmt != vfmt_buf)
1327 free(vfmt);
1328
1329 continue;
1330 }
1331 #endif /* VECTORS */
1332 /*
1333 * All reasonable formats wind up here. At this point, `cp'
1334 * points to a string which (if not flags&LADJUST) should be
1335 * padded out to `width' places. If flags&ZEROPAD, it should
1336 * first be prefixed by any sign or other prefix; otherwise,
1337 * it should be blank padded before the prefix is emitted.
1338 * After any left-hand padding and prefixing, emit zeroes
1339 * required by a decimal [diouxX] precision, then print the
1340 * string proper, then emit zeroes required by any leftover
1341 * floating precision; finally, if LADJUST, pad with blanks.
1342 *
1343 * Compute actual size, so we know how much to pad.
1344 * size excludes decimal prec; realsz includes it.
1345 */
1346 realsz = dprec > size ? dprec : size;
1347 if (sign)
1348 realsz++;
1349 if (ox[1])
1350 realsz += 2;
1351
1352 prsize = width > realsz ? width : realsz;
1353 if (ret + prsize >= INT_MAX) {
1354 ret = EOF;
1355 errno = EOVERFLOW;
1356 goto error;
1357 }
1358
1359 /* right-adjusting blank padding */
1360 if ((flags & (LADJUST|ZEROPAD)) == 0)
1361 PAD(width - realsz, blanks);
1362
1363 /* prefix */
1364 if (sign)
1365 PRINT(&sign, 1);
1366
1367 if (ox[1]) { /* ox[1] is either x, X, or \0 */
1368 ox[0] = '0';
1369 PRINT(ox, 2);
1370 }
1371
1372 /* right-adjusting zero padding */
1373 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
1374 PAD(width - realsz, zeroes);
1375
1376 /* the string or number proper */
1377 #ifndef NO_FLOATING_POINT
1378 if ((flags & FPT) == 0) {
1379 #endif
1380 /* leading zeroes from decimal precision */
1381 PAD(dprec - size, zeroes);
1382 if (gs.grouping) {
1383 if (grouping_print(&gs, &io, cp, buf+BUF, loc) < 0)
1384 goto error;
1385 } else {
1386 PRINT(cp, size);
1387 }
1388 #ifndef NO_FLOATING_POINT
1389 } else { /* glue together f_p fragments */
1390 if (!expchar) { /* %[fF] or sufficiently short %[gG] */
1391 if (expt <= 0) {
1392 PRINT(zeroes, 1);
1393 if (prec || flags & ALT)
1394 PRINT(decimal_point,decpt_len);
1395 PAD(-expt, zeroes);
1396 /* already handled initial 0's */
1397 prec += expt;
1398 } else {
1399 if (gs.grouping) {
1400 n = grouping_print(&gs, &io,
1401 cp, dtoaend, loc);
1402 if (n < 0)
1403 goto error;
1404 cp += n;
1405 } else {
1406 PRINTANDPAD(cp, dtoaend,
1407 expt, zeroes);
1408 cp += expt;
1409 }
1410 if (prec || flags & ALT)
1411 PRINT(decimal_point,decpt_len);
1412 }
1413 PRINTANDPAD(cp, dtoaend, prec, zeroes);
1414 } else { /* %[eE] or sufficiently long %[gG] */
1415 if (prec > 1 || flags & ALT) {
1416 PRINT(cp++, 1);
1417 PRINT(decimal_point, decpt_len);
1418 PRINT(cp, ndig-1);
1419 PAD(prec - ndig, zeroes);
1420 } else /* XeYYY */
1421 PRINT(cp, 1);
1422 PRINT(expstr, expsize);
1423 }
1424 }
1425 #endif
1426 /* left-adjusting padding (always blank) */
1427 if (flags & LADJUST)
1428 PAD(width - realsz, blanks);
1429
1430 /* finally, adjust ret */
1431 ret += prsize;
1432
1433 FLUSH(); /* copy out the I/O vectors */
1434 }
1435 done:
1436 FLUSH();
1437 error:
1438 va_end(orgap);
1439 #ifndef NO_FLOATING_POINT
1440 if (dtoaresult != NULL)
1441 freedtoa(dtoaresult);
1442 #endif
1443 free(convbuf);
1444 if (__sferror(fp))
1445 ret = EOF;
1446 if ((argtable != NULL) && (argtable != statargtable))
1447 free (argtable);
1448 return (ret < 0 || ret >= INT_MAX) ? -1 : (int)ret;
1449 /* NOTREACHED */
1450 }
1451