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