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