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