update from main archive 961229
[platform/upstream/glibc.git] / stdio-common / vfscanf.c
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with the GNU C Library; see the file COPYING.LIB.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 #include "../locale/localeinfo.h"
20 #include <errno.h>
21 #include <limits.h>
22 #include <ctype.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <wctype.h>
28 #include <libc-lock.h>
29
30 #ifdef  __GNUC__
31 #define HAVE_LONGLONG
32 #define LONGLONG        long long
33 #else
34 #define LONGLONG        long
35 #endif
36
37 /* Those are flags in the conversion format. */
38 # define LONG           0x001   /* l: long or double */
39 # define LONGDBL        0x002   /* L: long long or long double */
40 # define SHORT          0x004   /* h: short */
41 # define SUPPRESS       0x008   /* *: suppress assignment */
42 # define POINTER        0x010   /* weird %p pointer (`fake hex') */
43 # define NOSKIP         0x020   /* do not skip blanks */
44 # define WIDTH          0x040   /* width was given */
45 # define GROUP          0x080   /* ': group numbers */
46 # define MALLOC         0x100   /* a: malloc strings */
47
48 # define TYPEMOD        (LONG|LONGDBL|SHORT)
49
50
51 #ifdef USE_IN_LIBIO
52 # include <libioP.h>
53 # include <libio.h>
54
55 # undef va_list
56 # define va_list        _IO_va_list
57 # define ungetc(c, s)   (--read_in, _IO_ungetc (c, s))
58 # define inchar()       ((c = _IO_getc_unlocked (s)), (void) ++read_in, c)
59 # define encode_error() do {                                                  \
60                           if (errp != NULL) *errp |= 4;                       \
61                           _IO_funlockfile (s);                                \
62                           __set_errno (EILSEQ);                               \
63                           return done;                                        \
64                         } while (0)
65 # define conv_error()   do {                                                  \
66                           if (errp != NULL) *errp |= 2;                       \
67                           _IO_funlockfile (s);                                \
68                           return done;                                        \
69                         } while (0)
70 # define input_error()  do {                                                  \
71                           _IO_funlockfile (s);                                \
72                           if (errp != NULL) *errp |= 1;                       \
73                           return done ?: EOF;                                 \
74                         } while (0)
75 # define memory_error() do {                                                  \
76                           _IO_funlockfile (s);                                \
77                           __set_errno (ENOMEM);                               \
78                           return EOF;                                         \
79                         } while (0)
80 # define ARGCHECK(s, format)                                                  \
81   do                                                                          \
82     {                                                                         \
83       /* Check file argument for consistence.  */                             \
84       CHECK_FILE (s, EOF);                                                    \
85       if (s->_flags & _IO_NO_READS)                                           \
86         {                                                                     \
87           __set_errno (EBADF);                                                \
88           return EOF;                                                         \
89         }                                                                     \
90       else if (format == NULL)                                                \
91         {                                                                     \
92           MAYBE_SET_EINVAL;                                                   \
93           return EOF;                                                         \
94         }                                                                     \
95     } while (0)
96 # define LOCK_STREAM(S)                                                       \
97   __libc_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, (S));    \
98   _IO_flockfile (S)
99 # define UNLOCK_STREAM __libc_cleanup_region_end (1)
100 #else
101 # define ungetc(c, s)   (--read_in, ungetc (c, s))
102 # define inchar()       ((c = getc (s)), (void) ++read_in, c)
103 # define encode_error() do {                                                  \
104                           funlockfile (s);                                    \
105                           __set_errno (EILSEQ);                               \
106                           return done;                                        \
107                         } while (0)
108 # define conv_error()   do {                                                  \
109                           funlockfile (s);                                    \
110                           return done;                                        \
111                         } while (0)
112 # define input_error()  do {                                                  \
113                           funlockfile (s);                                    \
114                           return done ?: EOF;                                 \
115                         } while (0)
116 # define memory_error() do {                                                  \
117                           funlockfile (s);                                    \
118                           __set_errno (ENOMEM);                               \
119                           return EOF;                                         \
120                         } while (0)
121 # define ARGCHECK(s, format)                                                  \
122   do                                                                          \
123     {                                                                         \
124       /* Check file argument for consistence.  */                             \
125       if (!__validfp (s) || !s->__mode.__read)                                \
126         {                                                                     \
127           __set_errno (EBADF);                                                \
128           return EOF;                                                         \
129         }                                                                     \
130       else if (format == NULL)                                                \
131         {                                                                     \
132           __set_errno (EINVAL);                                               \
133           return EOF;                                                         \
134         }                                                                     \
135     } while (0)
136 #if 1
137       /* XXX For now !!! */
138 # define flockfile(S) /* nothing */
139 # define funlockfile(S) /* nothing */
140 # define LOCK_STREAM(S)
141 # define UNLOCK_STREAM
142 #else
143 # define LOCK_STREAM(S)                                                       \
144   __libc_cleanup_region_start (&__funlockfile, (S));                          \
145   __flockfile (S)
146 # define UNLOCK_STREAM __libc_cleanup_region_end (1)
147 #endif
148 #endif
149
150
151 /* Read formatted input from S according to the format string
152    FORMAT, using the argument list in ARG.
153    Return the number of assignments made, or -1 for an input error.  */
154 #ifdef USE_IN_LIBIO
155 int
156 _IO_vfscanf (s, format, argptr, errp)
157      _IO_FILE *s;
158      const char *format;
159      _IO_va_list argptr;
160      int *errp;
161 #else
162 int
163 __vfscanf (FILE *s, const char *format, va_list argptr)
164 #endif
165 {
166   va_list arg = (va_list) argptr;
167
168   register const char *f = format;
169   register unsigned char fc;    /* Current character of the format.  */
170   register size_t done = 0;     /* Assignments done.  */
171   register size_t read_in = 0;  /* Chars read in.  */
172   register int c = 0;           /* Last char read.  */
173   register int width;           /* Maximum field width.  */
174   register int flags;           /* Modifiers for current format element.  */
175
176   /* Status for reading F-P nums.  */
177   char got_dot, got_e, negative;
178   /* If a [...] is a [^...].  */
179   char not_in;
180   /* Base for integral numbers.  */
181   int base;
182   /* Signedness for integral numbers.  */
183   int number_signed;
184   /* Decimal point character.  */
185   wchar_t decimal;
186   /* The thousands character of the current locale.  */
187   wchar_t thousands;
188   /* Integral holding variables.  */
189   union
190     {
191       long long int q;
192       unsigned long long int uq;
193       long int l;
194       unsigned long int ul;
195     } num;
196   /* Character-buffer pointer.  */
197   char *str = NULL;
198   wchar_t *wstr = NULL;
199   char **strptr = NULL;
200   size_t strsize = 0;
201   /* We must not react on white spaces immediately because they can
202      possibly be matched even if in the input stream no character is
203      available anymore.  */
204   int skip_space = 0;
205   /* Workspace.  */
206   char *tw;                     /* Temporary pointer.  */
207   char *wp = NULL;              /* Workspace.  */
208   size_t wpmax = 0;             /* Maximal size of workspace.  */
209   size_t wpsize;                /* Currently used bytes in workspace.  */
210 #define ADDW(Ch)                                                            \
211   do                                                                        \
212     {                                                                       \
213       if (wpsize == wpmax)                                                  \
214         {                                                                   \
215           char *old = wp;                                                   \
216           wpmax = UCHAR_MAX > 2 * wpmax ? UCHAR_MAX : 2 * wpmax;            \
217           wp = (char *) alloca (wpmax);                                     \
218           if (old != NULL)                                                  \
219             memcpy (wp, old, wpsize);                                       \
220         }                                                                   \
221       wp[wpsize++] = (Ch);                                                  \
222     }                                                                       \
223   while (0)
224
225   ARGCHECK (s, format);
226
227   /* Figure out the decimal point character.  */
228   if (mbtowc (&decimal, _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT),
229               strlen (_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT))) <= 0)
230     decimal = (wchar_t) *_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
231   /* Figure out the thousands separator character.  */
232   if (mbtowc (&thousands, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
233               strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
234     thousands = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
235
236   /* Lock the stream.  */
237   LOCK_STREAM (s);
238
239   /* Run through the format string.  */
240   while (*f != '\0')
241     {
242       unsigned int argpos;
243       /* Extract the next argument, which is of type TYPE.
244          For a %N$... spec, this is the Nth argument from the beginning;
245          otherwise it is the next argument after the state now in ARG.  */
246 #if 0
247       /* XXX Possible optimization.  */
248 # define ARG(type)      (argpos == 0 ? va_arg (arg, type) :                   \
249                          ({ va_list arg = (va_list) argptr;                   \
250                             arg = (va_list) ((char *) arg                     \
251                                              + (argpos - 1)                   \
252                                              * __va_rounded_size (void *));   \
253                             va_arg (arg, type);                               \
254                          }))
255 #else
256 # define ARG(type)      (argpos == 0 ? va_arg (arg, type) :                   \
257                          ({ unsigned int pos = argpos;                        \
258                             va_list arg = (va_list) argptr;                   \
259                             while (--pos > 0)                                 \
260                               (void) va_arg (arg, void *);                    \
261                             va_arg (arg, type);                               \
262                           }))
263 #endif
264
265       if (!isascii (*f))
266         {
267           /* Non-ASCII, may be a multibyte.  */
268           int len = mblen (f, strlen (f));
269           if (len > 0)
270             {
271               do
272                 {
273                   c = inchar ();
274                   if (c == EOF)
275                     input_error ();
276                   else if (c != *f++)
277                     {
278                       ungetc (c, s);
279                       conv_error ();
280                     }
281                 }
282               while (--len > 0);
283               continue;
284             }
285         }
286
287       fc = *f++;
288       if (fc != '%')
289         {
290           /* Remember to skip spaces.  */
291           if (isspace (fc))
292             {
293               skip_space = 1;
294               continue;
295             }
296
297           /* Read a character.  */
298           c = inchar ();
299
300           /* Characters other than format specs must just match.  */
301           if (c == EOF)
302             input_error ();
303
304           /* We saw white space char as the last character in the format
305              string.  Now it's time to skip all leading white space.  */
306           if (skip_space)
307             {
308               while (isspace (c))
309                 if (inchar () == EOF && errno == EINTR)
310                   conv_error ();
311               skip_space = 0;
312             }
313
314           if (c != fc)
315             {
316               ungetc (c, s);
317               conv_error ();
318             }
319
320           continue;
321         }
322
323       /* This is the start of the conversion string. */
324       flags = 0;
325
326       /* Initialize state of modifiers.  */
327       argpos = 0;
328
329       /* Prepare temporary buffer.  */
330       wpsize = 0;
331
332       /* Check for a positional parameter specification.  */
333       if (isdigit (*f))
334         {
335           argpos = *f++ - '0';
336           while (isdigit (*f))
337             argpos = argpos * 10 + (*f++ - '0');
338           if (*f == '$')
339             ++f;
340           else
341             {
342               /* Oops; that was actually the field width.  */
343               width = argpos;
344               flags |= WIDTH;
345               argpos = 0;
346               goto got_width;
347             }
348         }
349
350       /* Check for the assignment-suppressing and the number grouping flag.  */
351       while (*f == '*' || *f == '\'')
352         switch (*f++)
353           {
354           case '*':
355             flags |= SUPPRESS;
356             break;
357           case '\'':
358             flags |= GROUP;
359             break;
360           }
361
362       /* We have seen width. */
363       if (isdigit (*f))
364         flags |= WIDTH;
365
366       /* Find the maximum field width.  */
367       width = 0;
368       while (isdigit (*f))
369         {
370           width *= 10;
371           width += *f++ - '0';
372         }
373     got_width:
374       if (width == 0)
375         width = -1;
376
377       /* Check for type modifiers.  */
378       while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'a' || *f == 'q')
379         switch (*f++)
380           {
381           case 'h':
382             /* int's are short int's.  */
383             if (flags & TYPEMOD)
384               /* Signal illegal format element.  */
385               conv_error ();
386             flags |= SHORT;
387             break;
388           case 'l':
389             if (flags & (SHORT|LONGDBL))
390               conv_error ();
391             else if (flags & LONG)
392               {
393                 /* A double `l' is equivalent to an `L'.  */
394                 flags &= ~LONG;
395                 flags |= LONGDBL;
396               }
397             else
398               /* int's are long int's.  */
399               flags |= LONG;
400             break;
401           case 'q':
402           case 'L':
403             /* double's are long double's, and int's are long long int's.  */
404             if (flags & TYPEMOD)
405               /* Signal illegal format element.  */
406               conv_error ();
407             flags |= LONGDBL;
408             break;
409           case 'a':
410             if (flags & TYPEMOD)
411               /* Signal illegal format element.  */
412               conv_error ();
413             /* String conversions (%s, %[) take a `char **'
414                arg and fill it in with a malloc'd pointer.  */
415             flags |= MALLOC;
416             break;
417           }
418
419       /* End of the format string?  */
420       if (*f == '\0')
421         conv_error ();
422
423       /* We must take care for EINTR errors.  */
424       if (c == EOF && errno == EINTR)
425         input_error ();
426
427       /* Find the conversion specifier.  */
428       fc = *f++;
429       if (skip_space || (fc != '[' && fc != 'c' && fc != 'C' && fc != 'n'))
430         {
431           /* Eat whitespace.  */
432           do
433             if (inchar () == EOF && errno == EINTR)
434               input_error ();
435           while (isspace (c));
436           ungetc (c, s);
437           skip_space = 0;
438         }
439
440       switch (fc)
441         {
442         case '%':       /* Must match a literal '%'.  */
443           c = inchar ();
444           if (c != fc)
445             {
446               ungetc (c, s);
447               conv_error ();
448             }
449           break;
450
451         case 'n':       /* Answer number of assignments done.  */
452           /* Corrigendum 1 to ISO C 1990 describes the allowed flags
453              with the 'n' conversion specifier.  */
454           if (!(flags & SUPPRESS))
455             /* Don't count the read-ahead.  */
456             if (flags & LONGDBL)
457               *ARG (long long int *) = read_in;
458             else if (flags & LONG)
459               *ARG (long int *) = read_in;
460             else if (flags & SHORT)
461               *ARG (short int *) = read_in;
462             else
463               *ARG (int *) = read_in;
464           break;
465
466         case 'c':       /* Match characters.  */
467           if ((flags & LONG) == 0)
468             {
469               if (!(flags & SUPPRESS))
470                 {
471                   str = ARG (char *);
472                   if (str == NULL)
473                     conv_error ();
474                 }
475
476               c = inchar ();
477               if (c == EOF)
478                 input_error ();
479
480               if (width == -1)
481                 width = 1;
482
483               if (!(flags & SUPPRESS))
484                 {
485                   do
486                     *str++ = c;
487                   while (--width > 0 && inchar () != EOF);
488                 }
489               else
490                 while (--width > 0 && inchar () != EOF);
491
492               if (width > 0)
493                 /* I.e., EOF was read.  */
494                 --read_in;
495
496               if (!(flags & SUPPRESS))
497                 ++done;
498
499               break;
500             }
501           /* FALLTHROUGH */
502         case 'C':
503           /* Get UTF-8 encoded wide character.  Here we assume (as in
504              other parts of the libc) that we only have to handle
505              UTF-8.  */
506           {
507             wint_t val;
508             size_t cnt = 0;
509             int first = 1;
510
511             if (!(flags & SUPPRESS))
512               {
513                 wstr = ARG (wchar_t *);
514                 if (str == NULL)
515                   conv_error ();
516               }
517
518             do
519               {
520 #define NEXT_WIDE_CHAR(First)                                                 \
521                 c = inchar ();                                                \
522                 if (c == EOF)                                                 \
523                   /* EOF is only an error for the first character.  */        \
524                   if (First)                                                  \
525                     input_error ();                                           \
526                   else                                                        \
527                     {                                                         \
528                       --read_in;                                              \
529                       break;                                                  \
530                     }                                                         \
531                 val = c;                                                      \
532                 if (val >= 0x80)                                              \
533                   {                                                           \
534                     if ((c & 0xc0) == 0x80 || (c & 0xfe) == 0xfe)             \
535                       encode_error ();                                        \
536                     if ((c & 0xe0) == 0xc0)                                   \
537                       {                                                       \
538                         /* We expect two bytes.  */                           \
539                         cnt = 1;                                              \
540                         val &= 0x1f;                                          \
541                       }                                                       \
542                     else if ((c & 0xf0) == 0xe0)                              \
543                       {                                                       \
544                         /* We expect three bytes.  */                         \
545                         cnt = 2;                                              \
546                         val &= 0x0f;                                          \
547                       }                                                       \
548                     else if ((c & 0xf8) == 0xf0)                              \
549                       {                                                       \
550                         /* We expect four bytes.  */                          \
551                         cnt = 3;                                              \
552                         val &= 0x07;                                          \
553                       }                                                       \
554                     else if ((c & 0xfc) == 0xf8)                              \
555                       {                                                       \
556                         /* We expect five bytes.  */                          \
557                         cnt = 4;                                              \
558                         val &= 0x03;                                          \
559                       }                                                       \
560                     else                                                      \
561                       {                                                       \
562                         /* We expect six bytes.  */                           \
563                         cnt = 5;                                              \
564                         val &= 0x01;                                          \
565                       }                                                       \
566                                                                               \
567                     do                                                        \
568                       {                                                       \
569                         c = inchar ();                                        \
570                         if (c == EOF                                          \
571                             || (c & 0xc0) == 0x80 || (c & 0xfe) == 0xfe)      \
572                           encode_error ();                                    \
573                         val <<= 6;                                            \
574                         val |= c & 0x3f;                                      \
575                       }                                                       \
576                     while (--cnt > 0);                                        \
577                   }                                                           \
578                                                                               \
579                 if (!(flags & SUPPRESS))                                      \
580                   *wstr++ = val;                                              \
581                 first = 0
582
583                 NEXT_WIDE_CHAR (first);
584               }
585             while (--width > 0);
586
587             if (width > 0)
588               /* I.e., EOF was read.  */
589               --read_in;
590
591             if (!(flags & SUPPRESS))
592               ++done;
593           }
594           break;
595
596         case 's':               /* Read a string.  */
597           if (flags & LONG)
598             /* We have to process a wide character string.  */
599             goto wide_char_string;
600
601 #define STRING_ARG(Str, Type)                                                 \
602           if (!(flags & SUPPRESS))                                            \
603             {                                                                 \
604               if (flags & MALLOC)                                             \
605                 {                                                             \
606                   /* The string is to be stored in a malloc'd buffer.  */     \
607                   strptr = ARG (char **);                                     \
608                   if (strptr == NULL)                                         \
609                     conv_error ();                                            \
610                   /* Allocate an initial buffer.  */                          \
611                   strsize = 100;                                              \
612                   *strptr = malloc (strsize * sizeof (Type));                 \
613                   Str = (Type *) *strptr;                                     \
614                 }                                                             \
615               else                                                            \
616                 Str = ARG (Type *);                                           \
617               if (Str == NULL)                                                \
618                 conv_error ();                                                \
619             }
620           STRING_ARG (str, char);
621
622           c = inchar ();
623           if (c == EOF)
624             input_error ();
625
626           do
627             {
628               if (isspace (c))
629                 {
630                   ungetc (c, s);
631                   break;
632                 }
633 #define STRING_ADD_CHAR(Str, c, Type)                                         \
634               if (!(flags & SUPPRESS))                                        \
635                 {                                                             \
636                   *Str++ = c;                                                 \
637                   if ((flags & MALLOC) && (char *) Str == *strptr + strsize)  \
638                     {                                                         \
639                       /* Enlarge the buffer.  */                              \
640                       Str = realloc (*strptr, strsize * 2 * sizeof (Type));   \
641                       if (Str == NULL)                                        \
642                         {                                                     \
643                           /* Can't allocate that much.  Last-ditch effort.  */\
644                           Str = realloc (*strptr,                             \
645                                          (strsize + 1) * sizeof (Type));      \
646                           if (Str == NULL)                                    \
647                             {                                                 \
648                               /* We lose.  Oh well.                           \
649                                  Terminate the string and stop converting,    \
650                                  so at least we don't skip any input.  */     \
651                               ((Type *) (*strptr))[strsize] = '\0';           \
652                               ++done;                                         \
653                               conv_error ();                                  \
654                             }                                                 \
655                           else                                                \
656                             {                                                 \
657                               *strptr = (char *) Str;                         \
658                               Str = ((Type *) *strptr) + strsize;             \
659                               ++strsize;                                      \
660                             }                                                 \
661                         }                                                     \
662                       else                                                    \
663                         {                                                     \
664                           *strptr = (char *) Str;                             \
665                           Str = ((Type *) *strptr) + strsize;                 \
666                           strsize *= 2;                                       \
667                         }                                                     \
668                     }                                                         \
669                 }
670               STRING_ADD_CHAR (str, c, char);
671             } while ((width <= 0 || --width > 0) && inchar () != EOF);
672
673           if (c == EOF)
674             --read_in;
675
676           if (!(flags & SUPPRESS))
677             {
678               *str = '\0';
679               ++done;
680             }
681           break;
682
683         case 'S':
684           /* Wide character string.  */
685         wide_char_string:
686           {
687             wint_t val;
688             int first = 1;
689             STRING_ARG (wstr, wchar_t);
690
691             do
692               {
693                 size_t cnt = 0;
694                 NEXT_WIDE_CHAR (first);
695
696                 if (iswspace (val))
697                   {
698                     /* XXX We would have to push back the whole wide char
699                        with possibly many bytes.  But since scanf does
700                        not make a difference for white space characters
701                        we can simply push back a simple <SP> which is
702                        guaranteed to be in the [:space:] class.  */
703                     ungetc (' ', s);
704                     break;
705                   }
706
707                 STRING_ADD_CHAR (wstr, val, wchar_t);
708                 first = 0;
709               }
710             while (width <= 0 || --width > 0);
711
712             if (!(flags & SUPPRESS))
713               {
714                 *wstr = L'\0';
715                 ++done;
716               }
717           }
718           break;
719
720         case 'x':       /* Hexadecimal integer.  */
721         case 'X':       /* Ditto.  */
722           base = 16;
723           number_signed = 0;
724           goto number;
725
726         case 'o':       /* Octal integer.  */
727           base = 8;
728           number_signed = 0;
729           goto number;
730
731         case 'u':       /* Unsigned decimal integer.  */
732           base = 10;
733           number_signed = 0;
734           goto number;
735
736         case 'd':       /* Signed decimal integer.  */
737           base = 10;
738           number_signed = 1;
739           goto number;
740
741         case 'i':       /* Generic number.  */
742           base = 0;
743           number_signed = 1;
744
745         number:
746           c = inchar ();
747           if (c == EOF)
748             input_error ();
749
750           /* Check for a sign.  */
751           if (c == '-' || c == '+')
752             {
753               ADDW (c);
754               if (width > 0)
755                 --width;
756               c = inchar ();
757             }
758
759           /* Look for a leading indication of base.  */
760           if (width != 0 && c == '0')
761             {
762               if (width > 0)
763                 --width;
764
765               ADDW (c);
766               c = inchar ();
767
768               if (width != 0 && tolower (c) == 'x')
769                 {
770                   if (base == 0)
771                     base = 16;
772                   if (base == 16)
773                     {
774                       if (width > 0)
775                         --width;
776                       c = inchar ();
777                     }
778                 }
779               else if (base == 0)
780                 base = 8;
781             }
782
783           if (base == 0)
784             base = 10;
785
786           /* Read the number into workspace.  */
787           while (c != EOF && width != 0)
788             {
789               if (base == 16 ? !isxdigit (c) :
790                   ((!isdigit (c) || c - '0' >= base) &&
791                    !((flags & GROUP) && base == 10 && c == thousands)))
792                 break;
793               ADDW (c);
794               if (width > 0)
795                 --width;
796
797               c = inchar ();
798             }
799
800           /* The just read character is not part of the number anymore.  */
801           ungetc (c, s);
802
803           if (wpsize == 0 ||
804               (wpsize == 1 && (wp[0] == '+' || wp[0] == '-')))
805             /* There was no number.  */
806             conv_error ();
807
808           /* Convert the number.  */
809           ADDW ('\0');
810           if (flags & LONGDBL)
811             {
812               if (number_signed)
813                 num.q = __strtoq_internal (wp, &tw, base, flags & GROUP);
814               else
815                 num.uq = __strtouq_internal (wp, &tw, base, flags & GROUP);
816             }
817           else
818             {
819               if (number_signed)
820                 num.l = __strtol_internal (wp, &tw, base, flags & GROUP);
821               else
822                 num.ul = __strtoul_internal (wp, &tw, base, flags & GROUP);
823             }
824           if (wp == tw)
825             conv_error ();
826
827           if (!(flags & SUPPRESS))
828             {
829               if (! number_signed)
830                 {
831                   if (flags & LONGDBL)
832                     *ARG (unsigned LONGLONG int *) = num.uq;
833                   else if (flags & LONG)
834                     *ARG (unsigned long int *) = num.ul;
835                   else if (flags & SHORT)
836                     *ARG (unsigned short int *)
837                       = (unsigned short int) num.ul;
838                   else
839                     *ARG (unsigned int *) = (unsigned int) num.ul;
840                 }
841               else
842                 {
843                   if (flags & LONGDBL)
844                     *ARG (LONGLONG int *) = num.q;
845                   else if (flags & LONG)
846                     *ARG (long int *) = num.l;
847                   else if (flags & SHORT)
848                     *ARG (short int *) = (short int) num.l;
849                   else
850                     *ARG (int *) = (int) num.l;
851                 }
852               ++done;
853             }
854           break;
855
856         case 'e':       /* Floating-point numbers.  */
857         case 'E':
858         case 'f':
859         case 'g':
860         case 'G':
861           c = inchar ();
862           if (c == EOF)
863             input_error ();
864
865           /* Check for a sign.  */
866           if (c == '-' || c == '+')
867             {
868               negative = c == '-';
869               if (inchar () == EOF)
870                 /* EOF is only an input error before we read any chars.  */
871                 conv_error ();
872               if (width > 0)
873                 --width;
874             }
875           else
876             negative = 0;
877
878           got_dot = got_e = 0;
879           do
880             {
881               if (isdigit (c))
882                 ADDW (c);
883               else if (got_e && wp[wpsize - 1] == 'e'
884                        && (c == '-' || c == '+'))
885                 ADDW (c);
886               else if (wpsize > 0 && !got_e && tolower (c) == 'e')
887                 {
888                   ADDW ('e');
889                   got_e = got_dot = 1;
890                 }
891               else if (c == decimal && !got_dot)
892                 {
893                   ADDW (c);
894                   got_dot = 1;
895                 }
896               else if ((flags & GROUP) && c == thousands && !got_dot)
897                 ADDW (c);
898               else
899                 break;
900               if (width > 0)
901                 --width;
902             }
903           while (inchar () != EOF && width != 0);
904
905           /* The last read character is not part of the number anymore.  */
906           ungetc (c, s);
907
908           if (wpsize == 0)
909             conv_error ();
910
911           /* Convert the number.  */
912           ADDW ('\0');
913           if (flags & LONGDBL)
914             {
915               long double d = __strtold_internal (wp, &tw, flags & GROUP);
916               if (!(flags & SUPPRESS) && tw != wp)
917                 *ARG (long double *) = negative ? -d : d;
918             }
919           else if (flags & LONG)
920             {
921               double d = __strtod_internal (wp, &tw, flags & GROUP);
922               if (!(flags & SUPPRESS) && tw != wp)
923                 *ARG (double *) = negative ? -d : d;
924             }
925           else
926             {
927               float d = __strtof_internal (wp, &tw, flags & GROUP);
928               if (!(flags & SUPPRESS) && tw != wp)
929                 *ARG (float *) = negative ? -d : d;
930             }
931
932           if (tw == wp)
933             conv_error ();
934
935           if (!(flags & SUPPRESS))
936             ++done;
937           break;
938
939         case '[':       /* Character class.  */
940           if (flags & LONG)
941             {
942               STRING_ARG (wstr, wchar_t);
943               c = '\0';         /* This is to keep gcc quiet.  */
944             }
945           else
946             {
947               STRING_ARG (str, char);
948
949               c = inchar ();
950               if (c == EOF)
951                 input_error ();
952             }
953
954           if (*f == '^')
955             {
956               ++f;
957               not_in = 1;
958             }
959           else
960             not_in = 0;
961
962           /* Fill WP with byte flags indexed by character.
963              We will use this flag map for matching input characters.  */
964           if (wpmax < UCHAR_MAX)
965             {
966               wpmax = UCHAR_MAX;
967               wp = (char *) alloca (wpmax);
968             }
969           memset (wp, 0, UCHAR_MAX);
970
971           fc = *f;
972           if (fc == ']' || fc == '-')
973             {
974               /* If ] or - appears before any char in the set, it is not
975                  the terminator or separator, but the first char in the
976                  set.  */
977               wp[fc] = 1;
978               ++f;
979             }
980
981           while ((fc = *f++) != '\0' && fc != ']')
982             {
983               if (fc == '-' && *f != '\0' && *f != ']' &&
984                   (unsigned char) f[-2] <= (unsigned char) *f)
985                 {
986                   /* Add all characters from the one before the '-'
987                      up to (but not including) the next format char.  */
988                   for (fc = f[-2]; fc < *f; ++fc)
989                     wp[fc] = 1;
990                 }
991               else
992                 /* Add the character to the flag map.  */
993                 wp[fc] = 1;
994             }
995           if (fc == '\0')
996             {
997               if (!(flags & LONG))
998                 ungetc (c, s);
999               conv_error();
1000             }
1001
1002           if (flags & LONG)
1003             {
1004               wint_t val;
1005               int first = 1;
1006
1007               do
1008                 {
1009                   size_t cnt = 0;
1010                   NEXT_WIDE_CHAR (first);
1011                   if (val > 255 || wp[val] == not_in)
1012                     {
1013                       /* XXX We have a problem here.  We read a wide
1014                          character and this possibly took several
1015                          bytes.  But we can only push back one single
1016                          character.  To be sure we don't create wrong
1017                          input we push it back only in case it is
1018                          representable within one byte.  */
1019                       if (val < 0x80)
1020                         ungetc (val, s);
1021                       break;
1022                     }
1023                   STRING_ADD_CHAR (wstr, val, wchar_t);
1024                   if (width > 0)
1025                     --width;
1026                   first = 0;
1027                 }
1028               while (width != 0);
1029
1030               if (first)
1031                 conv_error ();
1032
1033               if (!(flags & SUPPRESS))
1034                 {
1035                   *wstr = L'\0';
1036                   ++done;
1037                 }
1038             }
1039           else
1040             {
1041               num.ul = read_in - 1; /* -1 because we already read one char.  */
1042               do
1043                 {
1044                   if (wp[c] == not_in)
1045                     {
1046                       ungetc (c, s);
1047                       break;
1048                     }
1049                   STRING_ADD_CHAR (str, c, char);
1050                   if (width > 0)
1051                     --width;
1052                 }
1053               while (width != 0 && inchar () != EOF);
1054
1055               if (read_in == num.ul)
1056                 conv_error ();
1057
1058               if (!(flags & SUPPRESS))
1059                 {
1060                   *str = '\0';
1061                   ++done;
1062                 }
1063             }
1064           break;
1065
1066         case 'p':       /* Generic pointer.  */
1067           base = 16;
1068           /* A PTR must be the same size as a `long int'.  */
1069           flags &= ~(SHORT|LONGDBL);
1070           flags |= LONG;
1071           number_signed = 0;
1072           goto number;
1073         }
1074     }
1075
1076   /* The last thing we saw int the format string was a white space.
1077      Consume the last white spaces.  */
1078   if (skip_space)
1079     {
1080       do
1081         c = inchar ();
1082       while (isspace (c));
1083       ungetc (c, s);
1084     }
1085
1086   /* Unlock stream.  */
1087   UNLOCK_STREAM;
1088
1089   return done;
1090 }
1091
1092 #ifdef USE_IN_LIBIO
1093 int
1094 __vfscanf (FILE *s, const char *format, va_list argptr)
1095 {
1096   return _IO_vfscanf (s, format, argptr, NULL);
1097 }
1098 #endif
1099
1100 weak_alias (__vfscanf, vfscanf)