*** empty log message ***
[glibc.git] / stdio-common / vfscanf.c
blobbc7acd60deaa0f50042fac451862836c77d041ee
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
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA. */
19 #include <ansidecl.h>
20 #include "../locale/localeinfo.h"
21 #include <errno.h>
22 #include <limits.h>
23 #include <ctype.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.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 # define va_list _IO_va_list
56 # define ungetc(c, s) _IO_ungetc (c, s)
57 # define inchar() ((c = _IO_getc (s)), (void) ++read_in, c)
58 # define conv_error() return ((void) (errp != NULL && (*errp |= 2)), \
59 (void) (c == EOF || _IO_ungetc (c, s)), done)
61 # define input_error() return ((void) (errp != NULL && (*errp |= 1)), \
62 done == 0 ? EOF : done)
63 # define memory_error() return ((void) (errno = ENOMEM), EOF)
64 # define ARGCHECK(s, format) \
65 do \
66 { \
67 /* Check file argument for consistence. */ \
68 CHECK_FILE (s, -1); \
69 if (s->_flags & _IO_NO_READS || format == NULL) \
70 { \
71 MAYBE_SET_EINVAL; \
72 return -1; \
73 } \
74 } while (0)
75 #else
76 # define inchar() ((c = getc (s)), (void) ++read_in, c)
77 # define conv_error() return ((void) ungetc (c, s), done)
78 # define input_error() return (done == 0 ? EOF : done)
79 # define memory_error() return ((void) (errno = ENOMEM), EOF)
80 # define ARGCHECK(s, format) \
81 do \
82 { \
83 /* Check file argument for consistence. */ \
84 if (!__validfp (s) || !s->__mode.__read || format == NULL) \
85 { \
86 errno = EINVAL; \
87 return -1; \
88 } \
89 } while (0)
90 #endif
93 /* Read formatted input from S according to the format string
94 FORMAT, using the argument list in ARG.
95 Return the number of assignments made, or -1 for an input error. */
96 #ifdef USE_IN_LIBIO
97 int
98 _IO_vfscanf (s, format, argptr, errp)
99 _IO_FILE *s;
100 const char *format;
101 _IO_va_list argptr;
102 int *errp;
103 #else
105 __vfscanf (FILE *s, const char *format, va_list argptr)
106 #endif
108 va_list arg = (va_list) argptr;
110 register const char *f = format;
111 register unsigned char fc; /* Current character of the format. */
112 register size_t done = 0; /* Assignments done. */
113 register size_t read_in = 0; /* Chars read in. */
114 register int c; /* Last char read. */
115 register int width; /* Maximum field width. */
116 register int flags; /* Modifiers for current format element. */
118 /* Status for reading F-P nums. */
119 char got_dot, got_e, negative;
120 /* If a [...] is a [^...]. */
121 char not_in;
122 /* Base for integral numbers. */
123 int base;
124 /* Signedness for integral numbers. */
125 int number_signed;
126 /* Decimal point character. */
127 wchar_t decimal;
128 /* The thousands character of the current locale. */
129 wchar_t thousands;
130 /* Integral holding variables. */
131 union
133 long long int q;
134 unsigned long long int uq;
135 long int l;
136 unsigned long int ul;
137 } num;
138 /* Character-buffer pointer. */
139 register char *str, **strptr;
140 size_t strsize;
141 /* We must not react on white spaces immediately because they can
142 possibly be matched even if in the input stream no character is
143 available anymore. */
144 int skip_space = 0;
145 /* Workspace. */
146 char *tw; /* Temporary pointer. */
147 char *wp = NULL; /* Workspace. */
148 size_t wpmax = 0; /* Maximal size of workspace. */
149 size_t wpsize; /* Currently used bytes in workspace. */
150 #define ADDW(Ch) \
151 do \
153 if (wpsize == wpmax) \
155 char *old = wp; \
156 wpmax = UCHAR_MAX > 2 * wpmax ? UCHAR_MAX : 2 * wpmax; \
157 wp = (char *) alloca (wpmax); \
158 if (old != NULL) \
159 memcpy (wp, old, wpsize); \
161 wp[wpsize++] = (Ch); \
163 while (0)
165 ARGCHECK (s, format);
167 /* Figure out the decimal point character. */
168 if (mbtowc (&decimal, _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT),
169 strlen (_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT))) <= 0)
170 decimal = (wchar_t) *_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
171 /* Figure out the thousands separator character. */
172 if (mbtowc (&thousands, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
173 strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
174 thousands = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
176 c = inchar ();
178 /* Run through the format string. */
179 while (*f != '\0')
181 unsigned int argpos;
182 /* Extract the next argument, which is of type TYPE.
183 For a %N$... spec, this is the Nth argument from the beginning;
184 otherwise it is the next argument after the state now in ARG. */
185 #if 0
186 /* XXX Possible optimization. */
187 # define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
188 ({ va_list arg = (va_list) argptr; \
189 arg = (va_list) ((char *) arg \
190 + (argpos - 1) \
191 * __va_rounded_size (void *)); \
192 va_arg (arg, type); \
194 #else
195 # define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
196 ({ unsigned int pos = argpos; \
197 va_list arg = (va_list) argptr; \
198 while (--pos > 0) \
199 (void) va_arg (arg, void *); \
200 va_arg (arg, type); \
202 #endif
204 if (!isascii (*f))
206 /* Non-ASCII, may be a multibyte. */
207 int len = mblen (f, strlen (f));
208 if (len > 0)
210 while (len-- > 0)
211 if (c == EOF)
212 input_error ();
213 else if (c == *f++)
214 (void) inchar ();
215 else
216 conv_error ();
217 continue;
221 fc = *f++;
222 if (fc != '%')
224 /* Remember to skip spaces. */
225 if (isspace (fc))
227 skip_space = 1;
228 continue;
231 /* Characters other than format specs must just match. */
232 if (c == EOF)
233 input_error ();
235 /* We saw white space char as the last character in the format
236 string. Now it's time to skip all leading white space. */
237 if (skip_space)
239 while (isspace (c))
240 (void) inchar ();
241 skip_space = 0;
244 if (c == fc)
245 (void) inchar ();
246 else
247 conv_error ();
249 continue;
252 /* This is the start of the conversion string. */
253 flags = 0;
255 /* Initialize state of modifiers. */
256 argpos = 0;
258 /* Prepare temporary buffer. */
259 wpsize = 0;
261 /* Check for a positional parameter specification. */
262 if (isdigit (*f))
264 argpos = *f++ - '0';
265 while (isdigit (*f))
266 argpos = argpos * 10 + (*f++ - '0');
267 if (*f == '$')
268 ++f;
269 else
271 /* Oops; that was actually the field width. */
272 width = argpos;
273 flags |= WIDTH;
274 argpos = 0;
275 goto got_width;
279 /* Check for the assignment-suppressant and the number grouping flag. */
280 while (*f == '*' || *f == '\'')
281 switch (*f++)
283 case '*':
284 flags |= SUPPRESS;
285 break;
286 case '\'':
287 flags |= GROUP;
288 break;
291 /* We have seen width. */
292 if (isdigit (*f))
293 flags |= WIDTH;
295 /* Find the maximum field width. */
296 width = 0;
297 while (isdigit (*f))
299 width *= 10;
300 width += *f++ - '0';
302 got_width:
303 if (width == 0)
304 width = -1;
306 /* Check for type modifiers. */
307 while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'a' || *f == 'q')
308 switch (*f++)
310 case 'h':
311 /* int's are short int's. */
312 if (flags & TYPEMOD)
313 /* Signal illegal format element. */
314 conv_error ();
315 flags |= SHORT;
316 break;
317 case 'l':
318 if (flags & (SHORT|LONGDBL))
319 conv_error ();
320 else if (flags & LONG)
322 /* A double `l' is equivalent to an `L'. */
323 flags &= ~LONG;
324 flags |= LONGDBL;
326 else
327 /* int's are long int's. */
328 flags |= LONG;
329 break;
330 case 'q':
331 case 'L':
332 /* double's are long double's, and int's are long long int's. */
333 if (flags & TYPEMOD)
334 /* Signal illegal format element. */
335 conv_error ();
336 flags |= LONGDBL;
337 break;
338 case 'a':
339 if (flags & TYPEMOD)
340 /* Signal illegal format element. */
341 conv_error ();
342 /* String conversions (%s, %[) take a `char **'
343 arg and fill it in with a malloc'd pointer. */
344 flags |= MALLOC;
345 break;
348 /* End of the format string? */
349 if (*f == '\0')
350 conv_error ();
352 /* Find the conversion specifier. */
353 fc = *f++;
354 if (skip_space || (fc != '[' && fc != 'c' && fc != 'n'))
356 /* Eat whitespace. */
357 while (isspace (c))
358 (void) inchar ();
359 skip_space = 0;
362 switch (fc)
364 case '%': /* Must match a literal '%'. */
365 if (c != fc)
366 conv_error ();
367 inchar ();
368 break;
370 case 'n': /* Answer number of assignments done. */
371 /* Corrigendum 1 to ISO C 1990 describes the allowed flags
372 with the 'n' conversion specifier. */
373 if (!(flags & SUPPRESS))
374 /* Don't count the read-ahead. */
375 if (flags & LONGDBL)
376 *ARG (long long int *) = read_in - 1;
377 else if (flags & LONG)
378 *ARG (long int *) = read_in - 1;
379 else if (flags & SHORT)
380 *ARG (short int *) = read_in - 1;
381 else
382 *ARG (int *) = read_in - 1;
383 break;
385 case 'c': /* Match characters. */
386 if (!(flags & SUPPRESS))
388 str = ARG (char *);
389 if (str == NULL)
390 conv_error ();
393 if (c == EOF)
394 input_error ();
396 if (width == -1)
397 width = 1;
399 if (!(flags & SUPPRESS))
402 *str++ = c;
403 while (inchar () != EOF && --width > 0);
405 else
406 while (inchar () != EOF && --width > 0);
408 if (!(flags & SUPPRESS))
409 ++done;
411 break;
413 case 's': /* Read a string. */
414 #define STRING_ARG \
415 if (!(flags & SUPPRESS)) \
417 if (flags & MALLOC) \
419 /* The string is to be stored in a malloc'd buffer. */ \
420 strptr = ARG (char **); \
421 if (strptr == NULL) \
422 conv_error (); \
423 /* Allocate an initial buffer. */ \
424 strsize = 100; \
425 *strptr = str = malloc (strsize); \
427 else \
428 str = ARG (char *); \
429 if (str == NULL) \
430 conv_error (); \
432 STRING_ARG;
434 if (c == EOF)
435 input_error ();
439 if (isspace (c))
440 break;
441 #define STRING_ADD_CHAR(c) \
442 if (!(flags & SUPPRESS)) \
444 *str++ = c; \
445 if ((flags & MALLOC) && str == *strptr + strsize) \
447 /* Enlarge the buffer. */ \
448 str = realloc (*strptr, strsize * 2); \
449 if (str == NULL) \
451 /* Can't allocate that much. Last-ditch effort. */\
452 str = realloc (*strptr, strsize + 1); \
453 if (str == NULL) \
455 /* We lose. Oh well. \
456 Terminate the string and stop converting, \
457 so at least we don't skip any input. */ \
458 (*strptr)[strsize] = '\0'; \
459 ++done; \
460 conv_error (); \
462 else \
464 *strptr = str; \
465 str += strsize; \
466 ++strsize; \
469 else \
471 *strptr = str; \
472 str += strsize; \
473 strsize *= 2; \
477 STRING_ADD_CHAR (c);
478 } while (inchar () != EOF && (width <= 0 || --width > 0));
480 if (!(flags & SUPPRESS))
482 *str = '\0';
483 ++done;
485 break;
487 case 'x': /* Hexadecimal integer. */
488 case 'X': /* Ditto. */
489 base = 16;
490 number_signed = 0;
491 goto number;
493 case 'o': /* Octal integer. */
494 base = 8;
495 number_signed = 0;
496 goto number;
498 case 'u': /* Unsigned decimal integer. */
499 base = 10;
500 number_signed = 0;
501 goto number;
503 case 'd': /* Signed decimal integer. */
504 base = 10;
505 number_signed = 1;
506 goto number;
508 case 'i': /* Generic number. */
509 base = 0;
510 number_signed = 1;
512 number:
513 if (c == EOF)
514 input_error ();
516 /* Check for a sign. */
517 if (c == '-' || c == '+')
519 ADDW (c);
520 if (width > 0)
521 --width;
522 (void) inchar ();
525 /* Look for a leading indication of base. */
526 if (width != 0 && c == '0')
528 if (width > 0)
529 --width;
531 ADDW (c);
532 (void) inchar ();
534 if (width != 0 && tolower (c) == 'x')
536 if (base == 0)
537 base = 16;
538 if (base == 16)
540 if (width > 0)
541 --width;
542 (void) inchar ();
545 else if (base == 0)
546 base = 8;
549 if (base == 0)
550 base = 10;
552 /* Read the number into workspace. */
553 while (c != EOF && width != 0)
555 if (base == 16 ? !isxdigit (c) :
556 ((!isdigit (c) || c - '0' >= base) &&
557 !((flags & GROUP) && base == 10 && c == thousands)))
558 break;
559 ADDW (c);
560 if (width > 0)
561 --width;
563 (void) inchar ();
566 if (wpsize == 0 ||
567 (wpsize == 1 && (wp[0] == '+' || wp[0] == '-')))
568 /* There was no number. */
569 conv_error ();
571 /* Convert the number. */
572 ADDW ('\0');
573 if (flags & LONGDBL)
575 if (number_signed)
576 num.q = __strtoq_internal (wp, &tw, base, flags & GROUP);
577 else
578 num.uq = __strtouq_internal (wp, &tw, base, flags & GROUP);
580 else
582 if (number_signed)
583 num.l = __strtol_internal (wp, &tw, base, flags & GROUP);
584 else
585 num.ul = __strtoul_internal (wp, &tw, base, flags & GROUP);
587 if (wp == tw)
588 conv_error ();
590 if (!(flags & SUPPRESS))
592 if (! number_signed)
594 if (flags & LONGDBL)
595 *ARG (unsigned LONGLONG int *) = num.uq;
596 else if (flags & LONG)
597 *ARG (unsigned long int *) = num.ul;
598 else if (flags & SHORT)
599 *ARG (unsigned short int *)
600 = (unsigned short int) num.ul;
601 else
602 *ARG (unsigned int *) = (unsigned int) num.ul;
604 else
606 if (flags & LONGDBL)
607 *ARG (LONGLONG int *) = num.q;
608 else if (flags & LONG)
609 *ARG (long int *) = num.l;
610 else if (flags & SHORT)
611 *ARG (short int *) = (short int) num.l;
612 else
613 *ARG (int *) = (int) num.l;
615 ++done;
617 break;
619 case 'e': /* Floating-point numbers. */
620 case 'E':
621 case 'f':
622 case 'g':
623 case 'G':
624 if (c == EOF)
625 input_error ();
627 /* Check for a sign. */
628 if (c == '-' || c == '+')
630 negative = c == '-';
631 if (inchar () == EOF)
632 /* EOF is only an input error before we read any chars. */
633 conv_error ();
634 if (width > 0)
635 --width;
637 else
638 negative = 0;
640 got_dot = got_e = 0;
643 if (isdigit (c))
644 ADDW (c);
645 else if (got_e && wp[wpsize - 1] == 'e'
646 && (c == '-' || c == '+'))
647 ADDW (c);
648 else if (wpsize > 0 && !got_e && tolower (c) == 'e')
650 ADDW ('e');
651 got_e = got_dot = 1;
653 else if (c == decimal && !got_dot)
655 ADDW (c);
656 got_dot = 1;
658 else if ((flags & GROUP) && c == thousands && !got_dot)
659 ADDW (c);
660 else
661 break;
662 if (width > 0)
663 --width;
665 while (inchar () != EOF && width != 0);
667 if (wpsize == 0)
668 conv_error ();
670 /* Convert the number. */
671 ADDW ('\0');
672 if (flags & LONGDBL)
674 long double d = __strtold_internal (wp, &tw, flags & GROUP);
675 if (!(flags & SUPPRESS) && tw != wp)
676 *ARG (long double *) = negative ? -d : d;
678 else if (flags & LONG)
680 double d = __strtod_internal (wp, &tw, flags & GROUP);
681 if (!(flags & SUPPRESS) && tw != wp)
682 *ARG (double *) = negative ? -d : d;
684 else
686 float d = __strtof_internal (wp, &tw, flags & GROUP);
687 if (!(flags & SUPPRESS) && tw != wp)
688 *ARG (float *) = negative ? -d : d;
691 if (tw == wp)
692 conv_error ();
694 if (!(flags & SUPPRESS))
695 ++done;
696 break;
698 case '[': /* Character class. */
699 STRING_ARG;
701 if (c == EOF)
702 input_error();
704 if (*f == '^')
706 ++f;
707 not_in = 1;
709 else
710 not_in = 0;
712 /* Fill WP with byte flags indexed by character.
713 We will use this flag map for matching input characters. */
714 if (wpmax < UCHAR_MAX)
716 wpmax = UCHAR_MAX;
717 wp = (char *) alloca (wpmax);
719 memset (wp, 0, UCHAR_MAX);
721 fc = *f;
722 if (fc == ']' || fc == '-')
724 /* If ] or - appears before any char in the set, it is not
725 the terminator or separator, but the first char in the
726 set. */
727 wp[fc] = 1;
728 ++f;
731 while ((fc = *f++) != '\0' && fc != ']')
733 if (fc == '-' && *f != '\0' && *f != ']' &&
734 (unsigned char) f[-2] <= (unsigned char) *f)
736 /* Add all characters from the one before the '-'
737 up to (but not including) the next format char. */
738 for (fc = f[-2]; fc < *f; ++fc)
739 wp[fc] = 1;
741 else
742 /* Add the character to the flag map. */
743 wp[fc] = 1;
745 if (fc == '\0')
746 conv_error();
748 num.ul = read_in;
751 if (wp[c] == not_in)
752 break;
753 STRING_ADD_CHAR (c);
754 if (width > 0)
755 --width;
757 while (inchar () != EOF && width != 0);
758 if (read_in == num.ul)
759 conv_error ();
761 if (!(flags & SUPPRESS))
763 *str = '\0';
764 ++done;
766 break;
768 case 'p': /* Generic pointer. */
769 base = 16;
770 /* A PTR must be the same size as a `long int'. */
771 flags &= ~(SHORT|LONGDBL);
772 flags |= LONG;
773 number_signed = 0;
774 goto number;
778 /* The last thing we saw int the format string was a white space.
779 Consume the last white spaces. */
780 if (skip_space)
781 while (isspace (c))
782 (void) inchar ();
784 return ((void) (c == EOF || ungetc (c, s)), done);
787 #ifdef USE_IN_LIBIO
789 __vfscanf (FILE *s, const char *format, va_list argptr)
791 return _IO_vfscanf (s, format, argptr, NULL);
793 #endif
795 weak_alias (__vfscanf, vfscanf)