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