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