2 Copyright (C) 1993 Free Software Foundation
4 This file is part of the GNU IO Library. This library is free
5 software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option)
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this library; see the file COPYING. If not, write to the Free
17 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 As a special exception, if you link this library with files
20 compiled with a GNU compiler to produce an executable, this does not cause
21 the resulting executable to be covered by the GNU General Public License.
22 This exception does not however invalidate any other reasons why
23 the executable file might be covered by the GNU General Public License. */
26 * Copyright (c) 1990 The Regents of the University of California.
27 * All rights reserved.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. [rescinded 22 July 1999]
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 /* Extensively hacked for GNU iostream by Per Bothner 1991, 1992, 1993.
56 Changes copyright Free Software Foundation 1992, 1993. */
58 #if defined(LIBC_SCCS) && !defined(lint)
59 static char sccsid
[] = "%W% (Berkeley) %G%";
60 #endif /* LIBC_SCCS and not lint */
70 #ifndef NO_FLOATING_POINT
71 #define FLOATING_POINT
76 #define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */
82 * Flags used during conversion.
84 #define LONG 0x01 /* l: long or double */
85 #define LONGDBL 0x02 /* L: long double; unimplemented */
86 #define SHORT 0x04 /* h: short */
87 #define SUPPRESS 0x08 /* suppress assignment */
88 #define POINTER 0x10 /* weird %p pointer (`fake hex') */
89 #define NOSKIP 0x20 /* do not skip blanks */
90 #define WIDTH 0x40 /* width */
93 * The following are used in numeric conversions only:
94 * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
95 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
97 #define SIGNOK 0x40 /* +/- is (still) legal */
98 #define NDIGITS 0x80 /* no digits detected */
100 #define DPTOK 0x100 /* (float) decimal point is still legal */
101 #define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */
103 #define PFXOK 0x100 /* 0x prefix is (still) legal */
104 #define NZDIGITS 0x200 /* no zero digits detected */
109 #define CT_CHAR 0 /* %c conversion */
110 #define CT_CCL 1 /* %[...] conversion */
111 #define CT_STRING 2 /* %s conversion */
112 #define CT_INT 3 /* integer, i.e., strtol or strtoul */
113 #define CT_FLOAT 4 /* floating, i.e., strtod */
115 #define u_char unsigned char
116 #define u_long unsigned long
121 extern u_long strtoul
__P((const char*, char**, int));
122 extern long strtol
__P((const char*, char**, int));
123 static const u_char
*__sccl
__P((char *tab
, const u_char
*fmt
));
125 extern double atof();
131 /* If errp != NULL, *errp|=1 if we see a premature EOF;
132 *errp|=2 if we an invalid character. */
135 _IO_vfscanf (fp
, fmt0
, ap
, errp
)
141 register const u_char
*fmt
= (const u_char
*)fmt0
;
142 register int c
; /* character from format, or conversion */
143 register _IO_ssize_t width
; /* field width, or 0 */
144 register char *p
; /* points into all kinds of strings */
145 register int n
; /* handy integer */
146 register int flags
= 0; /* flags as defined above */
147 register char *p0
; /* saves original value of p when necessary */
148 int nassigned
; /* number of fields assigned */
149 int nread
; /* number of characters consumed from fp */
150 /* Assignments to base and ccfn are just to suppress warnings from gcc.*/
151 int base
= 0; /* base argument to strtol/strtoul */
152 typedef u_long (*strtoulfn
) __P((const char*, char**, int));
154 /* conversion function (strtol/strtoul) */
155 char ccltab
[256]; /* character class table for %[...] */
156 char buf
[BUF
]; /* buffer for numeric conversions */
159 /* `basefix' is used to avoid `if' tests in the integer scanner */
160 static short basefix
[17] =
161 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
189 * switch on the format. continue if done;
190 * break once format type is derived.
207 if (flags
) goto control_failure
;
211 if (flags
& ~(SUPPRESS
| WIDTH
)) goto control_failure
;
215 if (flags
& ~(SUPPRESS
| WIDTH
)) goto control_failure
;
219 if (flags
& ~(SUPPRESS
| WIDTH
)) goto control_failure
;
223 case '0': case '1': case '2': case '3': case '4':
224 case '5': case '6': case '7': case '8': case '9':
225 if (flags
& ~(SUPPRESS
| WIDTH
)) goto control_failure
;
227 width
= width
* 10 + c
- '0';
232 * Those marked `compat' are for 4.[123]BSD compatibility.
234 * (According to ANSI, E and X formats are supposed
235 * to the same as e and x. Sorry about that.)
237 case 'D': /* compat */
242 ccfn
= (strtoulfn
)strtol
;
248 ccfn
= (strtoulfn
)strtol
;
252 case 'O': /* compat */
269 flags
|= PFXOK
; /* enable 0x prefixing */
275 #ifdef FLOATING_POINT
277 case 'e': case 'f': case 'g':
287 fmt
= __sccl(ccltab
, fmt
);
297 case 'p': /* pointer format is like hex */
298 flags
|= POINTER
| PFXOK
;
305 if (flags
& SUPPRESS
) /* ??? */
308 *va_arg(ap
, short *) = nread
;
309 else if (flags
& LONG
)
310 *va_arg(ap
, long *) = nread
;
312 *va_arg(ap
, int *) = nread
;
316 * Disgusting backwards compatibility hacks. XXX
318 case '\0': /* compat */
322 default: /* compat */
326 ccfn
= (strtoulfn
)strtol
;
332 * We have a conversion that requires input.
334 if (_IO_peekc(fp
) == EOF
)
338 * Consume leading white space, except for formats
339 * that suppress this.
341 if ((flags
& NOSKIP
) == 0) {
342 n
= (unsigned char)*fp
->_IO_read_ptr
;
350 /* Note that there is at least one character in
351 the buffer, so conversions that do not set NOSKIP
352 can no longer result in an input failure. */
361 /* scan arbitrary characters (sets NOSKIP) */
362 if (width
== 0) /* FIXME! */
364 if (flags
& SUPPRESS
) {
367 n
= fp
->_IO_read_end
- fp
->_IO_read_ptr
;
368 if (n
< (int)width
) {
371 fp
->_IO_read_ptr
+= n
;
372 if (__underflow(fp
) == EOF
)
381 fp
->_IO_read_ptr
+= width
;
389 _IO_XSGETN (fp
, (char*)va_arg(ap
, char*), width
);
398 /* scan a (nonempty) character class (sets NOSKIP) */
400 width
= ~0; /* `infinity' */
401 /* take only those things in the class */
402 if (flags
& SUPPRESS
) {
404 while (ccltab
[(unsigned char)*fp
->_IO_read_ptr
]) {
405 n
++, fp
->_IO_read_ptr
++;
408 if (_IO_peekc(fp
) == EOF
) {
418 p0
= p
= va_arg(ap
, char *);
419 while (ccltab
[(unsigned char)*fp
->_IO_read_ptr
]) {
420 *p
++ = *fp
->_IO_read_ptr
++;
423 if (_IO_peekc(fp
) == EOF
) {
440 /* like CCL, but zero-length string OK, & no NOSKIP */
443 if (flags
& SUPPRESS
) {
445 while (!isspace((unsigned char)*fp
->_IO_read_ptr
)) {
446 n
++, fp
->_IO_read_ptr
++;
449 if (_IO_peekc(fp
) == EOF
) {
456 p0
= p
= va_arg(ap
, char *);
457 while (!isspace((unsigned char)*fp
->_IO_read_ptr
)) {
458 *p
++ = *fp
->_IO_read_ptr
++;
461 if (_IO_peekc(fp
) == EOF
) {
473 /* scan an integer as if by strtol/strtoul */
474 if (width
== 0 || width
> sizeof(buf
) - 1)
475 width
= sizeof(buf
) - 1;
476 flags
|= SIGNOK
| NDIGITS
| NZDIGITS
;
477 for (p
= buf
; width
; width
--) {
478 c
= (unsigned char)*fp
->_IO_read_ptr
;
480 * Switch on the character; `goto ok'
481 * if we accept it as a part of number.
486 * The digit 0 is always legal, but is
487 * special. For %i conversions, if no
488 * digits (zero or nonzero) have been
489 * scanned (only signs), we will have
490 * base==0. In that case, we should set
491 * it to 8 and enable 0x prefixing.
492 * Also, if we have not scanned zero digits
493 * before this, do not turn off prefixing
494 * (someone else will turn it off if we
495 * have scanned any nonzero digits).
502 if (flags
& NZDIGITS
)
503 flags
&= ~(SIGNOK
|NZDIGITS
|NDIGITS
);
505 flags
&= ~(SIGNOK
|PFXOK
|NDIGITS
);
508 /* 1 through 7 always legal */
509 case '1': case '2': case '3':
510 case '4': case '5': case '6': case '7':
511 base
= basefix
[base
];
512 flags
&= ~(SIGNOK
| PFXOK
| NDIGITS
);
515 /* digits 8 and 9 ok iff decimal or hex */
517 base
= basefix
[base
];
519 break; /* not legal here */
520 flags
&= ~(SIGNOK
| PFXOK
| NDIGITS
);
523 /* letters ok iff hex */
524 case 'A': case 'B': case 'C':
525 case 'D': case 'E': case 'F':
526 case 'a': case 'b': case 'c':
527 case 'd': case 'e': case 'f':
528 /* no need to fix base here */
530 break; /* not legal here */
531 flags
&= ~(SIGNOK
| PFXOK
| NDIGITS
);
534 /* sign ok only as first character */
536 if (flags
& SIGNOK
) {
542 /* x ok iff flag still set & 2nd char */
544 if (flags
& PFXOK
&& p
== buf
+ 1) {
545 base
= 16; /* if %i */
553 * If we got here, c is not a legal character
554 * for a number. Stop accumulating digits.
559 * c is legal: store it and look at the next.
563 if (_IO_peekc(fp
) == EOF
) {
569 * If we had only a sign, it is no good; push
570 * back the sign. If the number ends in `x',
571 * it was [sign] '0' 'x', so push back the x
572 * and treat it as [sign] '0'.
574 if (flags
& NDIGITS
) {
576 (void) _IO_ungetc(*(u_char
*)--p
, fp
);
579 c
= ((u_char
*)p
)[-1];
580 if (c
== 'x' || c
== 'X') {
582 (void) _IO_ungetc (c
, fp
);
584 if ((flags
& SUPPRESS
) == 0) {
588 res
= (*ccfn
)(buf
, (char **)NULL
, base
);
590 *va_arg(ap
, void **) = (void *)res
;
591 else if (flags
& SHORT
)
592 *va_arg(ap
, short *) = res
;
593 else if (flags
& LONG
)
594 *va_arg(ap
, long *) = res
;
596 *va_arg(ap
, int *) = res
;
602 #ifdef FLOATING_POINT
604 /* scan a floating point number as if by strtod */
605 if (width
== 0 || width
> sizeof(buf
) - 1)
606 width
= sizeof(buf
) - 1;
607 flags
|= SIGNOK
| NDIGITS
| DPTOK
| EXPOK
;
608 for (p
= buf
; width
; width
--) {
609 c
= (unsigned char)*fp
->_IO_read_ptr
;
611 * This code mimicks the integer conversion
612 * code, but is much simpler.
616 case '0': case '1': case '2': case '3':
617 case '4': case '5': case '6': case '7':
619 flags
&= ~(SIGNOK
| NDIGITS
);
623 if (flags
& SIGNOK
) {
630 flags
&= ~(SIGNOK
| DPTOK
);
635 /* no exponent without some digits */
636 if ((flags
&(NDIGITS
|EXPOK
)) == EXPOK
) {
638 (flags
& ~(EXPOK
|DPTOK
)) |
648 if (_IO_peekc(fp
) == EOF
) {
654 * If no digits, might be missing exponent digits
655 * (just give back the exponent) or might be missing
656 * regular digits, but had sign and/or decimal point.
658 if (flags
& NDIGITS
) {
660 /* no digits at all */
662 _IO_ungetc (*(u_char
*)--p
, fp
);
665 /* just a bad exponent (e and maybe sign) */
667 if (c
!= 'e' && c
!= 'E') {
668 (void) _IO_ungetc (c
, fp
);/* sign */
671 (void) _IO_ungetc (c
, fp
);
673 if ((flags
& SUPPRESS
) == 0) {
677 res
= _IO_strtod(buf
, NULL
);
682 *va_arg(ap
, double *) = res
;
684 *va_arg(ap
, float *) = res
;
689 #endif /* FLOATING_POINT */
702 if (errp
&& seen_eof
)
708 * Fill in the given table from the scanset at the given format
709 * (just after `['). Return a pointer to the character past the
710 * closing `]'. The table has a 1 wherever characters should be
711 * considered part of the scanset.
713 static const u_char
*
718 register int c
, n
, v
;
720 /* first `clear' the whole table */
721 c
= *fmt
++; /* first char hat => negated scanset */
723 v
= 1; /* default => accept */
724 c
= *fmt
++; /* get new first char */
726 v
= 0; /* default => reject */
727 /* should probably use memset here */
728 for (n
= 0; n
< 256; n
++)
731 return (fmt
- 1);/* format ended before closing ] */
734 * Now set the entries corresponding to the actual scanset
735 * to the opposite of the above.
737 * The first character may be ']' (or '-') without being special;
738 * the last character may be '-'.
742 tab
[c
] = v
; /* take character c */
744 n
= *fmt
++; /* and examine the next */
747 case 0: /* format ended too soon */
752 * A scanset of the form
754 * is defined as `the digit 0, the digit 1,
755 * the character +, the character -', but
756 * the effect of a scanset such as
758 * is implementation defined. The V7 Unix
759 * scanf treats `a-z' as `the letters a through
760 * z', but treats `a-a' as `the letter a, the
761 * character -, and the letter a'.
763 * For compatibility, the `-' is not considerd
764 * to define a range if the character following
765 * it is either a close bracket (required by ANSI)
766 * or is not numerically greater than the character
767 * we just stored in the table (c).
770 if (n
== ']' || n
< c
) {
772 break; /* resume the for(;;) */
775 do { /* fill in the range */
778 #if 1 /* XXX another disgusting compatibility hack */
780 * Alas, the V7 Unix scanf also treats formats
781 * such as [a-c-e] as `the letters a through e'.
782 * This too is permitted by the standard....
794 case ']': /* end of scanset */
797 default: /* just another character */