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