Update.
[glibc.git] / stdio-common / vfscanf.c
blob3738e44f0a69eeccecbeb67e6a3d7344e2370f36
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
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. */
19 #include "../locale/localeinfo.h"
20 #include <errno.h>
21 #include <limits.h>
22 #include <ctype.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <wctype.h>
28 #include <libc-lock.h>
30 #ifdef __GNUC__
31 #define HAVE_LONGLONG
32 #define LONGLONG long long
33 #else
34 #define LONGLONG long
35 #endif
37 /* Those are flags in the conversion format. */
38 # define LONG 0x001 /* l: long or double */
39 # define LONGDBL 0x002 /* L: long long or long double */
40 # define SHORT 0x004 /* h: short */
41 # define SUPPRESS 0x008 /* *: suppress assignment */
42 # define POINTER 0x010 /* weird %p pointer (`fake hex') */
43 # define NOSKIP 0x020 /* do not skip blanks */
44 # define WIDTH 0x040 /* width was given */
45 # define GROUP 0x080 /* ': group numbers */
46 # define MALLOC 0x100 /* a: malloc strings */
48 # define TYPEMOD (LONG|LONGDBL|SHORT)
51 #ifdef USE_IN_LIBIO
52 # include <libioP.h>
53 # include <libio.h>
55 # undef va_list
56 # define va_list _IO_va_list
57 # define ungetc(c, s) (--read_in, _IO_ungetc (c, s))
58 # define inchar() ((c = _IO_getc_unlocked (s)), (void) ++read_in, c)
59 # define encode_error() do { \
60 if (errp != NULL) *errp |= 4; \
61 _IO_funlockfile (s); \
62 __set_errno (EILSEQ); \
63 return done; \
64 } while (0)
65 # define conv_error() do { \
66 if (errp != NULL) *errp |= 2; \
67 _IO_funlockfile (s); \
68 return done; \
69 } while (0)
70 # define input_error() do { \
71 _IO_funlockfile (s); \
72 if (errp != NULL) *errp |= 1; \
73 return done ?: EOF; \
74 } while (0)
75 # define memory_error() do { \
76 _IO_funlockfile (s); \
77 __set_errno (ENOMEM); \
78 return EOF; \
79 } while (0)
80 # define ARGCHECK(s, format) \
81 do \
82 { \
83 /* Check file argument for consistence. */ \
84 CHECK_FILE (s, EOF); \
85 if (s->_flags & _IO_NO_READS) \
86 { \
87 __set_errno (EBADF); \
88 return EOF; \
89 } \
90 else if (format == NULL) \
91 { \
92 MAYBE_SET_EINVAL; \
93 return EOF; \
94 } \
95 } while (0)
96 # define LOCK_STREAM(S) \
97 __libc_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, (S)); \
98 _IO_flockfile (S)
99 # define UNLOCK_STREAM __libc_cleanup_region_end (1)
100 #else
101 # define ungetc(c, s) (--read_in, ungetc (c, s))
102 # define inchar() ((c = getc (s)), (void) ++read_in, c)
103 # define encode_error() do { \
104 funlockfile (s); \
105 __set_errno (EILSEQ); \
106 return done; \
107 } while (0)
108 # define conv_error() do { \
109 funlockfile (s); \
110 return done; \
111 } while (0)
112 # define input_error() do { \
113 funlockfile (s); \
114 return done ?: EOF; \
115 } while (0)
116 # define memory_error() do { \
117 funlockfile (s); \
118 __set_errno (ENOMEM); \
119 return EOF; \
120 } while (0)
121 # define ARGCHECK(s, format) \
122 do \
124 /* Check file argument for consistence. */ \
125 if (!__validfp (s) || !s->__mode.__read) \
127 __set_errno (EBADF); \
128 return EOF; \
130 else if (format == NULL) \
132 __set_errno (EINVAL); \
133 return EOF; \
135 } while (0)
136 #if 1
137 /* XXX For now !!! */
138 # define flockfile(S) /* nothing */
139 # define funlockfile(S) /* nothing */
140 # define LOCK_STREAM(S)
141 # define UNLOCK_STREAM
142 #else
143 # define LOCK_STREAM(S) \
144 __libc_cleanup_region_start (&__funlockfile, (S)); \
145 __flockfile (S)
146 # define UNLOCK_STREAM __libc_cleanup_region_end (1)
147 #endif
148 #endif
151 /* Read formatted input from S according to the format string
152 FORMAT, using the argument list in ARG.
153 Return the number of assignments made, or -1 for an input error. */
154 #ifdef USE_IN_LIBIO
156 _IO_vfscanf (s, format, argptr, errp)
157 _IO_FILE *s;
158 const char *format;
159 _IO_va_list argptr;
160 int *errp;
161 #else
163 __vfscanf (FILE *s, const char *format, va_list argptr)
164 #endif
166 va_list arg;
167 register const char *f = format;
168 register unsigned char fc; /* Current character of the format. */
169 register size_t done = 0; /* Assignments done. */
170 register size_t read_in = 0; /* Chars read in. */
171 register int c = 0; /* Last char read. */
172 register int width; /* Maximum field width. */
173 register int flags; /* Modifiers for current format element. */
175 /* Status for reading F-P nums. */
176 char got_dot, got_e, negative;
177 /* If a [...] is a [^...]. */
178 char not_in;
179 #define exp_char not_in
180 /* Base for integral numbers. */
181 int base;
182 /* Signedness for integral numbers. */
183 int number_signed;
184 #define is_hexa number_signed
185 /* Decimal point character. */
186 wchar_t decimal;
187 /* The thousands character of the current locale. */
188 wchar_t thousands;
189 /* Integral holding variables. */
190 union
192 long long int q;
193 unsigned long long int uq;
194 long int l;
195 unsigned long int ul;
196 } num;
197 /* Character-buffer pointer. */
198 char *str = NULL;
199 wchar_t *wstr = NULL;
200 char **strptr = NULL;
201 size_t strsize = 0;
202 /* We must not react on white spaces immediately because they can
203 possibly be matched even if in the input stream no character is
204 available anymore. */
205 int skip_space = 0;
206 /* Workspace. */
207 char *tw; /* Temporary pointer. */
208 char *wp = NULL; /* Workspace. */
209 size_t wpmax = 0; /* Maximal size of workspace. */
210 size_t wpsize; /* Currently used bytes in workspace. */
211 #define ADDW(Ch) \
212 do \
214 if (wpsize == wpmax) \
216 char *old = wp; \
217 wpmax = UCHAR_MAX > 2 * wpmax ? UCHAR_MAX : 2 * wpmax; \
218 wp = (char *) alloca (wpmax); \
219 if (old != NULL) \
220 memcpy (wp, old, wpsize); \
222 wp[wpsize++] = (Ch); \
224 while (0)
226 #ifdef __va_copy
227 __va_copy (arg, argptr);
228 #else
229 arg = (va_list) argptr;
230 #endif
232 ARGCHECK (s, format);
234 /* Figure out the decimal point character. */
235 if (mbtowc (&decimal, _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT),
236 strlen (_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT))) <= 0)
237 decimal = (wchar_t) *_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
238 /* Figure out the thousands separator character. */
239 if (mbtowc (&thousands, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
240 strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
241 thousands = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
243 /* Lock the stream. */
244 LOCK_STREAM (s);
246 /* Run through the format string. */
247 while (*f != '\0')
249 unsigned int argpos;
250 /* Extract the next argument, which is of type TYPE.
251 For a %N$... spec, this is the Nth argument from the beginning;
252 otherwise it is the next argument after the state now in ARG. */
253 #ifdef __va_copy
254 # define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
255 ({ unsigned int pos = argpos; \
256 va_list arg; \
257 __va_copy (arg, argptr); \
258 while (--pos > 0) \
259 (void) va_arg (arg, void *); \
260 va_arg (arg, type); \
262 #else
263 # if 0
264 /* XXX Possible optimization. */
265 # define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
266 ({ va_list arg = (va_list) argptr; \
267 arg = (va_list) ((char *) arg \
268 + (argpos - 1) \
269 * __va_rounded_size (void *)); \
270 va_arg (arg, type); \
272 # else
273 # define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
274 ({ unsigned int pos = argpos; \
275 va_list arg = (va_list) argptr; \
276 while (--pos > 0) \
277 (void) va_arg (arg, void *); \
278 va_arg (arg, type); \
280 # endif
281 #endif
283 if (!isascii (*f))
285 /* Non-ASCII, may be a multibyte. */
286 int len = mblen (f, strlen (f));
287 if (len > 0)
291 c = inchar ();
292 if (c == EOF)
293 input_error ();
294 else if (c != *f++)
296 ungetc (c, s);
297 conv_error ();
300 while (--len > 0);
301 continue;
305 fc = *f++;
306 if (fc != '%')
308 /* Remember to skip spaces. */
309 if (isspace (fc))
311 skip_space = 1;
312 continue;
315 /* Read a character. */
316 c = inchar ();
318 /* Characters other than format specs must just match. */
319 if (c == EOF)
320 input_error ();
322 /* We saw white space char as the last character in the format
323 string. Now it's time to skip all leading white space. */
324 if (skip_space)
326 while (isspace (c))
327 if (inchar () == EOF && errno == EINTR)
328 conv_error ();
329 skip_space = 0;
332 if (c != fc)
334 ungetc (c, s);
335 conv_error ();
338 continue;
341 /* This is the start of the conversion string. */
342 flags = 0;
344 /* Initialize state of modifiers. */
345 argpos = 0;
347 /* Prepare temporary buffer. */
348 wpsize = 0;
350 /* Check for a positional parameter specification. */
351 if (isdigit (*f))
353 argpos = *f++ - '0';
354 while (isdigit (*f))
355 argpos = argpos * 10 + (*f++ - '0');
356 if (*f == '$')
357 ++f;
358 else
360 /* Oops; that was actually the field width. */
361 width = argpos;
362 flags |= WIDTH;
363 argpos = 0;
364 goto got_width;
368 /* Check for the assignment-suppressing and the number grouping flag. */
369 while (*f == '*' || *f == '\'')
370 switch (*f++)
372 case '*':
373 flags |= SUPPRESS;
374 break;
375 case '\'':
376 flags |= GROUP;
377 break;
380 /* We have seen width. */
381 if (isdigit (*f))
382 flags |= WIDTH;
384 /* Find the maximum field width. */
385 width = 0;
386 while (isdigit (*f))
388 width *= 10;
389 width += *f++ - '0';
391 got_width:
392 if (width == 0)
393 width = -1;
395 /* Check for type modifiers. */
396 while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'a' || *f == 'q')
397 switch (*f++)
399 case 'h':
400 /* int's are short int's. */
401 if (flags & TYPEMOD)
402 /* Signal illegal format element. */
403 conv_error ();
404 flags |= SHORT;
405 break;
406 case 'l':
407 if (flags & (SHORT|LONGDBL))
408 conv_error ();
409 else if (flags & LONG)
411 /* A double `l' is equivalent to an `L'. */
412 flags &= ~LONG;
413 flags |= LONGDBL;
415 else
416 /* int's are long int's. */
417 flags |= LONG;
418 break;
419 case 'q':
420 case 'L':
421 /* double's are long double's, and int's are long long int's. */
422 if (flags & TYPEMOD)
423 /* Signal illegal format element. */
424 conv_error ();
425 flags |= LONGDBL;
426 break;
427 case 'a':
428 if (flags & TYPEMOD)
429 /* Signal illegal format element. */
430 conv_error ();
431 /* String conversions (%s, %[) take a `char **'
432 arg and fill it in with a malloc'd pointer. */
433 flags |= MALLOC;
434 break;
437 /* End of the format string? */
438 if (*f == '\0')
439 conv_error ();
441 /* We must take care for EINTR errors. */
442 if (c == EOF && errno == EINTR)
443 input_error ();
445 /* Find the conversion specifier. */
446 fc = *f++;
447 if (skip_space || (fc != '[' && fc != 'c' && fc != 'C' && fc != 'n'))
449 /* Eat whitespace. */
451 if (inchar () == EOF && errno == EINTR)
452 input_error ();
453 while (isspace (c));
454 ungetc (c, s);
455 skip_space = 0;
458 switch (fc)
460 case '%': /* Must match a literal '%'. */
461 c = inchar ();
462 if (c != fc)
464 ungetc (c, s);
465 conv_error ();
467 break;
469 case 'n': /* Answer number of assignments done. */
470 /* Corrigendum 1 to ISO C 1990 describes the allowed flags
471 with the 'n' conversion specifier. */
472 if (!(flags & SUPPRESS))
474 /* Don't count the read-ahead. */
475 if (flags & LONGDBL)
476 *ARG (long long int *) = read_in;
477 else if (flags & LONG)
478 *ARG (long int *) = read_in;
479 else if (flags & SHORT)
480 *ARG (short int *) = read_in;
481 else
482 *ARG (int *) = read_in;
484 #ifdef NO_BUG_IN_ISO_C_CORRIGENDUM_1
485 /* We have a severe problem here. The ISO C standard
486 contradicts itself in explaining the effect of the %n
487 format in `scanf'. While in ISO C:1990 and the ISO C
488 Amendement 1:1995 the result is described as
490 Execution of a %n directive does not effect the
491 assignment count returned at the completion of
492 execution of the f(w)scanf function.
494 in ISO C Corrigendum 1:1994 the following was added:
496 Subclause 7.9.6.2
497 Add the following fourth example:
499 #include <stdio.h>
500 int d1, d2, n1, n2, i;
501 i = sscanf("123", "%d%n%n%d", &d1, &n1, &n2, &d2);
502 the value 123 is assigned to d1 and the value3 to n1.
503 Because %n can never get an input failure the value
504 of 3 is also assigned to n2. The value of d2 is not
505 affected. The value 3 is assigned to i.
507 We go for now with the historically correct code fro ISO C,
508 i.e., we don't count the %n assignments. When it ever
509 should proof to be wrong just remove the #ifdef above. */
510 ++done;
511 #endif
513 break;
515 case 'c': /* Match characters. */
516 if ((flags & LONG) == 0)
518 if (!(flags & SUPPRESS))
520 str = ARG (char *);
521 if (str == NULL)
522 conv_error ();
525 c = inchar ();
526 if (c == EOF)
527 input_error ();
529 if (width == -1)
530 width = 1;
532 if (!(flags & SUPPRESS))
535 *str++ = c;
536 while (--width > 0 && inchar () != EOF);
538 else
539 while (--width > 0 && inchar () != EOF);
541 if (width > 0)
542 /* I.e., EOF was read. */
543 --read_in;
545 if (!(flags & SUPPRESS))
546 ++done;
548 break;
550 /* FALLTHROUGH */
551 case 'C':
552 /* Get UTF-8 encoded wide character. Here we assume (as in
553 other parts of the libc) that we only have to handle
554 UTF-8. */
556 wint_t val;
557 size_t cnt = 0;
558 int first = 1;
560 if (!(flags & SUPPRESS))
562 wstr = ARG (wchar_t *);
563 if (str == NULL)
564 conv_error ();
569 #define NEXT_WIDE_CHAR(First) \
570 c = inchar (); \
571 if (c == EOF) \
572 /* EOF is only an error for the first character. */ \
573 if (First) \
574 input_error (); \
575 else \
577 --read_in; \
578 break; \
580 val = c; \
581 if (val >= 0x80) \
583 if ((c & 0xc0) == 0x80 || (c & 0xfe) == 0xfe) \
584 encode_error (); \
585 if ((c & 0xe0) == 0xc0) \
587 /* We expect two bytes. */ \
588 cnt = 1; \
589 val &= 0x1f; \
591 else if ((c & 0xf0) == 0xe0) \
593 /* We expect three bytes. */ \
594 cnt = 2; \
595 val &= 0x0f; \
597 else if ((c & 0xf8) == 0xf0) \
599 /* We expect four bytes. */ \
600 cnt = 3; \
601 val &= 0x07; \
603 else if ((c & 0xfc) == 0xf8) \
605 /* We expect five bytes. */ \
606 cnt = 4; \
607 val &= 0x03; \
609 else \
611 /* We expect six bytes. */ \
612 cnt = 5; \
613 val &= 0x01; \
616 do \
618 c = inchar (); \
619 if (c == EOF \
620 || (c & 0xc0) == 0x80 || (c & 0xfe) == 0xfe) \
621 encode_error (); \
622 val <<= 6; \
623 val |= c & 0x3f; \
625 while (--cnt > 0); \
628 if (!(flags & SUPPRESS)) \
629 *wstr++ = val; \
630 first = 0
632 NEXT_WIDE_CHAR (first);
634 while (--width > 0);
636 if (width > 0)
637 /* I.e., EOF was read. */
638 --read_in;
640 if (!(flags & SUPPRESS))
641 ++done;
643 break;
645 case 's': /* Read a string. */
646 if (flags & LONG)
647 /* We have to process a wide character string. */
648 goto wide_char_string;
650 #define STRING_ARG(Str, Type) \
651 if (!(flags & SUPPRESS)) \
653 if (flags & MALLOC) \
655 /* The string is to be stored in a malloc'd buffer. */ \
656 strptr = ARG (char **); \
657 if (strptr == NULL) \
658 conv_error (); \
659 /* Allocate an initial buffer. */ \
660 strsize = 100; \
661 *strptr = malloc (strsize * sizeof (Type)); \
662 Str = (Type *) *strptr; \
664 else \
665 Str = ARG (Type *); \
666 if (Str == NULL) \
667 conv_error (); \
669 STRING_ARG (str, char);
671 c = inchar ();
672 if (c == EOF)
673 input_error ();
677 if (isspace (c))
679 ungetc (c, s);
680 break;
682 #define STRING_ADD_CHAR(Str, c, Type) \
683 if (!(flags & SUPPRESS)) \
685 *Str++ = c; \
686 if ((flags & MALLOC) && (char *) Str == *strptr + strsize) \
688 /* Enlarge the buffer. */ \
689 Str = realloc (*strptr, strsize * 2 * sizeof (Type)); \
690 if (Str == NULL) \
692 /* Can't allocate that much. Last-ditch effort. */\
693 Str = realloc (*strptr, \
694 (strsize + 1) * sizeof (Type)); \
695 if (Str == NULL) \
697 /* We lose. Oh well. \
698 Terminate the string and stop converting, \
699 so at least we don't skip any input. */ \
700 ((Type *) (*strptr))[strsize] = '\0'; \
701 ++done; \
702 conv_error (); \
704 else \
706 *strptr = (char *) Str; \
707 Str = ((Type *) *strptr) + strsize; \
708 ++strsize; \
711 else \
713 *strptr = (char *) Str; \
714 Str = ((Type *) *strptr) + strsize; \
715 strsize *= 2; \
719 STRING_ADD_CHAR (str, c, char);
720 } while ((width <= 0 || --width > 0) && inchar () != EOF);
722 if (c == EOF)
723 --read_in;
725 if (!(flags & SUPPRESS))
727 *str = '\0';
728 ++done;
730 break;
732 case 'S':
733 /* Wide character string. */
734 wide_char_string:
736 wint_t val;
737 int first = 1;
738 STRING_ARG (wstr, wchar_t);
742 size_t cnt = 0;
743 NEXT_WIDE_CHAR (first);
745 if (iswspace (val))
747 /* XXX We would have to push back the whole wide char
748 with possibly many bytes. But since scanf does
749 not make a difference for white space characters
750 we can simply push back a simple <SP> which is
751 guaranteed to be in the [:space:] class. */
752 ungetc (' ', s);
753 break;
756 STRING_ADD_CHAR (wstr, val, wchar_t);
757 first = 0;
759 while (width <= 0 || --width > 0);
761 if (!(flags & SUPPRESS))
763 *wstr = L'\0';
764 ++done;
767 break;
769 case 'x': /* Hexadecimal integer. */
770 case 'X': /* Ditto. */
771 base = 16;
772 number_signed = 0;
773 goto number;
775 case 'o': /* Octal integer. */
776 base = 8;
777 number_signed = 0;
778 goto number;
780 case 'u': /* Unsigned decimal integer. */
781 base = 10;
782 number_signed = 0;
783 goto number;
785 case 'd': /* Signed decimal integer. */
786 base = 10;
787 number_signed = 1;
788 goto number;
790 case 'i': /* Generic number. */
791 base = 0;
792 number_signed = 1;
794 number:
795 c = inchar ();
796 if (c == EOF)
797 input_error ();
799 /* Check for a sign. */
800 if (c == '-' || c == '+')
802 ADDW (c);
803 if (width > 0)
804 --width;
805 c = inchar ();
808 /* Look for a leading indication of base. */
809 if (width != 0 && c == '0')
811 if (width > 0)
812 --width;
814 ADDW (c);
815 c = inchar ();
817 if (width != 0 && tolower (c) == 'x')
819 if (base == 0)
820 base = 16;
821 if (base == 16)
823 if (width > 0)
824 --width;
825 c = inchar ();
828 else if (base == 0)
829 base = 8;
832 if (base == 0)
833 base = 10;
835 /* Read the number into workspace. */
836 while (c != EOF && width != 0)
838 if (base == 16 ? !isxdigit (c) :
839 ((!isdigit (c) || c - '0' >= base) &&
840 !((flags & GROUP) && base == 10 && c == thousands)))
841 break;
842 ADDW (c);
843 if (width > 0)
844 --width;
846 c = inchar ();
849 /* The just read character is not part of the number anymore. */
850 ungetc (c, s);
852 if (wpsize == 0 ||
853 (wpsize == 1 && (wp[0] == '+' || wp[0] == '-')))
854 /* There was no number. */
855 conv_error ();
857 /* Convert the number. */
858 ADDW ('\0');
859 if (flags & LONGDBL)
861 if (number_signed)
862 num.q = __strtoll_internal (wp, &tw, base, flags & GROUP);
863 else
864 num.uq = __strtoull_internal (wp, &tw, base, flags & GROUP);
866 else
868 if (number_signed)
869 num.l = __strtol_internal (wp, &tw, base, flags & GROUP);
870 else
871 num.ul = __strtoul_internal (wp, &tw, base, flags & GROUP);
873 if (wp == tw)
874 conv_error ();
876 if (!(flags & SUPPRESS))
878 if (! number_signed)
880 if (flags & LONGDBL)
881 *ARG (unsigned LONGLONG int *) = num.uq;
882 else if (flags & LONG)
883 *ARG (unsigned long int *) = num.ul;
884 else if (flags & SHORT)
885 *ARG (unsigned short int *)
886 = (unsigned short int) num.ul;
887 else
888 *ARG (unsigned int *) = (unsigned int) num.ul;
890 else
892 if (flags & LONGDBL)
893 *ARG (LONGLONG int *) = num.q;
894 else if (flags & LONG)
895 *ARG (long int *) = num.l;
896 else if (flags & SHORT)
897 *ARG (short int *) = (short int) num.l;
898 else
899 *ARG (int *) = (int) num.l;
901 ++done;
903 break;
905 case 'e': /* Floating-point numbers. */
906 case 'E':
907 case 'f':
908 case 'g':
909 case 'G':
910 case 'A':
911 c = inchar ();
912 if (c == EOF)
913 input_error ();
915 /* Check for a sign. */
916 if (c == '-' || c == '+')
918 negative = c == '-';
919 if (inchar () == EOF)
920 /* EOF is only an input error before we read any chars. */
921 conv_error ();
922 if (width > 0)
923 --width;
925 else
926 negative = 0;
928 is_hexa = 0;
929 exp_char = 'e';
930 if (c == '0')
932 ADDW (c);
933 c = inchar ();
934 if (tolower (c) == 'x')
936 /* It is a number in hexadecimal format. */
937 ADDW (c);
939 is_hexa = 1;
940 exp_char = 'p';
942 /* Grouping is not allowed. */
943 flags &= ~GROUP;
944 c = inchar ();
948 got_dot = got_e = 0;
951 if (isdigit (c))
952 ADDW (c);
953 else if (!got_e && is_hexa && isxdigit (c))
954 ADDW (c);
955 else if (got_e && wp[wpsize - 1] == exp_char
956 && (c == '-' || c == '+'))
957 ADDW (c);
958 else if (wpsize > 0 && !got_e && tolower (c) == exp_char)
960 ADDW (exp_char);
961 got_e = got_dot = 1;
963 else if (c == decimal && !got_dot)
965 ADDW (c);
966 got_dot = 1;
968 else if ((flags & GROUP) && c == thousands && !got_dot)
969 ADDW (c);
970 else
972 /* The last read character is not part of the number
973 anymore. */
974 ungetc (c, s);
975 break;
977 if (width > 0)
978 --width;
980 while (width != 0 && inchar () != EOF);
982 /* Have we read any character? If we try to read a number
983 in hexadecimal notation and we have read only the `0x'
984 prefix this is an error. */
985 if (wpsize == 0 || (is_hexa && wpsize == 2))
986 conv_error ();
988 /* Convert the number. */
989 ADDW ('\0');
990 if (flags & LONGDBL)
992 long double d = __strtold_internal (wp, &tw, flags & GROUP);
993 if (!(flags & SUPPRESS) && tw != wp)
994 *ARG (long double *) = negative ? -d : d;
996 else if (flags & LONG)
998 double d = __strtod_internal (wp, &tw, flags & GROUP);
999 if (!(flags & SUPPRESS) && tw != wp)
1000 *ARG (double *) = negative ? -d : d;
1002 else
1004 float d = __strtof_internal (wp, &tw, flags & GROUP);
1005 if (!(flags & SUPPRESS) && tw != wp)
1006 *ARG (float *) = negative ? -d : d;
1009 if (tw == wp)
1010 conv_error ();
1012 if (!(flags & SUPPRESS))
1013 ++done;
1014 break;
1016 case '[': /* Character class. */
1017 if (flags & LONG)
1019 STRING_ARG (wstr, wchar_t);
1020 c = '\0'; /* This is to keep gcc quiet. */
1022 else
1024 STRING_ARG (str, char);
1026 c = inchar ();
1027 if (c == EOF)
1028 input_error ();
1031 if (*f == '^')
1033 ++f;
1034 not_in = 1;
1036 else
1037 not_in = 0;
1039 /* Fill WP with byte flags indexed by character.
1040 We will use this flag map for matching input characters. */
1041 if (wpmax < UCHAR_MAX)
1043 wpmax = UCHAR_MAX;
1044 wp = (char *) alloca (wpmax);
1046 memset (wp, 0, UCHAR_MAX);
1048 fc = *f;
1049 if (fc == ']' || fc == '-')
1051 /* If ] or - appears before any char in the set, it is not
1052 the terminator or separator, but the first char in the
1053 set. */
1054 wp[fc] = 1;
1055 ++f;
1058 while ((fc = *f++) != '\0' && fc != ']')
1060 if (fc == '-' && *f != '\0' && *f != ']' &&
1061 (unsigned char) f[-2] <= (unsigned char) *f)
1063 /* Add all characters from the one before the '-'
1064 up to (but not including) the next format char. */
1065 for (fc = f[-2]; fc < *f; ++fc)
1066 wp[fc] = 1;
1068 else
1069 /* Add the character to the flag map. */
1070 wp[fc] = 1;
1072 if (fc == '\0')
1074 if (!(flags & LONG))
1075 ungetc (c, s);
1076 conv_error();
1079 if (flags & LONG)
1081 wint_t val;
1082 int first = 1;
1086 size_t cnt = 0;
1087 NEXT_WIDE_CHAR (first);
1088 if (val > 255 || wp[val] == not_in)
1090 /* XXX We have a problem here. We read a wide
1091 character and this possibly took several
1092 bytes. But we can only push back one single
1093 character. To be sure we don't create wrong
1094 input we push it back only in case it is
1095 representable within one byte. */
1096 if (val < 0x80)
1097 ungetc (val, s);
1098 break;
1100 STRING_ADD_CHAR (wstr, val, wchar_t);
1101 if (width > 0)
1102 --width;
1103 first = 0;
1105 while (width != 0);
1107 if (first)
1108 conv_error ();
1110 if (!(flags & SUPPRESS))
1112 *wstr = L'\0';
1113 ++done;
1116 else
1118 num.ul = read_in - 1; /* -1 because we already read one char. */
1121 if (wp[c] == not_in)
1123 ungetc (c, s);
1124 break;
1126 STRING_ADD_CHAR (str, c, char);
1127 if (width > 0)
1128 --width;
1130 while (width != 0 && inchar () != EOF);
1132 if (read_in == num.ul)
1133 conv_error ();
1135 if (!(flags & SUPPRESS))
1137 *str = '\0';
1138 ++done;
1141 break;
1143 case 'p': /* Generic pointer. */
1144 base = 16;
1145 /* A PTR must be the same size as a `long int'. */
1146 flags &= ~(SHORT|LONGDBL);
1147 flags |= LONG;
1148 number_signed = 0;
1149 goto number;
1153 /* The last thing we saw int the format string was a white space.
1154 Consume the last white spaces. */
1155 if (skip_space)
1158 c = inchar ();
1159 while (isspace (c));
1160 ungetc (c, s);
1163 /* Unlock stream. */
1164 UNLOCK_STREAM;
1166 return done;
1169 #ifdef USE_IN_LIBIO
1171 __vfscanf (FILE *s, const char *format, va_list argptr)
1173 return _IO_vfscanf (s, format, argptr, NULL);
1175 #endif
1177 weak_alias (__vfscanf, vfscanf)