2 * doscan.c - scan formatted input
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 unsigned 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 unsigned 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
= 0; /* width of field */
179 int flags
; /* some flags */
180 int reverse
; /* reverse the checking in [...] */
182 register int ic
= EOF
; /* 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
++) break; /* error */
211 if (*format
== '%') {
221 if (*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';
232 case 'h': flags
|= FL_SHORT
; format
++; break;
233 case 'l': flags
|= FL_LONG
; format
++; break;
234 case 'L': flags
|= FL_LONGDOUBLE
; format
++; break;
237 if ((kind
!= 'c') && (kind
!= '[') && (kind
!= 'n')) {
241 } while (isspace(ic
));
242 if (ic
== EOF
) break; /* outer while */
243 } else if (kind
!= 'n') { /* %c or %[ */
245 if (ic
== EOF
) break; /* outer while */
250 /* not recognized, like %q */
251 return conv
|| (ic
!= EOF
) ? done
: EOF
;
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
;
260 *va_arg(ap
, int *) = (int) nrchars
;
263 case 'p': /* pointer */
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
)
275 if (!width
) return done
;
277 str
= o_collect(ic
, stream
, kind
, width
, &base
);
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
);
293 val
= strtoul(inp_buf
, &tmp_string
, base
);
295 *va_arg(ap
, unsigned long *) = (unsigned long) val
;
296 else if (flags
& FL_SHORT
)
297 *va_arg(ap
, unsigned short *) = (unsigned short) val
;
299 *va_arg(ap
, unsigned *) = (unsigned) val
;
303 if (!(flags
& FL_WIDTHSPEC
))
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
))
319 if (ic
!= EOF
) ungetc(ic
,stream
);
324 if (!(flags
& FL_WIDTHSPEC
))
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
))
338 /* terminate the string */
339 if (!(flags
& FL_NOASSIGN
))
342 if (ic
!= EOF
) ungetc(ic
,stream
);
347 if (!(flags
& FL_WIDTHSPEC
))
349 if (!width
) return done
;
351 if ( *++format
== '^' ) {
357 for (str
= Xtable
; str
< &Xtable
[NR_CHARS
]
361 if (*format
== ']') Xtable
[*format
++] = 1;
363 while (*format
&& *format
!= ']') {
364 Xtable
[*format
++] = 1;
365 if (*format
== '-') {
369 && *(format
) >= *(format
-2)) {
372 for( c
= *(format
-2) + 1
373 ; c
<= *format
; c
++)
377 else Xtable
['-'] = 1;
380 if (!*format
) return done
;
382 if (!(Xtable
[ic
] ^ reverse
)) {
383 /* MAT 8/9/96 no match must return character */
388 if (!(flags
& FL_NOASSIGN
))
389 str
= va_arg(ap
, char *);
392 if (!(flags
& FL_NOASSIGN
))
398 } while (width
&& ic
!= EOF
&& (Xtable
[ic
] ^ reverse
));
401 if (ic
!= EOF
) ungetc(ic
, stream
);
404 if (!(flags
& FL_NOASSIGN
)) { /* terminate string */
414 if (!(flags
& FL_WIDTHSPEC
) || width
> NUMLEN
)
417 if (!width
) return done
;
418 str
= f_collect(ic
, stream
, width
);
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
;
437 *va_arg(ap
, double *) = (double) ld_val
;
439 *va_arg(ap
, float *) = (float) ld_val
;
445 if (!(flags
& FL_NOASSIGN
) && kind
!= 'n') done
++;
448 return conv
|| (ic
!= EOF
) ? done
: EOF
;