]> git.saurik.com Git - apple/libc.git/blob - stdio/FreeBSD/vfscanf.c
Libc-763.12.tar.gz
[apple/libc.git] / stdio / FreeBSD / vfscanf.c
1 /*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #if defined(LIBC_SCCS) && !defined(lint)
34 static char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93";
35 #endif /* LIBC_SCCS and not lint */
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD: src/lib/libc/stdio/vfscanf.c,v 1.43 2009/01/19 06:19:51 das Exp $");
38
39 #include "namespace.h"
40 #include <ctype.h>
41 #include <inttypes.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stddef.h>
45 #include <stdarg.h>
46 #include <string.h>
47 #include <wchar.h>
48 #include <wctype.h>
49 #include "un-namespace.h"
50
51 #include "collate.h"
52 #include "libc_private.h"
53 #include "local.h"
54
55 #ifndef NO_FLOATING_POINT
56 #include <locale.h>
57 #endif
58
59 #define BUF 513 /* Maximum length of numeric string. */
60
61 /*
62 * Flags used during conversion.
63 */
64 #define LONG 0x01 /* l: long or double */
65 #define LONGDBL 0x02 /* L: long double */
66 #define SHORT 0x04 /* h: short */
67 #define SUPPRESS 0x08 /* *: suppress assignment */
68 #define POINTER 0x10 /* p: void * (as hex) */
69 #define NOSKIP 0x20 /* [ or c: do not skip blanks */
70 #define LONGLONG 0x400 /* ll: long long (+ deprecated q: quad) */
71 #define INTMAXT 0x800 /* j: intmax_t */
72 #define PTRDIFFT 0x1000 /* t: ptrdiff_t */
73 #define SIZET 0x2000 /* z: size_t */
74 #define SHORTSHORT 0x4000 /* hh: char */
75 #define UNSIGNED 0x8000 /* %[oupxX] conversions */
76
77 /*
78 * The following are used in integral conversions only:
79 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS
80 */
81 #define SIGNOK 0x40 /* +/- is (still) legal */
82 #define NDIGITS 0x80 /* no digits detected */
83 #define PFXOK 0x100 /* 0x prefix is (still) legal */
84 #define NZDIGITS 0x200 /* no zero digits detected */
85 #define HAVESIGN 0x10000 /* sign detected */
86
87 /*
88 * Conversion types.
89 */
90 #define CT_CHAR 0 /* %c conversion */
91 #define CT_CCL 1 /* %[...] conversion */
92 #define CT_STRING 2 /* %s conversion */
93 #define CT_INT 3 /* %[dioupxX] conversion */
94 #define CT_FLOAT 4 /* %[efgEFG] conversion */
95
96 static const u_char *__sccl(char *, const u_char *);
97 #ifndef NO_FLOATING_POINT
98 static int parsefloat(FILE *, char *, char *);
99 #endif
100
101 __weak_reference(__vfscanf, vfscanf);
102
103 /*
104 * __vfscanf - MT-safe version
105 */
106 int
107 __vfscanf(FILE *fp, char const *fmt0, va_list ap)
108 {
109 int ret;
110
111 FLOCKFILE(fp);
112 ret = __svfscanf(fp, fmt0, ap);
113 FUNLOCKFILE(fp);
114 return (ret);
115 }
116
117 /*
118 * __svfscanf - non-MT-safe version of __vfscanf
119 */
120 int
121 __svfscanf(FILE *fp, const char *fmt0, va_list ap)
122 {
123 const u_char *fmt = (const u_char *)fmt0;
124 int c; /* character from format, or conversion */
125 size_t width; /* field width, or 0 */
126 char *p; /* points into all kinds of strings */
127 int n; /* handy integer */
128 int flags; /* flags as defined above */
129 char *p0; /* saves original value of p when necessary */
130 int nassigned; /* number of fields assigned */
131 int nconversions; /* number of conversions */
132 int nread; /* number of characters consumed from fp */
133 int base; /* base argument to conversion function */
134 char ccltab[256]; /* character class table for %[...] */
135 char buf[BUF]; /* buffer for numeric and mb conversions */
136 wchar_t *wcp; /* handy wide character pointer */
137 size_t nconv; /* length of multibyte sequence converted */
138 static const mbstate_t initial;
139 mbstate_t mbs;
140
141 /* `basefix' is used to avoid `if' tests in the integer scanner */
142 static short basefix[17] =
143 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
144
145 ORIENT(fp, -1);
146
147 nassigned = 0;
148 nconversions = 0;
149 nread = 0;
150 for (;;) {
151 c = *fmt++;
152 if (c == 0)
153 return (nassigned);
154 if (isspace(c)) {
155 while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p))
156 nread++, fp->_r--, fp->_p++;
157 continue;
158 }
159 if (c != '%')
160 goto literal;
161 width = 0;
162 flags = 0;
163 /*
164 * switch on the format. continue if done;
165 * break once format type is derived.
166 */
167 again: c = *fmt++;
168 switch (c) {
169 case '%':
170 literal:
171 if (fp->_r <= 0 && __srefill(fp))
172 goto input_failure;
173 if (*fp->_p != c)
174 goto match_failure;
175 fp->_r--, fp->_p++;
176 nread++;
177 continue;
178
179 case '*':
180 flags |= SUPPRESS;
181 goto again;
182 case 'j':
183 flags |= INTMAXT;
184 goto again;
185 case 'l':
186 if (flags & LONG) {
187 flags &= ~LONG;
188 flags |= LONGLONG;
189 } else
190 flags |= LONG;
191 goto again;
192 case 'q':
193 flags |= LONGLONG; /* not quite */
194 goto again;
195 case 't':
196 flags |= PTRDIFFT;
197 goto again;
198 case 'z':
199 flags |= SIZET;
200 goto again;
201 case 'L':
202 flags |= LONGDBL;
203 goto again;
204 case 'h':
205 if (flags & SHORT) {
206 flags &= ~SHORT;
207 flags |= SHORTSHORT;
208 } else
209 flags |= SHORT;
210 goto again;
211
212 case '0': case '1': case '2': case '3': case '4':
213 case '5': case '6': case '7': case '8': case '9':
214 width = width * 10 + c - '0';
215 goto again;
216
217 /*
218 * Conversions.
219 */
220 case 'd':
221 c = CT_INT;
222 base = 10;
223 break;
224
225 case 'i':
226 c = CT_INT;
227 base = 0;
228 break;
229
230 case 'o':
231 c = CT_INT;
232 flags |= UNSIGNED;
233 base = 8;
234 break;
235
236 case 'u':
237 c = CT_INT;
238 flags |= UNSIGNED;
239 base = 10;
240 break;
241
242 case 'X':
243 case 'x':
244 flags |= PFXOK; /* enable 0x prefixing */
245 c = CT_INT;
246 flags |= UNSIGNED;
247 base = 16;
248 break;
249
250 #ifndef NO_FLOATING_POINT
251 case 'A': case 'E': case 'F': case 'G':
252 case 'a': case 'e': case 'f': case 'g':
253 c = CT_FLOAT;
254 break;
255 #endif
256
257 case 'S':
258 flags |= LONG;
259 /* FALLTHROUGH */
260 case 's':
261 c = CT_STRING;
262 break;
263
264 case '[':
265 fmt = __sccl(ccltab, fmt);
266 flags |= NOSKIP;
267 c = CT_CCL;
268 break;
269
270 case 'C':
271 flags |= LONG;
272 /* FALLTHROUGH */
273 case 'c':
274 flags |= NOSKIP;
275 c = CT_CHAR;
276 break;
277
278 case 'p': /* pointer format is like hex */
279 flags |= POINTER | PFXOK;
280 c = CT_INT; /* assumes sizeof(uintmax_t) */
281 flags |= UNSIGNED; /* >= sizeof(uintptr_t) */
282 base = 16;
283 break;
284
285 case 'n':
286 nconversions++;
287 if (flags & SUPPRESS) /* ??? */
288 continue;
289 if (flags & SHORTSHORT)
290 *va_arg(ap, char *) = nread;
291 else if (flags & SHORT)
292 *va_arg(ap, short *) = nread;
293 else if (flags & LONG)
294 *va_arg(ap, long *) = nread;
295 else if (flags & LONGLONG)
296 *va_arg(ap, long long *) = nread;
297 else if (flags & INTMAXT)
298 *va_arg(ap, intmax_t *) = nread;
299 else if (flags & SIZET)
300 *va_arg(ap, size_t *) = nread;
301 else if (flags & PTRDIFFT)
302 *va_arg(ap, ptrdiff_t *) = nread;
303 else
304 *va_arg(ap, int *) = nread;
305 continue;
306
307 default:
308 goto match_failure;
309
310 /*
311 * Disgusting backwards compatibility hack. XXX
312 */
313 case '\0': /* compat */
314 return (EOF);
315 }
316
317 /*
318 * We have a conversion that requires input.
319 */
320 if (fp->_r <= 0 && __srefill(fp))
321 goto input_failure;
322
323 /*
324 * Consume leading white space, except for formats
325 * that suppress this.
326 */
327 if ((flags & NOSKIP) == 0) {
328 while (isspace(*fp->_p)) {
329 nread++;
330 if (--fp->_r > 0)
331 fp->_p++;
332 else if (__srefill(fp))
333 goto input_failure;
334 }
335 /*
336 * Note that there is at least one character in
337 * the buffer, so conversions that do not set NOSKIP
338 * ca no longer result in an input failure.
339 */
340 }
341
342 /*
343 * Do the conversion.
344 */
345 switch (c) {
346
347 case CT_CHAR:
348 /* scan arbitrary characters (sets NOSKIP) */
349 if (width == 0)
350 width = 1;
351 if (flags & LONG) {
352 if ((flags & SUPPRESS) == 0)
353 wcp = va_arg(ap, wchar_t *);
354 else
355 wcp = NULL;
356 n = 0;
357 while (width != 0) {
358 if (n == MB_CUR_MAX) {
359 fp->_flags |= __SERR;
360 goto input_failure;
361 }
362 buf[n++] = *fp->_p;
363 fp->_p++;
364 fp->_r--;
365 mbs = initial;
366 nconv = mbrtowc(wcp, buf, n, &mbs);
367 if (nconv == (size_t)-1) {
368 fp->_flags |= __SERR;
369 goto input_failure;
370 }
371 if (nconv == 0 && !(flags & SUPPRESS))
372 *wcp = L'\0';
373 if (nconv != (size_t)-2) {
374 nread += n;
375 width--;
376 if (!(flags & SUPPRESS))
377 wcp++;
378 n = 0;
379 }
380 if (fp->_r <= 0 && __srefill(fp)) {
381 if (n != 0) {
382 fp->_flags |= __SERR;
383 goto input_failure;
384 }
385 break;
386 }
387 }
388 if (!(flags & SUPPRESS))
389 nassigned++;
390 } else if (flags & SUPPRESS) {
391 size_t sum = 0;
392 for (;;) {
393 if ((n = fp->_r) < width) {
394 sum += n;
395 width -= n;
396 fp->_p += n;
397 if (__srefill(fp)) {
398 if (sum == 0)
399 goto input_failure;
400 break;
401 }
402 } else {
403 sum += width;
404 fp->_r -= width;
405 fp->_p += width;
406 break;
407 }
408 }
409 nread += sum;
410 } else {
411 size_t r = __fread((void *)va_arg(ap, char *), 1,
412 width, fp);
413
414 if (r == 0)
415 goto input_failure;
416 nread += r;
417 nassigned++;
418 }
419 nconversions++;
420 break;
421
422 case CT_CCL:
423 /* scan a (nonempty) character class (sets NOSKIP) */
424 if (width == 0)
425 width = (size_t)~0; /* `infinity' */
426 /* take only those things in the class */
427 if (flags & LONG) {
428 wchar_t twc;
429 int nchars;
430
431 if ((flags & SUPPRESS) == 0)
432 wcp = va_arg(ap, wchar_t *);
433 else
434 wcp = &twc;
435 n = 0;
436 nchars = 0;
437 while (width != 0) {
438 if (n == MB_CUR_MAX) {
439 fp->_flags |= __SERR;
440 goto input_failure;
441 }
442 buf[n++] = *fp->_p;
443 fp->_p++;
444 fp->_r--;
445 mbs = initial;
446 nconv = mbrtowc(wcp, buf, n, &mbs);
447 if (nconv == (size_t)-1) {
448 fp->_flags |= __SERR;
449 goto input_failure;
450 }
451 if (nconv == 0)
452 *wcp = L'\0';
453 if (nconv != (size_t)-2) {
454 if (wctob(*wcp) != EOF &&
455 !ccltab[wctob(*wcp)]) {
456 while (n != 0) {
457 n--;
458 __ungetc(buf[n],
459 fp);
460 }
461 break;
462 }
463 nread += n;
464 width--;
465 if (!(flags & SUPPRESS))
466 wcp++;
467 nchars++;
468 n = 0;
469 }
470 if (fp->_r <= 0 && __srefill(fp)) {
471 if (n != 0) {
472 fp->_flags |= __SERR;
473 goto input_failure;
474 }
475 break;
476 }
477 }
478 if (n != 0) {
479 fp->_flags |= __SERR;
480 goto input_failure;
481 }
482 n = nchars;
483 if (n == 0)
484 goto match_failure;
485 if (!(flags & SUPPRESS)) {
486 *wcp = L'\0';
487 nassigned++;
488 }
489 } else if (flags & SUPPRESS) {
490 n = 0;
491 while (ccltab[*fp->_p]) {
492 n++, fp->_r--, fp->_p++;
493 if (--width == 0)
494 break;
495 if (fp->_r <= 0 && __srefill(fp)) {
496 if (n == 0)
497 goto input_failure;
498 break;
499 }
500 }
501 if (n == 0)
502 goto match_failure;
503 } else {
504 p0 = p = va_arg(ap, char *);
505 while (ccltab[*fp->_p]) {
506 fp->_r--;
507 *p++ = *fp->_p++;
508 if (--width == 0)
509 break;
510 if (fp->_r <= 0 && __srefill(fp)) {
511 if (p == p0)
512 goto input_failure;
513 break;
514 }
515 }
516 n = p - p0;
517 if (n == 0)
518 goto match_failure;
519 *p = 0;
520 nassigned++;
521 }
522 nread += n;
523 nconversions++;
524 break;
525
526 case CT_STRING:
527 /* like CCL, but zero-length string OK, & no NOSKIP */
528 if (width == 0)
529 width = (size_t)~0;
530 if (flags & LONG) {
531 wchar_t twc;
532
533 if ((flags & SUPPRESS) == 0)
534 wcp = va_arg(ap, wchar_t *);
535 else
536 wcp = &twc;
537 n = 0;
538 while (!isspace(*fp->_p) && width != 0) {
539 if (n == MB_CUR_MAX) {
540 fp->_flags |= __SERR;
541 goto input_failure;
542 }
543 buf[n++] = *fp->_p;
544 fp->_p++;
545 fp->_r--;
546 mbs = initial;
547 nconv = mbrtowc(wcp, buf, n, &mbs);
548 if (nconv == (size_t)-1) {
549 fp->_flags |= __SERR;
550 goto input_failure;
551 }
552 if (nconv == 0)
553 *wcp = L'\0';
554 if (nconv != (size_t)-2) {
555 if (iswspace(*wcp)) {
556 while (n != 0) {
557 n--;
558 __ungetc(buf[n],
559 fp);
560 }
561 break;
562 }
563 nread += n;
564 width--;
565 if (!(flags & SUPPRESS))
566 wcp++;
567 n = 0;
568 }
569 if (fp->_r <= 0 && __srefill(fp)) {
570 if (n != 0) {
571 fp->_flags |= __SERR;
572 goto input_failure;
573 }
574 break;
575 }
576 }
577 if (!(flags & SUPPRESS)) {
578 *wcp = L'\0';
579 nassigned++;
580 }
581 } else if (flags & SUPPRESS) {
582 n = 0;
583 while (!isspace(*fp->_p)) {
584 n++, fp->_r--, fp->_p++;
585 if (--width == 0)
586 break;
587 if (fp->_r <= 0 && __srefill(fp))
588 break;
589 }
590 nread += n;
591 } else {
592 p0 = p = va_arg(ap, char *);
593 while (!isspace(*fp->_p)) {
594 fp->_r--;
595 *p++ = *fp->_p++;
596 if (--width == 0)
597 break;
598 if (fp->_r <= 0 && __srefill(fp))
599 break;
600 }
601 *p = 0;
602 nread += p - p0;
603 nassigned++;
604 }
605 nconversions++;
606 continue;
607
608 case CT_INT:
609 /* scan an integer as if by the conversion function */
610 #ifdef hardway
611 if (width == 0 || width > sizeof(buf) - 1)
612 width = sizeof(buf) - 1;
613 #else
614 /* size_t is unsigned, hence this optimisation */
615 if (--width > sizeof(buf) - 2)
616 width = sizeof(buf) - 2;
617 width++;
618 #endif
619 flags |= SIGNOK | NDIGITS | NZDIGITS;
620 for (p = buf; width; width--) {
621 c = *fp->_p;
622 /*
623 * Switch on the character; `goto ok'
624 * if we accept it as a part of number.
625 */
626 switch (c) {
627
628 /*
629 * The digit 0 is always legal, but is
630 * special. For %i conversions, if no
631 * digits (zero or nonzero) have been
632 * scanned (only signs), we will have
633 * base==0. In that case, we should set
634 * it to 8 and enable 0x prefixing.
635 * Also, if we have not scanned zero digits
636 * before this, do not turn off prefixing
637 * (someone else will turn it off if we
638 * have scanned any nonzero digits).
639 */
640 case '0':
641 if (base == 0) {
642 base = 8;
643 flags |= PFXOK;
644 }
645 if (flags & NZDIGITS)
646 flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
647 else
648 flags &= ~(SIGNOK|PFXOK|NDIGITS);
649 goto ok;
650
651 /* 1 through 7 always legal */
652 case '1': case '2': case '3':
653 case '4': case '5': case '6': case '7':
654 base = basefix[base];
655 flags &= ~(SIGNOK | PFXOK | NDIGITS);
656 goto ok;
657
658 /* digits 8 and 9 ok iff decimal or hex */
659 case '8': case '9':
660 base = basefix[base];
661 if (base <= 8)
662 break; /* not legal here */
663 flags &= ~(SIGNOK | PFXOK | NDIGITS);
664 goto ok;
665
666 /* letters ok iff hex */
667 case 'A': case 'B': case 'C':
668 case 'D': case 'E': case 'F':
669 case 'a': case 'b': case 'c':
670 case 'd': case 'e': case 'f':
671 /* no need to fix base here */
672 if (base <= 10)
673 break; /* not legal here */
674 flags &= ~(SIGNOK | PFXOK | NDIGITS);
675 goto ok;
676
677 /* sign ok only as first character */
678 case '+': case '-':
679 if (flags & SIGNOK) {
680 flags &= ~SIGNOK;
681 flags |= HAVESIGN;
682 goto ok;
683 }
684 break;
685
686 /*
687 * x ok iff flag still set & 2nd char (or
688 * 3rd char if we have a sign).
689 */
690 case 'x': case 'X':
691 if (flags & PFXOK && p ==
692 buf + 1 + !!(flags & HAVESIGN)) {
693 base = 16; /* if %i */
694 flags &= ~PFXOK;
695 goto ok;
696 }
697 break;
698 }
699
700 /*
701 * If we got here, c is not a legal character
702 * for a number. Stop accumulating digits.
703 */
704 break;
705 ok:
706 /*
707 * c is legal: store it and look at the next.
708 */
709 *p++ = c;
710 if (--fp->_r > 0)
711 fp->_p++;
712 else if (__srefill(fp))
713 break; /* EOF */
714 }
715 /*
716 * If we had only a sign, it is no good; push
717 * back the sign. If the number ends in `x',
718 * it was [sign] '0' 'x', so push back the x
719 * and treat it as [sign] '0'.
720 */
721 if (flags & NDIGITS) {
722 if (p > buf)
723 (void) __ungetc(*(u_char *)--p, fp);
724 goto match_failure;
725 }
726 c = ((u_char *)p)[-1];
727 if (c == 'x' || c == 'X') {
728 --p;
729 (void) __ungetc(c, fp);
730 }
731 if ((flags & SUPPRESS) == 0) {
732 uintmax_t res;
733
734 *p = 0;
735 if ((flags & UNSIGNED) == 0)
736 res = strtoimax(buf, (char **)NULL, base);
737 else
738 res = strtoumax(buf, (char **)NULL, base);
739 if (flags & POINTER)
740 *va_arg(ap, void **) =
741 (void *)(uintptr_t)res;
742 else if (flags & SHORTSHORT)
743 *va_arg(ap, char *) = res;
744 else if (flags & SHORT)
745 *va_arg(ap, short *) = res;
746 else if (flags & LONG)
747 *va_arg(ap, long *) = res;
748 else if (flags & LONGLONG)
749 *va_arg(ap, long long *) = res;
750 else if (flags & INTMAXT)
751 *va_arg(ap, intmax_t *) = res;
752 else if (flags & PTRDIFFT)
753 *va_arg(ap, ptrdiff_t *) = res;
754 else if (flags & SIZET)
755 *va_arg(ap, size_t *) = res;
756 else
757 *va_arg(ap, int *) = res;
758 nassigned++;
759 }
760 nread += p - buf;
761 nconversions++;
762 break;
763
764 #ifndef NO_FLOATING_POINT
765 case CT_FLOAT:
766 /* scan a floating point number as if by strtod */
767 if (width == 0 || width > sizeof(buf) - 1)
768 width = sizeof(buf) - 1;
769 if ((width = parsefloat(fp, buf, buf + width)) == 0)
770 goto match_failure;
771 if ((flags & SUPPRESS) == 0) {
772 if (flags & LONGDBL) {
773 long double res = strtold(buf, &p);
774 *va_arg(ap, long double *) = res;
775 } else if (flags & LONG) {
776 double res = strtod(buf, &p);
777 *va_arg(ap, double *) = res;
778 } else {
779 float res = strtof(buf, &p);
780 *va_arg(ap, float *) = res;
781 }
782 nassigned++;
783 }
784 nread += width;
785 nconversions++;
786 break;
787 #endif /* !NO_FLOATING_POINT */
788 }
789 }
790 input_failure:
791 return (nconversions != 0 ? nassigned : EOF);
792 match_failure:
793 return (nassigned);
794 }
795
796 /*
797 * Fill in the given table from the scanset at the given format
798 * (just after `['). Return a pointer to the character past the
799 * closing `]'. The table has a 1 wherever characters should be
800 * considered part of the scanset.
801 */
802 static const u_char *
803 __sccl(tab, fmt)
804 char *tab;
805 const u_char *fmt;
806 {
807 int c, n, v, i;
808
809 /* first `clear' the whole table */
810 c = *fmt++; /* first char hat => negated scanset */
811 if (c == '^') {
812 v = 1; /* default => accept */
813 c = *fmt++; /* get new first char */
814 } else
815 v = 0; /* default => reject */
816
817 /* XXX: Will not work if sizeof(tab*) > sizeof(char) */
818 (void) memset(tab, v, 256);
819
820 if (c == 0)
821 return (fmt - 1);/* format ended before closing ] */
822
823 /*
824 * Now set the entries corresponding to the actual scanset
825 * to the opposite of the above.
826 *
827 * The first character may be ']' (or '-') without being special;
828 * the last character may be '-'.
829 */
830 v = 1 - v;
831 for (;;) {
832 tab[c] = v; /* take character c */
833 doswitch:
834 n = *fmt++; /* and examine the next */
835 switch (n) {
836
837 case 0: /* format ended too soon */
838 return (fmt - 1);
839
840 case '-':
841 /*
842 * A scanset of the form
843 * [01+-]
844 * is defined as `the digit 0, the digit 1,
845 * the character +, the character -', but
846 * the effect of a scanset such as
847 * [a-zA-Z0-9]
848 * is implementation defined. The V7 Unix
849 * scanf treats `a-z' as `the letters a through
850 * z', but treats `a-a' as `the letter a, the
851 * character -, and the letter a'.
852 *
853 * For compatibility, the `-' is not considerd
854 * to define a range if the character following
855 * it is either a close bracket (required by ANSI)
856 * or is not numerically greater than the character
857 * we just stored in the table (c).
858 */
859 n = *fmt;
860 if (n == ']'
861 || (__collate_load_error ? n < c :
862 __collate_range_cmp (n, c) < 0
863 )
864 ) {
865 c = '-';
866 break; /* resume the for(;;) */
867 }
868 fmt++;
869 /* fill in the range */
870 if (__collate_load_error) {
871 do {
872 tab[++c] = v;
873 } while (c < n);
874 } else {
875 for (i = 0; i < 256; i ++)
876 if ( __collate_range_cmp (c, i) < 0
877 && __collate_range_cmp (i, n) <= 0
878 )
879 tab[i] = v;
880 }
881 #if 1 /* XXX another disgusting compatibility hack */
882 c = n;
883 /*
884 * Alas, the V7 Unix scanf also treats formats
885 * such as [a-c-e] as `the letters a through e'.
886 * This too is permitted by the standard....
887 */
888 goto doswitch;
889 #else
890 c = *fmt++;
891 if (c == 0)
892 return (fmt - 1);
893 if (c == ']')
894 return (fmt);
895 #endif
896 break;
897
898 case ']': /* end of scanset */
899 return (fmt);
900
901 default: /* just another character */
902 c = n;
903 break;
904 }
905 }
906 /* NOTREACHED */
907 }
908
909 #ifndef NO_FLOATING_POINT
910 static int
911 parsefloat(FILE *fp, char *buf, char *end)
912 {
913 char *commit, *p;
914 int infnanpos = 0, decptpos = 0;
915 enum {
916 S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX,
917 S_DIGITS, S_DECPT, S_FRAC, S_EXP, S_EXPDIGITS
918 } state = S_START;
919 unsigned char c;
920 const char *decpt = localeconv()->decimal_point;
921 _Bool gotmantdig = 0, ishex = 0;
922
923 /*
924 * We set commit = p whenever the string we have read so far
925 * constitutes a valid representation of a floating point
926 * number by itself. At some point, the parse will complete
927 * or fail, and we will ungetc() back to the last commit point.
928 * To ensure that the file offset gets updated properly, it is
929 * always necessary to read at least one character that doesn't
930 * match; thus, we can't short-circuit "infinity" or "nan(...)".
931 */
932 commit = buf - 1;
933 for (p = buf; p < end; ) {
934 c = *fp->_p;
935 reswitch:
936 switch (state) {
937 case S_START:
938 state = S_GOTSIGN;
939 if (c == '-' || c == '+')
940 break;
941 else
942 goto reswitch;
943 case S_GOTSIGN:
944 switch (c) {
945 case '0':
946 state = S_MAYBEHEX;
947 commit = p;
948 break;
949 case 'I':
950 case 'i':
951 state = S_INF;
952 break;
953 case 'N':
954 case 'n':
955 state = S_NAN;
956 break;
957 default:
958 state = S_DIGITS;
959 goto reswitch;
960 }
961 break;
962 case S_INF:
963 if (infnanpos > 6 ||
964 (c != "nfinity"[infnanpos] &&
965 c != "NFINITY"[infnanpos]))
966 goto parsedone;
967 if (infnanpos == 1 || infnanpos == 6)
968 commit = p; /* inf or infinity */
969 infnanpos++;
970 break;
971 case S_NAN:
972 switch (infnanpos) {
973 case 0:
974 if (c != 'A' && c != 'a')
975 goto parsedone;
976 break;
977 case 1:
978 if (c != 'N' && c != 'n')
979 goto parsedone;
980 else
981 commit = p;
982 break;
983 case 2:
984 if (c != '(')
985 goto parsedone;
986 break;
987 default:
988 if (c == ')') {
989 commit = p;
990 state = S_DONE;
991 } else if (!isalnum(c) && c != '_')
992 goto parsedone;
993 break;
994 }
995 infnanpos++;
996 break;
997 case S_DONE:
998 goto parsedone;
999 case S_MAYBEHEX:
1000 state = S_DIGITS;
1001 if (c == 'X' || c == 'x') {
1002 ishex = 1;
1003 break;
1004 } else { /* we saw a '0', but no 'x' */
1005 gotmantdig = 1;
1006 goto reswitch;
1007 }
1008 case S_DIGITS:
1009 if ((ishex && isxdigit(c)) || isdigit(c)) {
1010 gotmantdig = 1;
1011 commit = p;
1012 break;
1013 } else {
1014 state = S_DECPT;
1015 goto reswitch;
1016 }
1017 case S_DECPT:
1018 if (c == decpt[decptpos]) {
1019 if (decpt[++decptpos] == '\0') {
1020 /* We read the complete decpt seq. */
1021 state = S_FRAC;
1022 if (gotmantdig)
1023 commit = p;
1024 }
1025 break;
1026 } else if (!decptpos) {
1027 /* We didn't read any decpt characters. */
1028 state = S_FRAC;
1029 goto reswitch;
1030 } else {
1031 /*
1032 * We read part of a multibyte decimal point,
1033 * but the rest is invalid, so bail.
1034 */
1035 goto parsedone;
1036 }
1037 case S_FRAC:
1038 if (((c == 'E' || c == 'e') && !ishex) ||
1039 ((c == 'P' || c == 'p') && ishex)) {
1040 if (!gotmantdig)
1041 goto parsedone;
1042 else
1043 state = S_EXP;
1044 } else if ((ishex && isxdigit(c)) || isdigit(c)) {
1045 commit = p;
1046 gotmantdig = 1;
1047 } else
1048 goto parsedone;
1049 break;
1050 case S_EXP:
1051 state = S_EXPDIGITS;
1052 if (c == '-' || c == '+')
1053 break;
1054 else
1055 goto reswitch;
1056 case S_EXPDIGITS:
1057 if (isdigit(c))
1058 commit = p;
1059 else
1060 goto parsedone;
1061 break;
1062 default:
1063 abort();
1064 }
1065 *p++ = c;
1066 if (--fp->_r > 0)
1067 fp->_p++;
1068 else if (__srefill(fp))
1069 break; /* EOF */
1070 }
1071
1072 parsedone:
1073 while (commit < --p)
1074 __ungetc(*(u_char *)p, fp);
1075 *++commit = '\0';
1076 return (commit - buf);
1077 }
1078 #endif