]> git.saurik.com Git - apple/libc.git/blob - stdio/FreeBSD/vfscanf.c.patch
Libc-583.tar.gz
[apple/libc.git] / stdio / FreeBSD / vfscanf.c.patch
1 --- vfscanf.c.orig 2009-02-15 03:11:22.000000000 -0800
2 +++ vfscanf.c 2009-02-16 00:22:06.000000000 -0800
3 @@ -40,6 +40,8 @@ static char sccsid[] = "@(#)vfscanf.c 8.
4 #include <sys/cdefs.h>
5 __FBSDID("$FreeBSD: src/lib/libc/stdio/vfscanf.c,v 1.37 2004/05/02 10:55:05 das Exp $");
6
7 +#include "xlocale_private.h"
8 +
9 #include "namespace.h"
10 #include <ctype.h>
11 #include <inttypes.h>
12 @@ -50,6 +52,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/v
13 #include <string.h>
14 #include <wchar.h>
15 #include <wctype.h>
16 +#include <pthread.h>
17 #include "un-namespace.h"
18
19 #include "collate.h"
20 @@ -97,10 +100,21 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/v
21 #define CT_INT 3 /* %[dioupxX] conversion */
22 #define CT_FLOAT 4 /* %[efgEFG] conversion */
23
24 -static const u_char *__sccl(char *, const u_char *);
25 -static int parsefloat(FILE *, char *, char *);
26 +static const u_char *__sccl(char *, const u_char *, locale_t);
27 +#ifndef NO_FLOATING_POINT
28 +static int parsefloat(FILE *, char **, size_t, locale_t);
29 +#endif /* !NO_FLOATING_POINT */
30
31 +/*
32 + * For ppc, we need to have the 64-bit long double version defining storage for
33 + * __scanfdebug, to be compatible with 10.3. For ppc64 and i386, we want the
34 + * storage defined in the only version.
35 + */
36 +#if defined(__ppc__) && !defined(BUILDING_VARIANT)
37 +extern int __scanfdebug;
38 +#else /* !__ppc__ || BUILDING_VARIANT */
39 int __scanfdebug = 0;
40 +#endif /* __ppc__ && !BUILDING_VARIANT */
41
42 __weak_reference(__vfscanf, vfscanf);
43
44 @@ -108,12 +122,24 @@ __weak_reference(__vfscanf, vfscanf);
45 * __vfscanf - MT-safe version
46 */
47 int
48 -__vfscanf(FILE *fp, char const *fmt0, va_list ap)
49 +__vfscanf(FILE * __restrict fp, char const * __restrict fmt0, va_list ap)
50 {
51 int ret;
52
53 FLOCKFILE(fp);
54 - ret = __svfscanf(fp, fmt0, ap);
55 + ret = __svfscanf_l(fp, __current_locale(), fmt0, ap);
56 + FUNLOCKFILE(fp);
57 + return (ret);
58 +}
59 +
60 +int
61 +vfscanf_l(FILE * __restrict fp, locale_t loc, char const * __restrict fmt0, va_list ap)
62 +{
63 + int ret;
64 +
65 + NORMALIZE_LOCALE(loc);
66 + FLOCKFILE(fp);
67 + ret = __svfscanf_l(fp, loc, fmt0, ap);
68 FUNLOCKFILE(fp);
69 return (ret);
70 }
71 @@ -121,8 +147,8 @@ __vfscanf(FILE *fp, char const *fmt0, va
72 /*
73 * __svfscanf - non-MT-safe version of __vfscanf
74 */
75 -int
76 -__svfscanf(FILE *fp, const char *fmt0, va_list ap)
77 +__private_extern__ int
78 +__svfscanf_l(FILE * __restrict fp, locale_t loc, const char * __restrict fmt0, va_list ap)
79 {
80 const u_char *fmt = (const u_char *)fmt0;
81 int c; /* character from format, or conversion */
82 @@ -132,7 +158,6 @@ __svfscanf(FILE *fp, const char *fmt0, v
83 int flags; /* flags as defined above */
84 char *p0; /* saves original value of p when necessary */
85 int nassigned; /* number of fields assigned */
86 - int nconversions; /* number of conversions */
87 int nread; /* number of characters consumed from fp */
88 int base; /* base argument to conversion function */
89 char ccltab[256]; /* character class table for %[...] */
90 @@ -140,29 +165,37 @@ __svfscanf(FILE *fp, const char *fmt0, v
91 wchar_t *wcp; /* handy wide character pointer */
92 wchar_t *wcp0; /* saves original value of wcp */
93 size_t nconv; /* length of multibyte sequence converted */
94 + int index; /* %index$, zero if unset */
95 + va_list ap_orig; /* to reset ap to first argument */
96 static const mbstate_t initial;
97 mbstate_t mbs;
98 + int mb_cur_max;
99
100 /* `basefix' is used to avoid `if' tests in the integer scanner */
101 static short basefix[17] =
102 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
103
104 + NORMALIZE_LOCALE(loc);
105 + mb_cur_max = MB_CUR_MAX_L(loc);
106 ORIENT(fp, -1);
107
108 nassigned = 0;
109 - nconversions = 0;
110 nread = 0;
111 + va_copy(ap_orig, ap);
112 for (;;) {
113 c = *fmt++;
114 if (c == 0)
115 return (nassigned);
116 - if (isspace(c)) {
117 - while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p))
118 + if (isspace_l(c, loc)) {
119 + while ((fp->_r > 0 || __srefill(fp) == 0) && isspace_l(*fp->_p, loc))
120 nread++, fp->_r--, fp->_p++;
121 continue;
122 }
123 - if (c != '%')
124 + if (c != '%') {
125 + if (fp->_r <= 0 && __srefill(fp))
126 + goto input_failure;
127 goto literal;
128 + }
129 width = 0;
130 flags = 0;
131 /*
132 @@ -172,15 +205,35 @@ __svfscanf(FILE *fp, const char *fmt0, v
133 again: c = *fmt++;
134 switch (c) {
135 case '%':
136 + /* Consume leading white space */
137 + for(;;) {
138 + if (fp->_r <= 0 && __srefill(fp))
139 + goto input_failure;
140 + if (!isspace_l(*fp->_p, loc))
141 + break;
142 + nread++;
143 + fp->_r--;
144 + fp->_p++;
145 + }
146 literal:
147 - if (fp->_r <= 0 && __srefill(fp))
148 - goto input_failure;
149 if (*fp->_p != c)
150 goto match_failure;
151 fp->_r--, fp->_p++;
152 nread++;
153 continue;
154
155 + case '$':
156 + index = width;
157 + if (index < 1 || index > NL_ARGMAX || fmt[-3] != '%') {
158 + goto input_failure;
159 + }
160 + width = 0;
161 + va_end(ap);
162 + va_copy(ap, ap_orig); /* reset to %1$ */
163 + for (; index > 1; index--) {
164 + va_arg(ap, void*);
165 + }
166 + goto again;
167 case '*':
168 flags |= SUPPRESS;
169 goto again;
170 @@ -267,7 +320,7 @@ literal:
171 break;
172
173 case '[':
174 - fmt = __sccl(ccltab, fmt);
175 + fmt = __sccl(ccltab, fmt, loc);
176 flags |= NOSKIP;
177 c = CT_CCL;
178 break;
179 @@ -288,7 +341,6 @@ literal:
180 break;
181
182 case 'n':
183 - nconversions++;
184 if (flags & SUPPRESS) /* ??? */
185 continue;
186 if (flags & SHORTSHORT)
187 @@ -330,7 +382,7 @@ literal:
188 * that suppress this.
189 */
190 if ((flags & NOSKIP) == 0) {
191 - while (isspace(*fp->_p)) {
192 + while (isspace_l(*fp->_p, loc)) {
193 nread++;
194 if (--fp->_r > 0)
195 fp->_p++;
196 @@ -360,7 +412,7 @@ literal:
197 wcp = NULL;
198 n = 0;
199 while (width != 0) {
200 - if (n == MB_CUR_MAX) {
201 + if (n == mb_cur_max) {
202 fp->_flags |= __SERR;
203 goto input_failure;
204 }
205 @@ -368,7 +420,7 @@ literal:
206 fp->_p++;
207 fp->_r--;
208 mbs = initial;
209 - nconv = mbrtowc(wcp, buf, n, &mbs);
210 + nconv = mbrtowc_l(wcp, buf, n, &mbs, loc);
211 if (nconv == (size_t)-1) {
212 fp->_flags |= __SERR;
213 goto input_failure;
214 @@ -421,7 +473,6 @@ literal:
215 nread += r;
216 nassigned++;
217 }
218 - nconversions++;
219 break;
220
221 case CT_CCL:
222 @@ -440,7 +491,7 @@ literal:
223 n = 0;
224 nchars = 0;
225 while (width != 0) {
226 - if (n == MB_CUR_MAX) {
227 + if (n == mb_cur_max) {
228 fp->_flags |= __SERR;
229 goto input_failure;
230 }
231 @@ -448,7 +499,7 @@ literal:
232 fp->_p++;
233 fp->_r--;
234 mbs = initial;
235 - nconv = mbrtowc(wcp, buf, n, &mbs);
236 + nconv = mbrtowc_l(wcp, buf, n, &mbs, loc);
237 if (nconv == (size_t)-1) {
238 fp->_flags |= __SERR;
239 goto input_failure;
240 @@ -456,8 +507,8 @@ literal:
241 if (nconv == 0)
242 *wcp = L'\0';
243 if (nconv != (size_t)-2) {
244 - if (wctob(*wcp) != EOF &&
245 - !ccltab[wctob(*wcp)]) {
246 + if (wctob_l(*wcp, loc) != EOF &&
247 + !ccltab[wctob_l(*wcp, loc)]) {
248 while (n != 0) {
249 n--;
250 __ungetc(buf[n],
251 @@ -525,7 +576,6 @@ literal:
252 nassigned++;
253 }
254 nread += n;
255 - nconversions++;
256 break;
257
258 case CT_STRING:
259 @@ -540,8 +590,8 @@ literal:
260 else
261 wcp = &twc;
262 n = 0;
263 - while (!isspace(*fp->_p) && width != 0) {
264 - if (n == MB_CUR_MAX) {
265 + while (width != 0) {
266 + if (n == mb_cur_max) {
267 fp->_flags |= __SERR;
268 goto input_failure;
269 }
270 @@ -549,7 +599,7 @@ literal:
271 fp->_p++;
272 fp->_r--;
273 mbs = initial;
274 - nconv = mbrtowc(wcp, buf, n, &mbs);
275 + nconv = mbrtowc_l(wcp, buf, n, &mbs, loc);
276 if (nconv == (size_t)-1) {
277 fp->_flags |= __SERR;
278 goto input_failure;
279 @@ -557,7 +607,7 @@ literal:
280 if (nconv == 0)
281 *wcp = L'\0';
282 if (nconv != (size_t)-2) {
283 - if (iswspace(*wcp)) {
284 + if (iswspace_l(*wcp, loc)) {
285 while (n != 0) {
286 n--;
287 __ungetc(buf[n],
288 @@ -585,7 +635,7 @@ literal:
289 }
290 } else if (flags & SUPPRESS) {
291 n = 0;
292 - while (!isspace(*fp->_p)) {
293 + while (!isspace_l(*fp->_p, loc)) {
294 n++, fp->_r--, fp->_p++;
295 if (--width == 0)
296 break;
297 @@ -595,7 +645,7 @@ literal:
298 nread += n;
299 } else {
300 p0 = p = va_arg(ap, char *);
301 - while (!isspace(*fp->_p)) {
302 + while (!isspace_l(*fp->_p, loc)) {
303 fp->_r--;
304 *p++ = *fp->_p++;
305 if (--width == 0)
306 @@ -607,7 +657,6 @@ literal:
307 nread += p - p0;
308 nassigned++;
309 }
310 - nconversions++;
311 continue;
312
313 case CT_INT:
314 @@ -738,9 +787,9 @@ literal:
315
316 *p = 0;
317 if ((flags & UNSIGNED) == 0)
318 - res = strtoimax(buf, (char **)NULL, base);
319 + res = strtoimax_l(buf, (char **)NULL, base, loc);
320 else
321 - res = strtoumax(buf, (char **)NULL, base);
322 + res = strtoumax_l(buf, (char **)NULL, base, loc);
323 if (flags & POINTER)
324 *va_arg(ap, void **) =
325 (void *)(uintptr_t)res;
326 @@ -763,43 +812,48 @@ literal:
327 nassigned++;
328 }
329 nread += p - buf;
330 - nconversions++;
331 break;
332
333 #ifndef NO_FLOATING_POINT
334 case CT_FLOAT:
335 + {
336 + char *pbuf;
337 /* scan a floating point number as if by strtod */
338 - if (width == 0 || width > sizeof(buf) - 1)
339 - width = sizeof(buf) - 1;
340 - if ((width = parsefloat(fp, buf, buf + width)) == 0)
341 + if ((width = parsefloat(fp, &pbuf, width, loc)) == 0)
342 goto match_failure;
343 if ((flags & SUPPRESS) == 0) {
344 if (flags & LONGDBL) {
345 - long double res = strtold(buf, &p);
346 + long double res = strtold_l(pbuf, &p, loc);
347 *va_arg(ap, long double *) = res;
348 } else if (flags & LONG) {
349 - double res = strtod(buf, &p);
350 + double res = strtod_l(pbuf, &p, loc);
351 *va_arg(ap, double *) = res;
352 } else {
353 - float res = strtof(buf, &p);
354 + float res = strtof_l(pbuf, &p, loc);
355 *va_arg(ap, float *) = res;
356 }
357 - if (__scanfdebug && p - buf != width)
358 - abort();
359 + if (__scanfdebug && p - pbuf != width)
360 + LIBC_ABORT("p - pbuf %ld != width %ld", (long)(p - pbuf), width);
361 nassigned++;
362 }
363 nread += width;
364 - nconversions++;
365 break;
366 + }
367 #endif /* !NO_FLOATING_POINT */
368 }
369 }
370 input_failure:
371 - return (nconversions != 0 ? nassigned : EOF);
372 + return (nassigned ? nassigned : EOF);
373 match_failure:
374 return (nassigned);
375 }
376
377 +int
378 +__svfscanf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
379 +{
380 + return __svfscanf_l(fp, __current_locale(), fmt0, ap);
381 +}
382 +
383 /*
384 * Fill in the given table from the scanset at the given format
385 * (just after `['). Return a pointer to the character past the
386 @@ -807,9 +861,10 @@ match_failure:
387 * considered part of the scanset.
388 */
389 static const u_char *
390 -__sccl(tab, fmt)
391 +__sccl(tab, fmt, loc)
392 char *tab;
393 const u_char *fmt;
394 + locale_t loc;
395 {
396 int c, n, v, i;
397
398 @@ -845,6 +900,7 @@ doswitch:
399 return (fmt - 1);
400
401 case '-':
402 + {
403 /*
404 * A scanset of the form
405 * [01+-]
406 @@ -865,8 +921,8 @@ doswitch:
407 */
408 n = *fmt;
409 if (n == ']'
410 - || (__collate_load_error ? n < c :
411 - __collate_range_cmp (n, c) < 0
412 + || (loc->__collate_load_error ? n < c :
413 + __collate_range_cmp (n, c, loc) < 0
414 )
415 ) {
416 c = '-';
417 @@ -874,14 +930,14 @@ doswitch:
418 }
419 fmt++;
420 /* fill in the range */
421 - if (__collate_load_error) {
422 + if (loc->__collate_load_error) {
423 do {
424 tab[++c] = v;
425 } while (c < n);
426 } else {
427 for (i = 0; i < 256; i ++)
428 - if ( __collate_range_cmp (c, i) < 0
429 - && __collate_range_cmp (i, n) <= 0
430 + if ( __collate_range_cmp (c, i, loc) < 0
431 + && __collate_range_cmp (i, n, loc) <= 0
432 )
433 tab[i] = v;
434 }
435 @@ -901,7 +957,7 @@ doswitch:
436 return (fmt);
437 #endif
438 break;
439 -
440 + }
441 case ']': /* end of scanset */
442 return (fmt);
443
444 @@ -914,19 +970,75 @@ doswitch:
445 }
446
447 #ifndef NO_FLOATING_POINT
448 +/*
449 + * Maintain a per-thread parsefloat buffer, shared by __svfscanf_l and
450 + * __vfwscanf.
451 + */
452 +#ifdef BUILDING_VARIANT
453 +extern char *__parsefloat_buf(size_t s);
454 +#else /* !BUILDING_VARIANT */
455 +__private_extern__ char *
456 +__parsefloat_buf(size_t s)
457 +{
458 + char *b;
459 + static pthread_key_t parsefloat_tsd_key = (pthread_key_t)-1;
460 + static pthread_mutex_t parsefloat_tsd_lock = PTHREAD_MUTEX_INITIALIZER;
461 + static size_t bsiz = 0;
462 +
463 + if (parsefloat_tsd_key == (pthread_key_t)-1) {
464 + pthread_mutex_lock(&parsefloat_tsd_lock);
465 + if (parsefloat_tsd_key == (pthread_key_t)-1) {
466 + parsefloat_tsd_key = __LIBC_PTHREAD_KEY_PARSEFLOAT;
467 + pthread_key_init_np(parsefloat_tsd_key, free);
468 + }
469 + pthread_mutex_unlock(&parsefloat_tsd_lock);
470 + }
471 + if ((b = (char *)pthread_getspecific(parsefloat_tsd_key)) == NULL) {
472 + bsiz = s > BUF ? s : BUF;
473 + b = (char *)malloc(bsiz);
474 + if (b == NULL) {
475 + bsiz = 0;
476 + return NULL;
477 + }
478 + pthread_setspecific(parsefloat_tsd_key, b);
479 + return b;
480 + }
481 + if (s > bsiz) {
482 + b = (char *)reallocf(b, s);
483 + pthread_setspecific(parsefloat_tsd_key, b);
484 + if (b == NULL) {
485 + bsiz = 0;
486 + return NULL;
487 + }
488 + bsiz = s;
489 + }
490 + return b;
491 +}
492 +#endif /* BUILDING_VARIANT */
493 +
494 static int
495 -parsefloat(FILE *fp, char *buf, char *end)
496 +parsefloat(FILE *fp, char **buf, size_t width, locale_t loc)
497 {
498 char *commit, *p;
499 int infnanpos = 0;
500 enum {
501 S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,
502 - S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
503 + S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS, S_DECIMAL_POINT
504 } state = S_START;
505 unsigned char c;
506 - char decpt = *localeconv()->decimal_point;
507 + unsigned char *decpt = (unsigned char *)localeconv_l(loc)->decimal_point;
508 + char *decpt_start;
509 _Bool gotmantdig = 0, ishex = 0;
510 -
511 + char *b;
512 + char *e;
513 + size_t s;
514 +
515 + s = (width == 0 ? BUF : (width + 1));
516 + if ((b = __parsefloat_buf(s)) == NULL) {
517 + *buf = NULL;
518 + return 0;
519 + }
520 + e = b + (s - 1);
521 /*
522 * We set commit = p whenever the string we have read so far
523 * constitutes a valid representation of a floating point
524 @@ -936,8 +1048,8 @@ parsefloat(FILE *fp, char *buf, char *en
525 * always necessary to read at least one character that doesn't
526 * match; thus, we can't short-circuit "infinity" or "nan(...)".
527 */
528 - commit = buf - 1;
529 - for (p = buf; p < end; ) {
530 + commit = b - 1;
531 + for (p = b; width == 0 || p < e; ) {
532 c = *fp->_p;
533 reswitch:
534 switch (state) {
535 @@ -997,7 +1109,7 @@ reswitch:
536 if (c == ')') {
537 commit = p;
538 infnanpos = -2;
539 - } else if (!isalnum(c) && c != '_')
540 + } else if (!isalnum_l(c, loc) && c != '_')
541 goto parsedone;
542 break;
543 }
544 @@ -1013,16 +1125,33 @@ reswitch:
545 goto reswitch;
546 }
547 case S_DIGITS:
548 - if ((ishex && isxdigit(c)) || isdigit(c))
549 + if ((ishex && isxdigit_l(c, loc)) || isdigit_l(c, loc))
550 gotmantdig = 1;
551 else {
552 - state = S_FRAC;
553 - if (c != decpt)
554 - goto reswitch;
555 + state = S_DECIMAL_POINT;
556 + decpt_start = p;
557 + goto reswitch;
558 }
559 if (gotmantdig)
560 commit = p;
561 break;
562 + case S_DECIMAL_POINT:
563 + if (*decpt == 0) {
564 + if (gotmantdig)
565 + commit = p - 1;
566 + state = S_FRAC;
567 + goto reswitch;
568 + }
569 + if (*decpt++ == c)
570 + break;
571 + /* not decimal point */
572 + state = S_FRAC;
573 + if (decpt_start == p)
574 + goto reswitch;
575 + while (decpt_start < --p)
576 + __ungetc(*(u_char *)p, fp);
577 + c = *(u_char *)p;
578 + goto reswitch;
579 case S_FRAC:
580 if (((c == 'E' || c == 'e') && !ishex) ||
581 ((c == 'P' || c == 'p') && ishex)) {
582 @@ -1030,7 +1159,7 @@ reswitch:
583 goto parsedone;
584 else
585 state = S_EXP;
586 - } else if ((ishex && isxdigit(c)) || isdigit(c)) {
587 + } else if ((ishex && isxdigit_l(c, loc)) || isdigit_l(c, loc)) {
588 commit = p;
589 gotmantdig = 1;
590 } else
591 @@ -1043,13 +1172,26 @@ reswitch:
592 else
593 goto reswitch;
594 case S_EXPDIGITS:
595 - if (isdigit(c))
596 + if (isdigit_l(c, loc))
597 commit = p;
598 else
599 goto parsedone;
600 break;
601 default:
602 - abort();
603 + LIBC_ABORT("unknown state %d", state);
604 + }
605 + if (p >= e) {
606 + ssize_t diff = (p - b);
607 + ssize_t com = (commit - b);
608 + s += BUF;
609 + b = __parsefloat_buf(s);
610 + if (b == NULL) {
611 + *buf = NULL;
612 + return 0;
613 + }
614 + e = b + (s - 1);
615 + p = b + diff;
616 + commit = b + com;
617 }
618 *p++ = c;
619 if (--fp->_r > 0)
620 @@ -1062,6 +1204,7 @@ parsedone:
621 while (commit < --p)
622 __ungetc(*(u_char *)p, fp);
623 *++commit = '\0';
624 - return (commit - buf);
625 + *buf = b;
626 + return (commit - b);
627 }
628 #endif