|
|
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.