|
|
1.1 ! root 1: /* ! 2: * libc/stdio/_scanf.c ! 3: * ANSI-compliant C standard i/o library internals. ! 4: * _scanf() ! 5: * ANSI 4.9.6.2. ! 6: * Do the work for fscanf(), scanf(), sscanf(). ! 7: * ! 8: * Implementation-defined behavior: ! 9: * "%[a-z]" conversion treats '-' as a range specification #if SCANFRANGE, ! 10: * as a normal character #if !SCANFRANGE ! 11: * "%p" conversion expects input in printf format "%#.<PPREC>X" or "%#.<PPREC>lX" ! 12: */ ! 13: ! 14: #include <stdio.h> ! 15: #include <stdlib.h> ! 16: #include <stdarg.h> ! 17: #include <ctype.h> ! 18: #include <string.h> ! 19: #undef isspace ! 20: ! 21: /* Compile-time options. */ ! 22: #define PPREC 8 /* precision for %p format */ ! 23: #define LONGDOUBLE 0 /* iff sizeof(double) != sizeof(long double) */ ! 24: ! 25: #define MAX_WIDTH 128 /* max width of conversion item */ ! 26: ! 27: int ! 28: _scanf(fp, format, args) FILE *fp; const char *format; va_list args; ! 29: { ! 30: register int fc, gc; ! 31: register char * cp; ! 32: int base, width, count, nitems, n, sflag, lflag, flag; ! 33: long val; ! 34: double d; ! 35: __VOID__ * vp; ! 36: char buf[MAX_WIDTH]; ! 37: ! 38: for (nitems = count = 0; fc = *format++; ) { ! 39: ! 40: if (isspace(fc)) { /* white space directive */ ! 41: while (isspace(gc = getc(fp))) ! 42: ++count; ! 43: if (gc == EOF) ! 44: break; ! 45: ungetc(gc, fp); ! 46: continue; ! 47: } else if (fc != '%') { /* ordinary character directive */ ! 48: matchin: ! 49: if ((gc=getc(fp)) != fc) { ! 50: ungetc(gc, fp); ! 51: break; ! 52: } ! 53: count++; ! 54: continue; ! 55: } else { /* conversion directive */ ! 56: ! 57: /* Process '*', field width, "hlL" flags. */ ! 58: flag = sflag = lflag = 0; ! 59: if ((fc = *format++) == '*') { ! 60: ++sflag; ! 61: fc = *format++; ! 62: } ! 63: if (isdigit(fc)) ! 64: for (width = 0; isdigit(fc); fc = *format++) ! 65: width = width*10 + fc - '0'; ! 66: else ! 67: width = -1; ! 68: if (fc == 'h' || fc == 'l' || fc == 'L') { ! 69: lflag = fc; ! 70: fc = *format++; ! 71: } ! 72: ! 73: /* Skip leading white space. */ ! 74: if (fc != '[' && fc != 'c' && fc != 'n') { ! 75: while (isspace(gc = getc(fp))) ! 76: ++count; ! 77: ungetc(gc, fp); ! 78: } ! 79: ! 80: /* Perform a conversion. */ ! 81: /* Three generic cases: fixed, float, string. */ ! 82: switch (fc) { ! 83: ! 84: default: ! 85: case '\0': ! 86: break; ! 87: ! 88: case 'd': ! 89: base = 10; ! 90: ++flag; /* signed */ ! 91: goto fixed; ! 92: ! 93: case 'i': ! 94: base = 0; ! 95: ++flag; /* signed */ ! 96: goto fixed; ! 97: ! 98: case 'o': ! 99: base = 8; ! 100: goto fixed; ! 101: ! 102: case 'u': ! 103: base = 10; ! 104: goto fixed; ! 105: ! 106: case 'X': ! 107: case 'x': ! 108: base = 16; ! 109: fixed: ! 110: if (width == -1 || width > MAX_WIDTH) ! 111: width = MAX_WIDTH; ! 112: if ((n = lscan(buf, fp, base, width, flag, &val)) == 0) ! 113: break; ! 114: count += n; ! 115: if (sflag) ! 116: continue; ! 117: if (lflag == 'p') ! 118: *(va_arg(args, __VOID__ **)) = (__VOID__ *)val; ! 119: else if (lflag == 'l') ! 120: *(va_arg(args, long *)) = val; ! 121: else if (lflag == 'h') ! 122: *(va_arg(args, short *)) = (short)val; ! 123: else ! 124: *(va_arg(args, int *)) = (int)val; ! 125: nitems++; ! 126: continue; ! 127: ! 128: case 'e': ! 129: case 'f': ! 130: case 'g': ! 131: case 'E': ! 132: case 'G': ! 133: if (width == -1 || width > MAX_WIDTH) ! 134: width = MAX_WIDTH; ! 135: if ((n = _dscan(buf, fp, width, &d)) == 0) ! 136: break; ! 137: count += n; ! 138: if (sflag) ! 139: continue; ! 140: #if LONGDOUBLE ! 141: if (lflag == 'L') ! 142: vp = (__VOID__ *)va_arg(args, long double *); ! 143: else if (lflag == 'l') ! 144: #else ! 145: if (lflag == 'l' || lflag == 'L') ! 146: #endif ! 147: vp = (__VOID__ *)va_arg(args, double *); ! 148: else ! 149: vp = (__VOID__ *)va_arg(args, float *); ! 150: _dassign(vp, &d, lflag); ! 151: nitems++; ! 152: continue; ! 153: ! 154: case 's': ! 155: scanin: ! 156: if (!sflag) ! 157: cp = va_arg(args, char *); ! 158: for (n = 0; width < 0 || n < width; n++) { ! 159: if ((gc = getc(fp)) == EOF) ! 160: break; ! 161: if ((fc == 's' && isspace(gc)) ! 162: || (fc == '[' ! 163: && flag != (strchr(buf, gc)==NULL))) { ! 164: ungetc(gc, fp); ! 165: break; ! 166: } ! 167: if (!sflag) ! 168: *cp++ = gc; ! 169: } ! 170: if (n == 0) ! 171: break; ! 172: count += n; ! 173: if (sflag) ! 174: continue; ! 175: if (fc != 'c') ! 176: *cp = '\0'; ! 177: nitems++; ! 178: continue; ! 179: ! 180: case '[': ! 181: /* Set flag iff ^ specified. */ ! 182: flag = 0; ! 183: if ((fc = *format++) == '^') { ! 184: ++flag; ! 185: fc = *format++; ! 186: } ! 187: /* Copy scanlist into buf. */ ! 188: cp = buf; ! 189: if (fc == ']') { ! 190: *cp++ = fc; ! 191: fc = *format++; ! 192: } ! 193: while (fc != '\0' && fc != ']') { ! 194: #if SCANFRANGE ! 195: /* Accept character ranges. */ ! 196: if (fc == '-' && cp != buf && *format != ']') { ! 197: gc = *(cp-1); /* start */ ! 198: fc = *format++; /* end */ ! 199: if (gc > fc) ! 200: --cp; /* empty */ ! 201: else while (++gc <= fc) ! 202: *cp++ = gc; ! 203: } else ! 204: #endif ! 205: *cp++ = fc; ! 206: fc = *format++; ! 207: } ! 208: *cp = '\0'; ! 209: fc = '['; ! 210: goto scanin; ! 211: ! 212: case 'c': ! 213: if (width == -1) ! 214: width = 1; ! 215: goto scanin; ! 216: ! 217: case 'p': ! 218: width = PPREC + 2; /* "0x"+PPREC hex digits */ ! 219: base = 16; ! 220: lflag = 'p'; ! 221: goto fixed; ! 222: ! 223: case 'n': ! 224: if (lflag == 'l') ! 225: *(va_arg(args, long *)) = (long)count; ! 226: else if (lflag == 'h') ! 227: *(va_arg(args, short *)) = (short)count; ! 228: else ! 229: *(va_arg(args, int *)) = count; ! 230: continue; ! 231: ! 232: case '%': ! 233: goto matchin; ! 234: } ! 235: break; ! 236: } ! 237: break; ! 238: } ! 239: return (nitems==0 && feof(fp)) ? EOF : nitems; ! 240: } ! 241: ! 242: /* ! 243: * Read an ASCII number in given 'base' ! 244: * containing at most 'width' characters from 'fp' into 'buf'. ! 245: * Evaluate it using strtol()/strtoul() and store value through *lp. ! 246: * Return the number of characters read. ! 247: * The pre-ANSI source for this routine evaluated the number directly. ! 248: * ANSI 4.9.6.2 does not explicitly say anything about overflow, ! 249: * but it implies that integer conversions work like strtol()/strtoul(), ! 250: * so this scans the number into a buffer and uses the function. ! 251: * The routine implements a finite state machine with 8 states: ! 252: * (0) Initial state, base == 0 ! 253: * (1) After sign, base == 0 ! 254: * (2) After '0', base == 0 ! 255: * (3) Initial state, base != 0 && base != 16 ! 256: * (4) After sign, base != 0 && base != 16 ! 257: * (5) After digit, base != 0 ! 258: * (6) Initial state, base == 16 ! 259: * (7) After sign, base == 16 ! 260: * (8) After '0', base == 16 ! 261: * This cannot be done correctly with the single character pushback ! 262: * guaranteed by ungetc(); for example, rejecting "+y", "0xy" or "+0xy" ! 263: * requires two character pushback. ! 264: */ ! 265: static ! 266: int ! 267: lscan(buf, fp, base, width, flag, lp) ! 268: char * buf; ! 269: FILE * fp; ! 270: int base, width, flag; ! 271: long * lp; ! 272: { ! 273: register int c, state, count; ! 274: register char *cp; ! 275: ! 276: cp = buf; ! 277: state = (base == 0) ? 0 : (base == 16) ? 6 : 3; ! 278: for (count = 0; count < width; ++count) { ! 279: *cp++ = c = getc(fp); ! 280: switch(c) { ! 281: case '+': ! 282: case '-': ! 283: if (state != 0 && state != 3 && state != 6) ! 284: break; ! 285: ++state; ! 286: continue; ! 287: case '0': ! 288: if (state <= 1) ! 289: state = 2; ! 290: else if (state == 2) { ! 291: base = 8; ! 292: state = 5; ! 293: } else if (state <= 5 || state == 8) ! 294: state = 5; ! 295: else ! 296: state = 8; ! 297: continue; ! 298: case 'x': ! 299: case 'X': ! 300: if (state == 2) { ! 301: base = 16; ! 302: state = 5; ! 303: } else if (state == 8) ! 304: state = 5; ! 305: else ! 306: break; ! 307: continue; ! 308: default: ! 309: if (state <= 2) { ! 310: if (isdigit(c)) { ! 311: base = 10; ! 312: state = 5; ! 313: } else ! 314: break; ! 315: continue; ! 316: } ! 317: if ((isdigit(c) && c-'0' < base) ! 318: || (islower(c) && c-'a'+10 < base) ! 319: || (isupper(c) && c-'A'+10 < base)) ! 320: state = 5; ! 321: else ! 322: break; ! 323: continue; ! 324: } ! 325: --cp; ! 326: ungetc(c, fp); ! 327: break; ! 328: } ! 329: *cp = '\0'; ! 330: if (flag) ! 331: *lp = strtol(buf, (char **)NULL, base); ! 332: else ! 333: *lp = strtoul(buf, (char **)NULL, base); ! 334: return (int)(cp - buf); ! 335: } ! 336: ! 337: /* end of libc/stdio/_scanf.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.