|
1 /* VFSCANF.C |
|
2 * |
|
3 * Portions Copyright (c) 1990-2004 Nokia Corporation and/or its subsidiary(-ies). |
|
4 * All rights reserved. |
|
5 */ |
|
6 |
|
7 /* No user fns here. Pesch 15apr92. */ |
|
8 |
|
9 /* |
|
10 * Copyright (c) 1990 The Regents of the University of California. |
|
11 * All rights reserved. |
|
12 * |
|
13 * Redistribution and use in source and binary forms are permitted |
|
14 * provided that the above copyright notice and this paragraph are |
|
15 * duplicated in all such forms and that any documentation, |
|
16 * advertising materials, and other materials related to such |
|
17 * distribution and use acknowledge that the software was developed |
|
18 * by the University of California, Berkeley. The name of the |
|
19 * University may not be used to endorse or promote products derived |
|
20 * from this software without specific prior written permission. |
|
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
|
22 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
|
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
|
24 */ |
|
25 |
|
26 #include <_ansi.h> |
|
27 #include <ctype.h> |
|
28 #include <stdio.h> |
|
29 #include <stdlib.h> |
|
30 #include <stdarg.h> |
|
31 #include "LOCAL.H" |
|
32 |
|
33 #include "FLOATIO.H" |
|
34 #define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */ |
|
35 |
|
36 /* |
|
37 * Flags used during conversion. |
|
38 */ |
|
39 |
|
40 #define LONG 0x01 /* l: long or double */ |
|
41 #define LONGDBL 0x02 /* L: long double; unimplemented */ |
|
42 #define SHORT 0x04 /* h: short */ |
|
43 #define SUPPRESS 0x08 /* suppress assignment */ |
|
44 #define POINTER 0x10 /* weird %p pointer (`fake hex') */ |
|
45 #define NOSKIP 0x20 /* do not skip blanks */ |
|
46 |
|
47 /* |
|
48 * The following are used in numeric conversions only: |
|
49 * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point; |
|
50 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral. |
|
51 */ |
|
52 |
|
53 #define SIGNOK 0x40 /* +/- is (still) legal */ |
|
54 #define NDIGITS 0x80 /* no digits detected */ |
|
55 |
|
56 #define DPTOK 0x100 /* (float) decimal point is still legal */ |
|
57 #define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */ |
|
58 |
|
59 #define PFXOK 0x100 /* 0x prefix is (still) legal */ |
|
60 #define NZDIGITS 0x200 /* no zero digits detected */ |
|
61 |
|
62 /* |
|
63 * Conversion types. |
|
64 */ |
|
65 |
|
66 #define CT_CHAR 0 /* %c conversion */ |
|
67 #define CT_CCL 1 /* %[...] conversion */ |
|
68 #define CT_STRING 2 /* %s conversion */ |
|
69 #define CT_INT 3 /* integer, i.e., strtol or strtoul */ |
|
70 #define CT_FLOAT 4 /* floating, i.e., strtod */ |
|
71 |
|
72 #define u_char char |
|
73 #define u_long unsigned long |
|
74 |
|
75 /*static*/ u_char *__sccl (register char *tab,register u_char *fmt); |
|
76 |
|
77 /* |
|
78 * vfscanf |
|
79 */ |
|
80 |
|
81 #define BufferEmpty (fp->_r <= 0 && __srefill(fp)) |
|
82 |
|
83 int |
|
84 __svfscanf (register FILE *fp,char const *fmt0, va_list ap) |
|
85 { |
|
86 register u_char *fmt = (u_char *) fmt0; |
|
87 register int c; /* character from format, or conversion */ |
|
88 register size_t width; /* field width, or 0 */ |
|
89 register char *p; /* points into all kinds of strings */ |
|
90 register int n; /* handy integer */ |
|
91 register int flags; /* flags as defined above */ |
|
92 register char *p0; /* saves original value of p when necessary */ |
|
93 int nassigned; /* number of fields assigned */ |
|
94 int nread; /* number of characters consumed from fp */ |
|
95 int base = 0; /* base argument to strtol/strtoul */ |
|
96 |
|
97 u_long (*ccfn) (const char *_n, char **_end_PTR, int _base) = 0; /* conversion function (strtol/strtoul) */ |
|
98 char ccltab[256]; /* character class table for %[...] */ |
|
99 char buf[BUF]; /* buffer for numeric conversions */ |
|
100 |
|
101 short *sp; |
|
102 int *ip; |
|
103 float *flp; |
|
104 double *dp; |
|
105 long *lp; |
|
106 |
|
107 /* `basefix' is used to avoid `if' tests in the integer scanner */ |
|
108 static const short basefix[17] = |
|
109 {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; |
|
110 |
|
111 nassigned = 0; |
|
112 nread = 0; |
|
113 for (;;) |
|
114 { |
|
115 c = *fmt++; |
|
116 if (c == 0) |
|
117 return nassigned; |
|
118 if (isspace (c)) |
|
119 { |
|
120 for (;;) |
|
121 { |
|
122 if (BufferEmpty) |
|
123 return nassigned; |
|
124 if (!isspace (*fp->_p)) |
|
125 break; |
|
126 nread++, fp->_r--, fp->_p++; |
|
127 } |
|
128 continue; |
|
129 } |
|
130 if (c != '%') |
|
131 goto literal; |
|
132 width = 0; |
|
133 flags = 0; |
|
134 |
|
135 /* |
|
136 * switch on the format. continue if done; break once format |
|
137 * type is derived. |
|
138 */ |
|
139 |
|
140 again: |
|
141 c = *fmt++; |
|
142 |
|
143 switch (c) |
|
144 { |
|
145 case '%': |
|
146 literal: |
|
147 if (BufferEmpty) |
|
148 goto input_failure; |
|
149 if (*fp->_p != c) |
|
150 goto match_failure; |
|
151 fp->_r--, fp->_p++; |
|
152 nread++; |
|
153 continue; |
|
154 |
|
155 case '*': |
|
156 flags |= SUPPRESS; |
|
157 goto again; |
|
158 case 'l': |
|
159 flags |= LONG; |
|
160 goto again; |
|
161 case 'L': |
|
162 /* not supported flags |= LONGDBL; */ |
|
163 goto again; |
|
164 case 'h': |
|
165 flags |= SHORT; |
|
166 goto again; |
|
167 |
|
168 case '0': |
|
169 case '1': |
|
170 case '2': |
|
171 case '3': |
|
172 case '4': |
|
173 case '5': |
|
174 case '6': |
|
175 case '7': |
|
176 case '8': |
|
177 case '9': |
|
178 width = width * 10 + c - '0'; |
|
179 goto again; |
|
180 |
|
181 /* |
|
182 * Conversions. Those marked `compat' are for |
|
183 * 4.[123]BSD compatibility. |
|
184 * |
|
185 * (According to ANSI, E and X formats are supposed to |
|
186 * the same as e and x. Sorry about that.) |
|
187 */ |
|
188 |
|
189 case 'D': /* compat */ |
|
190 flags |= LONG; |
|
191 /* FALLTHROUGH */ |
|
192 case 'd': |
|
193 c = CT_INT; |
|
194 ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtol; |
|
195 base = 10; |
|
196 break; |
|
197 |
|
198 case 'i': |
|
199 c = CT_INT; |
|
200 ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtol; |
|
201 base = 0; |
|
202 break; |
|
203 |
|
204 case 'O': /* compat */ |
|
205 flags |= LONG; |
|
206 /* FALLTHROUGH */ |
|
207 case 'o': |
|
208 c = CT_INT; |
|
209 ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtoul; |
|
210 base = 8; |
|
211 break; |
|
212 |
|
213 case 'u': |
|
214 c = CT_INT; |
|
215 ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtoul; |
|
216 base = 10; |
|
217 break; |
|
218 |
|
219 case 'X': /* compat XXX */ |
|
220 case 'x': |
|
221 flags |= PFXOK; /* enable 0x prefixing */ |
|
222 c = CT_INT; |
|
223 ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtoul; |
|
224 base = 16; |
|
225 break; |
|
226 |
|
227 case 'E': /* compat XXX */ |
|
228 case 'G': /* compat XXX */ |
|
229 /* ANSI says that E,G and X behave the same way as e,g,x */ |
|
230 /* FALLTHROUGH */ |
|
231 case 'e': |
|
232 case 'f': |
|
233 case 'g': |
|
234 c = CT_FLOAT; |
|
235 break; |
|
236 |
|
237 case 's': |
|
238 c = CT_STRING; |
|
239 break; |
|
240 |
|
241 case '[': |
|
242 fmt = __sccl (ccltab, fmt); |
|
243 flags |= NOSKIP; |
|
244 c = CT_CCL; |
|
245 break; |
|
246 |
|
247 case 'c': |
|
248 flags |= NOSKIP; |
|
249 c = CT_CHAR; |
|
250 break; |
|
251 |
|
252 case 'p': /* pointer format is like hex */ |
|
253 flags |= POINTER | PFXOK; |
|
254 c = CT_INT; |
|
255 ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtoul; |
|
256 base = 16; |
|
257 break; |
|
258 |
|
259 case 'n': |
|
260 if (flags & SUPPRESS) /* ??? */ |
|
261 continue; |
|
262 if (flags & SHORT) |
|
263 { |
|
264 sp = va_arg (ap, short *); |
|
265 *sp = (short)nread; |
|
266 } |
|
267 else if (flags & LONG) |
|
268 { |
|
269 lp = va_arg (ap, long *); |
|
270 *lp = nread; |
|
271 } |
|
272 else |
|
273 { |
|
274 ip = va_arg (ap, int *); |
|
275 *ip = nread; |
|
276 } |
|
277 continue; |
|
278 |
|
279 /* |
|
280 * Disgusting backwards compatibility hacks. XXX |
|
281 */ |
|
282 case '\0': /* compat */ |
|
283 return EOF; |
|
284 |
|
285 default: /* compat */ |
|
286 if (isupper (c)) |
|
287 flags |= LONG; |
|
288 c = CT_INT; |
|
289 ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtol; |
|
290 base = 10; |
|
291 break; |
|
292 } |
|
293 |
|
294 /* |
|
295 * We have a conversion that requires input. |
|
296 */ |
|
297 if (BufferEmpty) |
|
298 goto input_failure; |
|
299 |
|
300 /* |
|
301 * Consume leading white space, except for formats that |
|
302 * suppress this. |
|
303 */ |
|
304 if ((flags & NOSKIP) == 0) |
|
305 { |
|
306 while (isspace (*fp->_p)) |
|
307 { |
|
308 nread++; |
|
309 if (--fp->_r > 0) |
|
310 fp->_p++; |
|
311 else |
|
312 if (__srefill (fp)) |
|
313 goto input_failure; |
|
314 } |
|
315 /* |
|
316 * Note that there is at least one character in the |
|
317 * buffer, so conversions that do not set NOSKIP ca |
|
318 * no longer result in an input failure. |
|
319 */ |
|
320 } |
|
321 |
|
322 /* |
|
323 * Do the conversion. |
|
324 */ |
|
325 switch (c) |
|
326 { |
|
327 |
|
328 case CT_CHAR: |
|
329 /* scan arbitrary characters (sets NOSKIP) */ |
|
330 if (width == 0) |
|
331 width = 1; |
|
332 if (flags & SUPPRESS) |
|
333 { |
|
334 size_t sum = 0; |
|
335 |
|
336 for (;;) |
|
337 { |
|
338 if ((n = fp->_r) < (int)width) |
|
339 { |
|
340 sum += n; |
|
341 width -= n; |
|
342 fp->_p += n; |
|
343 if (__srefill (fp)) |
|
344 { |
|
345 if (sum == 0) |
|
346 goto input_failure; |
|
347 break; |
|
348 } |
|
349 } |
|
350 else |
|
351 { |
|
352 sum += width; |
|
353 fp->_r -= width; |
|
354 fp->_p += width; |
|
355 break; |
|
356 } |
|
357 } |
|
358 nread += sum; |
|
359 } |
|
360 else |
|
361 { |
|
362 size_t r = fread ((void*) va_arg (ap, char *), 1, width, fp); |
|
363 |
|
364 if (r == 0) |
|
365 goto input_failure; |
|
366 nread += r; |
|
367 nassigned++; |
|
368 } |
|
369 break; |
|
370 |
|
371 case CT_CCL: |
|
372 /* scan a (nonempty) character class (sets NOSKIP) */ |
|
373 if (width == 0) |
|
374 width = (unsigned long)(~0); /* `infinity' */ |
|
375 /* take only those things in the class */ |
|
376 if (flags & SUPPRESS) |
|
377 { |
|
378 n = 0; |
|
379 while (ccltab[*fp->_p]) |
|
380 { |
|
381 n++, fp->_r--, fp->_p++; |
|
382 if (--width == 0) |
|
383 break; |
|
384 if (BufferEmpty) |
|
385 { |
|
386 if (n == 0) |
|
387 goto input_failure; |
|
388 break; |
|
389 } |
|
390 } |
|
391 if (n == 0) |
|
392 goto match_failure; |
|
393 } |
|
394 else |
|
395 { |
|
396 p0 = p = va_arg (ap, char *); |
|
397 while (ccltab[*fp->_p]) |
|
398 { |
|
399 fp->_r--; |
|
400 *p++ = *fp->_p++; |
|
401 if (--width == 0) |
|
402 break; |
|
403 if (BufferEmpty) |
|
404 { |
|
405 if (p == p0) |
|
406 goto input_failure; |
|
407 break; |
|
408 } |
|
409 } |
|
410 n = p - p0; |
|
411 if (n == 0) |
|
412 goto match_failure; |
|
413 *p = 0; |
|
414 nassigned++; |
|
415 } |
|
416 nread += n; |
|
417 break; |
|
418 |
|
419 case CT_STRING: |
|
420 /* like CCL, but zero-length string OK, & no NOSKIP */ |
|
421 if (width == 0) |
|
422 width = (unsigned long)(~0); |
|
423 if (flags & SUPPRESS) |
|
424 { |
|
425 n = 0; |
|
426 while (!isspace (*fp->_p)) |
|
427 { |
|
428 n++, fp->_r--, fp->_p++; |
|
429 if (--width == 0) |
|
430 break; |
|
431 if (BufferEmpty) |
|
432 break; |
|
433 } |
|
434 nread += n; |
|
435 } |
|
436 else |
|
437 { |
|
438 p0 = p = va_arg (ap, char *); |
|
439 while (!isspace (*fp->_p)) |
|
440 { |
|
441 fp->_r--; |
|
442 *p++ = *fp->_p++; |
|
443 if (--width == 0) |
|
444 break; |
|
445 if (BufferEmpty) |
|
446 break; |
|
447 } |
|
448 *p = 0; |
|
449 nread += p - p0; |
|
450 nassigned++; |
|
451 } |
|
452 continue; |
|
453 |
|
454 case CT_INT: |
|
455 /* scan an integer as if by strtol/strtoul */ |
|
456 #ifdef hardway |
|
457 if (width == 0 || width > sizeof (buf) - 1) |
|
458 width = sizeof (buf) - 1; |
|
459 #else |
|
460 /* size_t is unsigned, hence this optimisation */ |
|
461 if (--width > sizeof (buf) - 2) |
|
462 width = sizeof (buf) - 2; |
|
463 width++; |
|
464 #endif |
|
465 flags |= SIGNOK | NDIGITS | NZDIGITS; |
|
466 for (p = buf; width; width--) |
|
467 { |
|
468 c = *fp->_p; |
|
469 /* |
|
470 * Switch on the character; `goto ok' if we |
|
471 * accept it as a part of number. |
|
472 */ |
|
473 switch (c) |
|
474 { |
|
475 /* |
|
476 * The digit 0 is always legal, but is special. |
|
477 * For %i conversions, if no digits (zero or nonzero) |
|
478 * have been scanned (only signs), we will have base==0. |
|
479 * In that case, we should set it to 8 and enable 0x |
|
480 * prefixing. Also, if we have not scanned zero digits |
|
481 * before this, do not turn off prefixing (someone else |
|
482 * will turn it off if we have scanned any nonzero digits). |
|
483 */ |
|
484 case '0': |
|
485 if (base == 0) |
|
486 { |
|
487 base = 8; |
|
488 flags |= PFXOK; |
|
489 } |
|
490 if (flags & NZDIGITS) |
|
491 flags &= ~(SIGNOK | NZDIGITS | NDIGITS); |
|
492 else |
|
493 flags &= ~(SIGNOK | PFXOK | NDIGITS); |
|
494 goto ok; |
|
495 |
|
496 /* 1 through 7 always legal */ |
|
497 case '1': |
|
498 case '2': |
|
499 case '3': |
|
500 case '4': |
|
501 case '5': |
|
502 case '6': |
|
503 case '7': |
|
504 base = basefix[base]; |
|
505 flags &= ~(SIGNOK | PFXOK | NDIGITS); |
|
506 goto ok; |
|
507 |
|
508 /* digits 8 and 9 ok iff decimal or hex */ |
|
509 case '8': |
|
510 case '9': |
|
511 base = basefix[base]; |
|
512 if (base <= 8) |
|
513 break; /* not legal here */ |
|
514 flags &= ~(SIGNOK | PFXOK | NDIGITS); |
|
515 goto ok; |
|
516 |
|
517 /* letters ok iff hex */ |
|
518 case 'A': |
|
519 case 'B': |
|
520 case 'C': |
|
521 case 'D': |
|
522 case 'E': |
|
523 case 'F': |
|
524 case 'a': |
|
525 case 'b': |
|
526 case 'c': |
|
527 case 'd': |
|
528 case 'e': |
|
529 case 'f': |
|
530 /* no need to fix base here */ |
|
531 if (base <= 10) |
|
532 break; /* not legal here */ |
|
533 flags &= ~(SIGNOK | PFXOK | NDIGITS); |
|
534 goto ok; |
|
535 |
|
536 /* sign ok only as first character */ |
|
537 case '+': |
|
538 case '-': |
|
539 if (flags & SIGNOK) |
|
540 { |
|
541 flags &= ~SIGNOK; |
|
542 goto ok; |
|
543 } |
|
544 break; |
|
545 |
|
546 /* x ok iff flag still set & 2nd char */ |
|
547 case 'x': |
|
548 case 'X': |
|
549 if (flags & PFXOK && p == buf + 1) |
|
550 { |
|
551 base = 16;/* if %i */ |
|
552 flags &= ~PFXOK; |
|
553 goto ok; |
|
554 } |
|
555 break; |
|
556 } |
|
557 |
|
558 /* |
|
559 * If we got here, c is not a legal character |
|
560 * for a number. Stop accumulating digits. |
|
561 */ |
|
562 break; |
|
563 ok: |
|
564 /* |
|
565 * c is legal: store it and look at the next. |
|
566 */ |
|
567 *p++ = (char)c; |
|
568 if (--fp->_r > 0) |
|
569 fp->_p++; |
|
570 else |
|
571 if (__srefill (fp)) |
|
572 break; /* EOF */ |
|
573 } |
|
574 /* |
|
575 * If we had only a sign, it is no good; push back the sign. |
|
576 * If the number ends in `x', it was [sign] '0' 'x', so push back |
|
577 * the x and treat it as [sign] '0'. |
|
578 */ |
|
579 if (flags & NDIGITS) |
|
580 { |
|
581 if (p > buf) |
|
582 (void) ungetc (*(u_char *)-- p, fp); |
|
583 goto match_failure; |
|
584 } |
|
585 c = ((u_char *) p)[-1]; |
|
586 if (c == 'x' || c == 'X') |
|
587 { |
|
588 --p; |
|
589 /*(void)*/ ungetc (c, fp); |
|
590 } |
|
591 if ((flags & SUPPRESS) == 0) |
|
592 { |
|
593 u_long res; |
|
594 |
|
595 *p = 0; |
|
596 res = (*ccfn) (buf, (char **) NULL, base); |
|
597 if (flags & POINTER) |
|
598 *(va_arg (ap, void* *)) = (void*) res; |
|
599 else if (flags & SHORT) |
|
600 { |
|
601 sp = va_arg (ap, short *); |
|
602 *sp = (short)res; |
|
603 } |
|
604 else if (flags & LONG) |
|
605 { |
|
606 lp = va_arg (ap, long *); |
|
607 *lp = res; |
|
608 } |
|
609 else |
|
610 { |
|
611 ip = va_arg (ap, int *); |
|
612 *ip = res; |
|
613 } |
|
614 nassigned++; |
|
615 } |
|
616 nread += p - buf; |
|
617 break; |
|
618 |
|
619 case CT_FLOAT: |
|
620 /* scan a floating point number as if by strtod */ |
|
621 #ifdef hardway |
|
622 if (width == 0 || width > sizeof (buf) - 1) |
|
623 width = sizeof (buf) - 1; |
|
624 #else |
|
625 /* size_t is unsigned, hence this optimisation */ |
|
626 if (--width > sizeof (buf) - 2) |
|
627 width = sizeof (buf) - 2; |
|
628 width++; |
|
629 #endif |
|
630 flags |= SIGNOK | NDIGITS | DPTOK | EXPOK; |
|
631 for (p = buf; width; width--) |
|
632 { |
|
633 c = *fp->_p; |
|
634 /* |
|
635 * This code mimicks the integer conversion |
|
636 * code, but is much simpler. |
|
637 */ |
|
638 switch (c) |
|
639 { |
|
640 |
|
641 case '0': |
|
642 case '1': |
|
643 case '2': |
|
644 case '3': |
|
645 case '4': |
|
646 case '5': |
|
647 case '6': |
|
648 case '7': |
|
649 case '8': |
|
650 case '9': |
|
651 flags &= ~(SIGNOK | NDIGITS); |
|
652 goto fok; |
|
653 |
|
654 case '+': |
|
655 case '-': |
|
656 if (flags & SIGNOK) |
|
657 { |
|
658 flags &= ~SIGNOK; |
|
659 goto fok; |
|
660 } |
|
661 break; |
|
662 case '.': |
|
663 if (flags & DPTOK) |
|
664 { |
|
665 flags &= ~(SIGNOK | DPTOK); |
|
666 goto fok; |
|
667 } |
|
668 break; |
|
669 case 'e': |
|
670 case 'E': |
|
671 /* no exponent without some digits */ |
|
672 if ((flags & (NDIGITS | EXPOK)) == EXPOK) |
|
673 { |
|
674 flags = |
|
675 (flags & ~(EXPOK | DPTOK)) | |
|
676 SIGNOK | NDIGITS; |
|
677 goto fok; |
|
678 } |
|
679 break; |
|
680 } |
|
681 break; |
|
682 fok: |
|
683 *p++ = (char)c; |
|
684 if (--fp->_r > 0) |
|
685 fp->_p++; |
|
686 else |
|
687 if (__srefill (fp)) |
|
688 break; /* EOF */ |
|
689 } |
|
690 /* |
|
691 * If no digits, might be missing exponent digits |
|
692 * (just give back the exponent) or might be missing |
|
693 * regular digits, but had sign and/or decimal point. |
|
694 */ |
|
695 if (flags & NDIGITS) |
|
696 { |
|
697 if (flags & EXPOK) |
|
698 { |
|
699 /* no digits at all */ |
|
700 while (p > buf) |
|
701 ungetc (*(u_char *)-- p, fp); |
|
702 goto match_failure; |
|
703 } |
|
704 /* just a bad exponent (e and maybe sign) */ |
|
705 c = *(u_char *)-- p; |
|
706 if (c != 'e' && c != 'E') |
|
707 { |
|
708 (void) ungetc (c, fp); /* sign */ |
|
709 c = *(u_char *)-- p; |
|
710 } |
|
711 (void) ungetc (c, fp); |
|
712 } |
|
713 if ((flags & SUPPRESS) == 0) |
|
714 { |
|
715 double res; |
|
716 |
|
717 *p = 0; |
|
718 res = atof (buf); |
|
719 if (flags & LONG) |
|
720 { |
|
721 dp = va_arg (ap, double *); |
|
722 *dp = res; |
|
723 } |
|
724 else |
|
725 { |
|
726 flp = va_arg (ap, float *); |
|
727 *flp = (float)res; |
|
728 } |
|
729 nassigned++; |
|
730 } |
|
731 nread += p - buf; |
|
732 break; |
|
733 } |
|
734 } |
|
735 input_failure: |
|
736 return nassigned ? nassigned : -1; |
|
737 match_failure: |
|
738 return nassigned; |
|
739 } |
|
740 |
|
741 /* |
|
742 * Fill in the given table from the scanset at the given format |
|
743 * (just after `['). Return a pointer to the character past the |
|
744 * closing `]'. The table has a 1 wherever characters should be |
|
745 * considered part of the scanset. |
|
746 */ |
|
747 |
|
748 /*static*/ |
|
749 u_char * |
|
750 __sccl (register char *tab,register u_char *fmt) |
|
751 { |
|
752 register int c, n, v; |
|
753 |
|
754 /* first `clear' the whole table */ |
|
755 c = *fmt++; /* first char hat => negated scanset */ |
|
756 if (c == '^') |
|
757 { |
|
758 v = 1; /* default => accept */ |
|
759 c = *fmt++; /* get new first char */ |
|
760 } |
|
761 else |
|
762 v = 0; /* default => reject */ |
|
763 /* should probably use memset here */ |
|
764 for (n = 0; n < 256; n++) |
|
765 tab[n] = (char)v; |
|
766 if (c == 0) |
|
767 return fmt - 1; /* format ended before closing ] */ |
|
768 |
|
769 /* |
|
770 * Now set the entries corresponding to the actual scanset to the |
|
771 * opposite of the above. |
|
772 * |
|
773 * The first character may be ']' (or '-') without being special; the |
|
774 * last character may be '-'. |
|
775 */ |
|
776 |
|
777 v = 1 - v; |
|
778 for (;;) |
|
779 { |
|
780 tab[c] = (char)v; /* take character c */ |
|
781 doswitch: |
|
782 n = *fmt++; /* and examine the next */ |
|
783 switch (n) |
|
784 { |
|
785 |
|
786 case 0: /* format ended too soon */ |
|
787 return fmt - 1; |
|
788 |
|
789 case '-': |
|
790 /* |
|
791 * A scanset of the form [01+-] is defined as `the digit 0, the |
|
792 * digit 1, the character +, the character -', but the effect of a |
|
793 * scanset such as [a-zA-Z0-9] is implementation defined. The V7 |
|
794 * Unix scanf treats `a-z' as `the letters a through z', but treats |
|
795 * `a-a' as `the letter a, the character -, and the letter a'. |
|
796 * |
|
797 * For compatibility, the `-' is not considerd to define a range if |
|
798 * the character following it is either a close bracket (required by |
|
799 * ANSI) or is not numerically greater than the character we just |
|
800 * stored in the table (c). |
|
801 */ |
|
802 n = *fmt; |
|
803 if (n == ']' || n < c) |
|
804 { |
|
805 c = '-'; |
|
806 break; /* resume the for(;;) */ |
|
807 } |
|
808 fmt++; |
|
809 do |
|
810 { /* fill in the range */ |
|
811 tab[++c] = (char)v; |
|
812 } |
|
813 while (c < n); |
|
814 #if 1 /* XXX another disgusting compatibility hack */ |
|
815 /* |
|
816 * Alas, the V7 Unix scanf also treats formats such |
|
817 * as [a-c-e] as `the letters a through e'. This too |
|
818 * is permitted by the standard.... |
|
819 */ |
|
820 goto doswitch; |
|
821 #else |
|
822 c = *fmt++; |
|
823 if (c == 0) |
|
824 return fmt - 1; |
|
825 if (c == ']') |
|
826 return fmt; |
|
827 |
|
828 break; |
|
829 #endif |
|
830 |
|
831 case ']': /* end of scanset */ |
|
832 return fmt; |
|
833 |
|
834 default: /* just another character */ |
|
835 c = n; |
|
836 break; |
|
837 } |
|
838 } |
|
839 /* NOTREACHED */ |
|
840 } |