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