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