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