2000-12-19 Curtis Janssen <cljanss@ca.sandia.gov>
[official-gcc.git] / libio / iovfscanf.c
blobf1c4d224de563a0adc6b6dd1969324c5b24b9821
1 /*
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)
8 any later version.
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
31 * are met:
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
52 * SUCH DAMAGE.
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 */
62 #include <libioP.h>
63 #include <ctype.h>
64 #ifdef __STDC__
65 #include <stdarg.h>
66 #else
67 #include <varargs.h>
68 #endif
70 #ifndef NO_FLOATING_POINT
71 #define FLOATING_POINT
72 #endif
74 #ifdef FLOATING_POINT
75 #include "floatio.h"
76 #define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */
77 #else
78 #define BUF 40
79 #endif
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 */
107 * Conversion types.
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
118 #ifdef __cplusplus
119 extern "C" {
120 #endif
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));
124 #ifndef _IO_USE_DTOA
125 extern double atof();
126 #endif
127 #ifdef __cplusplus
129 #endif
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)
136 _IO_FILE *fp;
137 char const *fmt0;
138 _IO_va_list ap;
139 int *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));
153 strtoulfn ccfn = 0;
154 /* conversion function (strtol/strtoul) */
155 char ccltab[256]; /* character class table for %[...] */
156 char buf[BUF]; /* buffer for numeric conversions */
157 int seen_eof = 0;
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 };
163 nassigned = 0;
164 nread = 0;
165 for (;;) {
166 c = *fmt++;
167 if (c == 0)
168 goto done;
169 if (isspace(c)) {
170 for (;;) {
171 c = _IO_getc(fp);
172 if (c == EOF) {
173 seen_eof++;
174 break;
176 if (!isspace(c)) {
177 _IO_ungetc (c, fp);
178 break;
180 nread++;
182 continue;
184 if (c != '%')
185 goto literal;
186 width = 0;
187 flags = 0;
189 * switch on the format. continue if done;
190 * break once format type is derived.
192 again: c = *fmt++;
193 switch (c) {
194 case '%':
195 literal:
196 n = _IO_getc(fp);
197 if (n == EOF)
198 goto eof_failure;
199 if (n != c) {
200 _IO_ungetc (n, fp);
201 goto match_failure;
203 nread++;
204 continue;
206 case '*':
207 if (flags) goto control_failure;
208 flags = SUPPRESS;
209 goto again;
210 case 'l':
211 if (flags & ~(SUPPRESS | WIDTH)) goto control_failure;
212 flags |= LONG;
213 goto again;
214 case 'L':
215 if (flags & ~(SUPPRESS | WIDTH)) goto control_failure;
216 flags |= LONGDBL;
217 goto again;
218 case 'h':
219 if (flags & ~(SUPPRESS | WIDTH)) goto control_failure;
220 flags |= SHORT;
221 goto again;
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;
226 flags |= WIDTH;
227 width = width * 10 + c - '0';
228 goto again;
231 * Conversions.
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 */
238 flags |= LONG;
239 /* FALLTHROUGH */
240 case 'd':
241 c = CT_INT;
242 ccfn = (strtoulfn)strtol;
243 base = 10;
244 break;
246 case 'i':
247 c = CT_INT;
248 ccfn = (strtoulfn)strtol;
249 base = 0;
250 break;
252 case 'O': /* compat */
253 flags |= LONG;
254 /* FALLTHROUGH */
255 case 'o':
256 c = CT_INT;
257 ccfn = strtoul;
258 base = 8;
259 break;
261 case 'u':
262 c = CT_INT;
263 ccfn = strtoul;
264 base = 10;
265 break;
267 case 'X':
268 case 'x':
269 flags |= PFXOK; /* enable 0x prefixing */
270 c = CT_INT;
271 ccfn = strtoul;
272 base = 16;
273 break;
275 #ifdef FLOATING_POINT
276 case 'E': case 'F':
277 case 'e': case 'f': case 'g':
278 c = CT_FLOAT;
279 break;
280 #endif
282 case 's':
283 c = CT_STRING;
284 break;
286 case '[':
287 fmt = __sccl(ccltab, fmt);
288 flags |= NOSKIP;
289 c = CT_CCL;
290 break;
292 case 'c':
293 flags |= NOSKIP;
294 c = CT_CHAR;
295 break;
297 case 'p': /* pointer format is like hex */
298 flags |= POINTER | PFXOK;
299 c = CT_INT;
300 ccfn = strtoul;
301 base = 16;
302 break;
304 case 'n':
305 if (flags & SUPPRESS) /* ??? */
306 continue;
307 if (flags & SHORT)
308 *va_arg(ap, short *) = nread;
309 else if (flags & LONG)
310 *va_arg(ap, long *) = nread;
311 else
312 *va_arg(ap, int *) = nread;
313 continue;
316 * Disgusting backwards compatibility hacks. XXX
318 case '\0': /* compat */
319 nassigned = EOF;
320 goto done;
322 default: /* compat */
323 if (isupper(c))
324 flags |= LONG;
325 c = CT_INT;
326 ccfn = (strtoulfn)strtol;
327 base = 10;
328 break;
332 * We have a conversion that requires input.
334 if (_IO_peekc(fp) == EOF)
335 goto eof_failure;
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;
343 while (isspace(n)) {
344 fp->_IO_read_ptr++;
345 nread++;
346 n = _IO_peekc(fp);
347 if (n == EOF)
348 goto eof_failure;
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. */
356 * Do the conversion.
358 switch (c) {
360 case CT_CHAR:
361 /* scan arbitrary characters (sets NOSKIP) */
362 if (width == 0) /* FIXME! */
363 width = 1;
364 if (flags & SUPPRESS) {
365 _IO_size_t sum = 0;
366 for (;;) {
367 n = fp->_IO_read_end - fp->_IO_read_ptr;
368 if (n < (int)width) {
369 sum += n;
370 width -= n;
371 fp->_IO_read_ptr += n;
372 if (__underflow(fp) == EOF)
373 if (sum == 0)
374 goto eof_failure;
375 else {
376 seen_eof++;
377 break;
379 } else {
380 sum += width;
381 fp->_IO_read_ptr += width;
382 break;
385 nread += sum;
386 } else {
387 _IO_size_t r =
389 _IO_XSGETN (fp, (char*)va_arg(ap, char*), width);
390 if (r != width)
391 goto eof_failure;
392 nread += r;
393 nassigned++;
395 break;
397 case CT_CCL:
398 /* scan a (nonempty) character class (sets NOSKIP) */
399 if (width == 0)
400 width = ~0; /* `infinity' */
401 /* take only those things in the class */
402 if (flags & SUPPRESS) {
403 n = 0;
404 while (ccltab[(unsigned char)*fp->_IO_read_ptr]) {
405 n++, fp->_IO_read_ptr++;
406 if (--width == 0)
407 break;
408 if (_IO_peekc(fp) == EOF) {
409 if (n == 0)
410 goto eof_failure;
411 seen_eof++;
412 break;
415 if (n == 0)
416 goto match_failure;
417 } else {
418 p0 = p = va_arg(ap, char *);
419 while (ccltab[(unsigned char)*fp->_IO_read_ptr]) {
420 *p++ = *fp->_IO_read_ptr++;
421 if (--width == 0)
422 break;
423 if (_IO_peekc(fp) == EOF) {
424 if (p == p0)
425 goto eof_failure;
426 seen_eof++;
427 break;
430 n = p - p0;
431 if (n == 0)
432 goto match_failure;
433 *p = 0;
434 nassigned++;
436 nread += n;
437 break;
439 case CT_STRING:
440 /* like CCL, but zero-length string OK, & no NOSKIP */
441 if (width == 0)
442 width = ~0;
443 if (flags & SUPPRESS) {
444 n = 0;
445 while (!isspace((unsigned char)*fp->_IO_read_ptr)) {
446 n++, fp->_IO_read_ptr++;
447 if (--width == 0)
448 break;
449 if (_IO_peekc(fp) == EOF) {
450 seen_eof++;
451 break;
454 nread += n;
455 } else {
456 p0 = p = va_arg(ap, char *);
457 while (!isspace((unsigned char)*fp->_IO_read_ptr)) {
458 *p++ = *fp->_IO_read_ptr++;
459 if (--width == 0)
460 break;
461 if (_IO_peekc(fp) == EOF) {
462 seen_eof++;
463 break;
466 *p = 0;
467 nread += p - p0;
468 nassigned++;
470 continue;
472 case CT_INT:
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.
483 switch (c) {
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).
497 case '0':
498 if (base == 0) {
499 base = 8;
500 flags |= PFXOK;
502 if (flags & NZDIGITS)
503 flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
504 else
505 flags &= ~(SIGNOK|PFXOK|NDIGITS);
506 goto ok;
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);
513 goto ok;
515 /* digits 8 and 9 ok iff decimal or hex */
516 case '8': case '9':
517 base = basefix[base];
518 if (base <= 8)
519 break; /* not legal here */
520 flags &= ~(SIGNOK | PFXOK | NDIGITS);
521 goto ok;
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 */
529 if (base <= 10)
530 break; /* not legal here */
531 flags &= ~(SIGNOK | PFXOK | NDIGITS);
532 goto ok;
534 /* sign ok only as first character */
535 case '+': case '-':
536 if (flags & SIGNOK) {
537 flags &= ~SIGNOK;
538 goto ok;
540 break;
542 /* x ok iff flag still set & 2nd char */
543 case 'x': case 'X':
544 if (flags & PFXOK && p == buf + 1) {
545 base = 16; /* if %i */
546 flags &= ~PFXOK;
547 goto ok;
549 break;
553 * If we got here, c is not a legal character
554 * for a number. Stop accumulating digits.
556 break;
559 * c is legal: store it and look at the next.
561 *p++ = c;
562 fp->_IO_read_ptr++;
563 if (_IO_peekc(fp) == EOF) {
564 seen_eof++;
565 break; /* 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) {
575 if (p > buf)
576 (void) _IO_ungetc(*(u_char *)--p, fp);
577 goto match_failure;
579 c = ((u_char *)p)[-1];
580 if (c == 'x' || c == 'X') {
581 --p;
582 (void) _IO_ungetc (c, fp);
584 if ((flags & SUPPRESS) == 0) {
585 u_long res;
587 *p = 0;
588 res = (*ccfn)(buf, (char **)NULL, base);
589 if (flags & POINTER)
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;
595 else
596 *va_arg(ap, int *) = res;
597 nassigned++;
599 nread += p - buf;
600 break;
602 #ifdef FLOATING_POINT
603 case CT_FLOAT:
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.
614 switch (c) {
616 case '0': case '1': case '2': case '3':
617 case '4': case '5': case '6': case '7':
618 case '8': case '9':
619 flags &= ~(SIGNOK | NDIGITS);
620 goto fok;
622 case '+': case '-':
623 if (flags & SIGNOK) {
624 flags &= ~SIGNOK;
625 goto fok;
627 break;
628 case '.':
629 if (flags & DPTOK) {
630 flags &= ~(SIGNOK | DPTOK);
631 goto fok;
633 break;
634 case 'e': case 'E':
635 /* no exponent without some digits */
636 if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
637 flags =
638 (flags & ~(EXPOK|DPTOK)) |
639 SIGNOK | NDIGITS;
640 goto fok;
642 break;
644 break;
645 fok:
646 *p++ = c;
647 fp->_IO_read_ptr++;
648 if (_IO_peekc(fp) == EOF) {
649 seen_eof++;
650 break; /* 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) {
659 if (flags & EXPOK) {
660 /* no digits at all */
661 while (p > buf)
662 _IO_ungetc (*(u_char *)--p, fp);
663 goto match_failure;
665 /* just a bad exponent (e and maybe sign) */
666 c = *(u_char *)--p;
667 if (c != 'e' && c != 'E') {
668 (void) _IO_ungetc (c, fp);/* sign */
669 c = *(u_char *)--p;
671 (void) _IO_ungetc (c, fp);
673 if ((flags & SUPPRESS) == 0) {
674 double res;
675 *p = 0;
676 #ifdef _IO_USE_DTOA
677 res = _IO_strtod(buf, NULL);
678 #else
679 res = atof(buf);
680 #endif
681 if (flags & LONG)
682 *va_arg(ap, double *) = res;
683 else
684 *va_arg(ap, float *) = res;
685 nassigned++;
687 nread += p - buf;
688 break;
689 #endif /* FLOATING_POINT */
692 eof_failure:
693 seen_eof++;
694 input_failure:
695 if (nassigned == 0)
696 nassigned = -1;
697 control_failure:
698 match_failure:
699 if (errp)
700 *errp |= 2;
701 done:
702 if (errp && seen_eof)
703 *errp |= 1;
704 return (nassigned);
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 *
714 __sccl (tab, fmt)
715 char *tab;
716 const u_char *fmt;
718 register int c, n, v;
720 /* first `clear' the whole table */
721 c = *fmt++; /* first char hat => negated scanset */
722 if (c == '^') {
723 v = 1; /* default => accept */
724 c = *fmt++; /* get new first char */
725 } else
726 v = 0; /* default => reject */
727 /* should probably use memset here */
728 for (n = 0; n < 256; n++)
729 tab[n] = v;
730 if (c == 0)
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 '-'.
740 v = 1 - v;
741 for (;;) {
742 tab[c] = v; /* take character c */
743 doswitch:
744 n = *fmt++; /* and examine the next */
745 switch (n) {
747 case 0: /* format ended too soon */
748 return (fmt - 1);
750 case '-':
752 * A scanset of the form
753 * [01+-]
754 * is defined as `the digit 0, the digit 1,
755 * the character +, the character -', but
756 * the effect of a scanset such as
757 * [a-zA-Z0-9]
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).
769 n = *fmt;
770 if (n == ']' || n < c) {
771 c = '-';
772 break; /* resume the for(;;) */
774 fmt++;
775 do { /* fill in the range */
776 tab[++c] = v;
777 } while (c < n);
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....
784 goto doswitch;
785 #else
786 c = *fmt++;
787 if (c == 0)
788 return (fmt - 1);
789 if (c == ']')
790 return (fmt);
791 #endif
792 break;
794 case ']': /* end of scanset */
795 return (fmt);
797 default: /* just another character */
798 c = n;
799 break;
802 /* NOTREACHED */