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