]>
Commit | Line | Data |
---|---|---|
1f2f436a A |
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. | |
3d9156a7 | 4 | #include <sys/cdefs.h> |
1f2f436a | 5 | __FBSDID("$FreeBSD: src/lib/libc/stdio/vfscanf.c,v 1.43 2009/01/19 06:19:51 das Exp $"); |
3d9156a7 A |
6 | |
7 | +#include "xlocale_private.h" | |
8 | + | |
9 | #include "namespace.h" | |
10 | #include <ctype.h> | |
11 | #include <inttypes.h> | |
1f2f436a | 12 | @@ -46,6 +48,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/v |
34e8f829 A |
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" | |
1f2f436a | 20 | @@ -93,9 +96,9 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/v |
3d9156a7 | 21 | #define CT_INT 3 /* %[dioupxX] conversion */ |
59e0d9fe A |
22 | #define CT_FLOAT 4 /* %[efgEFG] conversion */ |
23 | ||
3d9156a7 | 24 | -static const u_char *__sccl(char *, const u_char *); |
3d9156a7 | 25 | +static const u_char *__sccl(char *, const u_char *, locale_t); |
1f2f436a A |
26 | #ifndef NO_FLOATING_POINT |
27 | -static int parsefloat(FILE *, char *, char *); | |
3d9156a7 | 28 | +static int parsefloat(FILE *, char **, size_t, locale_t); |
1f2f436a | 29 | #endif |
3d9156a7 A |
30 | |
31 | __weak_reference(__vfscanf, vfscanf); | |
1f2f436a | 32 | @@ -104,12 +107,24 @@ __weak_reference(__vfscanf, vfscanf); |
3d9156a7 A |
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) | |
34e8f829 A |
38 | { |
39 | int ret; | |
40 | ||
41 | FLOCKFILE(fp); | |
42 | - ret = __svfscanf(fp, fmt0, ap); | |
3d9156a7 A |
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) | |
34e8f829 A |
50 | +{ |
51 | + int ret; | |
52 | + | |
3d9156a7 | 53 | + NORMALIZE_LOCALE(loc); |
34e8f829 | 54 | + FLOCKFILE(fp); |
3d9156a7 A |
55 | + ret = __svfscanf_l(fp, loc, fmt0, ap); |
56 | FUNLOCKFILE(fp); | |
57 | return (ret); | |
58 | } | |
1f2f436a | 59 | @@ -117,8 +132,8 @@ __vfscanf(FILE *fp, char const *fmt0, va |
3d9156a7 A |
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 */ | |
1f2f436a | 70 | @@ -128,36 +143,43 @@ __svfscanf(FILE *fp, const char *fmt0, v |
59e0d9fe A |
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 %[...] */ | |
1f2f436a | 78 | char buf[BUF]; /* buffer for numeric and mb conversions */ |
3d9156a7 | 79 | wchar_t *wcp; /* handy wide character pointer */ |
3d9156a7 A |
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); | |
59e0d9fe A |
93 | ORIENT(fp, -1); |
94 | ||
95 | nassigned = 0; | |
96 | - nconversions = 0; | |
97 | nread = 0; | |
3d9156a7 | 98 | + va_copy(ap_orig, ap); |
59e0d9fe A |
99 | for (;;) { |
100 | c = *fmt++; | |
3d9156a7 A |
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 | } | |
34e8f829 A |
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 | /* | |
1f2f436a | 119 | @@ -167,15 +189,35 @@ __svfscanf(FILE *fp, const char *fmt0, v |
34e8f829 A |
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++; | |
3d9156a7 A |
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; | |
1f2f436a | 157 | @@ -262,7 +304,7 @@ literal: |
3d9156a7 A |
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; | |
1f2f436a | 166 | @@ -283,27 +325,28 @@ literal: |
59e0d9fe A |
167 | break; |
168 | ||
169 | case 'n': | |
170 | - nconversions++; | |
1f2f436a A |
171 | - if (flags & SUPPRESS) /* ??? */ |
172 | + { | |
173 | + void *ptr = va_arg(ap, void *); | |
174 | + if ((ptr == NULL) || (flags & SUPPRESS)) /* ??? */ | |
59e0d9fe | 175 | continue; |
1f2f436a A |
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: | |
3d9156a7 A |
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++; | |
1f2f436a | 216 | @@ -355,7 +398,7 @@ literal: |
3d9156a7 A |
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 | } | |
1f2f436a | 225 | @@ -363,7 +406,7 @@ literal: |
3d9156a7 A |
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; | |
1f2f436a | 234 | @@ -416,7 +459,6 @@ literal: |
59e0d9fe A |
235 | nread += r; |
236 | nassigned++; | |
237 | } | |
238 | - nconversions++; | |
239 | break; | |
240 | ||
241 | case CT_CCL: | |
1f2f436a | 242 | @@ -435,7 +477,7 @@ literal: |
3d9156a7 A |
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 | } | |
1f2f436a | 251 | @@ -443,7 +485,7 @@ literal: |
3d9156a7 A |
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; | |
1f2f436a | 260 | @@ -451,8 +493,8 @@ literal: |
3d9156a7 A |
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], | |
1f2f436a | 271 | @@ -520,7 +562,6 @@ literal: |
59e0d9fe A |
272 | nassigned++; |
273 | } | |
274 | nread += n; | |
275 | - nconversions++; | |
276 | break; | |
277 | ||
278 | case CT_STRING: | |
1f2f436a | 279 | @@ -535,8 +576,8 @@ literal: |
3d9156a7 A |
280 | else |
281 | wcp = &twc; | |
282 | n = 0; | |
283 | - while (!isspace(*fp->_p) && width != 0) { | |
284 | - if (n == MB_CUR_MAX) { | |
224c7076 | 285 | + while (width != 0) { |
3d9156a7 A |
286 | + if (n == mb_cur_max) { |
287 | fp->_flags |= __SERR; | |
288 | goto input_failure; | |
289 | } | |
1f2f436a | 290 | @@ -544,7 +585,7 @@ literal: |
3d9156a7 A |
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; | |
1f2f436a | 299 | @@ -552,7 +593,7 @@ literal: |
3d9156a7 A |
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], | |
1f2f436a | 308 | @@ -580,7 +621,7 @@ literal: |
3d9156a7 A |
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; | |
1f2f436a | 317 | @@ -590,7 +631,7 @@ literal: |
3d9156a7 A |
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) | |
1f2f436a | 326 | @@ -602,7 +643,6 @@ literal: |
59e0d9fe A |
327 | nread += p - p0; |
328 | nassigned++; | |
329 | } | |
330 | - nconversions++; | |
331 | continue; | |
332 | ||
333 | case CT_INT: | |
1f2f436a | 334 | @@ -733,9 +773,9 @@ literal: |
3d9156a7 A |
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; | |
1f2f436a | 346 | @@ -758,41 +798,46 @@ literal: |
59e0d9fe A |
347 | nassigned++; |
348 | } | |
349 | nread += p - buf; | |
350 | - nconversions++; | |
351 | break; | |
352 | ||
3d9156a7 | 353 | #ifndef NO_FLOATING_POINT |
59e0d9fe A |
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) | |
224c7076 | 361 | + if ((width = parsefloat(fp, &pbuf, width, loc)) == 0) |
59e0d9fe | 362 | goto match_failure; |
59e0d9fe A |
363 | if ((flags & SUPPRESS) == 0) { |
364 | if (flags & LONGDBL) { | |
365 | - long double res = strtold(buf, &p); | |
3d9156a7 | 366 | + long double res = strtold_l(pbuf, &p, loc); |
59e0d9fe A |
367 | *va_arg(ap, long double *) = res; |
368 | } else if (flags & LONG) { | |
369 | - double res = strtod(buf, &p); | |
3d9156a7 | 370 | + double res = strtod_l(pbuf, &p, loc); |
59e0d9fe A |
371 | *va_arg(ap, double *) = res; |
372 | } else { | |
373 | - float res = strtof(buf, &p); | |
3d9156a7 | 374 | + float res = strtof_l(pbuf, &p, loc); |
59e0d9fe A |
375 | *va_arg(ap, float *) = res; |
376 | } | |
59e0d9fe A |
377 | nassigned++; |
378 | } | |
379 | nread += width; | |
380 | - nconversions++; | |
59e0d9fe A |
381 | break; |
382 | + } | |
3d9156a7 | 383 | #endif /* !NO_FLOATING_POINT */ |
59e0d9fe A |
384 | } |
385 | } | |
386 | input_failure: | |
387 | - return (nconversions != 0 ? nassigned : EOF); | |
388 | + return (nassigned ? nassigned : EOF); | |
389 | match_failure: | |
390 | return (nassigned); | |
391 | } | |
59e0d9fe | 392 | |
3d9156a7 A |
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 | |
1f2f436a | 402 | @@ -800,9 +845,10 @@ match_failure: |
3d9156a7 A |
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 | ||
1f2f436a | 414 | @@ -838,6 +884,7 @@ doswitch: |
3d9156a7 A |
415 | return (fmt - 1); |
416 | ||
417 | case '-': | |
418 | + { | |
419 | /* | |
420 | * A scanset of the form | |
421 | * [01+-] | |
1f2f436a | 422 | @@ -858,8 +905,8 @@ doswitch: |
3d9156a7 A |
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 = '-'; | |
1f2f436a | 433 | @@ -867,14 +914,14 @@ doswitch: |
3d9156a7 A |
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 | } | |
1f2f436a | 451 | @@ -894,7 +941,7 @@ doswitch: |
3d9156a7 A |
452 | return (fmt); |
453 | #endif | |
454 | break; | |
455 | - | |
456 | + } | |
457 | case ']': /* end of scanset */ | |
458 | return (fmt); | |
459 | ||
1f2f436a | 460 | @@ -907,8 +954,54 @@ doswitch: |
34e8f829 | 461 | } |
3d9156a7 A |
462 | |
463 | #ifndef NO_FLOATING_POINT | |
34e8f829 A |
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 | + | |
59e0d9fe A |
510 | static int |
511 | -parsefloat(FILE *fp, char *buf, char *end) | |
3d9156a7 | 512 | +parsefloat(FILE *fp, char **buf, size_t width, locale_t loc) |
59e0d9fe A |
513 | { |
514 | char *commit, *p; | |
1f2f436a A |
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 | |
3d9156a7 | 518 | } state = S_START; |
59e0d9fe | 519 | unsigned char c; |
1f2f436a A |
520 | - const char *decpt = localeconv()->decimal_point; |
521 | + const char *decpt = localeconv_l(loc)->decimal_point; | |
59e0d9fe | 522 | _Bool gotmantdig = 0, ishex = 0; |
224c7076 | 523 | - |
34e8f829 | 524 | + char *b; |
224c7076 | 525 | + char *e; |
59e0d9fe | 526 | + size_t s; |
224c7076 | 527 | + |
224c7076 | 528 | + s = (width == 0 ? BUF : (width + 1)); |
34e8f829 A |
529 | + if ((b = __parsefloat_buf(s)) == NULL) { |
530 | + *buf = NULL; | |
531 | + return 0; | |
59e0d9fe A |
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 | |
1f2f436a | 537 | @@ -929,8 +1031,8 @@ parsefloat(FILE *fp, char *buf, char *en |
59e0d9fe A |
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) { | |
1f2f436a | 548 | @@ -988,7 +1090,7 @@ reswitch: |
3d9156a7 A |
549 | if (c == ')') { |
550 | commit = p; | |
1f2f436a | 551 | state = S_DONE; |
3d9156a7 A |
552 | - } else if (!isalnum(c) && c != '_') |
553 | + } else if (!isalnum_l(c, loc) && c != '_') | |
554 | goto parsedone; | |
555 | break; | |
556 | } | |
1f2f436a | 557 | @@ -1006,7 +1108,7 @@ reswitch: |
3d9156a7 A |
558 | goto reswitch; |
559 | } | |
560 | case S_DIGITS: | |
1f2f436a A |
561 | - if ((ishex && isxdigit(c)) || isdigit(c)) { |
562 | + if ((ishex && isxdigit_l(c, loc)) || isdigit_l(c, loc)) { | |
3d9156a7 | 563 | gotmantdig = 1; |
224c7076 | 564 | commit = p; |
1f2f436a A |
565 | break; |
566 | @@ -1041,7 +1143,7 @@ reswitch: | |
3d9156a7 A |
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 | |
1f2f436a | 575 | @@ -1054,13 +1156,26 @@ reswitch: |
3d9156a7 A |
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; | |
34e8f829 | 584 | break; |
59e0d9fe | 585 | default: |
34e8f829 A |
586 | - abort(); |
587 | + LIBC_ABORT("unknown state %d", state); | |
588 | + } | |
59e0d9fe | 589 | + if (p >= e) { |
224c7076 A |
590 | + ssize_t diff = (p - b); |
591 | + ssize_t com = (commit - b); | |
59e0d9fe | 592 | + s += BUF; |
34e8f829 | 593 | + b = __parsefloat_buf(s); |
59e0d9fe A |
594 | + if (b == NULL) { |
595 | + *buf = NULL; | |
596 | + return 0; | |
597 | + } | |
598 | + e = b + (s - 1); | |
599 | + p = b + diff; | |
224c7076 | 600 | + commit = b + com; |
34e8f829 | 601 | } |
59e0d9fe A |
602 | *p++ = c; |
603 | if (--fp->_r > 0) | |
1f2f436a | 604 | @@ -1073,6 +1188,7 @@ parsedone: |
59e0d9fe A |
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 |