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