source: trunk/minix/lib/stdio/doscan.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 10.0 KB
Line 
1/*
2 * doscan.c - scan formatted input
3 */
4/* $Header: /cvsup/minix/src/lib/stdio/doscan.c,v 1.1.1.1 2005/04/21 14:56:35 beng Exp $ */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <ctype.h>
9#include <stdarg.h>
10#include "loc_incl.h"
11
12#if _EM_WSIZE == _EM_PSIZE
13#define set_pointer(flags) /* nothing */
14#elif _EM_LSIZE == _EM_PSIZE
15#define set_pointer(flags) (flags |= FL_LONG)
16#else
17#error garbage pointer size
18#define set_pointer(flags) /* compilation might continue */
19#endif
20
21#define NUMLEN 512
22#define NR_CHARS 256
23
24static char Xtable[NR_CHARS];
25static char inp_buf[NUMLEN];
26
27/* Collect a number of characters which constitite an ordinal number.
28 * When the type is 'i', the base can be 8, 10, or 16, depending on the
29 * first 1 or 2 characters. This means that the base must be adjusted
30 * according to the format of the number. At the end of the function, base
31 * is then set to 0, so strtol() will get the right argument.
32 */
33static char *
34o_collect(register int c, register FILE *stream, char type,
35 unsigned int width, int *basep)
36{
37 register char *bufp = inp_buf;
38 register int base;
39
40 switch (type) {
41 case 'i': /* i means octal, decimal or hexadecimal */
42 case 'p':
43 case 'x':
44 case 'X': base = 16; break;
45 case 'd':
46 case 'u': base = 10; break;
47 case 'o': base = 8; break;
48 case 'b': base = 2; break;
49 }
50
51 if (c == '-' || c == '+') {
52 *bufp++ = c;
53 if (--width)
54 c = getc(stream);
55 }
56
57 if (width && c == '0' && base == 16) {
58 *bufp++ = c;
59 if (--width)
60 c = getc(stream);
61 if (c != 'x' && c != 'X') {
62 if (type == 'i') base = 8;
63 }
64 else if (width) {
65 *bufp++ = c;
66 if (--width)
67 c = getc(stream);
68 }
69 }
70 else if (type == 'i') base = 10;
71
72 while (width) {
73 if (((base == 10) && isdigit(c))
74 || ((base == 16) && isxdigit(c))
75 || ((base == 8) && isdigit(c) && (c < '8'))
76 || ((base == 2) && isdigit(c) && (c < '2'))) {
77 *bufp++ = c;
78 if (--width)
79 c = getc(stream);
80 }
81 else break;
82 }
83
84 if (width && c != EOF) ungetc(c, stream);
85 if (type == 'i') base = 0;
86 *basep = base;
87 *bufp = '\0';
88 return bufp - 1;
89}
90
91#ifndef NOFLOAT
92/* The function f_collect() reads a string that has the format of a
93 * floating-point number. The function returns as soon as a format-error
94 * is encountered, leaving the offending character in the input. This means
95 * that 1.el leaves the 'l' in the input queue. Since all detection of
96 * format errors is done here, _doscan() doesn't call strtod() when it's
97 * not necessary, although the use of the width field can cause incomplete
98 * numbers to be passed to strtod(). (e.g. 1.3e+)
99 */
100static char *
101f_collect(register int c, register FILE *stream, register unsigned int width)
102{
103 register char *bufp = inp_buf;
104 int digit_seen = 0;
105
106 if (c == '-' || c == '+') {
107 *bufp++ = c;
108 if (--width)
109 c = getc(stream);
110 }
111
112 while (width && isdigit(c)) {
113 digit_seen++;
114 *bufp++ = c;
115 if (--width)
116 c = getc(stream);
117 }
118 if (width && c == '.') {
119 *bufp++ = c;
120 if(--width)
121 c = getc(stream);
122 while (width && isdigit(c)) {
123 digit_seen++;
124 *bufp++ = c;
125 if (--width)
126 c = getc(stream);
127 }
128 }
129
130 if (!digit_seen) {
131 if (width && c != EOF) ungetc(c, stream);
132 return inp_buf - 1;
133 }
134 else digit_seen = 0;
135
136 if (width && (c == 'e' || c == 'E')) {
137 *bufp++ = c;
138 if (--width)
139 c = getc(stream);
140 if (width && (c == '+' || c == '-')) {
141 *bufp++ = c;
142 if (--width)
143 c = getc(stream);
144 }
145 while (width && isdigit(c)) {
146 digit_seen++;
147 *bufp++ = c;
148 if (--width)
149 c = getc(stream);
150 }
151 if (!digit_seen) {
152 if (width && c != EOF) ungetc(c,stream);
153 return inp_buf - 1;
154 }
155 }
156
157 if (width && c != EOF) ungetc(c, stream);
158 *bufp = '\0';
159 return bufp - 1;
160}
161#endif /* NOFLOAT */
162
163
164/*
165 * the routine that does the scanning
166 */
167
168int
169_doscan(register FILE *stream, const char *format, va_list ap)
170{
171 int done = 0; /* number of items done */
172 int nrchars = 0; /* number of characters read */
173 int conv = 0; /* # of conversions */
174 int base; /* conversion base */
175 unsigned long val; /* an integer value */
176 register char *str; /* temporary pointer */
177 char *tmp_string; /* ditto */
178 unsigned width = 0; /* width of field */
179 int flags; /* some flags */
180 int reverse; /* reverse the checking in [...] */
181 int kind;
182 register int ic = EOF; /* the input character */
183#ifndef NOFLOAT
184 long double ld_val;
185#endif
186
187 if (!*format) return 0;
188
189 while (1) {
190 if (isspace(*format)) {
191 while (isspace(*format))
192 format++; /* skip whitespace */
193 ic = getc(stream);
194 nrchars++;
195 while (isspace (ic)) {
196 ic = getc(stream);
197 nrchars++;
198 }
199 if (ic != EOF) ungetc(ic,stream);
200 nrchars--;
201 }
202 if (!*format) break; /* end of format */
203
204 if (*format != '%') {
205 ic = getc(stream);
206 nrchars++;
207 if (ic != *format++) break; /* error */
208 continue;
209 }
210 format++;
211 if (*format == '%') {
212 ic = getc(stream);
213 nrchars++;
214 if (ic == '%') {
215 format++;
216 continue;
217 }
218 else break;
219 }
220 flags = 0;
221 if (*format == '*') {
222 format++;
223 flags |= FL_NOASSIGN;
224 }
225 if (isdigit (*format)) {
226 flags |= FL_WIDTHSPEC;
227 for (width = 0; isdigit (*format);)
228 width = width * 10 + *format++ - '0';
229 }
230
231 switch (*format) {
232 case 'h': flags |= FL_SHORT; format++; break;
233 case 'l': flags |= FL_LONG; format++; break;
234 case 'L': flags |= FL_LONGDOUBLE; format++; break;
235 }
236 kind = *format;
237 if ((kind != 'c') && (kind != '[') && (kind != 'n')) {
238 do {
239 ic = getc(stream);
240 nrchars++;
241 } while (isspace(ic));
242 if (ic == EOF) break; /* outer while */
243 } else if (kind != 'n') { /* %c or %[ */
244 ic = getc(stream);
245 if (ic == EOF) break; /* outer while */
246 nrchars++;
247 }
248 switch (kind) {
249 default:
250 /* not recognized, like %q */
251 return conv || (ic != EOF) ? done : EOF;
252 break;
253 case 'n':
254 if (!(flags & FL_NOASSIGN)) { /* silly, though */
255 if (flags & FL_SHORT)
256 *va_arg(ap, short *) = (short) nrchars;
257 else if (flags & FL_LONG)
258 *va_arg(ap, long *) = (long) nrchars;
259 else
260 *va_arg(ap, int *) = (int) nrchars;
261 }
262 break;
263 case 'p': /* pointer */
264 set_pointer(flags);
265 /* fallthrough */
266 case 'b': /* binary */
267 case 'd': /* decimal */
268 case 'i': /* general integer */
269 case 'o': /* octal */
270 case 'u': /* unsigned */
271 case 'x': /* hexadecimal */
272 case 'X': /* ditto */
273 if (!(flags & FL_WIDTHSPEC) || width > NUMLEN)
274 width = NUMLEN;
275 if (!width) return done;
276
277 str = o_collect(ic, stream, kind, width, &base);
278 if (str < inp_buf
279 || (str == inp_buf
280 && (*str == '-'
281 || *str == '+'))) return done;
282
283 /*
284 * Although the length of the number is str-inp_buf+1
285 * we don't add the 1 since we counted it already
286 */
287 nrchars += str - inp_buf;
288
289 if (!(flags & FL_NOASSIGN)) {
290 if (kind == 'd' || kind == 'i')
291 val = strtol(inp_buf, &tmp_string, base);
292 else
293 val = strtoul(inp_buf, &tmp_string, base);
294 if (flags & FL_LONG)
295 *va_arg(ap, unsigned long *) = (unsigned long) val;
296 else if (flags & FL_SHORT)
297 *va_arg(ap, unsigned short *) = (unsigned short) val;
298 else
299 *va_arg(ap, unsigned *) = (unsigned) val;
300 }
301 break;
302 case 'c':
303 if (!(flags & FL_WIDTHSPEC))
304 width = 1;
305 if (!(flags & FL_NOASSIGN))
306 str = va_arg(ap, char *);
307 if (!width) return done;
308
309 while (width && ic != EOF) {
310 if (!(flags & FL_NOASSIGN))
311 *str++ = (char) ic;
312 if (--width) {
313 ic = getc(stream);
314 nrchars++;
315 }
316 }
317
318 if (width) {
319 if (ic != EOF) ungetc(ic,stream);
320 nrchars--;
321 }
322 break;
323 case 's':
324 if (!(flags & FL_WIDTHSPEC))
325 width = 0xffff;
326 if (!(flags & FL_NOASSIGN))
327 str = va_arg(ap, char *);
328 if (!width) return done;
329
330 while (width && ic != EOF && !isspace(ic)) {
331 if (!(flags & FL_NOASSIGN))
332 *str++ = (char) ic;
333 if (--width) {
334 ic = getc(stream);
335 nrchars++;
336 }
337 }
338 /* terminate the string */
339 if (!(flags & FL_NOASSIGN))
340 *str = '\0';
341 if (width) {
342 if (ic != EOF) ungetc(ic,stream);
343 nrchars--;
344 }
345 break;
346 case '[':
347 if (!(flags & FL_WIDTHSPEC))
348 width = 0xffff;
349 if (!width) return done;
350
351 if ( *++format == '^' ) {
352 reverse = 1;
353 format++;
354 } else
355 reverse = 0;
356
357 for (str = Xtable; str < &Xtable[NR_CHARS]
358 ; str++)
359 *str = 0;
360
361 if (*format == ']') Xtable[*format++] = 1;
362
363 while (*format && *format != ']') {
364 Xtable[*format++] = 1;
365 if (*format == '-') {
366 format++;
367 if (*format
368 && *format != ']'
369 && *(format) >= *(format -2)) {
370 int c;
371
372 for( c = *(format -2) + 1
373 ; c <= *format ; c++)
374 Xtable[c] = 1;
375 format++;
376 }
377 else Xtable['-'] = 1;
378 }
379 }
380 if (!*format) return done;
381
382 if (!(Xtable[ic] ^ reverse)) {
383 /* MAT 8/9/96 no match must return character */
384 ungetc(ic, stream);
385 return done;
386 }
387
388 if (!(flags & FL_NOASSIGN))
389 str = va_arg(ap, char *);
390
391 do {
392 if (!(flags & FL_NOASSIGN))
393 *str++ = (char) ic;
394 if (--width) {
395 ic = getc(stream);
396 nrchars++;
397 }
398 } while (width && ic != EOF && (Xtable[ic] ^ reverse));
399
400 if (width) {
401 if (ic != EOF) ungetc(ic, stream);
402 nrchars--;
403 }
404 if (!(flags & FL_NOASSIGN)) { /* terminate string */
405 *str = '\0';
406 }
407 break;
408#ifndef NOFLOAT
409 case 'e':
410 case 'E':
411 case 'f':
412 case 'g':
413 case 'G':
414 if (!(flags & FL_WIDTHSPEC) || width > NUMLEN)
415 width = NUMLEN;
416
417 if (!width) return done;
418 str = f_collect(ic, stream, width);
419
420 if (str < inp_buf
421 || (str == inp_buf
422 && (*str == '-'
423 || *str == '+'))) return done;
424
425 /*
426 * Although the length of the number is str-inp_buf+1
427 * we don't add the 1 since we counted it already
428 */
429 nrchars += str - inp_buf;
430
431 if (!(flags & FL_NOASSIGN)) {
432 ld_val = strtod(inp_buf, &tmp_string);
433 if (flags & FL_LONGDOUBLE)
434 *va_arg(ap, long double *) = (long double) ld_val;
435 else
436 if (flags & FL_LONG)
437 *va_arg(ap, double *) = (double) ld_val;
438 else
439 *va_arg(ap, float *) = (float) ld_val;
440 }
441 break;
442#endif
443 } /* end switch */
444 conv++;
445 if (!(flags & FL_NOASSIGN) && kind != 'n') done++;
446 format++;
447 }
448 return conv || (ic != EOF) ? done : EOF;
449}
Note: See TracBrowser for help on using the repository browser.