]> git.saurik.com Git - apple/libc.git/blob - stdio/vfscanf-fbsd.c
Libc-498.1.5.tar.gz
[apple/libc.git] / stdio / vfscanf-fbsd.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.37 2004/05/02 10:55:05 das Exp $");
42
43 #include "xlocale_private.h"
44
45 #include "namespace.h"
46 #include <ctype.h>
47 #include <inttypes.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <stddef.h>
51 #include <stdarg.h>
52 #include <string.h>
53 #include <wchar.h>
54 #include <wctype.h>
55 #include "un-namespace.h"
56
57 #include "collate.h"
58 #include "libc_private.h"
59 #include "local.h"
60
61 #ifndef NO_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 #define HAVESIGN 0x10000 /* sign detected */
92
93 /*
94 * Conversion types.
95 */
96 #define CT_CHAR 0 /* %c conversion */
97 #define CT_CCL 1 /* %[...] conversion */
98 #define CT_STRING 2 /* %s conversion */
99 #define CT_INT 3 /* %[dioupxX] conversion */
100 #define CT_FLOAT 4 /* %[efgEFG] conversion */
101
102 static const u_char *__sccl(char *, const u_char *, locale_t);
103 #ifndef NO_FLOATING_POINT
104 static int parsefloat(FILE *, char **, size_t, locale_t);
105 #endif /* !NO_FLOATING_POINT */
106
107 /*
108 * For ppc, we need to have the 64-bit long double version defining storage for
109 * __scanfdebug, to be compatible with 10.3. For ppc64 and i386, we want the
110 * storage defined in the only version.
111 */
112 #if defined(__ppc__) && !defined(BUILDING_VARIANT)
113 extern int __scanfdebug;
114 #else /* !__ppc__ || BUILDING_VARIANT */
115 int __scanfdebug = 0;
116 #endif /* __ppc__ && !BUILDING_VARIANT */
117
118 __weak_reference(__vfscanf, vfscanf);
119
120 /*
121 * __vfscanf - MT-safe version
122 */
123 int
124 __vfscanf(FILE * __restrict fp, char const * __restrict fmt0, va_list ap)
125 {
126 int ret;
127
128 FLOCKFILE(fp);
129 ret = __svfscanf_l(fp, __current_locale(), fmt0, ap);
130 FUNLOCKFILE(fp);
131 return (ret);
132 }
133
134 int
135 vfscanf_l(FILE * __restrict fp, locale_t loc, char const * __restrict fmt0, va_list ap)
136 {
137 int ret;
138
139 NORMALIZE_LOCALE(loc);
140 FLOCKFILE(fp);
141 ret = __svfscanf_l(fp, loc, fmt0, ap);
142 FUNLOCKFILE(fp);
143 return (ret);
144 }
145
146 /*
147 * __svfscanf - non-MT-safe version of __vfscanf
148 */
149 __private_extern__ int
150 __svfscanf_l(FILE * __restrict fp, locale_t loc, const char * __restrict fmt0, va_list ap)
151 {
152 const u_char *fmt = (const u_char *)fmt0;
153 int c; /* character from format, or conversion */
154 size_t width; /* field width, or 0 */
155 char *p; /* points into all kinds of strings */
156 int n; /* handy integer */
157 int flags; /* flags as defined above */
158 char *p0; /* saves original value of p when necessary */
159 int nassigned; /* number of fields assigned */
160 int nread; /* number of characters consumed from fp */
161 int base; /* base argument to conversion function */
162 char ccltab[256]; /* character class table for %[...] */
163 char buf[BUF]; /* buffer for numeric and mb conversions */
164 wchar_t *wcp; /* handy wide character pointer */
165 wchar_t *wcp0; /* saves original value of wcp */
166 size_t nconv; /* length of multibyte sequence converted */
167 int index; /* %index$, zero if unset */
168 va_list ap_orig; /* to reset ap to first argument */
169 static const mbstate_t initial;
170 mbstate_t mbs;
171 int mb_cur_max;
172
173 /* `basefix' is used to avoid `if' tests in the integer scanner */
174 static short basefix[17] =
175 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
176
177 NORMALIZE_LOCALE(loc);
178 mb_cur_max = MB_CUR_MAX_L(loc);
179 ORIENT(fp, -1);
180
181 nassigned = 0;
182 nread = 0;
183 va_copy(ap_orig, ap);
184 for (;;) {
185 c = *fmt++;
186 if (c == 0)
187 return (nassigned);
188 if (isspace_l(c, loc)) {
189 while ((fp->_r > 0 || __srefill(fp) == 0) && isspace_l(*fp->_p, loc))
190 nread++, fp->_r--, fp->_p++;
191 continue;
192 }
193 if (c != '%')
194 goto literal;
195 width = 0;
196 flags = 0;
197 /*
198 * switch on the format. continue if done;
199 * break once format type is derived.
200 */
201 again: c = *fmt++;
202 switch (c) {
203 case '%':
204 literal:
205 if (fp->_r <= 0 && __srefill(fp))
206 goto input_failure;
207 if (*fp->_p != c)
208 goto match_failure;
209 fp->_r--, fp->_p++;
210 nread++;
211 continue;
212
213 case '$':
214 index = width;
215 if (index < 1 || index > NL_ARGMAX || fmt[-3] != '%') {
216 goto input_failure;
217 }
218 width = 0;
219 va_end(ap);
220 va_copy(ap, ap_orig); /* reset to %1$ */
221 for (; index > 1; index--) {
222 va_arg(ap, void*);
223 }
224 goto again;
225 case '*':
226 flags |= SUPPRESS;
227 goto again;
228 case 'j':
229 flags |= INTMAXT;
230 goto again;
231 case 'l':
232 if (flags & LONG) {
233 flags &= ~LONG;
234 flags |= LONGLONG;
235 } else
236 flags |= LONG;
237 goto again;
238 case 'q':
239 flags |= LONGLONG; /* not quite */
240 goto again;
241 case 't':
242 flags |= PTRDIFFT;
243 goto again;
244 case 'z':
245 flags |= SIZET;
246 goto again;
247 case 'L':
248 flags |= LONGDBL;
249 goto again;
250 case 'h':
251 if (flags & SHORT) {
252 flags &= ~SHORT;
253 flags |= SHORTSHORT;
254 } else
255 flags |= SHORT;
256 goto again;
257
258 case '0': case '1': case '2': case '3': case '4':
259 case '5': case '6': case '7': case '8': case '9':
260 width = width * 10 + c - '0';
261 goto again;
262
263 /*
264 * Conversions.
265 */
266 case 'd':
267 c = CT_INT;
268 base = 10;
269 break;
270
271 case 'i':
272 c = CT_INT;
273 base = 0;
274 break;
275
276 case 'o':
277 c = CT_INT;
278 flags |= UNSIGNED;
279 base = 8;
280 break;
281
282 case 'u':
283 c = CT_INT;
284 flags |= UNSIGNED;
285 base = 10;
286 break;
287
288 case 'X':
289 case 'x':
290 flags |= PFXOK; /* enable 0x prefixing */
291 c = CT_INT;
292 flags |= UNSIGNED;
293 base = 16;
294 break;
295
296 #ifndef NO_FLOATING_POINT
297 case 'A': case 'E': case 'F': case 'G':
298 case 'a': case 'e': case 'f': case 'g':
299 c = CT_FLOAT;
300 break;
301 #endif
302
303 case 'S':
304 flags |= LONG;
305 /* FALLTHROUGH */
306 case 's':
307 c = CT_STRING;
308 break;
309
310 case '[':
311 fmt = __sccl(ccltab, fmt, loc);
312 flags |= NOSKIP;
313 c = CT_CCL;
314 break;
315
316 case 'C':
317 flags |= LONG;
318 /* FALLTHROUGH */
319 case 'c':
320 flags |= NOSKIP;
321 c = CT_CHAR;
322 break;
323
324 case 'p': /* pointer format is like hex */
325 flags |= POINTER | PFXOK;
326 c = CT_INT; /* assumes sizeof(uintmax_t) */
327 flags |= UNSIGNED; /* >= sizeof(uintptr_t) */
328 base = 16;
329 break;
330
331 case 'n':
332 if (flags & SUPPRESS) /* ??? */
333 continue;
334 if (flags & SHORTSHORT)
335 *va_arg(ap, char *) = nread;
336 else if (flags & SHORT)
337 *va_arg(ap, short *) = nread;
338 else if (flags & LONG)
339 *va_arg(ap, long *) = nread;
340 else if (flags & LONGLONG)
341 *va_arg(ap, long long *) = nread;
342 else if (flags & INTMAXT)
343 *va_arg(ap, intmax_t *) = nread;
344 else if (flags & SIZET)
345 *va_arg(ap, size_t *) = nread;
346 else if (flags & PTRDIFFT)
347 *va_arg(ap, ptrdiff_t *) = nread;
348 else
349 *va_arg(ap, int *) = nread;
350 continue;
351
352 default:
353 goto match_failure;
354
355 /*
356 * Disgusting backwards compatibility hack. XXX
357 */
358 case '\0': /* compat */
359 return (EOF);
360 }
361
362 /*
363 * We have a conversion that requires input.
364 */
365 if (fp->_r <= 0 && __srefill(fp))
366 goto input_failure;
367
368 /*
369 * Consume leading white space, except for formats
370 * that suppress this.
371 */
372 if ((flags & NOSKIP) == 0) {
373 while (isspace_l(*fp->_p, loc)) {
374 nread++;
375 if (--fp->_r > 0)
376 fp->_p++;
377 else if (__srefill(fp))
378 goto input_failure;
379 }
380 /*
381 * Note that there is at least one character in
382 * the buffer, so conversions that do not set NOSKIP
383 * ca no longer result in an input failure.
384 */
385 }
386
387 /*
388 * Do the conversion.
389 */
390 switch (c) {
391
392 case CT_CHAR:
393 /* scan arbitrary characters (sets NOSKIP) */
394 if (width == 0)
395 width = 1;
396 if (flags & LONG) {
397 if ((flags & SUPPRESS) == 0)
398 wcp = va_arg(ap, wchar_t *);
399 else
400 wcp = NULL;
401 n = 0;
402 while (width != 0) {
403 if (n == mb_cur_max) {
404 fp->_flags |= __SERR;
405 goto input_failure;
406 }
407 buf[n++] = *fp->_p;
408 fp->_p++;
409 fp->_r--;
410 mbs = initial;
411 nconv = mbrtowc_l(wcp, buf, n, &mbs, loc);
412 if (nconv == (size_t)-1) {
413 fp->_flags |= __SERR;
414 goto input_failure;
415 }
416 if (nconv == 0 && !(flags & SUPPRESS))
417 *wcp = L'\0';
418 if (nconv != (size_t)-2) {
419 nread += n;
420 width--;
421 if (!(flags & SUPPRESS))
422 wcp++;
423 n = 0;
424 }
425 if (fp->_r <= 0 && __srefill(fp)) {
426 if (n != 0) {
427 fp->_flags |= __SERR;
428 goto input_failure;
429 }
430 break;
431 }
432 }
433 if (!(flags & SUPPRESS))
434 nassigned++;
435 } else if (flags & SUPPRESS) {
436 size_t sum = 0;
437 for (;;) {
438 if ((n = fp->_r) < width) {
439 sum += n;
440 width -= n;
441 fp->_p += n;
442 if (__srefill(fp)) {
443 if (sum == 0)
444 goto input_failure;
445 break;
446 }
447 } else {
448 sum += width;
449 fp->_r -= width;
450 fp->_p += width;
451 break;
452 }
453 }
454 nread += sum;
455 } else {
456 size_t r = fread((void *)va_arg(ap, char *), 1,
457 width, fp);
458
459 if (r == 0)
460 goto input_failure;
461 nread += r;
462 nassigned++;
463 }
464 break;
465
466 case CT_CCL:
467 /* scan a (nonempty) character class (sets NOSKIP) */
468 if (width == 0)
469 width = (size_t)~0; /* `infinity' */
470 /* take only those things in the class */
471 if (flags & LONG) {
472 wchar_t twc;
473 int nchars;
474
475 if ((flags & SUPPRESS) == 0)
476 wcp = wcp0 = va_arg(ap, wchar_t *);
477 else
478 wcp = wcp0 = &twc;
479 n = 0;
480 nchars = 0;
481 while (width != 0) {
482 if (n == mb_cur_max) {
483 fp->_flags |= __SERR;
484 goto input_failure;
485 }
486 buf[n++] = *fp->_p;
487 fp->_p++;
488 fp->_r--;
489 mbs = initial;
490 nconv = mbrtowc_l(wcp, buf, n, &mbs, loc);
491 if (nconv == (size_t)-1) {
492 fp->_flags |= __SERR;
493 goto input_failure;
494 }
495 if (nconv == 0)
496 *wcp = L'\0';
497 if (nconv != (size_t)-2) {
498 if (wctob_l(*wcp, loc) != EOF &&
499 !ccltab[wctob_l(*wcp, loc)]) {
500 while (n != 0) {
501 n--;
502 __ungetc(buf[n],
503 fp);
504 }
505 break;
506 }
507 nread += n;
508 width--;
509 if (!(flags & SUPPRESS))
510 wcp++;
511 nchars++;
512 n = 0;
513 }
514 if (fp->_r <= 0 && __srefill(fp)) {
515 if (n != 0) {
516 fp->_flags |= __SERR;
517 goto input_failure;
518 }
519 break;
520 }
521 }
522 if (n != 0) {
523 fp->_flags |= __SERR;
524 goto input_failure;
525 }
526 n = nchars;
527 if (n == 0)
528 goto match_failure;
529 if (!(flags & SUPPRESS)) {
530 *wcp = L'\0';
531 nassigned++;
532 }
533 } else if (flags & SUPPRESS) {
534 n = 0;
535 while (ccltab[*fp->_p]) {
536 n++, fp->_r--, fp->_p++;
537 if (--width == 0)
538 break;
539 if (fp->_r <= 0 && __srefill(fp)) {
540 if (n == 0)
541 goto input_failure;
542 break;
543 }
544 }
545 if (n == 0)
546 goto match_failure;
547 } else {
548 p0 = p = va_arg(ap, char *);
549 while (ccltab[*fp->_p]) {
550 fp->_r--;
551 *p++ = *fp->_p++;
552 if (--width == 0)
553 break;
554 if (fp->_r <= 0 && __srefill(fp)) {
555 if (p == p0)
556 goto input_failure;
557 break;
558 }
559 }
560 n = p - p0;
561 if (n == 0)
562 goto match_failure;
563 *p = 0;
564 nassigned++;
565 }
566 nread += n;
567 break;
568
569 case CT_STRING:
570 /* like CCL, but zero-length string OK, & no NOSKIP */
571 if (width == 0)
572 width = (size_t)~0;
573 if (flags & LONG) {
574 wchar_t twc;
575
576 if ((flags & SUPPRESS) == 0)
577 wcp = va_arg(ap, wchar_t *);
578 else
579 wcp = &twc;
580 n = 0;
581 while (width != 0) {
582 if (n == mb_cur_max) {
583 fp->_flags |= __SERR;
584 goto input_failure;
585 }
586 buf[n++] = *fp->_p;
587 fp->_p++;
588 fp->_r--;
589 mbs = initial;
590 nconv = mbrtowc_l(wcp, buf, n, &mbs, loc);
591 if (nconv == (size_t)-1) {
592 fp->_flags |= __SERR;
593 goto input_failure;
594 }
595 if (nconv == 0)
596 *wcp = L'\0';
597 if (nconv != (size_t)-2) {
598 if (iswspace_l(*wcp, loc)) {
599 while (n != 0) {
600 n--;
601 __ungetc(buf[n],
602 fp);
603 }
604 break;
605 }
606 nread += n;
607 width--;
608 if (!(flags & SUPPRESS))
609 wcp++;
610 n = 0;
611 }
612 if (fp->_r <= 0 && __srefill(fp)) {
613 if (n != 0) {
614 fp->_flags |= __SERR;
615 goto input_failure;
616 }
617 break;
618 }
619 }
620 if (!(flags & SUPPRESS)) {
621 *wcp = L'\0';
622 nassigned++;
623 }
624 } else if (flags & SUPPRESS) {
625 n = 0;
626 while (!isspace_l(*fp->_p, loc)) {
627 n++, fp->_r--, fp->_p++;
628 if (--width == 0)
629 break;
630 if (fp->_r <= 0 && __srefill(fp))
631 break;
632 }
633 nread += n;
634 } else {
635 p0 = p = va_arg(ap, char *);
636 while (!isspace_l(*fp->_p, loc)) {
637 fp->_r--;
638 *p++ = *fp->_p++;
639 if (--width == 0)
640 break;
641 if (fp->_r <= 0 && __srefill(fp))
642 break;
643 }
644 *p = 0;
645 nread += p - p0;
646 nassigned++;
647 }
648 continue;
649
650 case CT_INT:
651 /* scan an integer as if by the conversion function */
652 #ifdef hardway
653 if (width == 0 || width > sizeof(buf) - 1)
654 width = sizeof(buf) - 1;
655 #else
656 /* size_t is unsigned, hence this optimisation */
657 if (--width > sizeof(buf) - 2)
658 width = sizeof(buf) - 2;
659 width++;
660 #endif
661 flags |= SIGNOK | NDIGITS | NZDIGITS;
662 for (p = buf; width; width--) {
663 c = *fp->_p;
664 /*
665 * Switch on the character; `goto ok'
666 * if we accept it as a part of number.
667 */
668 switch (c) {
669
670 /*
671 * The digit 0 is always legal, but is
672 * special. For %i conversions, if no
673 * digits (zero or nonzero) have been
674 * scanned (only signs), we will have
675 * base==0. In that case, we should set
676 * it to 8 and enable 0x prefixing.
677 * Also, if we have not scanned zero digits
678 * before this, do not turn off prefixing
679 * (someone else will turn it off if we
680 * have scanned any nonzero digits).
681 */
682 case '0':
683 if (base == 0) {
684 base = 8;
685 flags |= PFXOK;
686 }
687 if (flags & NZDIGITS)
688 flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
689 else
690 flags &= ~(SIGNOK|PFXOK|NDIGITS);
691 goto ok;
692
693 /* 1 through 7 always legal */
694 case '1': case '2': case '3':
695 case '4': case '5': case '6': case '7':
696 base = basefix[base];
697 flags &= ~(SIGNOK | PFXOK | NDIGITS);
698 goto ok;
699
700 /* digits 8 and 9 ok iff decimal or hex */
701 case '8': case '9':
702 base = basefix[base];
703 if (base <= 8)
704 break; /* not legal here */
705 flags &= ~(SIGNOK | PFXOK | NDIGITS);
706 goto ok;
707
708 /* letters ok iff hex */
709 case 'A': case 'B': case 'C':
710 case 'D': case 'E': case 'F':
711 case 'a': case 'b': case 'c':
712 case 'd': case 'e': case 'f':
713 /* no need to fix base here */
714 if (base <= 10)
715 break; /* not legal here */
716 flags &= ~(SIGNOK | PFXOK | NDIGITS);
717 goto ok;
718
719 /* sign ok only as first character */
720 case '+': case '-':
721 if (flags & SIGNOK) {
722 flags &= ~SIGNOK;
723 flags |= HAVESIGN;
724 goto ok;
725 }
726 break;
727
728 /*
729 * x ok iff flag still set & 2nd char (or
730 * 3rd char if we have a sign).
731 */
732 case 'x': case 'X':
733 if (flags & PFXOK && p ==
734 buf + 1 + !!(flags & HAVESIGN)) {
735 base = 16; /* if %i */
736 flags &= ~PFXOK;
737 goto ok;
738 }
739 break;
740 }
741
742 /*
743 * If we got here, c is not a legal character
744 * for a number. Stop accumulating digits.
745 */
746 break;
747 ok:
748 /*
749 * c is legal: store it and look at the next.
750 */
751 *p++ = c;
752 if (--fp->_r > 0)
753 fp->_p++;
754 else if (__srefill(fp))
755 break; /* EOF */
756 }
757 /*
758 * If we had only a sign, it is no good; push
759 * back the sign. If the number ends in `x',
760 * it was [sign] '0' 'x', so push back the x
761 * and treat it as [sign] '0'.
762 */
763 if (flags & NDIGITS) {
764 if (p > buf)
765 (void) __ungetc(*(u_char *)--p, fp);
766 goto match_failure;
767 }
768 c = ((u_char *)p)[-1];
769 if (c == 'x' || c == 'X') {
770 --p;
771 (void) __ungetc(c, fp);
772 }
773 if ((flags & SUPPRESS) == 0) {
774 uintmax_t res;
775
776 *p = 0;
777 if ((flags & UNSIGNED) == 0)
778 res = strtoimax_l(buf, (char **)NULL, base, loc);
779 else
780 res = strtoumax_l(buf, (char **)NULL, base, loc);
781 if (flags & POINTER)
782 *va_arg(ap, void **) =
783 (void *)(uintptr_t)res;
784 else if (flags & SHORTSHORT)
785 *va_arg(ap, char *) = res;
786 else if (flags & SHORT)
787 *va_arg(ap, short *) = res;
788 else if (flags & LONG)
789 *va_arg(ap, long *) = res;
790 else if (flags & LONGLONG)
791 *va_arg(ap, long long *) = res;
792 else if (flags & INTMAXT)
793 *va_arg(ap, intmax_t *) = res;
794 else if (flags & PTRDIFFT)
795 *va_arg(ap, ptrdiff_t *) = res;
796 else if (flags & SIZET)
797 *va_arg(ap, size_t *) = res;
798 else
799 *va_arg(ap, int *) = res;
800 nassigned++;
801 }
802 nread += p - buf;
803 break;
804
805 #ifndef NO_FLOATING_POINT
806 case CT_FLOAT:
807 {
808 char *pbuf;
809 /* scan a floating point number as if by strtod */
810 if ((width = parsefloat(fp, &pbuf, width, loc)) == 0)
811 goto match_failure;
812 if ((flags & SUPPRESS) == 0) {
813 if (flags & LONGDBL) {
814 long double res = strtold_l(pbuf, &p, loc);
815 *va_arg(ap, long double *) = res;
816 } else if (flags & LONG) {
817 double res = strtod_l(pbuf, &p, loc);
818 *va_arg(ap, double *) = res;
819 } else {
820 float res = strtof_l(pbuf, &p, loc);
821 *va_arg(ap, float *) = res;
822 }
823 if (__scanfdebug && p - pbuf != width)
824 abort();
825 nassigned++;
826 }
827 nread += width;
828 break;
829 }
830 #endif /* !NO_FLOATING_POINT */
831 }
832 }
833 input_failure:
834 return (nassigned ? nassigned : EOF);
835 match_failure:
836 return (nassigned);
837 }
838
839 int
840 __svfscanf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
841 {
842 return __svfscanf_l(fp, __current_locale(), fmt0, ap);
843 }
844
845 /*
846 * Fill in the given table from the scanset at the given format
847 * (just after `['). Return a pointer to the character past the
848 * closing `]'. The table has a 1 wherever characters should be
849 * considered part of the scanset.
850 */
851 static const u_char *
852 __sccl(tab, fmt, loc)
853 char *tab;
854 const u_char *fmt;
855 locale_t loc;
856 {
857 int c, n, v, i;
858
859 /* first `clear' the whole table */
860 c = *fmt++; /* first char hat => negated scanset */
861 if (c == '^') {
862 v = 1; /* default => accept */
863 c = *fmt++; /* get new first char */
864 } else
865 v = 0; /* default => reject */
866
867 /* XXX: Will not work if sizeof(tab*) > sizeof(char) */
868 (void) memset(tab, v, 256);
869
870 if (c == 0)
871 return (fmt - 1);/* format ended before closing ] */
872
873 /*
874 * Now set the entries corresponding to the actual scanset
875 * to the opposite of the above.
876 *
877 * The first character may be ']' (or '-') without being special;
878 * the last character may be '-'.
879 */
880 v = 1 - v;
881 for (;;) {
882 tab[c] = v; /* take character c */
883 doswitch:
884 n = *fmt++; /* and examine the next */
885 switch (n) {
886
887 case 0: /* format ended too soon */
888 return (fmt - 1);
889
890 case '-':
891 {
892 /*
893 * A scanset of the form
894 * [01+-]
895 * is defined as `the digit 0, the digit 1,
896 * the character +, the character -', but
897 * the effect of a scanset such as
898 * [a-zA-Z0-9]
899 * is implementation defined. The V7 Unix
900 * scanf treats `a-z' as `the letters a through
901 * z', but treats `a-a' as `the letter a, the
902 * character -, and the letter a'.
903 *
904 * For compatibility, the `-' is not considerd
905 * to define a range if the character following
906 * it is either a close bracket (required by ANSI)
907 * or is not numerically greater than the character
908 * we just stored in the table (c).
909 */
910 n = *fmt;
911 if (n == ']'
912 || (loc->__collate_load_error ? n < c :
913 __collate_range_cmp (n, c, loc) < 0
914 )
915 ) {
916 c = '-';
917 break; /* resume the for(;;) */
918 }
919 fmt++;
920 /* fill in the range */
921 if (loc->__collate_load_error) {
922 do {
923 tab[++c] = v;
924 } while (c < n);
925 } else {
926 for (i = 0; i < 256; i ++)
927 if ( __collate_range_cmp (c, i, loc) < 0
928 && __collate_range_cmp (i, n, loc) <= 0
929 )
930 tab[i] = v;
931 }
932 #if 1 /* XXX another disgusting compatibility hack */
933 c = n;
934 /*
935 * Alas, the V7 Unix scanf also treats formats
936 * such as [a-c-e] as `the letters a through e'.
937 * This too is permitted by the standard....
938 */
939 goto doswitch;
940 #else
941 c = *fmt++;
942 if (c == 0)
943 return (fmt - 1);
944 if (c == ']')
945 return (fmt);
946 #endif
947 break;
948 }
949 case ']': /* end of scanset */
950 return (fmt);
951
952 default: /* just another character */
953 c = n;
954 break;
955 }
956 }
957 /* NOTREACHED */
958 }
959
960 #ifndef NO_FLOATING_POINT
961 static int
962 parsefloat(FILE *fp, char **buf, size_t width, locale_t loc)
963 {
964 char *commit, *p;
965 int infnanpos = 0;
966 enum {
967 S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,
968 S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS, S_DECIMAL_POINT
969 } state = S_START;
970 unsigned char c;
971 unsigned char *decpt = (unsigned char *)localeconv_l(loc)->decimal_point;
972 char *decpt_start;
973 _Bool gotmantdig = 0, ishex = 0;
974 static char *b = NULL;
975 static size_t bsiz = 0;
976 char *e;
977 size_t s;
978
979 if (bsiz = 0) {
980 b = (char *)malloc(BUF);
981 if (b == NULL) {
982 *buf = NULL;
983 return 0;
984 }
985 bsiz = BUF;
986 }
987 s = (width == 0 ? BUF : (width + 1));
988 if (s > bsiz) {
989 b = (char *)reallocf(b, s);
990 if (b == NULL) {
991 bsiz = 0;
992 *buf = NULL;
993 return 0;
994 }
995 bsiz = s;
996 }
997 e = b + (s - 1);
998 /*
999 * We set commit = p whenever the string we have read so far
1000 * constitutes a valid representation of a floating point
1001 * number by itself. At some point, the parse will complete
1002 * or fail, and we will ungetc() back to the last commit point.
1003 * To ensure that the file offset gets updated properly, it is
1004 * always necessary to read at least one character that doesn't
1005 * match; thus, we can't short-circuit "infinity" or "nan(...)".
1006 */
1007 commit = b - 1;
1008 for (p = b; width == 0 || p < e; ) {
1009 c = *fp->_p;
1010 reswitch:
1011 switch (state) {
1012 case S_START:
1013 state = S_GOTSIGN;
1014 if (c == '-' || c == '+')
1015 break;
1016 else
1017 goto reswitch;
1018 case S_GOTSIGN:
1019 switch (c) {
1020 case '0':
1021 state = S_MAYBEHEX;
1022 commit = p;
1023 break;
1024 case 'I':
1025 case 'i':
1026 state = S_INF;
1027 break;
1028 case 'N':
1029 case 'n':
1030 state = S_NAN;
1031 break;
1032 default:
1033 state = S_DIGITS;
1034 goto reswitch;
1035 }
1036 break;
1037 case S_INF:
1038 if (infnanpos > 6 ||
1039 (c != "nfinity"[infnanpos] &&
1040 c != "NFINITY"[infnanpos]))
1041 goto parsedone;
1042 if (infnanpos == 1 || infnanpos == 6)
1043 commit = p; /* inf or infinity */
1044 infnanpos++;
1045 break;
1046 case S_NAN:
1047 switch (infnanpos) {
1048 case -1: /* XXX kludge to deal with nan(...) */
1049 goto parsedone;
1050 case 0:
1051 if (c != 'A' && c != 'a')
1052 goto parsedone;
1053 break;
1054 case 1:
1055 if (c != 'N' && c != 'n')
1056 goto parsedone;
1057 else
1058 commit = p;
1059 break;
1060 case 2:
1061 if (c != '(')
1062 goto parsedone;
1063 break;
1064 default:
1065 if (c == ')') {
1066 commit = p;
1067 infnanpos = -2;
1068 } else if (!isalnum_l(c, loc) && c != '_')
1069 goto parsedone;
1070 break;
1071 }
1072 infnanpos++;
1073 break;
1074 case S_MAYBEHEX:
1075 state = S_DIGITS;
1076 if (c == 'X' || c == 'x') {
1077 ishex = 1;
1078 break;
1079 } else { /* we saw a '0', but no 'x' */
1080 gotmantdig = 1;
1081 goto reswitch;
1082 }
1083 case S_DIGITS:
1084 if ((ishex && isxdigit_l(c, loc)) || isdigit_l(c, loc))
1085 gotmantdig = 1;
1086 else {
1087 state = S_DECIMAL_POINT;
1088 decpt_start = p;
1089 goto reswitch;
1090 }
1091 if (gotmantdig)
1092 commit = p;
1093 break;
1094 case S_DECIMAL_POINT:
1095 if (*decpt == 0) {
1096 if (gotmantdig)
1097 commit = p - 1;
1098 state = S_FRAC;
1099 goto reswitch;
1100 }
1101 if (*decpt++ == c)
1102 break;
1103 /* not decimal point */
1104 state = S_FRAC;
1105 if (decpt_start == p)
1106 goto reswitch;
1107 while (decpt_start < --p)
1108 __ungetc(*(u_char *)p, fp);
1109 c = *(u_char *)p;
1110 goto reswitch;
1111 case S_FRAC:
1112 if (((c == 'E' || c == 'e') && !ishex) ||
1113 ((c == 'P' || c == 'p') && ishex)) {
1114 if (!gotmantdig)
1115 goto parsedone;
1116 else
1117 state = S_EXP;
1118 } else if ((ishex && isxdigit_l(c, loc)) || isdigit_l(c, loc)) {
1119 commit = p;
1120 gotmantdig = 1;
1121 } else
1122 goto parsedone;
1123 break;
1124 case S_EXP:
1125 state = S_EXPDIGITS;
1126 if (c == '-' || c == '+')
1127 break;
1128 else
1129 goto reswitch;
1130 case S_EXPDIGITS:
1131 if (isdigit_l(c, loc))
1132 commit = p;
1133 else
1134 goto parsedone;
1135 break;
1136 default:
1137 abort();
1138 }
1139 if (p >= e) {
1140 ssize_t diff = (p - b);
1141 ssize_t com = (commit - b);
1142 s += BUF;
1143 b = (char *)reallocf(b, s);
1144 if (b == NULL) {
1145 bsiz = 0;
1146 *buf = NULL;
1147 return 0;
1148 }
1149 bsiz = s;
1150 e = b + (s - 1);
1151 p = b + diff;
1152 commit = b + com;
1153 }
1154 *p++ = c;
1155 if (--fp->_r > 0)
1156 fp->_p++;
1157 else if (__srefill(fp))
1158 break; /* EOF */
1159 }
1160
1161 parsedone:
1162 while (commit < --p)
1163 __ungetc(*(u_char *)p, fp);
1164 *++commit = '\0';
1165 *buf = b;
1166 return (commit - b);
1167 }
1168 #endif