X-Git-Url: https://git.saurik.com/apple/libc.git/blobdiff_plain/3d9156a7a519a5e3aa1b92e9d9d4b991f1aed7ff..HEAD:/stdio/FreeBSD/vfscanf.c diff --git a/stdio/FreeBSD/vfscanf.c b/stdio/FreeBSD/vfscanf.c index 61087e8..eca2766 100644 --- a/stdio/FreeBSD/vfscanf.c +++ b/stdio/FreeBSD/vfscanf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,11 +30,16 @@ * SUCH DAMAGE. */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcomma" + #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #include -__FBSDID("$FreeBSD: src/lib/libc/stdio/vfscanf.c,v 1.37 2004/05/02 10:55:05 das Exp $"); +__FBSDID("$FreeBSD: src/lib/libc/stdio/vfscanf.c,v 1.43 2009/01/19 06:19:51 das Exp $"); + +#include "xlocale_private.h" #include "namespace.h" #include @@ -50,6 +51,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/vfscanf.c,v 1.37 2004/05/02 10:55:05 das #include #include #include +#include #include "un-namespace.h" #include "collate.h" @@ -97,10 +99,10 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/vfscanf.c,v 1.37 2004/05/02 10:55:05 das #define CT_INT 3 /* %[dioupxX] conversion */ #define CT_FLOAT 4 /* %[efgEFG] conversion */ -static const u_char *__sccl(char *, const u_char *); -static int parsefloat(FILE *, char *, char *); - -int __scanfdebug = 0; +static const u_char *__sccl(char *, const u_char *, locale_t); +#ifndef NO_FLOATING_POINT +static int parsefloat(FILE *, char **, size_t, locale_t); +#endif __weak_reference(__vfscanf, vfscanf); @@ -108,12 +110,24 @@ __weak_reference(__vfscanf, vfscanf); * __vfscanf - MT-safe version */ int -__vfscanf(FILE *fp, char const *fmt0, va_list ap) +__vfscanf(FILE * __restrict fp, char const * __restrict fmt0, va_list ap) { int ret; FLOCKFILE(fp); - ret = __svfscanf(fp, fmt0, ap); + ret = __svfscanf_l(fp, __current_locale(), fmt0, ap); + FUNLOCKFILE(fp); + return (ret); +} + +int +vfscanf_l(FILE * __restrict fp, locale_t loc, char const * __restrict fmt0, va_list ap) +{ + int ret; + + NORMALIZE_LOCALE(loc); + FLOCKFILE(fp); + ret = __svfscanf_l(fp, loc, fmt0, ap); FUNLOCKFILE(fp); return (ret); } @@ -121,8 +135,8 @@ __vfscanf(FILE *fp, char const *fmt0, va_list ap) /* * __svfscanf - non-MT-safe version of __vfscanf */ -int -__svfscanf(FILE *fp, const char *fmt0, va_list ap) +__private_extern__ int +__svfscanf_l(FILE * __restrict fp, locale_t loc, const char * __restrict fmt0, va_list ap) { const u_char *fmt = (const u_char *)fmt0; int c; /* character from format, or conversion */ @@ -132,37 +146,43 @@ __svfscanf(FILE *fp, const char *fmt0, va_list ap) int flags; /* flags as defined above */ char *p0; /* saves original value of p when necessary */ int nassigned; /* number of fields assigned */ - int nconversions; /* number of conversions */ int nread; /* number of characters consumed from fp */ int base; /* base argument to conversion function */ char ccltab[256]; /* character class table for %[...] */ char buf[BUF]; /* buffer for numeric and mb conversions */ wchar_t *wcp; /* handy wide character pointer */ - wchar_t *wcp0; /* saves original value of wcp */ size_t nconv; /* length of multibyte sequence converted */ + int index; /* %index$, zero if unset */ + va_list ap_orig; /* to reset ap to first argument */ static const mbstate_t initial; mbstate_t mbs; + int mb_cur_max; /* `basefix' is used to avoid `if' tests in the integer scanner */ - static short basefix[17] = + static const short basefix[17] = { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + NORMALIZE_LOCALE(loc); + mb_cur_max = MB_CUR_MAX_L(loc); ORIENT(fp, -1); nassigned = 0; - nconversions = 0; nread = 0; + va_copy(ap_orig, ap); for (;;) { c = *fmt++; if (c == 0) return (nassigned); - if (isspace(c)) { - while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p)) + if (isspace_l(c, loc)) { + while ((fp->_r > 0 || __srefill(fp) == 0) && isspace_l(*fp->_p, loc)) nread++, fp->_r--, fp->_p++; continue; } - if (c != '%') + if (c != '%') { + if (fp->_r <= 0 && __srefill(fp)) + goto input_failure; goto literal; + } width = 0; flags = 0; /* @@ -172,15 +192,35 @@ __svfscanf(FILE *fp, const char *fmt0, va_list ap) again: c = *fmt++; switch (c) { case '%': + /* Consume leading white space */ + for(;;) { + if (fp->_r <= 0 && __srefill(fp)) + goto input_failure; + if (!isspace_l(*fp->_p, loc)) + break; + nread++; + fp->_r--; + fp->_p++; + } literal: - if (fp->_r <= 0 && __srefill(fp)) - goto input_failure; if (*fp->_p != c) goto match_failure; fp->_r--, fp->_p++; nread++; continue; + case '$': + index = width; + if (index < 1 || index > NL_ARGMAX || fmt[-3] != '%') { + goto input_failure; + } + width = 0; + va_end(ap); + va_copy(ap, ap_orig); /* reset to %1$ */ + for (; index > 1; index--) { + va_arg(ap, void*); + } + goto again; case '*': flags |= SUPPRESS; goto again; @@ -267,7 +307,7 @@ literal: break; case '[': - fmt = __sccl(ccltab, fmt); + fmt = __sccl(ccltab, fmt, loc); flags |= NOSKIP; c = CT_CCL; break; @@ -288,27 +328,30 @@ literal: break; case 'n': - nconversions++; + { if (flags & SUPPRESS) /* ??? */ continue; - if (flags & SHORTSHORT) - *va_arg(ap, char *) = nread; + void *ptr = va_arg(ap, void *); + if (ptr == NULL) + continue; + else if (flags & SHORTSHORT) + *(char *)ptr = nread; else if (flags & SHORT) - *va_arg(ap, short *) = nread; + *(short *)ptr = nread; else if (flags & LONG) - *va_arg(ap, long *) = nread; + *(long *)ptr = nread; else if (flags & LONGLONG) - *va_arg(ap, long long *) = nread; + *(long long *)ptr = nread; else if (flags & INTMAXT) - *va_arg(ap, intmax_t *) = nread; + *(intmax_t *)ptr = nread; else if (flags & SIZET) - *va_arg(ap, size_t *) = nread; + *(size_t *)ptr = nread; else if (flags & PTRDIFFT) - *va_arg(ap, ptrdiff_t *) = nread; + *(ptrdiff_t *)ptr = nread; else - *va_arg(ap, int *) = nread; + *(int *)ptr = nread; continue; - + } default: goto match_failure; @@ -330,7 +373,7 @@ literal: * that suppress this. */ if ((flags & NOSKIP) == 0) { - while (isspace(*fp->_p)) { + while (isspace_l(*fp->_p, loc)) { nread++; if (--fp->_r > 0) fp->_p++; @@ -360,7 +403,7 @@ literal: wcp = NULL; n = 0; while (width != 0) { - if (n == MB_CUR_MAX) { + if (n == mb_cur_max) { fp->_flags |= __SERR; goto input_failure; } @@ -368,7 +411,7 @@ literal: fp->_p++; fp->_r--; mbs = initial; - nconv = mbrtowc(wcp, buf, n, &mbs); + nconv = mbrtowc_l(wcp, buf, n, &mbs, loc); if (nconv == (size_t)-1) { fp->_flags |= __SERR; goto input_failure; @@ -413,7 +456,7 @@ literal: } nread += sum; } else { - size_t r = fread((void *)va_arg(ap, char *), 1, + size_t r = __fread((void *)va_arg(ap, char *), 1, width, fp); if (r == 0) @@ -421,7 +464,6 @@ literal: nread += r; nassigned++; } - nconversions++; break; case CT_CCL: @@ -434,13 +476,13 @@ literal: int nchars; if ((flags & SUPPRESS) == 0) - wcp = wcp0 = va_arg(ap, wchar_t *); + wcp = va_arg(ap, wchar_t *); else - wcp = wcp0 = &twc; + wcp = &twc; n = 0; nchars = 0; while (width != 0) { - if (n == MB_CUR_MAX) { + if (n == mb_cur_max) { fp->_flags |= __SERR; goto input_failure; } @@ -448,7 +490,7 @@ literal: fp->_p++; fp->_r--; mbs = initial; - nconv = mbrtowc(wcp, buf, n, &mbs); + nconv = mbrtowc_l(wcp, buf, n, &mbs, loc); if (nconv == (size_t)-1) { fp->_flags |= __SERR; goto input_failure; @@ -456,8 +498,8 @@ literal: if (nconv == 0) *wcp = L'\0'; if (nconv != (size_t)-2) { - if (wctob(*wcp) != EOF && - !ccltab[wctob(*wcp)]) { + if (wctob_l(*wcp, loc) != EOF && + !ccltab[wctob_l(*wcp, loc)]) { while (n != 0) { n--; __ungetc(buf[n], @@ -525,7 +567,6 @@ literal: nassigned++; } nread += n; - nconversions++; break; case CT_STRING: @@ -540,8 +581,8 @@ literal: else wcp = &twc; n = 0; - while (!isspace(*fp->_p) && width != 0) { - if (n == MB_CUR_MAX) { + while (width != 0) { + if (n == mb_cur_max) { fp->_flags |= __SERR; goto input_failure; } @@ -549,7 +590,7 @@ literal: fp->_p++; fp->_r--; mbs = initial; - nconv = mbrtowc(wcp, buf, n, &mbs); + nconv = mbrtowc_l(wcp, buf, n, &mbs, loc); if (nconv == (size_t)-1) { fp->_flags |= __SERR; goto input_failure; @@ -557,7 +598,7 @@ literal: if (nconv == 0) *wcp = L'\0'; if (nconv != (size_t)-2) { - if (iswspace(*wcp)) { + if (iswspace_l(*wcp, loc)) { while (n != 0) { n--; __ungetc(buf[n], @@ -585,7 +626,7 @@ literal: } } else if (flags & SUPPRESS) { n = 0; - while (!isspace(*fp->_p)) { + while (!isspace_l(*fp->_p, loc)) { n++, fp->_r--, fp->_p++; if (--width == 0) break; @@ -595,7 +636,7 @@ literal: nread += n; } else { p0 = p = va_arg(ap, char *); - while (!isspace(*fp->_p)) { + while (!isspace_l(*fp->_p, loc)) { fp->_r--; *p++ = *fp->_p++; if (--width == 0) @@ -607,7 +648,6 @@ literal: nread += p - p0; nassigned++; } - nconversions++; continue; case CT_INT: @@ -738,9 +778,9 @@ literal: *p = 0; if ((flags & UNSIGNED) == 0) - res = strtoimax(buf, (char **)NULL, base); + res = strtoimax_l(buf, (char **)NULL, base, loc); else - res = strtoumax(buf, (char **)NULL, base); + res = strtoumax_l(buf, (char **)NULL, base, loc); if (flags & POINTER) *va_arg(ap, void **) = (void *)(uintptr_t)res; @@ -763,43 +803,46 @@ literal: nassigned++; } nread += p - buf; - nconversions++; break; #ifndef NO_FLOATING_POINT case CT_FLOAT: + { + char *pbuf; /* scan a floating point number as if by strtod */ - if (width == 0 || width > sizeof(buf) - 1) - width = sizeof(buf) - 1; - if ((width = parsefloat(fp, buf, buf + width)) == 0) + if ((width = parsefloat(fp, &pbuf, width, loc)) == 0) goto match_failure; if ((flags & SUPPRESS) == 0) { if (flags & LONGDBL) { - long double res = strtold(buf, &p); + long double res = strtold_l(pbuf, &p, loc); *va_arg(ap, long double *) = res; } else if (flags & LONG) { - double res = strtod(buf, &p); + double res = strtod_l(pbuf, &p, loc); *va_arg(ap, double *) = res; } else { - float res = strtof(buf, &p); + float res = strtof_l(pbuf, &p, loc); *va_arg(ap, float *) = res; } - if (__scanfdebug && p - buf != width) - abort(); nassigned++; } nread += width; - nconversions++; break; + } #endif /* !NO_FLOATING_POINT */ } } input_failure: - return (nconversions != 0 ? nassigned : EOF); + return (nassigned ? nassigned : EOF); match_failure: return (nassigned); } +int +__svfscanf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) +{ + return __svfscanf_l(fp, __current_locale(), fmt0, ap); +} + /* * Fill in the given table from the scanset at the given format * (just after `['). Return a pointer to the character past the @@ -807,9 +850,10 @@ match_failure: * considered part of the scanset. */ static const u_char * -__sccl(tab, fmt) +__sccl(tab, fmt, loc) char *tab; const u_char *fmt; + locale_t loc; { int c, n, v, i; @@ -845,6 +889,7 @@ doswitch: return (fmt - 1); case '-': + { /* * A scanset of the form * [01+-] @@ -865,8 +910,8 @@ doswitch: */ n = *fmt; if (n == ']' - || (__collate_load_error ? n < c : - __collate_range_cmp (n, c) < 0 + || (loc->__collate_load_error ? n < c : + __collate_range_cmp (n, c, loc) < 0 ) ) { c = '-'; @@ -874,14 +919,14 @@ doswitch: } fmt++; /* fill in the range */ - if (__collate_load_error) { + if (loc->__collate_load_error) { do { tab[++c] = v; } while (c < n); } else { for (i = 0; i < 256; i ++) - if ( __collate_range_cmp (c, i) < 0 - && __collate_range_cmp (i, n) <= 0 + if ( __collate_range_cmp (c, i, loc) < 0 + && __collate_range_cmp (i, n, loc) <= 0 ) tab[i] = v; } @@ -901,7 +946,7 @@ doswitch: return (fmt); #endif break; - + } case ']': /* end of scanset */ return (fmt); @@ -914,19 +959,74 @@ doswitch: } #ifndef NO_FLOATING_POINT +/* + * Maintain a per-thread parsefloat buffer, shared by __svfscanf_l and + * __vfwscanf. + */ +#ifdef BUILDING_VARIANT +extern char *__parsefloat_buf(size_t s); +#else /* !BUILDING_VARIANT */ +__private_extern__ char * +__parsefloat_buf(size_t s) +{ + char *b; + static pthread_key_t parsefloat_tsd_key = (pthread_key_t)-1; + static pthread_mutex_t parsefloat_tsd_lock = PTHREAD_MUTEX_INITIALIZER; + static size_t bsiz = 0; + + if (parsefloat_tsd_key == (pthread_key_t)-1) { + pthread_mutex_lock(&parsefloat_tsd_lock); + if (parsefloat_tsd_key == (pthread_key_t)-1) { + parsefloat_tsd_key = __LIBC_PTHREAD_KEY_PARSEFLOAT; + pthread_key_init_np(parsefloat_tsd_key, free); + } + pthread_mutex_unlock(&parsefloat_tsd_lock); + } + if ((b = (char *)pthread_getspecific(parsefloat_tsd_key)) == NULL) { + bsiz = s > BUF ? s : BUF; + b = (char *)malloc(bsiz); + if (b == NULL) { + bsiz = 0; + return NULL; + } + pthread_setspecific(parsefloat_tsd_key, b); + return b; + } + if (s > bsiz) { + b = (char *)reallocf(b, s); + pthread_setspecific(parsefloat_tsd_key, b); + if (b == NULL) { + bsiz = 0; + return NULL; + } + bsiz = s; + } + return b; +} +#endif /* BUILDING_VARIANT */ + static int -parsefloat(FILE *fp, char *buf, char *end) +parsefloat(FILE *fp, char **buf, size_t width, locale_t loc) { char *commit, *p; - int infnanpos = 0; + int infnanpos = 0, decptpos = 0; enum { - S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX, - S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS + S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX, + S_DIGITS, S_DECPT, S_FRAC, S_EXP, S_EXPDIGITS } state = S_START; unsigned char c; - char decpt = *localeconv()->decimal_point; + const char *decpt = localeconv_l(loc)->decimal_point; _Bool gotmantdig = 0, ishex = 0; + char *b; + char *e; + size_t s; + s = (width == 0 ? BUF : (width + 1)); + if ((b = __parsefloat_buf(s)) == NULL) { + *buf = NULL; + return 0; + } + e = b + (s - 1); /* * We set commit = p whenever the string we have read so far * constitutes a valid representation of a floating point @@ -936,8 +1036,8 @@ parsefloat(FILE *fp, char *buf, char *end) * always necessary to read at least one character that doesn't * match; thus, we can't short-circuit "infinity" or "nan(...)". */ - commit = buf - 1; - for (p = buf; p < end; ) { + commit = b - 1; + for (p = b; width == 0 || p < e; ) { c = *fp->_p; reswitch: switch (state) { @@ -977,8 +1077,6 @@ reswitch: break; case S_NAN: switch (infnanpos) { - case -1: /* XXX kludge to deal with nan(...) */ - goto parsedone; case 0: if (c != 'A' && c != 'a') goto parsedone; @@ -996,13 +1094,15 @@ reswitch: default: if (c == ')') { commit = p; - infnanpos = -2; - } else if (!isalnum(c) && c != '_') + state = S_DONE; + } else if (!isalnum_l(c, loc) && c != '_') goto parsedone; break; } infnanpos++; break; + case S_DONE: + goto parsedone; case S_MAYBEHEX: state = S_DIGITS; if (c == 'X' || c == 'x') { @@ -1013,16 +1113,34 @@ reswitch: goto reswitch; } case S_DIGITS: - if ((ishex && isxdigit(c)) || isdigit(c)) + if ((ishex && isxdigit_l(c, loc)) || isdigit_l(c, loc)) { gotmantdig = 1; - else { + commit = p; + break; + } else { + state = S_DECPT; + goto reswitch; + } + case S_DECPT: + if (c == decpt[decptpos]) { + if (decpt[++decptpos] == '\0') { + /* We read the complete decpt seq. */ + state = S_FRAC; + if (gotmantdig) + commit = p; + } + break; + } else if (!decptpos) { + /* We didn't read any decpt characters. */ state = S_FRAC; - if (c != decpt) - goto reswitch; + goto reswitch; + } else { + /* + * We read part of a multibyte decimal point, + * but the rest is invalid, so bail. + */ + goto parsedone; } - if (gotmantdig) - commit = p; - break; case S_FRAC: if (((c == 'E' || c == 'e') && !ishex) || ((c == 'P' || c == 'p') && ishex)) { @@ -1030,7 +1148,7 @@ reswitch: goto parsedone; else state = S_EXP; - } else if ((ishex && isxdigit(c)) || isdigit(c)) { + } else if ((ishex && isxdigit_l(c, loc)) || isdigit_l(c, loc)) { commit = p; gotmantdig = 1; } else @@ -1043,13 +1161,26 @@ reswitch: else goto reswitch; case S_EXPDIGITS: - if (isdigit(c)) + if (isdigit_l(c, loc)) commit = p; else goto parsedone; break; default: - abort(); + LIBC_ABORT("unknown state %d", state); + } + if (p >= e) { + ssize_t diff = (p - b); + ssize_t com = (commit - b); + s += BUF; + b = __parsefloat_buf(s); + if (b == NULL) { + *buf = NULL; + return 0; + } + e = b + (s - 1); + p = b + diff; + commit = b + com; } *p++ = c; if (--fp->_r > 0) @@ -1062,6 +1193,8 @@ parsedone: while (commit < --p) __ungetc(*(u_char *)p, fp); *++commit = '\0'; - return (commit - buf); + *buf = b; + return (commit - b); } #endif +#pragma clang diagnostic push