secondary cache feature in vm.
[minix.git] / lib / libc / stdio / doscan.c
bloba9386a61fb240123e33d0081a005dac02d88b00a
1 /*
2 * doscan.c - scan formatted input
3 */
4 /* $Header$ */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <ctype.h>
9 #include <stdarg.h>
10 #include "loc_incl.h"
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
21 #define NUMLEN 512
22 #define NR_CHARS 256
24 static char Xtable[NR_CHARS];
25 static char inp_buf[NUMLEN];
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.
33 static char *
34 o_collect(register int c, register FILE *stream, char type,
35 unsigned int width, int *basep)
37 register char *bufp = inp_buf;
38 register int base;
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 default: base = 10; break;
52 if (c == '-' || c == '+') {
53 *bufp++ = c;
54 if (--width)
55 c = getc(stream);
58 if (width && c == '0' && base == 16) {
59 *bufp++ = c;
60 if (--width)
61 c = getc(stream);
62 if (c != 'x' && c != 'X') {
63 if (type == 'i') base = 8;
65 else if (width) {
66 *bufp++ = c;
67 if (--width)
68 c = getc(stream);
71 else if (type == 'i') base = 10;
73 while (width) {
74 if (((base == 10) && isdigit(c))
75 || ((base == 16) && isxdigit(c))
76 || ((base == 8) && isdigit(c) && (c < '8'))
77 || ((base == 2) && isdigit(c) && (c < '2'))) {
78 *bufp++ = c;
79 if (--width)
80 c = getc(stream);
82 else break;
85 if (width && c != EOF) ungetc(c, stream);
86 if (type == 'i') base = 0;
87 *basep = base;
88 *bufp = '\0';
89 return bufp - 1;
92 #ifndef NOFLOAT
93 /* The function f_collect() reads a string that has the format of a
94 * floating-point number. The function returns as soon as a format-error
95 * is encountered, leaving the offending character in the input. This means
96 * that 1.el leaves the 'l' in the input queue. Since all detection of
97 * format errors is done here, _doscan() doesn't call strtod() when it's
98 * not necessary, although the use of the width field can cause incomplete
99 * numbers to be passed to strtod(). (e.g. 1.3e+)
101 static char *
102 f_collect(register int c, register FILE *stream, register unsigned int width)
104 register char *bufp = inp_buf;
105 int digit_seen = 0;
107 if (c == '-' || c == '+') {
108 *bufp++ = c;
109 if (--width)
110 c = getc(stream);
113 while (width && isdigit(c)) {
114 digit_seen++;
115 *bufp++ = c;
116 if (--width)
117 c = getc(stream);
119 if (width && c == '.') {
120 *bufp++ = c;
121 if(--width)
122 c = getc(stream);
123 while (width && isdigit(c)) {
124 digit_seen++;
125 *bufp++ = c;
126 if (--width)
127 c = getc(stream);
131 if (!digit_seen) {
132 if (width && c != EOF) ungetc(c, stream);
133 return inp_buf - 1;
135 else digit_seen = 0;
137 if (width && (c == 'e' || c == 'E')) {
138 *bufp++ = c;
139 if (--width)
140 c = getc(stream);
141 if (width && (c == '+' || c == '-')) {
142 *bufp++ = c;
143 if (--width)
144 c = getc(stream);
146 while (width && isdigit(c)) {
147 digit_seen++;
148 *bufp++ = c;
149 if (--width)
150 c = getc(stream);
152 if (!digit_seen) {
153 if (width && c != EOF) ungetc(c,stream);
154 return inp_buf - 1;
158 if (width && c != EOF) ungetc(c, stream);
159 *bufp = '\0';
160 return bufp - 1;
162 #endif /* NOFLOAT */
166 * the routine that does the scanning
170 _doscan(register FILE *stream, const char *format, va_list ap)
172 int done = 0; /* number of items done */
173 int nrchars = 0; /* number of characters read */
174 int conv = 0; /* # of conversions */
175 int base; /* conversion base */
176 unsigned long val; /* an integer value */
177 register char *str; /* temporary pointer */
178 char *tmp_string; /* ditto */
179 unsigned width = 0; /* width of field */
180 int flags; /* some flags */
181 int reverse; /* reverse the checking in [...] */
182 int kind;
183 register int ic = EOF; /* the input character */
184 #ifndef NOFLOAT
185 long double ld_val;
186 #endif
188 if (!*format) return 0;
190 while (1) {
191 if (isspace(*format)) {
192 while (isspace(*format))
193 format++; /* skip whitespace */
194 ic = getc(stream);
195 nrchars++;
196 while (isspace (ic)) {
197 ic = getc(stream);
198 nrchars++;
200 if (ic != EOF) ungetc(ic,stream);
201 nrchars--;
203 if (!*format) break; /* end of format */
205 if (*format != '%') {
206 ic = getc(stream);
207 nrchars++;
208 if (ic != *format++) break; /* error */
209 continue;
211 format++;
212 if (*format == '%') {
213 ic = getc(stream);
214 nrchars++;
215 if (ic == '%') {
216 format++;
217 continue;
219 else break;
221 flags = 0;
222 if (*format == '*') {
223 format++;
224 flags |= FL_NOASSIGN;
226 if (isdigit (*format)) {
227 flags |= FL_WIDTHSPEC;
228 for (width = 0; isdigit (*format);)
229 width = width * 10 + *format++ - '0';
232 switch (*format) {
233 case 'h': flags |= FL_SHORT; format++; break;
234 case 'l': flags |= FL_LONG; format++; break;
235 case 'L': flags |= FL_LONGDOUBLE; format++; break;
237 kind = *format;
238 if ((kind != 'c') && (kind != '[') && (kind != 'n')) {
239 do {
240 ic = getc(stream);
241 nrchars++;
242 } while (isspace(ic));
243 if (ic == EOF) break; /* outer while */
244 } else if (kind != 'n') { /* %c or %[ */
245 ic = getc(stream);
246 if (ic == EOF) break; /* outer while */
247 nrchars++;
249 switch (kind) {
250 default:
251 /* not recognized, like %q */
252 return conv || (ic != EOF) ? done : EOF;
253 break;
254 case 'n':
255 if (!(flags & FL_NOASSIGN)) { /* silly, though */
256 if (flags & FL_SHORT)
257 *va_arg(ap, short *) = (short) nrchars;
258 else if (flags & FL_LONG)
259 *va_arg(ap, long *) = (long) nrchars;
260 else
261 *va_arg(ap, int *) = (int) nrchars;
263 break;
264 case 'p': /* pointer */
265 set_pointer(flags);
266 /* fallthrough */
267 case 'b': /* binary */
268 case 'd': /* decimal */
269 case 'i': /* general integer */
270 case 'o': /* octal */
271 case 'u': /* unsigned */
272 case 'x': /* hexadecimal */
273 case 'X': /* ditto */
274 if (!(flags & FL_WIDTHSPEC) || width > NUMLEN)
275 width = NUMLEN;
276 if (!width) return done;
278 str = o_collect(ic, stream, kind, width, &base);
279 if (str < inp_buf
280 || (str == inp_buf
281 && (*str == '-'
282 || *str == '+'))) return done;
285 * Although the length of the number is str-inp_buf+1
286 * we don't add the 1 since we counted it already
288 nrchars += str - inp_buf;
290 if (!(flags & FL_NOASSIGN)) {
291 if (kind == 'd' || kind == 'i')
292 val = strtol(inp_buf, &tmp_string, base);
293 else
294 val = strtoul(inp_buf, &tmp_string, base);
295 if (flags & FL_LONG)
296 *va_arg(ap, unsigned long *) = (unsigned long) val;
297 else if (flags & FL_SHORT)
298 *va_arg(ap, unsigned short *) = (unsigned short) val;
299 else
300 *va_arg(ap, unsigned *) = (unsigned) val;
302 break;
303 case 'c':
304 if (!(flags & FL_WIDTHSPEC))
305 width = 1;
306 if (!(flags & FL_NOASSIGN))
307 str = va_arg(ap, char *);
308 if (!width) return done;
310 while (width && ic != EOF) {
311 if (!(flags & FL_NOASSIGN))
312 *str++ = (char) ic;
313 if (--width) {
314 ic = getc(stream);
315 nrchars++;
319 if (width) {
320 if (ic != EOF) ungetc(ic,stream);
321 nrchars--;
323 break;
324 case 's':
325 if (!(flags & FL_WIDTHSPEC))
326 width = 0xffff;
327 if (!(flags & FL_NOASSIGN))
328 str = va_arg(ap, char *);
329 if (!width) return done;
331 while (width && ic != EOF && !isspace(ic)) {
332 if (!(flags & FL_NOASSIGN))
333 *str++ = (char) ic;
334 if (--width) {
335 ic = getc(stream);
336 nrchars++;
339 /* terminate the string */
340 if (!(flags & FL_NOASSIGN))
341 *str = '\0';
342 if (width) {
343 if (ic != EOF) ungetc(ic,stream);
344 nrchars--;
346 break;
347 case '[':
348 if (!(flags & FL_WIDTHSPEC))
349 width = 0xffff;
350 if (!width) return done;
352 if ( *++format == '^' ) {
353 reverse = 1;
354 format++;
355 } else
356 reverse = 0;
358 for (str = Xtable; str < &Xtable[NR_CHARS]
359 ; str++)
360 *str = 0;
362 if (*format == ']') Xtable[*format++] = 1;
364 while (*format && *format != ']') {
365 Xtable[*format++] = 1;
366 if (*format == '-') {
367 format++;
368 if (*format
369 && *format != ']'
370 && *(format) >= *(format -2)) {
371 int c;
373 for( c = *(format -2) + 1
374 ; c <= *format ; c++)
375 Xtable[c] = 1;
376 format++;
378 else Xtable['-'] = 1;
381 if (!*format) return done;
383 if (!(Xtable[ic] ^ reverse)) {
384 /* MAT 8/9/96 no match must return character */
385 ungetc(ic, stream);
386 return done;
389 if (!(flags & FL_NOASSIGN))
390 str = va_arg(ap, char *);
392 do {
393 if (!(flags & FL_NOASSIGN))
394 *str++ = (char) ic;
395 if (--width) {
396 ic = getc(stream);
397 nrchars++;
399 } while (width && ic != EOF && (Xtable[ic] ^ reverse));
401 if (width) {
402 if (ic != EOF) ungetc(ic, stream);
403 nrchars--;
405 if (!(flags & FL_NOASSIGN)) { /* terminate string */
406 *str = '\0';
408 break;
409 #ifndef NOFLOAT
410 case 'e':
411 case 'E':
412 case 'f':
413 case 'g':
414 case 'G':
415 if (!(flags & FL_WIDTHSPEC) || width > NUMLEN)
416 width = NUMLEN;
418 if (!width) return done;
419 str = f_collect(ic, stream, width);
421 if (str < inp_buf
422 || (str == inp_buf
423 && (*str == '-'
424 || *str == '+'))) return done;
427 * Although the length of the number is str-inp_buf+1
428 * we don't add the 1 since we counted it already
430 nrchars += str - inp_buf;
432 if (!(flags & FL_NOASSIGN)) {
433 ld_val = strtod(inp_buf, &tmp_string);
434 if (flags & FL_LONGDOUBLE)
435 *va_arg(ap, long double *) = (long double) ld_val;
436 else
437 if (flags & FL_LONG)
438 *va_arg(ap, double *) = (double) ld_val;
439 else
440 *va_arg(ap, float *) = (float) ld_val;
442 break;
443 #endif
444 } /* end switch */
445 conv++;
446 if (!(flags & FL_NOASSIGN) && kind != 'n') done++;
447 format++;
449 return conv || (ic != EOF) ? done : EOF;