at_wini also needs a pci_reserve() for the pci compatability device, if
[minix3.git] / lib / stdio / doscan.c
blob2c1034e64581d2f8839deb4c62b2667f3cf96066
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;
51 if (c == '-' || c == '+') {
52 *bufp++ = c;
53 if (--width)
54 c = getc(stream);
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;
64 else if (width) {
65 *bufp++ = c;
66 if (--width)
67 c = getc(stream);
70 else if (type == 'i') base = 10;
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);
81 else break;
84 if (width && c != EOF) ungetc(c, stream);
85 if (type == 'i') base = 0;
86 *basep = base;
87 *bufp = '\0';
88 return bufp - 1;
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+)
100 static char *
101 f_collect(register int c, register FILE *stream, register unsigned int width)
103 register char *bufp = inp_buf;
104 int digit_seen = 0;
106 if (c == '-' || c == '+') {
107 *bufp++ = c;
108 if (--width)
109 c = getc(stream);
112 while (width && isdigit(c)) {
113 digit_seen++;
114 *bufp++ = c;
115 if (--width)
116 c = getc(stream);
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);
130 if (!digit_seen) {
131 if (width && c != EOF) ungetc(c, stream);
132 return inp_buf - 1;
134 else digit_seen = 0;
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);
145 while (width && isdigit(c)) {
146 digit_seen++;
147 *bufp++ = c;
148 if (--width)
149 c = getc(stream);
151 if (!digit_seen) {
152 if (width && c != EOF) ungetc(c,stream);
153 return inp_buf - 1;
157 if (width && c != EOF) ungetc(c, stream);
158 *bufp = '\0';
159 return bufp - 1;
161 #endif /* NOFLOAT */
165 * the routine that does the scanning
169 _doscan(register FILE *stream, const char *format, va_list ap)
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
187 if (!*format) return 0;
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++;
199 if (ic != EOF) ungetc(ic,stream);
200 nrchars--;
202 if (!*format) break; /* end of format */
204 if (*format != '%') {
205 ic = getc(stream);
206 nrchars++;
207 if (ic != *format++) break; /* error */
208 continue;
210 format++;
211 if (*format == '%') {
212 ic = getc(stream);
213 nrchars++;
214 if (ic == '%') {
215 format++;
216 continue;
218 else break;
220 flags = 0;
221 if (*format == '*') {
222 format++;
223 flags |= FL_NOASSIGN;
225 if (isdigit (*format)) {
226 flags |= FL_WIDTHSPEC;
227 for (width = 0; isdigit (*format);)
228 width = width * 10 + *format++ - '0';
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;
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++;
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;
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;
277 str = o_collect(ic, stream, kind, width, &base);
278 if (str < inp_buf
279 || (str == inp_buf
280 && (*str == '-'
281 || *str == '+'))) return done;
284 * Although the length of the number is str-inp_buf+1
285 * we don't add the 1 since we counted it already
287 nrchars += str - inp_buf;
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;
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;
309 while (width && ic != EOF) {
310 if (!(flags & FL_NOASSIGN))
311 *str++ = (char) ic;
312 if (--width) {
313 ic = getc(stream);
314 nrchars++;
318 if (width) {
319 if (ic != EOF) ungetc(ic,stream);
320 nrchars--;
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;
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++;
338 /* terminate the string */
339 if (!(flags & FL_NOASSIGN))
340 *str = '\0';
341 if (width) {
342 if (ic != EOF) ungetc(ic,stream);
343 nrchars--;
345 break;
346 case '[':
347 if (!(flags & FL_WIDTHSPEC))
348 width = 0xffff;
349 if (!width) return done;
351 if ( *++format == '^' ) {
352 reverse = 1;
353 format++;
354 } else
355 reverse = 0;
357 for (str = Xtable; str < &Xtable[NR_CHARS]
358 ; str++)
359 *str = 0;
361 if (*format == ']') Xtable[*format++] = 1;
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;
372 for( c = *(format -2) + 1
373 ; c <= *format ; c++)
374 Xtable[c] = 1;
375 format++;
377 else Xtable['-'] = 1;
380 if (!*format) return done;
382 if (!(Xtable[ic] ^ reverse)) {
383 /* MAT 8/9/96 no match must return character */
384 ungetc(ic, stream);
385 return done;
388 if (!(flags & FL_NOASSIGN))
389 str = va_arg(ap, char *);
391 do {
392 if (!(flags & FL_NOASSIGN))
393 *str++ = (char) ic;
394 if (--width) {
395 ic = getc(stream);
396 nrchars++;
398 } while (width && ic != EOF && (Xtable[ic] ^ reverse));
400 if (width) {
401 if (ic != EOF) ungetc(ic, stream);
402 nrchars--;
404 if (!(flags & FL_NOASSIGN)) { /* terminate string */
405 *str = '\0';
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;
417 if (!width) return done;
418 str = f_collect(ic, stream, width);
420 if (str < inp_buf
421 || (str == inp_buf
422 && (*str == '-'
423 || *str == '+'))) return done;
426 * Although the length of the number is str-inp_buf+1
427 * we don't add the 1 since we counted it already
429 nrchars += str - inp_buf;
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;
441 break;
442 #endif
443 } /* end switch */
444 conv++;
445 if (!(flags & FL_NOASSIGN) && kind != 'n') done++;
446 format++;
448 return conv || (ic != EOF) ? done : EOF;