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;
49 default: base
= 10; break;
52 if (c
== '-' || c
== '+') {
58 if (width
&& c
== '0' && base
== 16) {
62 if (c
!= 'x' && c
!= 'X') {
63 if (type
== 'i') base
= 8;
71 else if (type
== 'i') base
= 10;
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'))) {
85 if (width
&& c
!= EOF
) ungetc(c
, stream
);
86 if (type
== 'i') base
= 0;
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+)
102 f_collect(register int c
, register FILE *stream
, register unsigned int width
)
104 register char *bufp
= inp_buf
;
107 if (c
== '-' || c
== '+') {
113 while (width
&& isdigit(c
)) {
119 if (width
&& c
== '.') {
123 while (width
&& isdigit(c
)) {
132 if (width
&& c
!= EOF
) ungetc(c
, stream
);
137 if (width
&& (c
== 'e' || c
== 'E')) {
141 if (width
&& (c
== '+' || c
== '-')) {
146 while (width
&& isdigit(c
)) {
153 if (width
&& c
!= EOF
) ungetc(c
,stream
);
158 if (width
&& c
!= EOF
) ungetc(c
, stream
);
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 [...] */
183 register int ic
= EOF
; /* the input character */
188 if (!*format
) return 0;
191 if (isspace(*format
)) {
192 while (isspace(*format
))
193 format
++; /* skip whitespace */
196 while (isspace (ic
)) {
200 if (ic
!= EOF
) ungetc(ic
,stream
);
203 if (!*format
) break; /* end of format */
205 if (*format
!= '%') {
208 if (ic
!= *format
++) break; /* error */
212 if (*format
== '%') {
222 if (*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';
233 case 'h': flags
|= FL_SHORT
; format
++; break;
234 case 'l': flags
|= FL_LONG
; format
++; break;
235 case 'L': flags
|= FL_LONGDOUBLE
; format
++; break;
238 if ((kind
!= 'c') && (kind
!= '[') && (kind
!= 'n')) {
242 } while (isspace(ic
));
243 if (ic
== EOF
) break; /* outer while */
244 } else if (kind
!= 'n') { /* %c or %[ */
246 if (ic
== EOF
) break; /* outer while */
251 /* not recognized, like %q */
252 return conv
|| (ic
!= EOF
) ? done
: EOF
;
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
;
261 *va_arg(ap
, int *) = (int) nrchars
;
264 case 'p': /* pointer */
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
)
276 if (!width
) return done
;
278 str
= o_collect(ic
, stream
, kind
, width
, &base
);
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
);
294 val
= strtoul(inp_buf
, &tmp_string
, base
);
296 *va_arg(ap
, unsigned long *) = (unsigned long) val
;
297 else if (flags
& FL_SHORT
)
298 *va_arg(ap
, unsigned short *) = (unsigned short) val
;
300 *va_arg(ap
, unsigned *) = (unsigned) val
;
304 if (!(flags
& FL_WIDTHSPEC
))
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
))
320 if (ic
!= EOF
) ungetc(ic
,stream
);
325 if (!(flags
& FL_WIDTHSPEC
))
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
))
339 /* terminate the string */
340 if (!(flags
& FL_NOASSIGN
))
343 if (ic
!= EOF
) ungetc(ic
,stream
);
348 if (!(flags
& FL_WIDTHSPEC
))
350 if (!width
) return done
;
352 if ( *++format
== '^' ) {
358 for (str
= Xtable
; str
< &Xtable
[NR_CHARS
]
362 if (*format
== ']') Xtable
[*format
++] = 1;
364 while (*format
&& *format
!= ']') {
365 Xtable
[*format
++] = 1;
366 if (*format
== '-') {
370 && *(format
) >= *(format
-2)) {
373 for( c
= *(format
-2) + 1
374 ; c
<= *format
; c
++)
378 else Xtable
['-'] = 1;
381 if (!*format
) return done
;
383 if (!(Xtable
[ic
] ^ reverse
)) {
384 /* MAT 8/9/96 no match must return character */
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
;