patches from bug-gnu-utils to support more architectures
[glibc.git] / stdio-common / vfscanf.c
blob70d8bf0b183fdbad4e4d14ae904b12a8be68c9b6
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96 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 || format == NULL) \
86 { \
87 MAYBE_SET_EINVAL; \
88 return EOF; \
89 } \
90 } while (0)
91 # define LOCK_STREAM(S) \
92 __libc_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, (S)); \
93 _IO_flockfile (S)
94 # define UNLOCK_STREAM __libc_cleanup_region_end (1)
95 #else
96 # define ungetc(c, s) (--read_in, ungetc (c, s))
97 # define inchar() ((c = getc (s)), (void) ++read_in, c)
98 # define encode_error() do { \
99 _IO_funlockfile (s); \
100 __set_errno (EILSEQ); \
101 return done; \
102 } while (0)
103 # define conv_error() do { \
104 funlockfile (s); \
105 return done; \
106 } while (0)
107 # define input_error() do { \
108 funlockfile (s); \
109 return done ?: EOF; \
110 } while (0)
111 # define memory_error() do { \
112 funlockfile (s); \
113 __set_errno (ENOMEM); \
114 return EOF; \
115 } while (0)
116 # define ARGCHECK(s, format) \
117 do \
119 /* Check file argument for consistence. */ \
120 if (!__validfp (s) || !s->__mode.__read || format == NULL) \
122 __set_errno (EINVAL); \
123 return EOF; \
125 } while (0)
126 #if 1
127 /* XXX For now !!! */
128 # define flockfile(S) /* nothing */
129 # define funlockfile(S) /* nothing */
130 # define LOCK_STREAM(S)
131 # define UNLOCK_STREAM
132 #else
133 # define LOCK_STREAM(S) \
134 __libc_cleanup_region_start (&__funlockfile, (S)); \
135 __flockfile (S)
136 # define UNLOCK_STREAM __libc_cleanup_region_end (1)
137 #endif
138 #endif
141 /* Read formatted input from S according to the format string
142 FORMAT, using the argument list in ARG.
143 Return the number of assignments made, or -1 for an input error. */
144 #ifdef USE_IN_LIBIO
146 _IO_vfscanf (s, format, argptr, errp)
147 _IO_FILE *s;
148 const char *format;
149 _IO_va_list argptr;
150 int *errp;
151 #else
153 __vfscanf (FILE *s, const char *format, va_list argptr)
154 #endif
156 va_list arg = (va_list) argptr;
158 register const char *f = format;
159 register unsigned char fc; /* Current character of the format. */
160 register size_t done = 0; /* Assignments done. */
161 register size_t read_in = 0; /* Chars read in. */
162 register int c; /* Last char read. */
163 register int width; /* Maximum field width. */
164 register int flags; /* Modifiers for current format element. */
166 /* Status for reading F-P nums. */
167 char got_dot, got_e, negative;
168 /* If a [...] is a [^...]. */
169 char not_in;
170 /* Base for integral numbers. */
171 int base;
172 /* Signedness for integral numbers. */
173 int number_signed;
174 /* Decimal point character. */
175 wchar_t decimal;
176 /* The thousands character of the current locale. */
177 wchar_t thousands;
178 /* Integral holding variables. */
179 union
181 long long int q;
182 unsigned long long int uq;
183 long int l;
184 unsigned long int ul;
185 } num;
186 /* Character-buffer pointer. */
187 char *str = NULL;
188 wchar_t *wstr = NULL;
189 char **strptr = NULL;
190 size_t strsize = 0;
191 /* We must not react on white spaces immediately because they can
192 possibly be matched even if in the input stream no character is
193 available anymore. */
194 int skip_space = 0;
195 /* Workspace. */
196 char *tw; /* Temporary pointer. */
197 char *wp = NULL; /* Workspace. */
198 size_t wpmax = 0; /* Maximal size of workspace. */
199 size_t wpsize; /* Currently used bytes in workspace. */
200 #define ADDW(Ch) \
201 do \
203 if (wpsize == wpmax) \
205 char *old = wp; \
206 wpmax = UCHAR_MAX > 2 * wpmax ? UCHAR_MAX : 2 * wpmax; \
207 wp = (char *) alloca (wpmax); \
208 if (old != NULL) \
209 memcpy (wp, old, wpsize); \
211 wp[wpsize++] = (Ch); \
213 while (0)
215 ARGCHECK (s, format);
217 /* Figure out the decimal point character. */
218 if (mbtowc (&decimal, _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT),
219 strlen (_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT))) <= 0)
220 decimal = (wchar_t) *_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
221 /* Figure out the thousands separator character. */
222 if (mbtowc (&thousands, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
223 strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
224 thousands = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
226 /* Lock the stream. */
227 LOCK_STREAM (s);
229 /* Run through the format string. */
230 while (*f != '\0')
232 unsigned int argpos;
233 /* Extract the next argument, which is of type TYPE.
234 For a %N$... spec, this is the Nth argument from the beginning;
235 otherwise it is the next argument after the state now in ARG. */
236 #if 0
237 /* XXX Possible optimization. */
238 # define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
239 ({ va_list arg = (va_list) argptr; \
240 arg = (va_list) ((char *) arg \
241 + (argpos - 1) \
242 * __va_rounded_size (void *)); \
243 va_arg (arg, type); \
245 #else
246 # define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
247 ({ unsigned int pos = argpos; \
248 va_list arg = (va_list) argptr; \
249 while (--pos > 0) \
250 (void) va_arg (arg, void *); \
251 va_arg (arg, type); \
253 #endif
255 if (!isascii (*f))
257 /* Non-ASCII, may be a multibyte. */
258 int len = mblen (f, strlen (f));
259 if (len > 0)
263 c = inchar ();
264 if (c == EOF)
265 input_error ();
266 else if (c != *f++)
268 ungetc (c, s);
269 conv_error ();
272 while (--len > 0);
273 continue;
277 fc = *f++;
278 if (fc != '%')
280 /* Remember to skip spaces. */
281 if (isspace (fc))
283 skip_space = 1;
284 continue;
287 /* Read a character. */
288 c = inchar ();
290 /* Characters other than format specs must just match. */
291 if (c == EOF)
292 input_error ();
294 /* We saw white space char as the last character in the format
295 string. Now it's time to skip all leading white space. */
296 if (skip_space)
298 while (isspace (c))
299 (void) inchar ();
300 skip_space = 0;
303 if (c != fc)
305 ungetc (c, s);
306 conv_error ();
309 continue;
312 /* This is the start of the conversion string. */
313 flags = 0;
315 /* Initialize state of modifiers. */
316 argpos = 0;
318 /* Prepare temporary buffer. */
319 wpsize = 0;
321 /* Check for a positional parameter specification. */
322 if (isdigit (*f))
324 argpos = *f++ - '0';
325 while (isdigit (*f))
326 argpos = argpos * 10 + (*f++ - '0');
327 if (*f == '$')
328 ++f;
329 else
331 /* Oops; that was actually the field width. */
332 width = argpos;
333 flags |= WIDTH;
334 argpos = 0;
335 goto got_width;
339 /* Check for the assignment-suppressant and the number grouping flag. */
340 while (*f == '*' || *f == '\'')
341 switch (*f++)
343 case '*':
344 flags |= SUPPRESS;
345 break;
346 case '\'':
347 flags |= GROUP;
348 break;
351 /* We have seen width. */
352 if (isdigit (*f))
353 flags |= WIDTH;
355 /* Find the maximum field width. */
356 width = 0;
357 while (isdigit (*f))
359 width *= 10;
360 width += *f++ - '0';
362 got_width:
363 if (width == 0)
364 width = -1;
366 /* Check for type modifiers. */
367 while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'a' || *f == 'q')
368 switch (*f++)
370 case 'h':
371 /* int's are short int's. */
372 if (flags & TYPEMOD)
373 /* Signal illegal format element. */
374 conv_error ();
375 flags |= SHORT;
376 break;
377 case 'l':
378 if (flags & (SHORT|LONGDBL))
379 conv_error ();
380 else if (flags & LONG)
382 /* A double `l' is equivalent to an `L'. */
383 flags &= ~LONG;
384 flags |= LONGDBL;
386 else
387 /* int's are long int's. */
388 flags |= LONG;
389 break;
390 case 'q':
391 case 'L':
392 /* double's are long double's, and int's are long long int's. */
393 if (flags & TYPEMOD)
394 /* Signal illegal format element. */
395 conv_error ();
396 flags |= LONGDBL;
397 break;
398 case 'a':
399 if (flags & TYPEMOD)
400 /* Signal illegal format element. */
401 conv_error ();
402 /* String conversions (%s, %[) take a `char **'
403 arg and fill it in with a malloc'd pointer. */
404 flags |= MALLOC;
405 break;
408 /* End of the format string? */
409 if (*f == '\0')
410 conv_error ();
412 /* Find the conversion specifier. */
413 fc = *f++;
414 if (skip_space || (fc != '[' && fc != 'c' && fc != 'n'))
416 /* Eat whitespace. */
418 (void) inchar ();
419 while (isspace (c));
420 ungetc (c, s);
421 skip_space = 0;
424 switch (fc)
426 case '%': /* Must match a literal '%'. */
427 c = inchar ();
428 if (c != fc)
430 ungetc (c, s);
431 conv_error ();
433 break;
435 case 'n': /* Answer number of assignments done. */
436 /* Corrigendum 1 to ISO C 1990 describes the allowed flags
437 with the 'n' conversion specifier. */
438 if (!(flags & SUPPRESS))
439 /* Don't count the read-ahead. */
440 if (flags & LONGDBL)
441 *ARG (long long int *) = read_in;
442 else if (flags & LONG)
443 *ARG (long int *) = read_in;
444 else if (flags & SHORT)
445 *ARG (short int *) = read_in;
446 else
447 *ARG (int *) = read_in;
448 break;
450 case 'c': /* Match characters. */
451 if ((flags & LONG) == 0)
453 if (!(flags & SUPPRESS))
455 str = ARG (char *);
456 if (str == NULL)
457 conv_error ();
460 c = inchar ();
461 if (c == EOF)
462 input_error ();
464 if (width == -1)
465 width = 1;
467 if (!(flags & SUPPRESS))
470 *str++ = c;
471 while (--width > 0 && inchar () != EOF);
473 else
474 while (--width > 0 && inchar () != EOF);
476 if (width > 0)
477 /* I.e., EOF was read. */
478 --read_in;
480 if (!(flags & SUPPRESS))
481 ++done;
483 break;
485 /* FALLTHROUGH */
486 case 'C':
487 /* Get UTF-8 encoded wide character. Here we assume (as in
488 other parts of the libc) that we only have to handle
489 UTF-8. */
491 wint_t val;
492 size_t cnt = 0;
493 int first = 1;
495 if (!(flags & SUPPRESS))
497 wstr = ARG (wchar_t *);
498 if (str == NULL)
499 conv_error ();
504 #define NEXT_WIDE_CHAR(First) \
505 c = inchar (); \
506 if (c == EOF) \
507 /* EOF is only an error for the first character. */ \
508 if (First) \
509 input_error (); \
510 else \
511 break; \
512 val = c; \
513 if (val >= 0x80) \
515 if ((c & 0xc0) == 0x80 || (c & 0xfe) == 0xfe) \
516 encode_error (); \
517 if ((c & 0xe0) == 0xc0) \
519 /* We expect two bytes. */ \
520 cnt = 1; \
521 val &= 0x1f; \
523 else if ((c & 0xf0) == 0xe0) \
525 /* We expect three bytes. */ \
526 cnt = 2; \
527 val &= 0x0f; \
529 else if ((c & 0xf8) == 0xf0) \
531 /* We expect four bytes. */ \
532 cnt = 3; \
533 val &= 0x07; \
535 else if ((c & 0xfc) == 0xf8) \
537 /* We expect five bytes. */ \
538 cnt = 4; \
539 val &= 0x03; \
541 else \
543 /* We expect six bytes. */ \
544 cnt = 5; \
545 val &= 0x01; \
548 do \
550 c = inchar (); \
551 if (c == EOF \
552 || (c & 0xc0) == 0x80 || (c & 0xfe) == 0xfe) \
553 encode_error (); \
554 val <<= 6; \
555 val |= c & 0x3f; \
557 while (--cnt > 0); \
560 if (!(flags & SUPPRESS)) \
561 *wstr++ = val; \
562 first = 0
564 NEXT_WIDE_CHAR (first);
566 while (--width > 0);
568 if (width > 0)
569 /* I.e., EOF was read. */
570 --read_in;
572 if (!(flags & SUPPRESS))
573 ++done;
575 break;
577 case 's': /* Read a string. */
578 if (flags & LONG)
579 /* We have to process a wide character string. */
580 goto wide_char_string;
582 #define STRING_ARG(Str, Type) \
583 if (!(flags & SUPPRESS)) \
585 if (flags & MALLOC) \
587 /* The string is to be stored in a malloc'd buffer. */ \
588 strptr = ARG (char **); \
589 if (strptr == NULL) \
590 conv_error (); \
591 /* Allocate an initial buffer. */ \
592 strsize = 100; \
593 *strptr = malloc (strsize * sizeof (Type)); \
594 Str = (Type *) *strptr; \
596 else \
597 Str = ARG (Type *); \
598 if (Str == NULL) \
599 conv_error (); \
601 STRING_ARG (str, char);
603 c = inchar ();
604 if (c == EOF)
605 input_error ();
609 if (isspace (c))
611 ungetc (c, s);
612 break;
614 #define STRING_ADD_CHAR(Str, c, Type) \
615 if (!(flags & SUPPRESS)) \
617 *Str++ = c; \
618 if ((flags & MALLOC) && (char *) Str == *strptr + strsize) \
620 /* Enlarge the buffer. */ \
621 Str = realloc (*strptr, strsize * 2 * sizeof (Type)); \
622 if (Str == NULL) \
624 /* Can't allocate that much. Last-ditch effort. */\
625 Str = realloc (*strptr, \
626 (strsize + 1) * sizeof (Type)); \
627 if (Str == NULL) \
629 /* We lose. Oh well. \
630 Terminate the string and stop converting, \
631 so at least we don't skip any input. */ \
632 ((Type *) (*strptr))[strsize] = '\0'; \
633 ++done; \
634 conv_error (); \
636 else \
638 *strptr = (char *) Str; \
639 Str = ((Type *) *strptr) + strsize; \
640 ++strsize; \
643 else \
645 *strptr = (char *) Str; \
646 Str = ((Type *) *strptr) + strsize; \
647 strsize *= 2; \
651 STRING_ADD_CHAR (str, c, char);
652 } while ((width <= 0 || --width > 0) && inchar () != EOF);
654 if (!(flags & SUPPRESS))
656 *str = '\0';
657 ++done;
659 break;
661 case 'S':
662 /* Wide character string. */
663 wide_char_string:
665 wint_t val;
666 int first = 1;
667 STRING_ARG (wstr, wchar_t);
671 size_t cnt = 0;
672 NEXT_WIDE_CHAR (first);
674 if (iswspace (val))
676 /* XXX We would have to push back the whole wide char
677 with possibly many bytes. But since scanf does
678 not make a difference for white space characters
679 we can simply push back a simple <SP> which is
680 guaranteed to be in the [:space:] class. */
681 ungetc (' ', s);
682 break;
685 STRING_ADD_CHAR (wstr, val, wchar_t);
686 first = 0;
688 while (width <= 0 || --width > 0);
690 if (!(flags & SUPPRESS))
692 *wstr = L'\0';
693 ++done;
696 break;
698 case 'x': /* Hexadecimal integer. */
699 case 'X': /* Ditto. */
700 base = 16;
701 number_signed = 0;
702 goto number;
704 case 'o': /* Octal integer. */
705 base = 8;
706 number_signed = 0;
707 goto number;
709 case 'u': /* Unsigned decimal integer. */
710 base = 10;
711 number_signed = 0;
712 goto number;
714 case 'd': /* Signed decimal integer. */
715 base = 10;
716 number_signed = 1;
717 goto number;
719 case 'i': /* Generic number. */
720 base = 0;
721 number_signed = 1;
723 number:
724 c = inchar ();
725 if (c == EOF)
726 input_error ();
728 /* Check for a sign. */
729 if (c == '-' || c == '+')
731 ADDW (c);
732 if (width > 0)
733 --width;
734 c = inchar ();
737 /* Look for a leading indication of base. */
738 if (width != 0 && c == '0')
740 if (width > 0)
741 --width;
743 ADDW (c);
744 c = inchar ();
746 if (width != 0 && tolower (c) == 'x')
748 if (base == 0)
749 base = 16;
750 if (base == 16)
752 if (width > 0)
753 --width;
754 c = inchar ();
757 else if (base == 0)
758 base = 8;
761 if (base == 0)
762 base = 10;
764 /* Read the number into workspace. */
765 while (c != EOF && width != 0)
767 if (base == 16 ? !isxdigit (c) :
768 ((!isdigit (c) || c - '0' >= base) &&
769 !((flags & GROUP) && base == 10 && c == thousands)))
770 break;
771 ADDW (c);
772 if (width > 0)
773 --width;
775 c = inchar ();
778 /* The just read character is not part of the number anymore. */
779 ungetc (c, s);
781 if (wpsize == 0 ||
782 (wpsize == 1 && (wp[0] == '+' || wp[0] == '-')))
783 /* There was no number. */
784 conv_error ();
786 /* Convert the number. */
787 ADDW ('\0');
788 if (flags & LONGDBL)
790 if (number_signed)
791 num.q = __strtoq_internal (wp, &tw, base, flags & GROUP);
792 else
793 num.uq = __strtouq_internal (wp, &tw, base, flags & GROUP);
795 else
797 if (number_signed)
798 num.l = __strtol_internal (wp, &tw, base, flags & GROUP);
799 else
800 num.ul = __strtoul_internal (wp, &tw, base, flags & GROUP);
802 if (wp == tw)
803 conv_error ();
805 if (!(flags & SUPPRESS))
807 if (! number_signed)
809 if (flags & LONGDBL)
810 *ARG (unsigned LONGLONG int *) = num.uq;
811 else if (flags & LONG)
812 *ARG (unsigned long int *) = num.ul;
813 else if (flags & SHORT)
814 *ARG (unsigned short int *)
815 = (unsigned short int) num.ul;
816 else
817 *ARG (unsigned int *) = (unsigned int) num.ul;
819 else
821 if (flags & LONGDBL)
822 *ARG (LONGLONG int *) = num.q;
823 else if (flags & LONG)
824 *ARG (long int *) = num.l;
825 else if (flags & SHORT)
826 *ARG (short int *) = (short int) num.l;
827 else
828 *ARG (int *) = (int) num.l;
830 ++done;
832 break;
834 case 'e': /* Floating-point numbers. */
835 case 'E':
836 case 'f':
837 case 'g':
838 case 'G':
839 c = inchar ();
840 if (c == EOF)
841 input_error ();
843 /* Check for a sign. */
844 if (c == '-' || c == '+')
846 negative = c == '-';
847 if (inchar () == EOF)
848 /* EOF is only an input error before we read any chars. */
849 conv_error ();
850 if (width > 0)
851 --width;
853 else
854 negative = 0;
856 got_dot = got_e = 0;
859 if (isdigit (c))
860 ADDW (c);
861 else if (got_e && wp[wpsize - 1] == 'e'
862 && (c == '-' || c == '+'))
863 ADDW (c);
864 else if (wpsize > 0 && !got_e && tolower (c) == 'e')
866 ADDW ('e');
867 got_e = got_dot = 1;
869 else if (c == decimal && !got_dot)
871 ADDW (c);
872 got_dot = 1;
874 else if ((flags & GROUP) && c == thousands && !got_dot)
875 ADDW (c);
876 else
877 break;
878 if (width > 0)
879 --width;
881 while (inchar () != EOF && width != 0);
883 /* The last read character is not part of the number anymore. */
884 ungetc (c, s);
886 if (wpsize == 0)
887 conv_error ();
889 /* Convert the number. */
890 ADDW ('\0');
891 if (flags & LONGDBL)
893 long double d = __strtold_internal (wp, &tw, flags & GROUP);
894 if (!(flags & SUPPRESS) && tw != wp)
895 *ARG (long double *) = negative ? -d : d;
897 else if (flags & LONG)
899 double d = __strtod_internal (wp, &tw, flags & GROUP);
900 if (!(flags & SUPPRESS) && tw != wp)
901 *ARG (double *) = negative ? -d : d;
903 else
905 float d = __strtof_internal (wp, &tw, flags & GROUP);
906 if (!(flags & SUPPRESS) && tw != wp)
907 *ARG (float *) = negative ? -d : d;
910 if (tw == wp)
911 conv_error ();
913 if (!(flags & SUPPRESS))
914 ++done;
915 break;
917 case '[': /* Character class. */
918 if (flags & LONG)
920 STRING_ARG (wstr, wchar_t);
921 c = '\0'; /* This is to keep gcc quiet. */
923 else
925 STRING_ARG (str, char);
927 c = inchar ();
928 if (c == EOF)
929 input_error ();
932 if (*f == '^')
934 ++f;
935 not_in = 1;
937 else
938 not_in = 0;
940 /* Fill WP with byte flags indexed by character.
941 We will use this flag map for matching input characters. */
942 if (wpmax < UCHAR_MAX)
944 wpmax = UCHAR_MAX;
945 wp = (char *) alloca (wpmax);
947 memset (wp, 0, UCHAR_MAX);
949 fc = *f;
950 if (fc == ']' || fc == '-')
952 /* If ] or - appears before any char in the set, it is not
953 the terminator or separator, but the first char in the
954 set. */
955 wp[fc] = 1;
956 ++f;
959 while ((fc = *f++) != '\0' && fc != ']')
961 if (fc == '-' && *f != '\0' && *f != ']' &&
962 (unsigned char) f[-2] <= (unsigned char) *f)
964 /* Add all characters from the one before the '-'
965 up to (but not including) the next format char. */
966 for (fc = f[-2]; fc < *f; ++fc)
967 wp[fc] = 1;
969 else
970 /* Add the character to the flag map. */
971 wp[fc] = 1;
973 if (fc == '\0')
975 if (!(flags & LONG))
976 ungetc (c, s);
977 conv_error();
980 if (flags & LONG)
982 wint_t val;
983 int first = 1;
987 size_t cnt = 0;
988 NEXT_WIDE_CHAR (first);
989 if (val > 255 || wp[val] == not_in)
991 /* XXX We have a problem here. We read a wide
992 character and this possibly took several
993 bytes. But we can only push back one single
994 character. To be sure we don't create wrong
995 input we push it back only in case it is
996 representable within one byte. */
997 if (val < 0x80)
998 ungetc (val, s);
999 break;
1001 STRING_ADD_CHAR (wstr, val, wchar_t);
1002 if (width > 0)
1003 --width;
1004 first = 0;
1006 while (width != 0);
1008 if (first)
1009 conv_error ();
1011 if (!(flags & SUPPRESS))
1013 *wstr = L'\0';
1014 ++done;
1017 else
1019 num.ul = read_in - 1; /* -1 because we already read one char. */
1022 if (wp[c] == not_in)
1024 ungetc (c, s);
1025 break;
1027 STRING_ADD_CHAR (str, c, char);
1028 if (width > 0)
1029 --width;
1031 while (width != 0 && inchar () != EOF);
1033 if (read_in == num.ul)
1034 conv_error ();
1036 if (!(flags & SUPPRESS))
1038 *str = '\0';
1039 ++done;
1042 break;
1044 case 'p': /* Generic pointer. */
1045 base = 16;
1046 /* A PTR must be the same size as a `long int'. */
1047 flags &= ~(SHORT|LONGDBL);
1048 flags |= LONG;
1049 number_signed = 0;
1050 goto number;
1054 /* The last thing we saw int the format string was a white space.
1055 Consume the last white spaces. */
1056 if (skip_space)
1059 c = inchar ();
1060 while (isspace (c));
1061 ungetc (c, s);
1064 /* Unlock stream. */
1065 UNLOCK_STREAM;
1067 return done;
1070 #ifdef USE_IN_LIBIO
1072 __vfscanf (FILE *s, const char *format, va_list argptr)
1074 return _IO_vfscanf (s, format, argptr, NULL);
1076 #endif
1078 weak_alias (__vfscanf, vfscanf)