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