|
|
1.1 root 1: /*
2: * Standard I/O Library formatted input
3: * Non-portable things:
4: * 1) alignment of arguments is assumed to be completely contiguous.
5: */
6:
7: #include <stdio.h>
8:
9: union alltypes {
10: char *c;
11: short *h;
12: int *i;
13: unsigned *u;
14: long *l;
15: double *d;
16: char *s;
17: };
18:
19:
20: /*
21: * scan standard input
22: */
23:
24: int
25: scanf(args)
26: union alltypes args;
27: {
28: return (xscanf(stdin, &args));
29: }
30:
31:
32: /*
33: * scan given file
34: */
35:
36: int
37: fscanf(fp, args)
38: FILE *fp;
39: union alltypes args;
40: {
41: return (xscanf(fp, &args));
42: }
43:
44:
45: /*
46: * scan given string by handcrafting file structure for getc
47: */
48:
49: int
50: sscanf(sp, args)
51: char *sp;
52: union alltypes args;
53: {
54: FILE file;
55:
56: _stropen(sp, strlen(sp), &file);
57: return (xscanf(&file, &args));
58: }
59:
60:
61: static
62: int
63: xscanf(fp, argp)
64: FILE *fp;
65: union alltypes *argp;
66: {
67: register int fc, gc;
68: int base, width, gotany, supprf, longf, shortf, retval = 0;
69: char *fmt;
70: extern char *index();
71:
72: fmt = *(char **)argp++;
73: for (;;) {
74: switch (fc = *fmt++) {
75: case '\0':
76: break;
77: case '\t':
78: case '\n':
79: case ' ':
80: ungetc(gc=skipws(fp), fp);
81: if (gc == EOF)
82: break;
83: else
84: continue;
85: default:
86: matchin:
87: if ((gc=getc(fp)) != fc) {
88: ungetc(gc, fp);
89: break;
90: } else
91: continue;
92: case '%':
93: supprf = (fc = *fmt++) == '*';
94: if (supprf)
95: fc = *fmt++;
96: for (width = 0; '0'<=fc && fc<='9'; fc = *fmt++)
97: width = width*10 + fc - '0';
98: longf = fc=='l';
99: shortf = fc=='h';
100: if (longf || shortf)
101: fc = *fmt++;
102: switch (fc) {
103: default:
104: fputs("Bad format in scanf\n", stderr);
105: abort();
106: case '\0':
107: break;
108: case '%':
109: goto matchin;
110: case 'D':
111: longf++;
112: case 'd':
113: base = 10;
114: goto fixed;
115: case 'O':
116: longf++;
117: case 'o':
118: base = 8;
119: goto fixed;
120: case 'N':
121: longf++;
122: case 'n':
123: base = 0;
124: goto fixed;
125: case 'X':
126: longf++;
127: case 'x':
128: base = 16;
129: fixed:
130: {
131: long longn, fgetnum();
132:
133: longn = fgetnum(fp, base, width, &gotany);
134: if (!gotany)
135: break;
136: if (supprf)
137: continue;
138: if (longf)
139: **(long **)argp++ = longn;
140: else if (shortf)
141: **(short **)argp++ = (short)longn;
142: else
143: **(int **)argp++ = (int)longn;
144: retval++;
145: continue;
146: }
147: case 'E':
148: case 'F':
149: longf++;
150: case 'e':
151: case 'f':
152: {
153: double doublen, fgetdbl();
154:
155: doublen = fgetdbl(fp, width, &gotany);
156: if (!gotany)
157: break;
158: if (supprf)
159: continue;
160: if (longf)
161: **(double **)argp++ = doublen;
162: else
163: **(float **)argp++ = doublen;
164: retval++;
165: continue;
166: }
167: case '[':
168: {
169: char ss[64], *s = ss;
170: int breakf;
171: register char *cp;
172:
173: breakf = (fc = *fmt++) == '^';
174: if (breakf)
175: fc = *fmt++;
176: while (fc!='\0' && fc!=']') {
177: *s++ = fc;
178: fc = *fmt++;
179: }
180: *s = '\0';
181: s = ss;
182: gc = getc(fp);
183: goto scanin;
184: case 'c':
185: if (width==0)
186: width = 1;
187: gc = getc(fp);
188: s = "";
189: breakf = 1;
190: goto scanin;
191: case 's':
192: gc = skipws(fp);
193: s = "\t\n ";
194: breakf = 1;
195: scanin:
196: if (!supprf)
197: cp = *(char **)argp++;
198: gotany = 0;
199: while (gc!=EOF
200: && (index(s, gc)==NULL)==breakf) {
201: gotany++;
202: if (!supprf)
203: *cp++ = gc;
204: if (--width==0)
205: gc = EOF;
206: else
207: gc = getc(fp);
208: }
209: if (gc!=EOF)
210: ungetc(gc, fp);
211: if (!gotany)
212: break;
213: if (supprf)
214: continue;
215: if (fc!='c')
216: *cp = '\0';
217: retval++;
218: continue;
219: }
220: case 'r':
221: retval += xscanf(fp, *(union alltypes **)argp++);
222: continue;
223: }
224: break;
225: }
226: break;
227: }
228: return (retval==0&&feof(fp) ? EOF : retval);
229: }
230:
231: /*
232: * Read a long integer from file fp
233: */
234: static
235: long
236: fgetnum(fp, base, width, got)
237: FILE *fp;
238: register int base, width;
239: int *got;
240: {
241: long val = 0;
242: register int c, i;
243: int neg;
244:
245: if (width <= 0 || 32 < width)
246: width = 32;
247: *got = 0;
248: c = skipws(fp);
249: if ((neg=c=='-') || c=='+')
250: c = getc(fp), ++*got;
251: if (*got>width)
252: ;
253: else if (base!=0)
254: ;
255: else if (c!='0')
256: base = 10;
257: else if (c=getc(fp), ++*got>width)
258: ;
259: else if (c!='x')
260: base = 8;
261: else {
262: base = 16;
263: c = getc(fp), ++*got;
264: }
265: for (; *got < width; ++*got) {
266: if ((10<=(i=c-('a'-10))
267: || 10<=(i=c-('A'-10))
268: || 0<=(i=c-'0') && i<=9)
269: && i<base
270: || base==16 && val==0L && (i=c-'x')==0) {
271: val = val*base - i;
272: c = getc(fp);
273: } else
274: break;
275: }
276: ungetc(c, fp);
277: return (neg ? val : -val);
278: }
279:
280: /*
281: * Scan off floating point number into buffer for atof
282: * using automaton shown below
283: * states in parantheses
284: * inputs in brackets
285: * for all inputs not shown, transition is to (end)
286: *
287: * --
288: * / \
289: * v \
290: * ----------> [0-9] -> (3)
291: * / ^ | \
292: * / / | \
293: * / / v \
294: * / / [.] \ ->[+-] -
295: * / / | \ / \
296: * / / | \ / \
297: * / / v v / v
298: * (0) --> [+-] -> (1) (4) --> [Ee] -> (6) -> [0-9] -> (7)
299: * \ / / ^ ^ /
300: * \ / / / \ /
301: * \ / / / --
302: * \ / / /
303: * \ / / /
304: * \ / / /
305: * v v /
306: * [.] --> (2) -> [0-9] -> (5)
307: * ^ /
308: * \ /
309: * --
310: *
311: */
312: static
313: double
314: fgetdbl(fp, width, got)
315: FILE *fp;
316: int width, *got;
317: {
318: double atof();
319: register int c, state = 0;
320: char str[33];
321: register char *s = str;
322:
323: if (width<=0 || 32<width)
324: width = 32;
325: for (*got = 0; *got < width; ++*got) {
326: switch (c=getc(fp)) {
327: case '\t':
328: case '\n':
329: case ' ':
330: if (state!=0)
331: break;
332: --*got;
333: continue;
334: case '+':
335: case '-':
336: if (state!=0 && state!=6)
337: break;
338: state++;
339: *s++ = c;
340: continue;
341: case '.':
342: if (state<=1)
343: state = 2;
344: else if (state==3)
345: state++;
346: else
347: break;
348: *s++ = c;
349: continue;
350: case '0':
351: case '1':
352: case '2':
353: case '3':
354: case '4':
355: case '5':
356: case '6':
357: case '7':
358: case '8':
359: case '9':
360: if (state==0 || state==1 || state==3)
361: state = 3;
362: else if (state==2 || state==4 || state==5)
363: state = 5;
364: else if (state==6 || state==7)
365: state = 7;
366: else
367: break;
368: *s++ = c;
369: continue;
370: case 'E':
371: case 'e':
372: if (state<3 || 5<state)
373: break;
374: state = 6;
375: *s++ = c;
376: continue;
377: default:
378: break;
379: }
380: ungetc(c, fp);
381: break;
382: }
383: *s = '\0';
384: return (atof(str));
385: }
386:
387: static
388: int
389: skipws(fp)
390: FILE *fp;
391: {
392: register int c;
393:
394: while ((c=getc(fp))==' ' || c=='\n' || c=='\t')
395: ;
396: return (c);
397: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.