X-Git-Url: https://git.saurik.com/apple/libc.git/blobdiff_plain/1f2f436a38f7ae2d39a943ad2898d8fed4ed2e58..refs/heads/master:/stdio/FreeBSD/vfprintf.c?ds=sidebyside diff --git a/stdio/FreeBSD/vfprintf.c b/stdio/FreeBSD/vfprintf.c index df992ce..cf51045 100644 --- a/stdio/FreeBSD/vfprintf.c +++ b/stdio/FreeBSD/vfprintf.c @@ -30,12 +30,22 @@ * SUCH DAMAGE. */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wint-conversion" + +#include +#if !TARGET_OS_DRIVERKIT +#define OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE 1 +#endif + #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #include __FBSDID("$FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.90 2009/02/28 06:06:57 das Exp $"); +#include "xlocale_private.h" + /* * Actual printf innards. * @@ -54,20 +64,30 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.90 2009/02/28 06:06:57 das #include #include #include +#if 0 // xprintf pending API review #include +#endif +#include #include #include "un-namespace.h" +#include +#include +#include + #include "libc_private.h" #include "local.h" #include "fvwrite.h" #include "printflocal.h" -static int __sprint(FILE *, struct __suio *); -static int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0) - __noinline; -static char *__wcsconv(wchar_t *, int); +static int __sprint(FILE *, locale_t, struct __suio *); +#if 0 +static int __sbprintf(FILE *, locale_t, const char *, va_list) __printflike(3, 0); +#endif +static char *__wcsconv(wchar_t *, int, locale_t); + +__private_extern__ const char *__fix_nogrouping(const char *); #define CHAR char #include "printfcommon.h" @@ -87,12 +107,12 @@ struct grouping_state { * of bytes that will be needed. */ static int -grouping_init(struct grouping_state *gs, int ndigits) +grouping_init(struct grouping_state *gs, int ndigits, locale_t loc) { struct lconv *locale; - locale = localeconv(); - gs->grouping = locale->grouping; + locale = localeconv_l(loc); + gs->grouping = __fix_nogrouping(locale->grouping); gs->thousands_sep = locale->thousands_sep; gs->thousep_len = strlen(gs->thousands_sep); @@ -116,11 +136,11 @@ grouping_init(struct grouping_state *gs, int ndigits) */ static int grouping_print(struct grouping_state *gs, struct io_state *iop, - const CHAR *cp, const CHAR *ep) + const CHAR *cp, const CHAR *ep, locale_t loc) { const CHAR *cp0 = cp; - if (io_printandpad(iop, cp, ep, gs->lead, zeroes)) + if (io_printandpad(iop, cp, ep, gs->lead, zeroes, loc)) return (-1); cp += gs->lead; while (gs->nseps > 0 || gs->nrepeats > 0) { @@ -130,9 +150,9 @@ grouping_print(struct grouping_state *gs, struct io_state *iop, gs->grouping--; gs->nseps--; } - if (io_print(iop, gs->thousands_sep, gs->thousep_len)) + if (io_print(iop, gs->thousands_sep, gs->thousep_len, loc)) return (-1); - if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes)) + if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, loc)) return (-1); cp += *gs->grouping; } @@ -146,7 +166,7 @@ grouping_print(struct grouping_state *gs, struct io_state *iop, * then reset it so that it can be reused. */ static int -__sprint(FILE *fp, struct __suio *uio) +__sprint(FILE *fp, locale_t loc __unused, struct __suio *uio) { int err; @@ -160,17 +180,21 @@ __sprint(FILE *fp, struct __suio *uio) return (err); } +#if 0 /* * Helper function for `fprintf to unbuffered unix file': creates a * temporary buffer. We only work on write-only files; this avoids * worries about ungetc buffers and so forth. */ static int -__sbprintf(FILE *fp, const char *fmt, va_list ap) +__sbprintf(FILE *fp, locale_t loc, const char *fmt, va_list ap) { int ret; FILE fake; unsigned char buf[BUFSIZ]; + struct __sFILEX ext; + fake._extra = &ext; + INITEXTRA(&fake); /* XXX This is probably not needed. */ if (prepwrite(fp) != 0) @@ -190,13 +214,14 @@ __sbprintf(FILE *fp, const char *fmt, va_list ap) fake._lbfsize = 0; /* not actually used, but Just In Case */ /* do the work, then copy any error status */ - ret = __vfprintf(&fake, fmt, ap); + ret = __vfprintf(&fake, loc, fmt, ap); if (ret >= 0 && __fflush(&fake)) ret = EOF; if (fake._flags & __SERR) fp->_flags |= __SERR; return (ret); } +#endif /* * Convert a wide character string argument for the %ls format to a multibyte @@ -205,7 +230,7 @@ __sbprintf(FILE *fp, const char *fmt, va_list ap) * string ends is null-terminated. */ static char * -__wcsconv(wchar_t *wcsarg, int prec) +__wcsconv(wchar_t *wcsarg, int prec, locale_t loc) { static const mbstate_t initial; mbstate_t mbs; @@ -218,7 +243,7 @@ __wcsconv(wchar_t *wcsarg, int prec) if (prec < 0) { p = wcsarg; mbs = initial; - nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); + nbytes = wcsrtombs_l(NULL, (const wchar_t **)&p, 0, &mbs, loc); if (nbytes == (size_t)-1) return (NULL); } else { @@ -234,7 +259,7 @@ __wcsconv(wchar_t *wcsarg, int prec) p = wcsarg; mbs = initial; for (;;) { - clen = wcrtomb(buf, *p++, &mbs); + clen = wcrtomb_l(buf, *p++, &mbs, loc); if (clen == 0 || clen == (size_t)-1 || nbytes + clen > prec) break; @@ -248,8 +273,8 @@ __wcsconv(wchar_t *wcsarg, int prec) /* Fill the output buffer. */ p = wcsarg; mbs = initial; - if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, - nbytes, &mbs)) == (size_t)-1) { + if ((nbytes = wcsrtombs_l(convbuf, (const wchar_t **)&p, + nbytes, &mbs, loc)) == (size_t)-1) { free(convbuf); return (NULL); } @@ -261,22 +286,29 @@ __wcsconv(wchar_t *wcsarg, int prec) * MT-safe version */ int -vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) +vfprintf_l(FILE * __restrict fp, locale_t loc, const char * __restrict fmt0, va_list ap) { int ret; FLOCKFILE(fp); - /* optimise fprintf(stderr) (and other unbuffered Unix files) */ - if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && - fp->_file >= 0) - ret = __sbprintf(fp, fmt0, ap); - else - ret = __vfprintf(fp, fmt0, ap); + ret = __xvprintf(XPRINTF_PLAIN, NULL, fp, loc, fmt0, ap); FUNLOCKFILE(fp); return (ret); } +int +vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) + +{ + int ret; + + FLOCKFILE(fp); + ret = __xvprintf(XPRINTF_PLAIN, NULL, fp, __current_locale(), fmt0, ap); + FUNLOCKFILE(fp); + return ret; +} + /* * The size of the buffer we use as scratch space for integer * conversions, among other things. We need enough space to @@ -288,23 +320,47 @@ vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) #error "BUF must be large enough to format a uintmax_t" #endif +__private_extern__ bool +__printf_is_memory_read_only(void *addr, size_t __unused size) +{ + vm_address_t address = addr; + vm_size_t vmsize = 0; + vm_region_basic_info_data_64_t info; + mach_msg_type_number_t info_cnt = VM_REGION_BASIC_INFO_COUNT_64; + memory_object_name_t object = MACH_PORT_NULL; + kern_return_t kr = KERN_SUCCESS; + + kr = vm_region_64(mach_task_self(), + &address, + &vmsize, + VM_REGION_BASIC_INFO_64, + (vm_region_info_t) &info, + &info_cnt, + &object); + return (kr == KERN_SUCCESS) && !(info.protection & VM_PROT_WRITE); +} + /* * Non-MT-safe version */ -int -__vfprintf(FILE *fp, const char *fmt0, va_list ap) +__private_extern__ int +__vfprintf(FILE *fp, locale_t loc, const char *fmt0, va_list ap) { char *fmt; /* format string */ int ch; /* character from fmt */ - int n, n2; /* handy integer (short term usage) */ + ssize_t n, n2; /* handy integer (short term usage) */ char *cp; /* handy char pointer (short term usage) */ int flags; /* flags as above */ - int ret; /* return value accumulator */ - int width; /* width from format (%8d), or 0 */ - int prec; /* precision from format; <0 for N/A */ + ssize_t ret; /* return value accumulator */ + ssize_t width; /* width from format (%8d), or 0 */ + ssize_t prec; /* precision from format; <0 for N/A */ char sign; /* sign prefix (' ', '+', '-', or \0) */ struct grouping_state gs; /* thousands' grouping info */ +#ifndef ALLOW_DYNAMIC_PERCENT_N + bool static_format_checked = false; +#endif // ALLOW_DYNAMIC_PERCENT_N + #ifndef NO_FLOATING_POINT /* * We can decompose the printed representation of floating @@ -334,14 +390,19 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) int ndig; /* actual number of digits returned by dtoa */ char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ char *dtoaresult; /* buffer allocated by dtoa */ +#endif +#ifdef VECTORS + union arg vval; /* Vector argument. */ + char *pct; /* Pointer to '%' at beginning of specifier. */ + char vsep; /* Vector separator character. */ #endif u_long ulval; /* integer arguments %[diouxX] */ uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ int base; /* base for [diouxX] conversion */ int dprec; /* a copy of prec if [diouxX], 0 otherwise */ - int realsz; /* field size expanded by dprec, sign, etc */ - int size; /* size of converted field or string */ - int prsize; /* max size of printed field */ + ssize_t realsz; /* field size expanded by dprec, sign, etc */ + ssize_t size; /* size of converted field or string */ + ssize_t prsize; /* max size of printed field */ const char *xdigs; /* digits for %[xX] conversion */ struct io_state io; /* I/O buffering state */ char buf[BUF]; /* buffer with space for digits of uintmax_t */ @@ -357,19 +418,19 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) /* BEWARE, these `goto error' on error. */ #define PRINT(ptr, len) { \ - if (io_print(&io, (ptr), (len))) \ + if (io_print(&io, (ptr), (len), loc)) \ goto error; \ } #define PAD(howmany, with) { \ - if (io_pad(&io, (howmany), (with))) \ + if (io_pad(&io, (howmany), (with), loc)) \ goto error; \ } #define PRINTANDPAD(p, ep, len, with) { \ - if (io_printandpad(&io, (p), (ep), (len), (with))) \ + if (io_printandpad(&io, (p), (ep), (len), (with), loc)) \ goto error; \ } #define FLUSH() { \ - if (io_flush(&io)) \ + if (io_flush(&io, loc)) \ goto error; \ } @@ -405,7 +466,7 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) #define UJARG() \ (flags&INTMAXT ? GETARG(uintmax_t) : \ flags&SIZET ? (uintmax_t)GETARG(size_t) : \ - flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ + flags&PTRDIFFT ? (uintmax_t)(unsigned long)GETARG(ptrdiff_t) : \ (uintmax_t)GETARG(unsigned long long)) /* @@ -436,14 +497,15 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) val = GETARG (int); \ } - if (__use_xprintf == 0 && getenv("USE_XPRINTF")) - __use_xprintf = 1; - if (__use_xprintf > 0) - return (__xvprintf(fp, fmt0, ap)); - + /* The following has been moved to __v2printf() */ +#if 0 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ - if (prepwrite(fp) != 0) + if (prepwrite(fp) != 0) { + errno = EBADF; return (EOF); + } + ORIENT(fp, -1); +#endif convbuf = NULL; fmt = (char *)fmt0; @@ -454,7 +516,7 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) ret = 0; #ifndef NO_FLOATING_POINT dtoaresult = NULL; - decimal_point = localeconv()->decimal_point; + decimal_point = localeconv_l(loc)->decimal_point; /* The overwhelmingly common case is decpt_len == 1. */ decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point)); #endif @@ -466,8 +528,9 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) /* void */; if ((n = fmt - cp) != 0) { - if ((unsigned)ret + n > INT_MAX) { + if (ret + n >= INT_MAX) { ret = EOF; + errno = EOVERFLOW; goto error; } PRINT(cp, n); @@ -475,6 +538,9 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) } if (ch == '\0') goto done; +#ifdef VECTORS + pct = fmt; +#endif /* VECTORS */ fmt++; /* skip over '%' */ flags = 0; @@ -484,6 +550,9 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) gs.grouping = NULL; sign = '\0'; ox[1] = '\0'; +#ifdef VECTORS + vsep = 'X'; /* Illegal value, changed to defaults later. */ +#endif /* VECTORS */ rflag: ch = *fmt++; reswitch: switch (ch) { @@ -499,6 +568,11 @@ reswitch: switch (ch) { case '#': flags |= ALT; goto rflag; +#ifdef VECTORS + case ',': case ';': case ':': case '_': + vsep = ch; + goto rflag; +#endif /* VECTORS */ case '*': /*- * ``A negative field width argument is taken as a @@ -595,14 +669,18 @@ reswitch: switch (ch) { flags |= LONGINT; /*FALLTHROUGH*/ case 'c': +#ifdef VECTORS + if (flags & VECTOR) + break; +#endif /* VECTORS */ if (flags & LONGINT) { static const mbstate_t initial; mbstate_t mbs; size_t mbseqlen; mbs = initial; - mbseqlen = wcrtomb(cp = buf, - (wchar_t)GETARG(wint_t), &mbs); + mbseqlen = wcrtomb_l(cp = buf, + (wchar_t)GETARG(wint_t), &mbs, loc); if (mbseqlen == (size_t)-1) { fp->_flags |= __SERR; goto error; @@ -619,6 +697,10 @@ reswitch: switch (ch) { /*FALLTHROUGH*/ case 'd': case 'i': +#ifdef VECTORS + if (flags & VECTOR) + break; +#endif /* VECTORS */ if (flags & INTMAX_SIZE) { ujval = SJARG(); if ((intmax_t)ujval < 0) { @@ -637,6 +719,12 @@ reswitch: switch (ch) { #ifndef NO_FLOATING_POINT case 'a': case 'A': +#ifdef VECTORS + if (flags & VECTOR) { + flags |= FPT; + break; + } +#endif /* VECTORS */ if (ch == 'a') { ox[1] = 'x'; xdigs = xdigs_lower; @@ -668,6 +756,12 @@ reswitch: switch (ch) { goto fp_common; case 'e': case 'E': +#ifdef VECTORS + if (flags & VECTOR) { + flags |= FPT; + break; + } +#endif /* VECTORS */ expchar = ch; if (prec < 0) /* account for digit before decpt */ prec = DEFPREC + 1; @@ -676,10 +770,22 @@ reswitch: switch (ch) { goto fp_begin; case 'f': case 'F': +#ifdef VECTORS + if (flags & VECTOR) { + flags |= FPT; + break; + } +#endif /* VECTORS */ expchar = '\0'; goto fp_begin; case 'g': case 'G': +#ifdef VECTORS + if (flags & VECTOR) { + flags |= FPT; + break; + } +#endif /* VECTORS */ expchar = ch - ('g' - 'e'); if (prec == 0) prec = 1; @@ -750,37 +856,60 @@ fp_common: if (prec || flags & ALT) size += prec + decpt_len; if ((flags & GROUPING) && expt > 0) - size += grouping_init(&gs, expt); + size += grouping_init(&gs, expt, loc); } break; #endif /* !NO_FLOATING_POINT */ case 'n': + { /* * Assignment-like behavior is specified if the * value overflows or is otherwise unrepresentable. * C99 says to use `signed char' for %hhn conversions. */ + void *ptr = GETARG(void *); + if (ptr == NULL) + continue; + +#ifndef ALLOW_DYNAMIC_PERCENT_N + if (!static_format_checked) { + static_format_checked = __printf_is_memory_read_only((void*)fmt0, strlen(fmt0)); + } + if (!static_format_checked) { +#if OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE + os_crash("%%n used in a non-immutable format string: %s", fmt0); +#else + os_crash("%%n used in a non-immutable format string"); +#endif + } +#endif // ALLOW_DYNAMIC_PERCENT_N + if (flags & LLONGINT) - *GETARG(long long *) = ret; + *(long long *)ptr = ret; else if (flags & SIZET) - *GETARG(ssize_t *) = (ssize_t)ret; + *(ssize_t *)ptr = (ssize_t)ret; else if (flags & PTRDIFFT) - *GETARG(ptrdiff_t *) = ret; + *(ptrdiff_t *)ptr = ret; else if (flags & INTMAXT) - *GETARG(intmax_t *) = ret; + *(intmax_t *)ptr = ret; else if (flags & LONGINT) - *GETARG(long *) = ret; + *(long *)ptr = ret; else if (flags & SHORTINT) - *GETARG(short *) = ret; + *(short *)ptr = ret; else if (flags & CHARINT) - *GETARG(signed char *) = ret; + *(signed char *)ptr = ret; else - *GETARG(int *) = ret; + *(int *)ptr = ret; continue; /* no output */ + } case 'O': flags |= LONGINT; /*FALLTHROUGH*/ case 'o': +#ifdef VECTORS + if (flags & VECTOR) + break; +#endif /* VECTORS */ if (flags & INTMAX_SIZE) ujval = UJARG(); else @@ -795,6 +924,10 @@ fp_common: * defined manner.'' * -- ANSI X3J11 */ +#ifdef VECTORS + if (flags & VECTOR) + break; +#endif /* VECTORS */ ujval = (uintmax_t)(uintptr_t)GETARG(void *); base = 16; xdigs = xdigs_lower; @@ -808,12 +941,12 @@ fp_common: if (flags & LONGINT) { wchar_t *wcp; - if (convbuf != NULL) - free(convbuf); - if ((wcp = GETARG(wchar_t *)) == NULL) + free(convbuf); + if ((wcp = GETARG(wchar_t *)) == NULL) { + convbuf = NULL; cp = "(null)"; - else { - convbuf = __wcsconv(wcp, prec); + } else { + convbuf = __wcsconv(wcp, prec, loc); if (convbuf == NULL) { fp->_flags |= __SERR; goto error; @@ -822,13 +955,25 @@ fp_common: } } else if ((cp = GETARG(char *)) == NULL) cp = "(null)"; - size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp); + { + size_t cp_len = (prec >= 0) ? strnlen(cp, prec) : strlen(cp); + if (cp_len < INT_MAX) { + size = cp_len; + } else { + ret = EOF; + goto error; + } + } sign = '\0'; break; case 'U': flags |= LONGINT; /*FALLTHROUGH*/ case 'u': +#ifdef VECTORS + if (flags & VECTOR) + break; +#endif /* VECTORS */ if (flags & INTMAX_SIZE) ujval = UJARG(); else @@ -841,6 +986,10 @@ fp_common: case 'x': xdigs = xdigs_lower; hex: +#ifdef VECTORS + if (flags & VECTOR) + break; +#endif /* VECTORS */ if (flags & INTMAX_SIZE) ujval = UJARG(); else @@ -858,6 +1007,7 @@ nosign: sign = '\0'; * ``... diouXx conversions ... if a precision is * specified, the 0 flag will be ignored.'' * -- ANSI X3J11 + * except for %#.0o and zero value */ number: if ((dprec = prec) >= 0) flags &= ~ZEROPAD; @@ -885,10 +1035,15 @@ number: if ((dprec = prec) >= 0) } size = buf + BUF - cp; if (size > BUF) /* should never happen */ - abort(); + LIBC_ABORT("size (%zd) > BUF (%d)", size, BUF); if ((flags & GROUPING) && size != 0) - size += grouping_init(&gs, size); + size += grouping_init(&gs, size, loc); break; +#ifdef VECTORS + case 'v': + flags |= VECTOR; + goto rflag; +#endif /* VECTORS */ default: /* "%?" prints ?, unless ? is NUL */ if (ch == '\0') goto done; @@ -900,6 +1055,290 @@ number: if ((dprec = prec) >= 0) break; } +#ifdef VECTORS + if (flags & VECTOR) { + /* + * Do the minimum amount of work necessary to construct + * a format specifier that can be used to recursively + * call vfprintf() for each element in the vector. + */ + int i, j; /* Counter. */ + int vcnt; /* Number of elements in vector. */ + char *vfmt; /* Pointer to format specifier. */ +#define EXTRAHH 2 + char vfmt_buf[32 + EXTRAHH]; /* Static buffer for format spec. */ + int vwidth = 0; /* Width specified via '*'. */ + int vprec = 0; /* Precision specified via '*'. */ + char *vstr; /* Used for asprintf(). */ + int vlen; /* Length returned by asprintf(). */ + enum { + V_CHAR, V_SHORT, V_INT, + V_PCHAR, V_PSHORT, V_PINT, + V_FLOAT, +#ifdef V64TYPE + V_LONGLONG, V_PLONGLONG, + V_DOUBLE, +#endif /* V64TYPE */ + } vtype; + + vval.vectorarg = GETARG(VECTORTYPE); + /* + * Set vfmt. If vfmt_buf may not be big enough, + * malloc() space, taking care to free it later. + * (EXTRAHH is for possible extra "hh") + */ + if (&fmt[-1] - pct + EXTRAHH < sizeof(vfmt_buf)) + vfmt = vfmt_buf; + else + vfmt = (char *)malloc(&fmt[-1] - pct + EXTRAHH + 1); + + /* Set the separator character, if not specified. */ + if (vsep == 'X') { + if (ch == 'c') + vsep = '\0'; + else + vsep = ' '; + } + + /* Create the format specifier. */ + for (i = j = 0; i < &fmt[-1] - pct; i++) { + switch (pct[i]) { + case ',': case ';': case ':': case '_': + case 'v': case 'h': case 'l': + /* Ignore. */ + break; + case '*': + if (pct[i - 1] != '.') + vwidth = 1; + else + vprec = 1; + /* FALLTHROUGH */ + default: + vfmt[j++] = pct[i]; + } + } + + /* + * Determine the number of elements in the vector and + * finish up the format specifier. + */ + if (flags & SHORTINT) { + switch (ch) { + case 'c': + vtype = V_SHORT; + break; + case 'p': + vtype = V_PSHORT; + break; + default: + vfmt[j++] = 'h'; + vtype = V_SHORT; + break; + } + vcnt = 8; + } else if (flags & LONGINT) { + vcnt = 4; + vtype = (ch == 'p') ? V_PINT : V_INT; +#ifdef V64TYPE + } else if (flags & LLONGINT) { + switch (ch) { + case 'a': + case 'A': + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + vcnt = 2; + vtype = V_DOUBLE; + break; + case 'd': + case 'i': + case 'u': + case 'o': + case 'p': + case 'x': + case 'X': + vfmt[j++] = 'l'; + vfmt[j++] = 'l'; + vcnt = 2; + vtype = (ch == 'p') ? V_PLONGLONG : V_LONGLONG; + break; + default: + /* + * The default case should never + * happen. + */ + case 'c': + vcnt = 16; + vtype = V_CHAR; + } +#endif /* V64TYPE */ + } else { + switch (ch) { + case 'a': + case 'A': + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + vcnt = 4; + vtype = V_FLOAT; + break; + default: + /* + * The default case should never + * happen. + */ + case 'd': + case 'i': + case 'u': + case 'o': + case 'x': + case 'X': + vfmt[j++] = 'h'; + vfmt[j++] = 'h'; + /* drop through */ + case 'p': + case 'c': + vcnt = 16; + vtype = (ch == 'p') ? V_PCHAR : V_CHAR; + } + } + vfmt[j++] = ch; + vfmt[j++] = '\0'; + +/* Get a vector element. */ +#ifdef V64TYPE +#define VPRINT(type, ind, args...) do { \ + switch (type) { \ + case V_CHAR: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vuchararg[ind]); \ + break; \ + case V_PCHAR: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vuchararg[ind]); \ + break; \ + case V_SHORT: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vushortarg[ind]); \ + break; \ + case V_PSHORT: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vushortarg[ind]); \ + break; \ + case V_INT: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vuintarg[ind]); \ + break; \ + case V_PINT: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vuintarg[ind]); \ + break; \ + case V_LONGLONG: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vulonglongarg[ind]); \ + break; \ + case V_PLONGLONG: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vulonglongarg[ind]); \ + break; \ + case V_FLOAT: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vfloatarg[ind]); \ + break; \ + case V_DOUBLE: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vdoublearg[ind]); \ + break; \ + } \ + ret += vlen; \ + PRINT(vstr, vlen); \ + FLUSH(); \ + free(vstr); \ +} while (0) +#else /* !V64TYPE */ +#define VPRINT(type, ind, args...) do { \ + switch (type) { \ + case V_CHAR: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vuchararg[ind]); \ + break; \ + case V_PCHAR: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vuchararg[ind]); \ + break; \ + case V_SHORT: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vushortarg[ind]); \ + break; \ + case V_PSHORT: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vushortarg[ind]); \ + break; \ + case V_INT: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vuintarg[ind]); \ + break; \ + case V_PINT: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vuintarg[ind]); \ + break; \ + case V_FLOAT: \ + vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vfloatarg[ind]); \ + break; \ + } \ + ret += vlen; \ + PRINT(vstr, vlen); \ + FLUSH(); \ + free(vstr); \ +} while (0) +#endif /* V64TYPE */ + + /* Actually print. */ + if (vwidth == 0) { + if (vprec == 0) { + /* First element. */ + VPRINT(vtype, 0); + for (i = 1; i < vcnt; i++) { + /* Separator. */ + if(vsep) + PRINT(&vsep, 1); + + /* Element. */ + VPRINT(vtype, i); + } + } else { + /* First element. */ + VPRINT(vtype, 0, prec); + for (i = 1; i < vcnt; i++) { + /* Separator. */ + if(vsep) + PRINT(&vsep, 1); + + /* Element. */ + VPRINT(vtype, i, prec); + } + } + } else { + if (vprec == 0) { + /* First element. */ + VPRINT(vtype, 0, width); + for (i = 1; i < vcnt; i++) { + /* Separator. */ + if(vsep) + PRINT(&vsep, 1); + + /* Element. */ + VPRINT(vtype, i, width); + } + } else { + /* First element. */ + VPRINT(vtype, 0, width, prec); + for (i = 1; i < vcnt; i++) { + /* Separator. */ + if(vsep) + PRINT(&vsep, 1); + + /* Element. */ + VPRINT(vtype, i, width, prec); + } + } + } +#undef VPRINT + + if (vfmt != vfmt_buf) + free(vfmt); + + continue; + } +#endif /* VECTORS */ /* * All reasonable formats wind up here. At this point, `cp' * points to a string which (if not flags&LADJUST) should be @@ -921,8 +1360,9 @@ number: if ((dprec = prec) >= 0) realsz += 2; prsize = width > realsz ? width : realsz; - if ((unsigned)ret + prsize > INT_MAX) { + if (ret + prsize >= INT_MAX) { ret = EOF; + errno = EOVERFLOW; goto error; } @@ -950,7 +1390,7 @@ number: if ((dprec = prec) >= 0) /* leading zeroes from decimal precision */ PAD(dprec - size, zeroes); if (gs.grouping) { - if (grouping_print(&gs, &io, cp, buf+BUF) < 0) + if (grouping_print(&gs, &io, cp, buf+BUF, loc) < 0) goto error; } else { PRINT(cp, size); @@ -968,7 +1408,7 @@ number: if ((dprec = prec) >= 0) } else { if (gs.grouping) { n = grouping_print(&gs, &io, - cp, dtoaend); + cp, dtoaend, loc); if (n < 0) goto error; cp += n; @@ -1010,13 +1450,12 @@ error: if (dtoaresult != NULL) freedtoa(dtoaresult); #endif - if (convbuf != NULL) - free(convbuf); + free(convbuf); if (__sferror(fp)) ret = EOF; if ((argtable != NULL) && (argtable != statargtable)) free (argtable); - return (ret); + return (ret < 0 || ret >= INT_MAX) ? -1 : (int)ret; /* NOTREACHED */ } - +#pragma clang diagnostic pop