2 * doscan.c - scan formatted input
4 /* $Id: doscan.c,v 1.13 1996/04/01 09:08:59 ceriel Exp $ */
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)
17 #error garbage pointer size
18 #define set_pointer(flags) /* compilation might continue */
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.
34 o_collect(register int c, register FILE *stream, char type,
35 int width, int *basep)
37 register char *bufp = inp_buf;
41 case 'i': /* i means octal, decimal or hexadecimal */
44 case 'X': base = 16; break;
46 case 'u': base = 10; break;
47 case 'o': base = 8; break;
48 case 'b': base = 2; break;
51 if (c == '-' || c == '+') {
57 if (width && c == '0' && base == 16) {
61 if (c != 'x' && c != 'X') {
62 if (type == 'i') base = 8;
70 else if (type == 'i') base = 10;
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'))) {
84 if (width && c != EOF) ungetc(c, stream);
85 if (type == 'i') base = 0;
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+)
101 f_collect(register int c, register FILE *stream, register int width)
103 register char *bufp = inp_buf;
106 if (c == '-' || c == '+') {
112 while (width && isdigit(c)) {
118 if (width && c == '.') {
122 while (width && isdigit(c)) {
131 if (width && c != EOF) ungetc(c, stream);
136 if (width && (c == 'e' || c == 'E')) {
140 if (width && (c == '+' || c == '-')) {
145 while (width && isdigit(c)) {
152 if (width && c != EOF) ungetc(c,stream);
157 if (width && c != EOF) ungetc(c, stream);
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; /* width of field */
179 int flags; /* some flags */
180 int reverse; /* reverse the checking in [...] */
182 register int ic; /* the input character */
187 if (!*format) return 0;
190 if (isspace(*format)) {
191 while (isspace(*format))
192 format++; /* skip whitespace */
195 while (isspace (ic)) {
199 if (ic != EOF) ungetc(ic,stream);
202 if (!*format) break; /* end of format */
204 if (*format != '%') {
207 if (ic != *format++) {
208 if (ic != EOF) ungetc(ic,stream);
215 if (*format == '%') {
225 if (*format == '*') {
227 flags |= FL_NOASSIGN;
229 if (isdigit (*format)) {
230 flags |= FL_WIDTHSPEC;
231 for (width = 0; isdigit (*format);)
232 width = width * 10 + *format++ - '0';
236 case 'h': flags |= FL_SHORT; format++; break;
237 case 'l': flags |= FL_LONG; format++; break;
238 case 'L': flags |= FL_LONGDOUBLE; format++; break;
241 if ((kind != 'c') && (kind != '[') && (kind != 'n')) {
245 } while (isspace(ic));
246 if (ic == EOF) break; /* outer while */
247 } else if (kind != 'n') { /* %c or %[ */
249 if (ic == EOF) break; /* outer while */
254 /* not recognized, like %q */
255 return conv || (ic != EOF) ? done : EOF;
258 if (!(flags & FL_NOASSIGN)) { /* silly, though */
259 if (flags & FL_SHORT)
260 *va_arg(ap, short *) = (short) nrchars;
261 else if (flags & FL_LONG)
262 *va_arg(ap, long *) = (long) nrchars;
264 *va_arg(ap, int *) = (int) nrchars;
267 case 'p': /* pointer */
270 case 'b': /* binary */
271 case 'd': /* decimal */
272 case 'i': /* general integer */
273 case 'o': /* octal */
274 case 'u': /* unsigned */
275 case 'x': /* hexadecimal */
276 case 'X': /* ditto */
277 if (!(flags & FL_WIDTHSPEC) || width > NUMLEN)
279 if (!width) return done;
281 str = o_collect(ic, stream, kind, width, &base);
285 || *str == '+'))) return done;
288 * Although the length of the number is str-inp_buf+1
289 * we don't add the 1 since we counted it already
291 nrchars += str - inp_buf;
293 if (!(flags & FL_NOASSIGN)) {
294 if (kind == 'd' || kind == 'i')
295 val = strtol(inp_buf, &tmp_string, base);
297 val = strtoul(inp_buf, &tmp_string, base);
299 *va_arg(ap, unsigned long *) = (unsigned long) val;
300 else if (flags & FL_SHORT)
301 *va_arg(ap, unsigned short *) = (unsigned short) val;
303 *va_arg(ap, unsigned *) = (unsigned) val;
307 if (!(flags & FL_WIDTHSPEC))
309 if (!(flags & FL_NOASSIGN))
310 str = va_arg(ap, char *);
311 if (!width) return done;
313 while (width && ic != EOF) {
314 if (!(flags & FL_NOASSIGN))
323 if (ic != EOF) ungetc(ic,stream);
328 if (!(flags & FL_WIDTHSPEC))
330 if (!(flags & FL_NOASSIGN))
331 str = va_arg(ap, char *);
332 if (!width) return done;
334 while (width && ic != EOF && !isspace(ic)) {
335 if (!(flags & FL_NOASSIGN))
342 /* terminate the string */
343 if (!(flags & FL_NOASSIGN))
346 if (ic != EOF) ungetc(ic,stream);
351 if (!(flags & FL_WIDTHSPEC))
353 if (!width) return done;
355 if ( *++format == '^' ) {
361 for (str = Xtable; str < &Xtable[NR_CHARS]
365 if (*format == ']') Xtable[*format++] = 1;
367 while (*format && *format != ']') {
368 Xtable[*format++] = 1;
369 if (*format == '-') {
373 && *(format) >= *(format -2)) {
376 for( c = *(format -2) + 1
377 ; c <= *format ; c++)
381 else Xtable['-'] = 1;
384 if (!*format || !(Xtable[ic] ^ reverse)) {
385 if (ic != EOF) ungetc(ic, stream);
389 if (!(flags & FL_NOASSIGN))
390 str = va_arg(ap, char *);
393 if (!(flags & FL_NOASSIGN))
399 } while (width && ic != EOF && (Xtable[ic] ^ reverse));
402 if (ic != EOF) ungetc(ic, stream);
405 if (!(flags & FL_NOASSIGN)) { /* terminate string */
415 if (!(flags & FL_WIDTHSPEC) || width > NUMLEN)
418 if (!width) return done;
419 str = f_collect(ic, stream, width);
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;
438 *va_arg(ap, double *) = (double) ld_val;
440 *va_arg(ap, float *) = (float) ld_val;
446 if (!(flags & FL_NOASSIGN) && kind != 'n') done++;
449 return conv || (ic != EOF) ? done : EOF;