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