Sync libc/stdio with FreeBSD:
[dragonfly.git] / lib / libc / stdio / 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  * @(#)vfscanf.c        8.1 (Berkeley) 6/4/93
33  * $FreeBSD: src/lib/libc/stdio/vfscanf.c,v 1.43 2009/01/19 06:19:51 das Exp $
34  * $DragonFly: src/lib/libc/stdio/vfscanf.c,v 1.11 2006/02/18 17:55:52 joerg Exp $
35  */
36
37 #include "namespace.h"
38 #include <ctype.h>
39 #include <inttypes.h>
40 #include <stddef.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <stdarg.h>
44 #include <string.h>
45 #include <wchar.h>
46 #include <wctype.h>
47 #include "un-namespace.h"
48
49 #include "collate.h"
50 #include "libc_private.h"
51 #include "local.h"
52 #include "priv_stdio.h"
53
54 #ifndef NO_FLOATING_POINT
55 #include <locale.h>
56 #endif
57
58 #define BUF             513     /* Maximum length of numeric string. */
59
60 /*
61  * Flags used during conversion.
62  */
63 #define LONG            0x01    /* l: long or double */
64 #define LONGDBL         0x02    /* L: long double */
65 #define SHORT           0x04    /* h: short */
66 #define SUPPRESS        0x08    /* *: suppress assignment */
67 #define POINTER         0x10    /* p: void * (as hex) */
68 #define NOSKIP          0x20    /* [ or c: do not skip blanks */
69 #define LONGLONG        0x400   /* ll: long long (+ deprecated q: quad) */
70 #define INTMAXT         0x800   /* j: intmax_t */
71 #define PTRDIFFT        0x1000  /* t: ptrdiff_t */
72 #define SIZET           0x2000  /* z: size_t */
73 #define SHORTSHORT      0x4000  /* hh: char */
74 #define UNSIGNED        0x8000  /* %[oupxX] conversions */
75
76 /*
77  * The following are used in integral conversions only:
78  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS
79  */
80 #define SIGNOK          0x40    /* +/- is (still) legal */
81 #define NDIGITS         0x80    /* no digits detected */
82 #define PFXOK           0x100   /* 0x prefix is (still) legal */
83 #define NZDIGITS        0x200   /* no zero digits detected */
84 #define HAVESIGN        0x10000 /* sign detected */
85
86 /*
87  * Conversion types.
88  */
89 #define CT_CHAR         0       /* %c conversion */
90 #define CT_CCL          1       /* %[...] conversion */
91 #define CT_STRING       2       /* %s conversion */
92 #define CT_INT          3       /* %[dioupxX] conversion */
93 #define CT_FLOAT        4       /* %[efgEFG] conversion */
94
95 static const u_char *__sccl(char *, const u_char *);
96 #ifndef NO_FLOATING_POINT
97 static int parsefloat(FILE *, char *, char *);
98 #endif
99
100 __weak_reference(__vfscanf, vfscanf);
101
102 /*
103  * __vfscanf - MT-safe version
104  */
105 int
106 __vfscanf(FILE *fp, const char *fmt0, va_list ap)
107 {
108         int ret;
109
110         FLOCKFILE(fp);
111         ret = __svfscanf(fp, fmt0, ap);
112         FUNLOCKFILE(fp);
113         return (ret);
114 }
115
116 /*
117  * __svfscanf - non-MT-safe version of __vfscanf
118  */
119 int
120 __svfscanf(FILE *fp, const char *fmt0, va_list ap)
121 {
122         const u_char *fmt = (const u_char *)fmt0;
123         int c;                  /* character from format, or conversion */
124         size_t width;           /* field width, or 0 */
125         char *p;                /* points into all kinds of strings */
126         int n;                  /* handy integer */
127         int flags;              /* flags as defined above */
128         char *p0;               /* saves original value of p when necessary */
129         int nassigned;          /* number of fields assigned */
130         int nconversions;       /* number of conversions */
131         int nread;              /* number of characters consumed from fp */
132         int base;               /* base argument to conversion function */
133         char ccltab[256];       /* character class table for %[...] */
134         char buf[BUF];          /* buffer for numeric and mb conversions */
135         wchar_t *wcp;           /* handy wide character pointer */
136         size_t nconv;           /* length of multibyte sequence converted */
137         static const mbstate_t initial;
138         mbstate_t mbs;
139
140         /* `basefix' is used to avoid `if' tests in the integer scanner */
141         static short basefix[17] =
142                 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
143
144         _SET_ORIENTATION(fp, -1);
145
146         nassigned = 0;
147         nconversions = 0;
148         nread = 0;
149         for (;;) {
150                 c = *fmt++;
151                 if (c == 0)
152                         return (nassigned);
153                 if (isspace(c)) {
154                         while ((fp->pub._r > 0 || __srefill(fp) == 0) &&
155                             isspace(*fp->pub._p))
156                                 nread++, fp->pub._r--, fp->pub._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->pub._r <= 0 && __srefill(fp))
172                                 goto input_failure;
173                         if (*fp->pub._p != c)
174                                 goto match_failure;
175                         fp->pub._r--, fp->pub._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                         }
192                         goto again;
193                 case 'q':
194                         flags |= LONGLONG;      /* assume long long == quad */
195                         goto again;
196                 case 't':
197                         flags |= PTRDIFFT;
198                         goto again;
199                 case 'z':
200                         flags |= SIZET;
201                         goto again;
202                 case 'L':
203                         flags |= LONGDBL;
204                         goto again;
205                 case 'h':
206                         if (flags & SHORT) {
207                                 flags &= ~SHORT;
208                                 flags |= SHORTSHORT;
209                         } else {
210                                 flags |= SHORT;
211                         }
212                         goto again;
213
214                 case '0': case '1': case '2': case '3': case '4':
215                 case '5': case '6': case '7': case '8': case '9':
216                         width = width * 10 + c - '0';
217                         goto again;
218
219                 /*
220                  * Conversions.
221                  */
222                 case 'd':
223                         c = CT_INT;
224                         base = 10;
225                         break;
226
227                 case 'i':
228                         c = CT_INT;
229                         base = 0;
230                         break;
231
232                 case 'o':
233                         c = CT_INT;
234                         flags |= UNSIGNED;
235                         base = 8;
236                         break;
237
238                 case 'u':
239                         c = CT_INT;
240                         flags |= UNSIGNED;
241                         base = 10;
242                         break;
243
244                 case 'X':
245                 case 'x':
246                         flags |= PFXOK; /* enable 0x prefixing */
247                         c = CT_INT;
248                         flags |= UNSIGNED;
249                         base = 16;
250                         break;
251
252 #ifndef NO_FLOATING_POINT
253                 case 'A': case 'E': case 'F': case 'G':
254                 case 'a': case 'e': case 'f': case 'g':
255                         c = CT_FLOAT;
256                         break;
257 #endif
258
259                 case 'S':
260                         flags |= LONG;
261                         /* FALLTHROUGH */
262                 case 's':
263                         c = CT_STRING;
264                         break;
265
266                 case '[':
267                         fmt = __sccl(ccltab, fmt);
268                         flags |= NOSKIP;
269                         c = CT_CCL;
270                         break;
271
272                 case 'C':
273                         flags |= LONG;
274                         /* FALLTHROUGH */
275                 case 'c':
276                         flags |= NOSKIP;
277                         c = CT_CHAR;
278                         break;
279
280                 case 'p':       /* pointer format is like hex */
281                         flags |= POINTER | PFXOK;
282                         c = CT_INT;             /* assumes sizeof(uintmax_t) */
283                         flags |= UNSIGNED;      /*      >= sizeof(uintptr_t) */
284                         base = 16;
285                         break;
286
287                 case 'n':
288                         nconversions++;
289                         if (flags & SUPPRESS)   /* ??? */
290                                 continue;
291                         if (flags & SHORTSHORT)
292                                 *va_arg(ap, char *) = nread;
293                         else if (flags & SHORT)
294                                 *va_arg(ap, short *) = nread;
295                         else if (flags & LONG)
296                                 *va_arg(ap, long *) = nread;
297                         else if (flags & LONGLONG)
298                                 *va_arg(ap, long long *) = nread;
299                         else if (flags & INTMAXT)
300                                 *va_arg(ap, intmax_t *) = nread;
301                         else if (flags & SIZET)
302                                 *va_arg(ap, size_t *) = nread;
303                         else if (flags & PTRDIFFT)
304                                 *va_arg(ap, ptrdiff_t *) = nread;
305                         else
306                                 *va_arg(ap, int *) = nread;
307                         continue;
308
309                 default:
310                         goto match_failure;
311
312                 /*
313                  * Disgusting backwards compatibility hack.     XXX
314                  */
315                 case '\0':      /* compat */
316                         return (EOF);
317                 }
318
319                 /*
320                  * We have a conversion that requires input.
321                  */
322                 if (fp->pub._r <= 0 && __srefill(fp))
323                         goto input_failure;
324
325                 /*
326                  * Consume leading white space, except for formats
327                  * that suppress this.
328                  */
329                 if ((flags & NOSKIP) == 0) {
330                         while (isspace(*fp->pub._p)) {
331                                 nread++;
332                                 if (--fp->pub._r > 0)
333                                         fp->pub._p++;
334                                 else if (__srefill(fp))
335                                         goto input_failure;
336                         }
337                         /*
338                          * Note that there is at least one character in
339                          * the buffer, so conversions that do not set NOSKIP
340                          * ca no longer result in an input failure.
341                          */
342                 }
343
344                 /*
345                  * Do the conversion.
346                  */
347                 switch (c) {
348
349                 case CT_CHAR:
350                         /* scan arbitrary characters (sets NOSKIP) */
351                         if (width == 0)
352                                 width = 1;
353                         if (flags & LONG) {
354                                 if ((flags & SUPPRESS) == 0)
355                                         wcp = va_arg(ap, wchar_t *);
356                                 else
357                                         wcp = NULL;
358                                 n = 0;
359                                 while (width != 0) {
360                                         if (n == MB_CUR_MAX) {
361                                                 fp->pub._flags |= __SERR;
362                                                 goto input_failure;
363                                         }
364                                         buf[n++] = *fp->pub._p;
365                                         fp->pub._p++;
366                                         fp->pub._r--;
367                                         mbs = initial;
368                                         nconv = mbrtowc(wcp, buf, n, &mbs);
369                                         if (nconv == (size_t)-1) {
370                                                 fp->pub._flags |= __SERR;
371                                                 goto input_failure;
372                                         }
373                                         if (nconv == 0 && !(flags & SUPPRESS))
374                                                 *wcp = L'\0';
375                                         if (nconv != (size_t)-2) {
376                                                 nread += n;
377                                                 width--;
378                                                 if (!(flags & SUPPRESS))
379                                                         wcp++;
380                                                 n = 0;
381                                         }
382                                         if (fp->pub._r <= 0 && __srefill(fp)) {
383                                                 if (n != 0) {
384                                                         fp->pub._flags |= __SERR;
385                                                         goto input_failure;
386                                                 }
387                                                 break;
388                                         }
389                                 }
390                                 if ((flags & SUPPRESS) == 0)
391                                         nassigned++;
392                         } else if (flags & SUPPRESS) {
393                                 size_t sum = 0;
394                                 for (;;) {
395                                         if ((n = fp->pub._r) < width) {
396                                                 sum += n;
397                                                 width -= n;
398                                                 fp->pub._p += n;
399                                                 if (__srefill(fp)) {
400                                                         if (sum == 0)
401                                                             goto input_failure;
402                                                         break;
403                                                 }
404                                         } else {
405                                                 sum += width;
406                                                 fp->pub._r -= width;
407                                                 fp->pub._p += width;
408                                                 break;
409                                         }
410                                 }
411                                 nread += sum;
412                         } else {
413                                 size_t r = __fread((void *)va_arg(ap, char *),
414                                     1, width, fp);
415
416                                 if (r == 0)
417                                         goto input_failure;
418                                 nread += r;
419                                 nassigned++;
420                         }
421                         nconversions++;
422                         break;
423
424                 case CT_CCL:
425                         /* scan a (nonempty) character class (sets NOSKIP) */
426                         if (width == 0)
427                                 width = (size_t)~0;     /* `infinity' */
428                         /* take only those things in the class */
429                         if (flags & LONG) {
430                                 wchar_t twc;
431                                 int nchars;
432
433                                 if ((flags & SUPPRESS) == 0)
434                                         wcp = va_arg(ap, wchar_t *);
435                                 else
436                                         wcp = &twc;
437                                 n = 0;
438                                 nchars = 0;
439                                 while (width != 0) {
440                                         if (n == MB_CUR_MAX) {
441                                                 fp->pub._flags |= __SERR;
442                                                 goto input_failure;
443                                         }
444                                         buf[n++] = *fp->pub._p;
445                                         fp->pub._p++;
446                                         fp->pub._r--;
447                                         mbs = initial;
448                                         nconv = mbrtowc(wcp, buf, n, &mbs);
449                                         if (nconv == (size_t)-1) {
450                                                 fp->pub._flags |= __SERR;
451                                                 goto input_failure;
452                                         }
453                                         if (nconv == 0)
454                                                 *wcp = L'\0';
455                                         if (nconv != (size_t)-2) {
456                                                 if (wctob(*wcp) != EOF &&
457                                                     !ccltab[wctob(*wcp)]) {
458                                                         while (n != 0) {
459                                                                 n--;
460                                                                 __ungetc(buf[n],
461                                                                     fp);
462                                                         }
463                                                         break;
464                                                 }
465                                                 nread += n;
466                                                 width--;
467                                                 if (!(flags & SUPPRESS))
468                                                         wcp++;
469                                                 nchars++;
470                                                 n = 0;
471                                         }
472                                         if (fp->pub._r <= 0 && __srefill(fp)) {
473                                                 if (n != 0) {
474                                                         fp->pub._flags |= __SERR;
475                                                         goto input_failure;
476                                                 }
477                                                 break;
478                                         }
479                                 }
480                                 if (n != 0) {
481                                         fp->pub._flags |= __SERR;
482                                         goto input_failure;
483                                 }
484                                 n = nchars;
485                                 if (n == 0)
486                                         goto match_failure;
487                                 if (!(flags & SUPPRESS)) {
488                                         *wcp = L'\0';
489                                         nassigned++;
490                                 }
491                         } else if (flags & SUPPRESS) {
492                                 n = 0;
493                                 while (ccltab[*fp->pub._p]) {
494                                         n++, fp->pub._r--, fp->pub._p++;
495                                         if (--width == 0)
496                                                 break;
497                                         if (fp->pub._r <= 0 && __srefill(fp)) {
498                                                 if (n == 0)
499                                                         goto input_failure;
500                                                 break;
501                                         }
502                                 }
503                                 if (n == 0)
504                                         goto match_failure;
505                         } else {
506                                 p0 = p = va_arg(ap, char *);
507                                 while (ccltab[*fp->pub._p]) {
508                                         fp->pub._r--;
509                                         *p++ = *fp->pub._p++;
510                                         if (--width == 0)
511                                                 break;
512                                         if (fp->pub._r <= 0 && __srefill(fp)) {
513                                                 if (p == p0)
514                                                         goto input_failure;
515                                                 break;
516                                         }
517                                 }
518                                 n = p - p0;
519                                 if (n == 0)
520                                         goto match_failure;
521                                 *p = 0;
522                                 nassigned++;
523                         }
524                         nread += n;
525                         nconversions++;
526                         break;
527
528                 case CT_STRING:
529                         /* like CCL, but zero-length string OK, & no NOSKIP */
530                         if (width == 0)
531                                 width = (size_t)~0;
532                         if (flags & LONG) {
533                                 wchar_t twc;
534
535                                 if ((flags & SUPPRESS) == 0)
536                                         wcp = va_arg(ap, wchar_t *);
537                                 else
538                                         wcp = &twc;
539                                 n = 0;
540                                 while (!isspace(*fp->pub._p) && width != 0) {
541                                         if (n == MB_CUR_MAX) {
542                                                 fp->pub._flags |= __SERR;
543                                                 goto input_failure;
544                                         }
545                                         buf[n++] = *fp->pub._p;
546                                         fp->pub._p++;
547                                         fp->pub._r--;
548                                         mbs = initial;
549                                         nconv = mbrtowc(wcp, buf, n, &mbs);
550                                         if (nconv == (size_t)-1) {
551                                                 fp->pub._flags |= __SERR;
552                                                 goto input_failure;
553                                         }
554                                         if (nconv == 0)
555                                                 *wcp = L'\0';
556                                         if (nconv != (size_t)-2) {
557                                                 if (iswspace(*wcp)) {
558                                                         while (n != 0) {
559                                                                 n--;
560                                                                 __ungetc(buf[n],
561                                                                     fp);
562                                                         }
563                                                         break;
564                                                 }
565                                                 nread += n;
566                                                 width--;
567                                                 if (!(flags & SUPPRESS))
568                                                         wcp++;
569                                                 n = 0;
570                                         }
571                                         if (fp->pub._r <= 0 && __srefill(fp)) {
572                                                 if (n != 0) {
573                                                         fp->pub._flags |= __SERR;
574                                                         goto input_failure;
575                                                 }
576                                                 break;
577                                         }
578                                 }
579                                 if (!(flags & SUPPRESS)) {
580                                         *wcp = L'\0';
581                                         nassigned++;
582                                 }
583                         } else if (flags & SUPPRESS) {
584                                 n = 0;
585                                 while (!isspace(*fp->pub._p)) {
586                                         n++, fp->pub._r--, fp->pub._p++;
587                                         if (--width == 0)
588                                                 break;
589                                         if (fp->pub._r <= 0 && __srefill(fp))
590                                                 break;
591                                 }
592                                 nread += n;
593                         } else {
594                                 p0 = p = va_arg(ap, char *);
595                                 while (!isspace(*fp->pub._p)) {
596                                         fp->pub._r--;
597                                         *p++ = *fp->pub._p++;
598                                         if (--width == 0)
599                                                 break;
600                                         if (fp->pub._r <= 0 && __srefill(fp))
601                                                 break;
602                                 }
603                                 *p = 0;
604                                 nread += p - p0;
605                                 nassigned++;
606                         }
607                         nconversions++;
608                         continue;
609
610                 case CT_INT:
611                         /* scan an integer as if by the conversion function */
612 #ifdef hardway
613                         if (width == 0 || width > sizeof(buf) - 1)
614                                 width = sizeof(buf) - 1;
615 #else
616                         /* size_t is unsigned, hence this optimisation */
617                         if (--width > sizeof(buf) - 2)
618                                 width = sizeof(buf) - 2;
619                         width++;
620 #endif
621                         flags |= SIGNOK | NDIGITS | NZDIGITS;
622                         for (p = buf; width; width--) {
623                                 c = *fp->pub._p;
624                                 /*
625                                  * Switch on the character; `goto ok'
626                                  * if we accept it as a part of number.
627                                  */
628                                 switch (c) {
629
630                                 /*
631                                  * The digit 0 is always legal, but is
632                                  * special.  For %i conversions, if no
633                                  * digits (zero or nonzero) have been
634                                  * scanned (only signs), we will have
635                                  * base==0.  In that case, we should set
636                                  * it to 8 and enable 0x prefixing.
637                                  * Also, if we have not scanned zero digits
638                                  * before this, do not turn off prefixing
639                                  * (someone else will turn it off if we
640                                  * have scanned any nonzero digits).
641                                  */
642                                 case '0':
643                                         if (base == 0) {
644                                                 base = 8;
645                                                 flags |= PFXOK;
646                                         }
647                                         if (flags & NZDIGITS)
648                                             flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
649                                         else
650                                             flags &= ~(SIGNOK|PFXOK|NDIGITS);
651                                         goto ok;
652
653                                 /* 1 through 7 always legal */
654                                 case '1': case '2': case '3':
655                                 case '4': case '5': case '6': case '7':
656                                         base = basefix[base];
657                                         flags &= ~(SIGNOK | PFXOK | NDIGITS);
658                                         goto ok;
659
660                                 /* digits 8 and 9 ok iff decimal or hex */
661                                 case '8': case '9':
662                                         base = basefix[base];
663                                         if (base <= 8)
664                                                 break;  /* not legal here */
665                                         flags &= ~(SIGNOK | PFXOK | NDIGITS);
666                                         goto ok;
667
668                                 /* letters ok iff hex */
669                                 case 'A': case 'B': case 'C':
670                                 case 'D': case 'E': case 'F':
671                                 case 'a': case 'b': case 'c':
672                                 case 'd': case 'e': case 'f':
673                                         /* no need to fix base here */
674                                         if (base <= 10)
675                                                 break;  /* not legal here */
676                                         flags &= ~(SIGNOK | PFXOK | NDIGITS);
677                                         goto ok;
678
679                                 /* sign ok only as first character */
680                                 case '+': case '-':
681                                         if (flags & SIGNOK) {
682                                                 flags &= ~SIGNOK;
683                                                 flags |= HAVESIGN;
684                                                 goto ok;
685                                         }
686                                         break;
687                                         
688                                 /*
689                                  * x ok iff flag still set & 2nd char (or
690                                  * 3rd char if we have a sign).
691                                  */
692                                 case 'x': case 'X':
693                                         if (flags & PFXOK && p ==
694                                             buf + 1 + !!(flags & HAVESIGN)) {
695                                                 base = 16;      /* if %i */
696                                                 flags &= ~PFXOK;
697                                                 goto ok;
698                                         }
699                                         break;
700                                 }
701
702                                 /*
703                                  * If we got here, c is not a legal character
704                                  * for a number.  Stop accumulating digits.
705                                  */
706                                 break;
707                 ok:
708                                 /*
709                                  * c is legal: store it and look at the next.
710                                  */
711                                 *p++ = c;
712                                 if (--fp->pub._r > 0)
713                                         fp->pub._p++;
714                                 else if (__srefill(fp))
715                                         break;          /* EOF */
716                         }
717                         /*
718                          * If we had only a sign, it is no good; push
719                          * back the sign.  If the number ends in `x',
720                          * it was [sign] '0' 'x', so push back the x
721                          * and treat it as [sign] '0'.
722                          */
723                         if (flags & NDIGITS) {
724                                 if (p > buf)
725                                         __ungetc(*(u_char *)--p, fp);
726                                 goto match_failure;
727                         }
728                         c = ((u_char *)p)[-1];
729                         if (c == 'x' || c == 'X') {
730                                 --p;
731                                 __ungetc(c, fp);
732                         }
733                         if ((flags & SUPPRESS) == 0) {
734                                 uintmax_t res;
735
736                                 *p = 0;
737                                 if ((flags & UNSIGNED) == 0)
738                                     res = strtoimax(buf, NULL, base);
739                                 else
740                                     res = strtoumax(buf, NULL, base);
741                                 if (flags & POINTER)
742                                         *va_arg(ap, void **) =
743                                                         (void *)(uintptr_t)res;
744                                 else if (flags & SHORTSHORT)
745                                         *va_arg(ap, char *) = res;
746                                 else if (flags & SHORT)
747                                         *va_arg(ap, short *) = res;
748                                 else if (flags & LONG)
749                                         *va_arg(ap, long *) = res;
750                                 else if (flags & LONGLONG)
751                                         *va_arg(ap, long long *) = res;
752                                 else if (flags & INTMAXT)
753                                         *va_arg(ap, intmax_t *) = res;
754                                 else if (flags & PTRDIFFT)
755                                         *va_arg(ap, ptrdiff_t *) = res;
756                                 else if (flags & SIZET)
757                                         *va_arg(ap, size_t *) = res;
758                                 else
759                                         *va_arg(ap, int *) = res;
760                                 nassigned++;
761                         }
762                         nread += p - buf;
763                         nconversions++;
764                         break;
765
766 #ifndef NO_FLOATING_POINT
767                 case CT_FLOAT:
768                         /* scan a floating point number as if by strtod */
769                         if (width == 0 || width > sizeof(buf) - 1)
770                                 width = sizeof(buf) - 1;
771                         if ((width = parsefloat(fp, buf, buf + width)) == 0)
772                                 goto match_failure;
773                         if ((flags & SUPPRESS) == 0) {
774                                 if (flags & LONGDBL) {
775                                         long double res = strtold(buf, &p);
776                                         *va_arg(ap, long double *) = res;
777                                 } else if (flags & LONG) {
778                                         double res = strtod(buf, &p);
779                                         *va_arg(ap, double *) = res;
780                                 } else {
781                                         float res = strtof(buf, &p);
782                                         *va_arg(ap, float *) = res;
783                                 }
784                                 nassigned++;
785                         }
786                         nread += width;
787                         nconversions++;
788                         break;
789 #endif /* !NO_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(char *tab, 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         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->pub._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->pub._r > 0)
1067                         fp->pub._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