|
|
1.1 root 1: /*
2: Copyright (C) 1993 Free Software Foundation
3:
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.
9:
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.
14:
15: You should have received a copy of the GNU General Public License
16: along with GNU CC; see the file COPYING. If not, write to
17: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18:
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. */
24:
25: /*
26: * Copyright (c) 1990 The Regents of the University of California.
27: * All rights reserved.
28: *
29: * Redistribution and use in source and binary forms are permitted
30: * provided that the above copyright notice and this paragraph are
31: * duplicated in all such forms and that any documentation,
32: * advertising materials, and other materials related to such
33: * distribution and use acknowledge that the software was developed
34: * by the University of California, Berkeley. The name of the
35: * University may not be used to endorse or promote products derived
36: * from this software without specific prior written permission.
37: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
38: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
39: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
40: */
41:
42: /* Extensively hacked for GNU iostream by Per Bothner 1991, 1992, 1993.
43: Changes copyright Free Software Foundation 1992, 1993. */
44:
45: #if defined(LIBC_SCCS) && !defined(lint)
46: static char sccsid[] = "%W% (Berkeley) %G%";
47: #endif /* LIBC_SCCS and not lint */
48:
49: #include <libioP.h>
50: #include <ctype.h>
51: #ifdef __STDC__
52: #include <stdarg.h>
53: #else
54: #include <varargs.h>
55: #endif
56:
57: #ifndef NO_FLOATING_POINT
58: #define FLOATING_POINT
59: #endif
60:
61: #ifdef FLOATING_POINT
62: #include "floatio.h"
63: #define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */
64: #else
65: #define BUF 40
66: #endif
67:
68: /*
69: * Flags used during conversion.
70: */
71: #define LONG 0x01 /* l: long or double */
72: #define LONGDBL 0x02 /* L: long double; unimplemented */
73: #define SHORT 0x04 /* h: short */
74: #define SUPPRESS 0x08 /* suppress assignment */
75: #define POINTER 0x10 /* weird %p pointer (`fake hex') */
76: #define NOSKIP 0x20 /* do not skip blanks */
77:
78: /*
79: * The following are used in numeric conversions only:
80: * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
81: * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
82: */
83: #define SIGNOK 0x40 /* +/- is (still) legal */
84: #define NDIGITS 0x80 /* no digits detected */
85:
86: #define DPTOK 0x100 /* (float) decimal point is still legal */
87: #define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */
88:
89: #define PFXOK 0x100 /* 0x prefix is (still) legal */
90: #define NZDIGITS 0x200 /* no zero digits detected */
91:
92: /*
93: * Conversion types.
94: */
95: #define CT_CHAR 0 /* %c conversion */
96: #define CT_CCL 1 /* %[...] conversion */
97: #define CT_STRING 2 /* %s conversion */
98: #define CT_INT 3 /* integer, i.e., strtol or strtoul */
99: #define CT_FLOAT 4 /* floating, i.e., strtod */
100:
101: #define u_char unsigned char
102: #define u_long unsigned long
103:
104: extern u_long strtoul _PARAMS((const char*, char**, int));
105: extern long strtol _PARAMS((const char*, char**, int));
106: static const u_char *__sccl _PARAMS((char *tab, const u_char *fmt));
107: #ifndef USE_DTOA
108: extern double atof();
109: #endif
110:
111: /* If errp != NULL, *errp|=1 if we see a premature EOF;
112: *errp|=2 if we an invalid character. */
113:
114: int
115: _IO_vfscanf(fp, fmt0, ap, errp)
116: register _IO_FILE *fp;
117: char const *fmt0;
118: _IO_va_list ap;
119: int *errp;
120: {
121: register const u_char *fmt = (const u_char *)fmt0;
122: register int c; /* character from format, or conversion */
123: register _IO_ssize_t width; /* field width, or 0 */
124: register char *p; /* points into all kinds of strings */
125: register int n; /* handy integer */
126: register int flags; /* flags as defined above */
127: register char *p0; /* saves original value of p when necessary */
128: int nassigned; /* number of fields assigned */
129: int nread; /* number of characters consumed from fp */
130: /* Assignments to base and ccfn are just to suppress warnings from gcc.*/
131: int base = 0; /* base argument to strtol/strtoul */
132: typedef u_long (*strtoulfn) _PARAMS((const char*, char**, int));
133: strtoulfn ccfn = 0;
134: /* conversion function (strtol/strtoul) */
135: char ccltab[256]; /* character class table for %[...] */
136: char buf[BUF]; /* buffer for numeric conversions */
137: int seen_eof = 0;
138:
139: /* `basefix' is used to avoid `if' tests in the integer scanner */
140: static short basefix[17] =
141: { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
142:
143: nassigned = 0;
144: nread = 0;
145: for (;;) {
146: c = *fmt++;
147: if (c == 0)
148: goto done;
149: if (isspace(c)) {
150: for (;;) {
151: c = _IO_getc(fp);
152: if (c == EOF) {
153: seen_eof++;
154: break;
155: }
156: if (!isspace(c)) {
157: _IO_ungetc (c, fp);
158: break;
159: }
160: nread++;
161: }
162: continue;
163: }
164: if (c != '%')
165: goto literal;
166: width = 0;
167: flags = 0;
168: /*
169: * switch on the format. continue if done;
170: * break once format type is derived.
171: */
172: again: c = *fmt++;
173: switch (c) {
174: case '%':
175: literal:
176: n = _IO_getc(fp);
177: if (n == EOF)
178: goto eof_failure;
179: if (n != c) {
180: _IO_ungetc (n, fp);
181: goto match_failure;
182: }
183: nread++;
184: continue;
185:
186: case '*':
187: flags |= SUPPRESS;
188: goto again;
189: case 'l':
190: flags |= LONG;
191: goto again;
192: case 'L':
193: flags |= LONGDBL;
194: goto again;
195: case 'h':
196: flags |= SHORT;
197: goto again;
198:
199: case '0': case '1': case '2': case '3': case '4':
200: case '5': case '6': case '7': case '8': case '9':
201: width = width * 10 + c - '0';
202: goto again;
203:
204: /*
205: * Conversions.
206: * Those marked `compat' are for 4.[123]BSD compatibility.
207: *
208: * (According to ANSI, E and X formats are supposed
209: * to the same as e and x. Sorry about that.)
210: */
211: case 'D': /* compat */
212: flags |= LONG;
213: /* FALLTHROUGH */
214: case 'd':
215: c = CT_INT;
216: ccfn = (strtoulfn)strtol;
217: base = 10;
218: break;
219:
220: case 'i':
221: c = CT_INT;
222: ccfn = (strtoulfn)strtol;
223: base = 0;
224: break;
225:
226: case 'O': /* compat */
227: flags |= LONG;
228: /* FALLTHROUGH */
229: case 'o':
230: c = CT_INT;
231: ccfn = strtoul;
232: base = 8;
233: break;
234:
235: case 'u':
236: c = CT_INT;
237: ccfn = strtoul;
238: base = 10;
239: break;
240:
241: case 'X':
242: case 'x':
243: flags |= PFXOK; /* enable 0x prefixing */
244: c = CT_INT;
245: ccfn = strtoul;
246: base = 16;
247: break;
248:
249: #ifdef FLOATING_POINT
250: case 'E': case 'F':
251: case 'e': case 'f': case 'g':
252: c = CT_FLOAT;
253: break;
254: #endif
255:
256: case 's':
257: c = CT_STRING;
258: break;
259:
260: case '[':
261: fmt = __sccl(ccltab, fmt);
262: flags |= NOSKIP;
263: c = CT_CCL;
264: break;
265:
266: case 'c':
267: flags |= NOSKIP;
268: c = CT_CHAR;
269: break;
270:
271: case 'p': /* pointer format is like hex */
272: flags |= POINTER | PFXOK;
273: c = CT_INT;
274: ccfn = strtoul;
275: base = 16;
276: break;
277:
278: case 'n':
279: if (flags & SUPPRESS) /* ??? */
280: continue;
281: if (flags & SHORT)
282: *va_arg(ap, short *) = nread;
283: else if (flags & LONG)
284: *va_arg(ap, long *) = nread;
285: else
286: *va_arg(ap, int *) = nread;
287: continue;
288:
289: /*
290: * Disgusting backwards compatibility hacks. XXX
291: */
292: case '\0': /* compat */
293: nassigned = EOF;
294: goto done;
295:
296: default: /* compat */
297: if (isupper(c))
298: flags |= LONG;
299: c = CT_INT;
300: ccfn = (strtoulfn)strtol;
301: base = 10;
302: break;
303: }
304:
305: /*
306: * We have a conversion that requires input.
307: */
308: if (_IO_peekc(fp) == EOF)
309: goto eof_failure;
310:
311: /*
312: * Consume leading white space, except for formats
313: * that suppress this.
314: */
315: if ((flags & NOSKIP) == 0) {
316: n = (unsigned char)*fp->_IO_read_ptr;
317: while (isspace(n)) {
318: fp->_IO_read_ptr++;
319: nread++;
320: n = _IO_peekc(fp);
321: if (n == EOF)
322: goto eof_failure;
323: }
324: /* Note that there is at least one character in
325: the buffer, so conversions that do not set NOSKIP
326: can no longer result in an input failure. */
327: }
328:
329: /*
330: * Do the conversion.
331: */
332: switch (c) {
333:
334: case CT_CHAR:
335: /* scan arbitrary characters (sets NOSKIP) */
336: if (width == 0) /* FIXME! */
337: width = 1;
338: if (flags & SUPPRESS) {
339: _IO_size_t sum = 0;
340: for (;;) {
341: n = fp->_IO_read_end - fp->_IO_read_ptr;
342: if (n < (int)width) {
343: sum += n;
344: width -= n;
345: fp->_IO_read_ptr += n;
346: if (__underflow(fp) == EOF)
347: if (sum == 0)
348: goto eof_failure;
349: else {
350: seen_eof++;
351: break;
352: }
353: } else {
354: sum += width;
355: fp->_IO_read_ptr += width;
356: break;
357: }
358: }
359: nread += sum;
360: } else {
361: _IO_size_t r =
362: (*fp->_jumps->__xsgetn)(fp,
363: (char*)va_arg(ap, char*),
364: width);
365: if (r != width)
366: goto eof_failure;
367: nread += r;
368: nassigned++;
369: }
370: break;
371:
372: case CT_CCL:
373: /* scan a (nonempty) character class (sets NOSKIP) */
374: if (width == 0)
375: width = ~0; /* `infinity' */
376: /* take only those things in the class */
377: if (flags & SUPPRESS) {
378: n = 0;
379: while (ccltab[(unsigned char)*fp->_IO_read_ptr]) {
380: n++, fp->_IO_read_ptr++;
381: if (--width == 0)
382: break;
383: if (_IO_peekc(fp) == EOF) {
384: if (n == 0)
385: goto eof_failure;
386: seen_eof++;
387: break;
388: }
389: }
390: if (n == 0)
391: goto match_failure;
392: } else {
393: p0 = p = va_arg(ap, char *);
394: while (ccltab[(unsigned char)*fp->_IO_read_ptr]) {
395: *p++ = *fp->_IO_read_ptr++;
396: if (--width == 0)
397: break;
398: if (_IO_peekc(fp) == EOF) {
399: if (p == p0)
400: goto eof_failure;
401: seen_eof++;
402: break;
403: }
404: }
405: n = p - p0;
406: if (n == 0)
407: goto match_failure;
408: *p = 0;
409: nassigned++;
410: }
411: nread += n;
412: break;
413:
414: case CT_STRING:
415: /* like CCL, but zero-length string OK, & no NOSKIP */
416: if (width == 0)
417: width = ~0;
418: if (flags & SUPPRESS) {
419: n = 0;
420: while (!isspace((unsigned char)*fp->_IO_read_ptr)) {
421: n++, fp->_IO_read_ptr++;
422: if (--width == 0)
423: break;
424: if (_IO_peekc(fp) == EOF) {
425: seen_eof++;
426: break;
427: }
428: }
429: nread += n;
430: } else {
431: p0 = p = va_arg(ap, char *);
432: while (!isspace((unsigned char)*fp->_IO_read_ptr)) {
433: *p++ = *fp->_IO_read_ptr++;
434: if (--width == 0)
435: break;
436: if (_IO_peekc(fp) == EOF) {
437: seen_eof++;
438: break;
439: }
440: }
441: *p = 0;
442: nread += p - p0;
443: nassigned++;
444: }
445: continue;
446:
447: case CT_INT:
448: /* scan an integer as if by strtol/strtoul */
449: if (width == 0 || width > sizeof(buf) - 1)
450: width = sizeof(buf) - 1;
451: flags |= SIGNOK | NDIGITS | NZDIGITS;
452: for (p = buf; width; width--) {
453: c = (unsigned char)*fp->_IO_read_ptr;
454: /*
455: * Switch on the character; `goto ok'
456: * if we accept it as a part of number.
457: */
458: switch (c) {
459:
460: /*
461: * The digit 0 is always legal, but is
462: * special. For %i conversions, if no
463: * digits (zero or nonzero) have been
464: * scanned (only signs), we will have
465: * base==0. In that case, we should set
466: * it to 8 and enable 0x prefixing.
467: * Also, if we have not scanned zero digits
468: * before this, do not turn off prefixing
469: * (someone else will turn it off if we
470: * have scanned any nonzero digits).
471: */
472: case '0':
473: if (base == 0) {
474: base = 8;
475: flags |= PFXOK;
476: }
477: if (flags & NZDIGITS)
478: flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
479: else
480: flags &= ~(SIGNOK|PFXOK|NDIGITS);
481: goto ok;
482:
483: /* 1 through 7 always legal */
484: case '1': case '2': case '3':
485: case '4': case '5': case '6': case '7':
486: base = basefix[base];
487: flags &= ~(SIGNOK | PFXOK | NDIGITS);
488: goto ok;
489:
490: /* digits 8 and 9 ok iff decimal or hex */
491: case '8': case '9':
492: base = basefix[base];
493: if (base <= 8)
494: break; /* not legal here */
495: flags &= ~(SIGNOK | PFXOK | NDIGITS);
496: goto ok;
497:
498: /* letters ok iff hex */
499: case 'A': case 'B': case 'C':
500: case 'D': case 'E': case 'F':
501: case 'a': case 'b': case 'c':
502: case 'd': case 'e': case 'f':
503: /* no need to fix base here */
504: if (base <= 10)
505: break; /* not legal here */
506: flags &= ~(SIGNOK | PFXOK | NDIGITS);
507: goto ok;
508:
509: /* sign ok only as first character */
510: case '+': case '-':
511: if (flags & SIGNOK) {
512: flags &= ~SIGNOK;
513: goto ok;
514: }
515: break;
516:
517: /* x ok iff flag still set & 2nd char */
518: case 'x': case 'X':
519: if (flags & PFXOK && p == buf + 1) {
520: base = 16; /* if %i */
521: flags &= ~PFXOK;
522: goto ok;
523: }
524: break;
525: }
526:
527: /*
528: * If we got here, c is not a legal character
529: * for a number. Stop accumulating digits.
530: */
531: break;
532: ok:
533: /*
534: * c is legal: store it and look at the next.
535: */
536: *p++ = c;
537: fp->_IO_read_ptr++;
538: if (_IO_peekc(fp) == EOF) {
539: seen_eof++;
540: break; /* EOF */
541: }
542: }
543: /*
544: * If we had only a sign, it is no good; push
545: * back the sign. If the number ends in `x',
546: * it was [sign] '0' 'x', so push back the x
547: * and treat it as [sign] '0'.
548: */
549: if (flags & NDIGITS) {
550: if (p > buf)
551: (void) _IO_ungetc(*(u_char *)--p, fp);
552: goto match_failure;
553: }
554: c = ((u_char *)p)[-1];
555: if (c == 'x' || c == 'X') {
556: --p;
557: (void) _IO_ungetc (c, fp);
558: }
559: if ((flags & SUPPRESS) == 0) {
560: u_long res;
561:
562: *p = 0;
563: res = (*ccfn)(buf, (char **)NULL, base);
564: if (flags & POINTER)
565: *va_arg(ap, void **) = (void *)res;
566: else if (flags & SHORT)
567: *va_arg(ap, short *) = res;
568: else if (flags & LONG)
569: *va_arg(ap, long *) = res;
570: else
571: *va_arg(ap, int *) = res;
572: nassigned++;
573: }
574: nread += p - buf;
575: break;
576:
577: #ifdef FLOATING_POINT
578: case CT_FLOAT:
579: /* scan a floating point number as if by strtod */
580: if (width == 0 || width > sizeof(buf) - 1)
581: width = sizeof(buf) - 1;
582: flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
583: for (p = buf; width; width--) {
584: c = (unsigned char)*fp->_IO_read_ptr;
585: /*
586: * This code mimicks the integer conversion
587: * code, but is much simpler.
588: */
589: switch (c) {
590:
591: case '0': case '1': case '2': case '3':
592: case '4': case '5': case '6': case '7':
593: case '8': case '9':
594: flags &= ~(SIGNOK | NDIGITS);
595: goto fok;
596:
597: case '+': case '-':
598: if (flags & SIGNOK) {
599: flags &= ~SIGNOK;
600: goto fok;
601: }
602: break;
603: case '.':
604: if (flags & DPTOK) {
605: flags &= ~(SIGNOK | DPTOK);
606: goto fok;
607: }
608: break;
609: case 'e': case 'E':
610: /* no exponent without some digits */
611: if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
612: flags =
613: (flags & ~(EXPOK|DPTOK)) |
614: SIGNOK | NDIGITS;
615: goto fok;
616: }
617: break;
618: }
619: break;
620: fok:
621: *p++ = c;
622: fp->_IO_read_ptr++;
623: if (_IO_peekc(fp) == EOF) {
624: seen_eof++;
625: break; /* EOF */
626: }
627: }
628: /*
629: * If no digits, might be missing exponent digits
630: * (just give back the exponent) or might be missing
631: * regular digits, but had sign and/or decimal point.
632: */
633: if (flags & NDIGITS) {
634: if (flags & EXPOK) {
635: /* no digits at all */
636: while (p > buf)
637: _IO_ungetc (*(u_char *)--p, fp);
638: goto match_failure;
639: }
640: /* just a bad exponent (e and maybe sign) */
641: c = *(u_char *)--p;
642: if (c != 'e' && c != 'E') {
643: (void) _IO_ungetc (c, fp);/* sign */
644: c = *(u_char *)--p;
645: }
646: (void) _IO_ungetc (c, fp);
647: }
648: if ((flags & SUPPRESS) == 0) {
649: double res;
650: *p = 0;
651: #ifdef USE_DTOA
652: res = _IO_strtod(buf, NULL);
653: #else
654: res = atof(buf);
655: #endif
656: if (flags & LONG)
657: *va_arg(ap, double *) = res;
658: else
659: *va_arg(ap, float *) = res;
660: nassigned++;
661: }
662: nread += p - buf;
663: break;
664: #endif /* FLOATING_POINT */
665: }
666: }
667: eof_failure:
668: seen_eof++;
669: input_failure:
670: if (nassigned == 0)
671: nassigned = -1;
672: match_failure:
673: if (errp)
674: *errp |= 2;
675: done:
676: if (errp && seen_eof)
677: *errp |= 1;
678: return (nassigned);
679: }
680:
681: /*
682: * Fill in the given table from the scanset at the given format
683: * (just after `['). Return a pointer to the character past the
684: * closing `]'. The table has a 1 wherever characters should be
685: * considered part of the scanset.
686: */
687: static const u_char *__sccl(tab, fmt)
688: register char *tab;
689: register const u_char *fmt;
690: {
691: register int c, n, v;
692:
693: /* first `clear' the whole table */
694: c = *fmt++; /* first char hat => negated scanset */
695: if (c == '^') {
696: v = 1; /* default => accept */
697: c = *fmt++; /* get new first char */
698: } else
699: v = 0; /* default => reject */
700: /* should probably use memset here */
701: for (n = 0; n < 256; n++)
702: tab[n] = v;
703: if (c == 0)
704: return (fmt - 1);/* format ended before closing ] */
705:
706: /*
707: * Now set the entries corresponding to the actual scanset
708: * to the opposite of the above.
709: *
710: * The first character may be ']' (or '-') without being special;
711: * the last character may be '-'.
712: */
713: v = 1 - v;
714: for (;;) {
715: tab[c] = v; /* take character c */
716: doswitch:
717: n = *fmt++; /* and examine the next */
718: switch (n) {
719:
720: case 0: /* format ended too soon */
721: return (fmt - 1);
722:
723: case '-':
724: /*
725: * A scanset of the form
726: * [01+-]
727: * is defined as `the digit 0, the digit 1,
728: * the character +, the character -', but
729: * the effect of a scanset such as
730: * [a-zA-Z0-9]
731: * is implementation defined. The V7 Unix
732: * scanf treats `a-z' as `the letters a through
733: * z', but treats `a-a' as `the letter a, the
734: * character -, and the letter a'.
735: *
736: * For compatibility, the `-' is not considerd
737: * to define a range if the character following
738: * it is either a close bracket (required by ANSI)
739: * or is not numerically greater than the character
740: * we just stored in the table (c).
741: */
742: n = *fmt;
743: if (n == ']' || n < c) {
744: c = '-';
745: break; /* resume the for(;;) */
746: }
747: fmt++;
748: do { /* fill in the range */
749: tab[++c] = v;
750: } while (c < n);
751: #if 1 /* XXX another disgusting compatibility hack */
752: /*
753: * Alas, the V7 Unix scanf also treats formats
754: * such as [a-c-e] as `the letters a through e'.
755: * This too is permitted by the standard....
756: */
757: goto doswitch;
758: #else
759: c = *fmt++;
760: if (c == 0)
761: return (fmt - 1);
762: if (c == ']')
763: return (fmt);
764: #endif
765: break;
766:
767: case ']': /* end of scanset */
768: return (fmt);
769:
770: default: /* just another character */
771: c = n;
772: break;
773: }
774: }
775: /* NOTREACHED */
776: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.