Update from main archive 961219
[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                     break;                                                    \
528                 val = c;                                                      \
529                 if (val >= 0x80)                                              \
530                   {                                                           \
531                     if ((c & 0xc0) == 0x80 || (c & 0xfe) == 0xfe)             \
532                       encode_error ();                                        \
533                     if ((c & 0xe0) == 0xc0)                                   \
534                       {                                                       \
535                         /* We expect two bytes.  */                           \
536                         cnt = 1;                                              \
537                         val &= 0x1f;                                          \
538                       }                                                       \
539                     else if ((c & 0xf0) == 0xe0)                              \
540                       {                                                       \
541                         /* We expect three bytes.  */                         \
542                         cnt = 2;                                              \
543                         val &= 0x0f;                                          \
544                       }                                                       \
545                     else if ((c & 0xf8) == 0xf0)                              \
546                       {                                                       \
547                         /* We expect four bytes.  */                          \
548                         cnt = 3;                                              \
549                         val &= 0x07;                                          \
550                       }                                                       \
551                     else if ((c & 0xfc) == 0xf8)                              \
552                       {                                                       \
553                         /* We expect five bytes.  */                          \
554                         cnt = 4;                                              \
555                         val &= 0x03;                                          \
556                       }                                                       \
557                     else                                                      \
558                       {                                                       \
559                         /* We expect six bytes.  */                           \
560                         cnt = 5;                                              \
561                         val &= 0x01;                                          \
562                       }                                                       \
563                                                                               \
564                     do                                                        \
565                       {                                                       \
566                         c = inchar ();                                        \
567                         if (c == EOF                                          \
568                             || (c & 0xc0) == 0x80 || (c & 0xfe) == 0xfe)      \
569                           encode_error ();                                    \
570                         val <<= 6;                                            \
571                         val |= c & 0x3f;                                      \
572                       }                                                       \
573                     while (--cnt > 0);                                        \
574                   }                                                           \
575                                                                               \
576                 if (!(flags & SUPPRESS))                                      \
577                   *wstr++ = val;                                              \
578                 first = 0
579
580                 NEXT_WIDE_CHAR (first);
581               }
582             while (--width > 0);
583
584             if (width > 0)
585               /* I.e., EOF was read.  */
586               --read_in;
587
588             if (!(flags & SUPPRESS))
589               ++done;
590           }
591           break;
592
593         case 's':               /* Read a string.  */
594           if (flags & LONG)
595             /* We have to process a wide character string.  */
596             goto wide_char_string;
597
598 #define STRING_ARG(Str, Type)                                                 \
599           if (!(flags & SUPPRESS))                                            \
600             {                                                                 \
601               if (flags & MALLOC)                                             \
602                 {                                                             \
603                   /* The string is to be stored in a malloc'd buffer.  */     \
604                   strptr = ARG (char **);                                     \
605                   if (strptr == NULL)                                         \
606                     conv_error ();                                            \
607                   /* Allocate an initial buffer.  */                          \
608                   strsize = 100;                                              \
609                   *strptr = malloc (strsize * sizeof (Type));                 \
610                   Str = (Type *) *strptr;                                     \
611                 }                                                             \
612               else                                                            \
613                 Str = ARG (Type *);                                           \
614               if (Str == NULL)                                                \
615                 conv_error ();                                                \
616             }
617           STRING_ARG (str, char);
618
619           c = inchar ();
620           if (c == EOF)
621             input_error ();
622
623           do
624             {
625               if (isspace (c))
626                 {
627                   ungetc (c, s);
628                   break;
629                 }
630 #define STRING_ADD_CHAR(Str, c, Type)                                         \
631               if (!(flags & SUPPRESS))                                        \
632                 {                                                             \
633                   *Str++ = c;                                                 \
634                   if ((flags & MALLOC) && (char *) Str == *strptr + strsize)  \
635                     {                                                         \
636                       /* Enlarge the buffer.  */                              \
637                       Str = realloc (*strptr, strsize * 2 * sizeof (Type));   \
638                       if (Str == NULL)                                        \
639                         {                                                     \
640                           /* Can't allocate that much.  Last-ditch effort.  */\
641                           Str = realloc (*strptr,                             \
642                                          (strsize + 1) * sizeof (Type));      \
643                           if (Str == NULL)                                    \
644                             {                                                 \
645                               /* We lose.  Oh well.                           \
646                                  Terminate the string and stop converting,    \
647                                  so at least we don't skip any input.  */     \
648                               ((Type *) (*strptr))[strsize] = '\0';           \
649                               ++done;                                         \
650                               conv_error ();                                  \
651                             }                                                 \
652                           else                                                \
653                             {                                                 \
654                               *strptr = (char *) Str;                         \
655                               Str = ((Type *) *strptr) + strsize;             \
656                               ++strsize;                                      \
657                             }                                                 \
658                         }                                                     \
659                       else                                                    \
660                         {                                                     \
661                           *strptr = (char *) Str;                             \
662                           Str = ((Type *) *strptr) + strsize;                 \
663                           strsize *= 2;                                       \
664                         }                                                     \
665                     }                                                         \
666                 }
667               STRING_ADD_CHAR (str, c, char);
668             } while ((width <= 0 || --width > 0) && inchar () != EOF);
669
670           if (!(flags & SUPPRESS))
671             {
672               *str = '\0';
673               ++done;
674             }
675           break;
676
677         case 'S':
678           /* Wide character string.  */
679         wide_char_string:
680           {
681             wint_t val;
682             int first = 1;
683             STRING_ARG (wstr, wchar_t);
684
685             do
686               {
687                 size_t cnt = 0;
688                 NEXT_WIDE_CHAR (first);
689
690                 if (iswspace (val))
691                   {
692                     /* XXX We would have to push back the whole wide char
693                        with possibly many bytes.  But since scanf does
694                        not make a difference for white space characters
695                        we can simply push back a simple <SP> which is
696                        guaranteed to be in the [:space:] class.  */
697                     ungetc (' ', s);
698                     break;
699                   }
700
701                 STRING_ADD_CHAR (wstr, val, wchar_t);
702                 first = 0;
703               }
704             while (width <= 0 || --width > 0);
705
706             if (!(flags & SUPPRESS))
707               {
708                 *wstr = L'\0';
709                 ++done;
710               }
711           }
712           break;
713
714         case 'x':       /* Hexadecimal integer.  */
715         case 'X':       /* Ditto.  */
716           base = 16;
717           number_signed = 0;
718           goto number;
719
720         case 'o':       /* Octal integer.  */
721           base = 8;
722           number_signed = 0;
723           goto number;
724
725         case 'u':       /* Unsigned decimal integer.  */
726           base = 10;
727           number_signed = 0;
728           goto number;
729
730         case 'd':       /* Signed decimal integer.  */
731           base = 10;
732           number_signed = 1;
733           goto number;
734
735         case 'i':       /* Generic number.  */
736           base = 0;
737           number_signed = 1;
738
739         number:
740           c = inchar ();
741           if (c == EOF)
742             input_error ();
743
744           /* Check for a sign.  */
745           if (c == '-' || c == '+')
746             {
747               ADDW (c);
748               if (width > 0)
749                 --width;
750               c = inchar ();
751             }
752
753           /* Look for a leading indication of base.  */
754           if (width != 0 && c == '0')
755             {
756               if (width > 0)
757                 --width;
758
759               ADDW (c);
760               c = inchar ();
761
762               if (width != 0 && tolower (c) == 'x')
763                 {
764                   if (base == 0)
765                     base = 16;
766                   if (base == 16)
767                     {
768                       if (width > 0)
769                         --width;
770                       c = inchar ();
771                     }
772                 }
773               else if (base == 0)
774                 base = 8;
775             }
776
777           if (base == 0)
778             base = 10;
779
780           /* Read the number into workspace.  */
781           while (c != EOF && width != 0)
782             {
783               if (base == 16 ? !isxdigit (c) :
784                   ((!isdigit (c) || c - '0' >= base) &&
785                    !((flags & GROUP) && base == 10 && c == thousands)))
786                 break;
787               ADDW (c);
788               if (width > 0)
789                 --width;
790
791               c = inchar ();
792             }
793
794           /* The just read character is not part of the number anymore.  */
795           ungetc (c, s);
796
797           if (wpsize == 0 ||
798               (wpsize == 1 && (wp[0] == '+' || wp[0] == '-')))
799             /* There was no number.  */
800             conv_error ();
801
802           /* Convert the number.  */
803           ADDW ('\0');
804           if (flags & LONGDBL)
805             {
806               if (number_signed)
807                 num.q = __strtoq_internal (wp, &tw, base, flags & GROUP);
808               else
809                 num.uq = __strtouq_internal (wp, &tw, base, flags & GROUP);
810             }
811           else
812             {
813               if (number_signed)
814                 num.l = __strtol_internal (wp, &tw, base, flags & GROUP);
815               else
816                 num.ul = __strtoul_internal (wp, &tw, base, flags & GROUP);
817             }
818           if (wp == tw)
819             conv_error ();
820
821           if (!(flags & SUPPRESS))
822             {
823               if (! number_signed)
824                 {
825                   if (flags & LONGDBL)
826                     *ARG (unsigned LONGLONG int *) = num.uq;
827                   else if (flags & LONG)
828                     *ARG (unsigned long int *) = num.ul;
829                   else if (flags & SHORT)
830                     *ARG (unsigned short int *)
831                       = (unsigned short int) num.ul;
832                   else
833                     *ARG (unsigned int *) = (unsigned int) num.ul;
834                 }
835               else
836                 {
837                   if (flags & LONGDBL)
838                     *ARG (LONGLONG int *) = num.q;
839                   else if (flags & LONG)
840                     *ARG (long int *) = num.l;
841                   else if (flags & SHORT)
842                     *ARG (short int *) = (short int) num.l;
843                   else
844                     *ARG (int *) = (int) num.l;
845                 }
846               ++done;
847             }
848           break;
849
850         case 'e':       /* Floating-point numbers.  */
851         case 'E':
852         case 'f':
853         case 'g':
854         case 'G':
855           c = inchar ();
856           if (c == EOF)
857             input_error ();
858
859           /* Check for a sign.  */
860           if (c == '-' || c == '+')
861             {
862               negative = c == '-';
863               if (inchar () == EOF)
864                 /* EOF is only an input error before we read any chars.  */
865                 conv_error ();
866               if (width > 0)
867                 --width;
868             }
869           else
870             negative = 0;
871
872           got_dot = got_e = 0;
873           do
874             {
875               if (isdigit (c))
876                 ADDW (c);
877               else if (got_e && wp[wpsize - 1] == 'e'
878                        && (c == '-' || c == '+'))
879                 ADDW (c);
880               else if (wpsize > 0 && !got_e && tolower (c) == 'e')
881                 {
882                   ADDW ('e');
883                   got_e = got_dot = 1;
884                 }
885               else if (c == decimal && !got_dot)
886                 {
887                   ADDW (c);
888                   got_dot = 1;
889                 }
890               else if ((flags & GROUP) && c == thousands && !got_dot)
891                 ADDW (c);
892               else
893                 break;
894               if (width > 0)
895                 --width;
896             }
897           while (inchar () != EOF && width != 0);
898
899           /* The last read character is not part of the number anymore.  */
900           ungetc (c, s);
901
902           if (wpsize == 0)
903             conv_error ();
904
905           /* Convert the number.  */
906           ADDW ('\0');
907           if (flags & LONGDBL)
908             {
909               long double d = __strtold_internal (wp, &tw, flags & GROUP);
910               if (!(flags & SUPPRESS) && tw != wp)
911                 *ARG (long double *) = negative ? -d : d;
912             }
913           else if (flags & LONG)
914             {
915               double d = __strtod_internal (wp, &tw, flags & GROUP);
916               if (!(flags & SUPPRESS) && tw != wp)
917                 *ARG (double *) = negative ? -d : d;
918             }
919           else
920             {
921               float d = __strtof_internal (wp, &tw, flags & GROUP);
922               if (!(flags & SUPPRESS) && tw != wp)
923                 *ARG (float *) = negative ? -d : d;
924             }
925
926           if (tw == wp)
927             conv_error ();
928
929           if (!(flags & SUPPRESS))
930             ++done;
931           break;
932
933         case '[':       /* Character class.  */
934           if (flags & LONG)
935             {
936               STRING_ARG (wstr, wchar_t);
937               c = '\0';         /* This is to keep gcc quiet.  */
938             }
939           else
940             {
941               STRING_ARG (str, char);
942
943               c = inchar ();
944               if (c == EOF)
945                 input_error ();
946             }
947
948           if (*f == '^')
949             {
950               ++f;
951               not_in = 1;
952             }
953           else
954             not_in = 0;
955
956           /* Fill WP with byte flags indexed by character.
957              We will use this flag map for matching input characters.  */
958           if (wpmax < UCHAR_MAX)
959             {
960               wpmax = UCHAR_MAX;
961               wp = (char *) alloca (wpmax);
962             }
963           memset (wp, 0, UCHAR_MAX);
964
965           fc = *f;
966           if (fc == ']' || fc == '-')
967             {
968               /* If ] or - appears before any char in the set, it is not
969                  the terminator or separator, but the first char in the
970                  set.  */
971               wp[fc] = 1;
972               ++f;
973             }
974
975           while ((fc = *f++) != '\0' && fc != ']')
976             {
977               if (fc == '-' && *f != '\0' && *f != ']' &&
978                   (unsigned char) f[-2] <= (unsigned char) *f)
979                 {
980                   /* Add all characters from the one before the '-'
981                      up to (but not including) the next format char.  */
982                   for (fc = f[-2]; fc < *f; ++fc)
983                     wp[fc] = 1;
984                 }
985               else
986                 /* Add the character to the flag map.  */
987                 wp[fc] = 1;
988             }
989           if (fc == '\0')
990             {
991               if (!(flags & LONG))
992                 ungetc (c, s);
993               conv_error();
994             }
995
996           if (flags & LONG)
997             {
998               wint_t val;
999               int first = 1;
1000
1001               do
1002                 {
1003                   size_t cnt = 0;
1004                   NEXT_WIDE_CHAR (first);
1005                   if (val > 255 || wp[val] == not_in)
1006                     {
1007                       /* XXX We have a problem here.  We read a wide
1008                          character and this possibly took several
1009                          bytes.  But we can only push back one single
1010                          character.  To be sure we don't create wrong
1011                          input we push it back only in case it is
1012                          representable within one byte.  */
1013                       if (val < 0x80)
1014                         ungetc (val, s);
1015                       break;
1016                     }
1017                   STRING_ADD_CHAR (wstr, val, wchar_t);
1018                   if (width > 0)
1019                     --width;
1020                   first = 0;
1021                 }
1022               while (width != 0);
1023
1024               if (first)
1025                 conv_error ();
1026
1027               if (!(flags & SUPPRESS))
1028                 {
1029                   *wstr = L'\0';
1030                   ++done;
1031                 }
1032             }
1033           else
1034             {
1035               num.ul = read_in - 1; /* -1 because we already read one char.  */
1036               do
1037                 {
1038                   if (wp[c] == not_in)
1039                     {
1040                       ungetc (c, s);
1041                       break;
1042                     }
1043                   STRING_ADD_CHAR (str, c, char);
1044                   if (width > 0)
1045                     --width;
1046                 }
1047               while (width != 0 && inchar () != EOF);
1048
1049               if (read_in == num.ul)
1050                 conv_error ();
1051
1052               if (!(flags & SUPPRESS))
1053                 {
1054                   *str = '\0';
1055                   ++done;
1056                 }
1057             }
1058           break;
1059
1060         case 'p':       /* Generic pointer.  */
1061           base = 16;
1062           /* A PTR must be the same size as a `long int'.  */
1063           flags &= ~(SHORT|LONGDBL);
1064           flags |= LONG;
1065           number_signed = 0;
1066           goto number;
1067         }
1068     }
1069
1070   /* The last thing we saw int the format string was a white space.
1071      Consume the last white spaces.  */
1072   if (skip_space)
1073     {
1074       do
1075         c = inchar ();
1076       while (isspace (c));
1077       ungetc (c, s);
1078     }
1079
1080   /* Unlock stream.  */
1081   UNLOCK_STREAM;
1082
1083   return done;
1084 }
1085
1086 #ifdef USE_IN_LIBIO
1087 int
1088 __vfscanf (FILE *s, const char *format, va_list argptr)
1089 {
1090   return _IO_vfscanf (s, format, argptr, NULL);
1091 }
1092 #endif
1093
1094 weak_alias (__vfscanf, vfscanf)