1 /*
2 FUNCTION
3 <<vscanf>>, <<vfscanf>>, <<vsscanf>>---format argument list
4
5 INDEX
6 vscanf
7 INDEX
8 vfscanf
9 INDEX
10 vsscanf
11
12 ANSI_SYNOPSIS
13 #include <stdio.h>
14 #include <stdarg.h>
15 int vscanf(const char *restrict <[fmt]>, va_list <[list]>);
16 int vfscanf(FILE *restrict <[fp]>, const char *restrict <[fmt]>, va_list <[list]>);
17 int vsscanf(const char *restrict <[str]>, const char *restrict <[fmt]>, va_list <[list]>);
18
19 int _vscanf_r(void *<[reent]>, const char *restrict <[fmt]>,
20 va_list <[list]>);
21 int _vfscanf_r(void *<[reent]>, FILE *restrict <[fp]>, const char *restrict <[fmt]>,
22 va_list <[list]>);
23 int _vsscanf_r(void *<[reent]>, const char *restrict <[str]>, const char *restrict <[fmt]>,
24 va_list <[list]>);
25
26 TRAD_SYNOPSIS
27 #include <stdio.h>
28 #include <varargs.h>
29 int vscanf( <[fmt]>, <[ist]>)
30 char *<[fmt]>;
31 va_list <[list]>;
32
33 int vfscanf( <[fp]>, <[fmt]>, <[list]>)
34 FILE *<[fp]>;
35 char *<[fmt]>;
36 va_list <[list]>;
37
38 int vsscanf( <[str]>, <[fmt]>, <[list]>)
39 char *<[str]>;
40 char *<[fmt]>;
41 va_list <[list]>;
42
43 int _vscanf_r( <[reent]>, <[fmt]>, <[ist]>)
44 char *<[reent]>;
45 char *<[fmt]>;
46 va_list <[list]>;
47
48 int _vfscanf_r( <[reent]>, <[fp]>, <[fmt]>, <[list]>)
49 char *<[reent]>;
50 FILE *<[fp]>;
51 char *<[fmt]>;
52 va_list <[list]>;
53
54 int _vsscanf_r( <[reent]>, <[str]>, <[fmt]>, <[list]>)
55 char *<[reent]>;
56 char *<[str]>;
57 char *<[fmt]>;
58 va_list <[list]>;
59
60 DESCRIPTION
61 <<vscanf>>, <<vfscanf>>, and <<vsscanf>> are (respectively) variants
62 of <<scanf>>, <<fscanf>>, and <<sscanf>>. They differ only in
63 allowing their caller to pass the variable argument list as a
64 <<va_list>> object (initialized by <<va_start>>) rather than
65 directly accepting a variable number of arguments.
66
67 RETURNS
68 The return values are consistent with the corresponding functions:
69 <<vscanf>> returns the number of input fields successfully scanned,
70 converted, and stored; the return value does not include scanned
71 fields which were not stored.
72
73 If <<vscanf>> attempts to read at end-of-file, the return value
74 is <<EOF>>.
75
76 If no fields were stored, the return value is <<0>>.
77
78 The routines <<_vscanf_r>>, <<_vfscanf_f>>, and <<_vsscanf_r>> are
79 reentrant versions which take an additional first parameter which points to the
80 reentrancy structure.
81
82 PORTABILITY
83 These are GNU extensions.
84
85 Supporting OS subroutines required:
86 */
87
88 /*-
89 * Copyright (c) 1990 The Regents of the University of California.
90 * All rights reserved.
91 *
92 * Redistribution and use in source and binary forms are permitted
93 * provided that the above copyright notice and this paragraph are
94 * duplicated in all such forms and that any documentation,
95 * advertising materials, and other materials related to such
96 * distribution and use acknowledge that the software was developed
97 * by the University of California, Berkeley. The name of the
98 * University may not be used to endorse or promote products derived
99 * from this software without specific prior written permission.
100 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
101 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
102 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
103 */
104
105 #include <_ansi.h>
106 #include <reent.h>
107 #include <newlib.h>
108 #include <ctype.h>
109 #include <stdio.h>
110 #include <stdlib.h>
111 #include <limits.h>
112 #include <wchar.h>
113 #include <string.h>
114 #ifdef _HAVE_STDC
115 #include <stdarg.h>
116 #else
117 #include <varargs.h>
118 #endif
119 #include "local.h"
120
121 #ifndef NO_FLOATING_POINT
122 #define FLOATING_POINT
123 #endif
124
125 #ifdef FLOATING_POINT
126 #include <float.h>
127
128 /* Currently a test is made to see if long double processing is warranted.
129 This could be changed in the future should the _ldtoa_r code be
130 preferred over _dtoa_r. */
131 #define _NO_LONGDBL
132 #if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
133 #undef _NO_LONGDBL
134 #endif
135
136 #define _NO_LONGLONG
137 #if defined _WANT_IO_LONG_LONG && defined __GNUC__
138 # undef _NO_LONGLONG
139 #endif
140
141 #include "floatio.h"
142 #define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */
143 /* An upper bound for how long a long prints in decimal. 4 / 13 approximates
144 log (2). Add one char for roundoff compensation and one for the sign. */
145 #define MAX_LONG_LEN ((CHAR_BIT * sizeof (long) - 1) * 4 / 13 + 2)
146 #else
147 #define BUF 40
148 #endif
149
150 /*
151 * Flags used during conversion.
152 */
153
154 #define LONG 0x01 /* l: long or double */
155 #define LONGDBL 0x02 /* L: long double or long long */
156 #define SHORT 0x04 /* h: short */
157 #define SUPPRESS 0x10 /* suppress assignment */
158 #define POINTER 0x20 /* weird %p pointer (`fake hex') */
159 #define NOSKIP 0x40 /* do not skip blanks */
160
161 /*
162 * The following are used in numeric conversions only:
163 * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
164 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
165 */
166
167 #define SIGNOK 0x80 /* +/- is (still) legal */
168 #define NDIGITS 0x100 /* no digits detected */
169
170 #define DPTOK 0x200 /* (float) decimal point is still legal */
171 #define EXPOK 0x400 /* (float) exponent (e+3, etc) still legal */
172
173 #define PFXOK 0x200 /* 0x prefix is (still) legal */
174 #define NZDIGITS 0x400 /* no zero digits detected */
175 #define NNZDIGITS 0x800 /* no non-zero digits detected */
176
177 #define VECTOR 0x2000 /* v: vector */
178 #define FIXEDPOINT 0x4000 /* r/R: fixed-point */
179 #define SIGNED 0x8000 /* r: signed fixed-point */
180
181 /*
182 * Conversion types.
183 */
184
185 #define CT_CHAR 0 /* %c conversion */
186 #define CT_CCL 1 /* %[...] conversion */
187 #define CT_STRING 2 /* %s conversion */
188 #define CT_INT 3 /* integer, i.e., strtol or strtoul */
189 #define CT_FLOAT 4 /* floating, i.e., strtod */
190
191 #if 0
192 #define u_char unsigned char
193 #endif
194 #define u_char char
195 #define u_long unsigned long
196
197 #ifndef _NO_LONGLONG
198 typedef unsigned long long u_long_long;
199 #endif
200
201 typedef union
202 {
203 char c[16] __attribute__ ((__aligned__ (16)));
204 short h[8];
205 long l[4];
206 int i[4];
207 float f[4];
208 } vec_union;
209
210 /*
211 * vfscanf
212 */
213
214 #define BufferEmpty (fp->_r <= 0 && __srefill(fp))
215
216 #ifndef _REENT_ONLY
217
218 int
219 _DEFUN (vfscanf, (fp, fmt, ap),
220 register FILE *__restrict fp _AND
221 _CONST char *__restrict fmt _AND
222 va_list ap)
223 {
224 CHECK_INIT(_REENT, fp);
225 return __svfscanf_r (_REENT, fp, fmt, ap);
226 }
227
228 int
__svfscanf(fp,fmt0,ap)229 __svfscanf (fp, fmt0, ap)
230 register FILE *fp;
231 char _CONST *fmt0;
232 va_list ap;
233 {
234 return __svfscanf_r (_REENT, fp, fmt0, ap);
235 }
236
237 #endif /* !_REENT_ONLY */
238
239 int
240 _DEFUN (_vfscanf_r, (data, fp, fmt, ap),
241 struct _reent *data _AND
242 register FILE *__restrict fp _AND
243 _CONST char *__restrict fmt _AND
244 va_list ap)
245 {
246 return __svfscanf_r (data, fp, fmt, ap);
247 }
248
249
250 int
__svfscanf_r(rptr,fp,fmt0,ap)251 __svfscanf_r (rptr, fp, fmt0, ap)
252 struct _reent *rptr;
253 register FILE *fp;
254 char _CONST *fmt0;
255 va_list ap;
256 {
257 register u_char *fmt = (u_char *) fmt0;
258 register int c; /* character from format, or conversion */
259 register int type; /* conversion type */
260 register size_t width; /* field width, or 0 */
261 register char *p; /* points into all kinds of strings */
262 register int n; /* handy integer */
263 register int flags; /* flags as defined above */
264 register char *p0; /* saves original value of p when necessary */
265 int orig_flags; /* saved flags used when processing vector */
266 int int_width; /* tmp area to store width when processing int */
267 int nassigned; /* number of fields assigned */
268 int nread; /* number of characters consumed from fp */
269 int base = 0; /* base argument to strtol/strtoul */
270 int nbytes = 1; /* number of bytes read from fmt string */
271 wchar_t wc; /* wchar to use to read format string */
272 char vec_sep; /* vector separator char */
273 char last_space_char; /* last white-space char eaten - needed for vec support */
274 int vec_read_count; /* number of vector items to read separately */
275 int looped; /* has vector processing looped */
276 u_long (*ccfn) () = 0; /* conversion function (strtol/strtoul) */
277 char ccltab[256]; /* character class table for %[...] */
278 char buf[BUF]; /* buffer for numeric conversions */
279 vec_union vec_buf;
280 char *lptr; /* literal pointer */
281 #ifdef _MB_CAPABLE
282 mbstate_t state; /* value to keep track of multibyte state */
283 #endif
284
285 char *ch_dest;
286 short *sp;
287 int *ip;
288 float *flp;
289 _LONG_DOUBLE *ldp;
290 double *dp;
291 long *lp;
292 #ifndef _NO_LONGLONG
293 long long *llp;
294 #else
295 u_long _uquad;
296 #endif
297
298 /* `basefix' is used to avoid `if' tests in the integer scanner */
299 static _CONST short basefix[17] =
300 {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
301
302 nassigned = 0;
303 nread = 0;
304 for (;;)
305 {
306 #ifndef _MB_CAPABLE
307 wc = *fmt;
308 #else
309 memset (&state, '\0', sizeof (state));
310 nbytes = _mbtowc_r (rptr, &wc, fmt, MB_CUR_MAX, &state);
311 #endif
312 fmt += nbytes;
313 if (wc == 0)
314 return nassigned;
315 if (nbytes == 1 && isspace (wc))
316 {
317 for (;;)
318 {
319 if (BufferEmpty)
320 return nassigned;
321 if (!isspace (*fp->_p))
322 break;
323 nread++, fp->_r--, fp->_p++;
324 }
325 continue;
326 }
327 if (wc != '%')
328 goto literal;
329 width = 0;
330 flags = 0;
331 vec_sep = ' ';
332 vec_read_count = 0;
333 looped = 0;
334
335 /*
336 * switch on the format. continue if done; break once format
337 * type is derived.
338 */
339
340 again:
341 c = *fmt++;
342
343 switch (c)
344 {
345 case '%':
346 literal:
347 lptr = fmt - nbytes;
348 for (n = 0; n < nbytes; ++n)
349 {
350 if (BufferEmpty)
351 goto input_failure;
352 if (*fp->_p != *lptr)
353 goto match_failure;
354 fp->_r--, fp->_p++;
355 nread++;
356 ++lptr;
357 }
358 continue;
359
360 case '*':
361 flags |= SUPPRESS;
362 goto again;
363 case ',':
364 case ';':
365 case ':':
366 case '_':
367 if (flags == SUPPRESS || flags == 0)
368 vec_sep = c;
369 goto again;
370 case 'l':
371 if (flags & SHORT)
372 continue; /* invalid format, don't process any further */
373 if (flags & LONG)
374 {
375 flags &= ~LONG;
376 flags &= ~VECTOR;
377 flags |= LONGDBL;
378 }
379 else
380 {
381 flags |= LONG;
382 if (flags & VECTOR)
383 vec_read_count = 4;
384 }
385 goto again;
386 case 'L':
387 flags |= LONGDBL;
388 flags &= ~VECTOR;
389 goto again;
390 case 'h':
391 flags |= SHORT;
392 if (flags & LONG)
393 continue; /* invalid format, don't process any further */
394 if (flags & VECTOR)
395 vec_read_count = 8;
396 goto again;
397 #ifdef __ALTIVEC__
398 case 'v':
399 flags |= VECTOR;
400 vec_read_count = (flags & SHORT) ? 8 : ((flags & LONG) ? 4 : 16);
401 goto again;
402 #endif
403 case '0':
404 case '1':
405 case '2':
406 case '3':
407 case '4':
408 case '5':
409 case '6':
410 case '7':
411 case '8':
412 case '9':
413 width = width * 10 + c - '0';
414 goto again;
415
416 /*
417 * Conversions. Those marked `compat' are for
418 * 4.[123]BSD compatibility.
419 *
420 * (According to ANSI, E and X formats are supposed to
421 * the same as e and x. Sorry about that.)
422 */
423
424 case 'D': /* compat */
425 flags |= LONG;
426 /* FALLTHROUGH */
427 case 'd':
428 type = CT_INT;
429 ccfn = (u_long (*)())_strtol_r;
430 base = 10;
431 break;
432
433 case 'i':
434 type = CT_INT;
435 ccfn = (u_long (*)())_strtol_r;
436 base = 0;
437 break;
438
439 case 'O': /* compat */
440 flags |= LONG;
441 /* FALLTHROUGH */
442 case 'o':
443 type = CT_INT;
444 ccfn = _strtoul_r;
445 base = 8;
446 break;
447
448 case 'u':
449 type = CT_INT;
450 ccfn = _strtoul_r;
451 base = 10;
452 break;
453
454 case 'X': /* compat XXX */
455 case 'x':
456 flags |= PFXOK; /* enable 0x prefixing */
457 type = CT_INT;
458 ccfn = _strtoul_r;
459 base = 16;
460 break;
461
462 #ifdef FLOATING_POINT
463 case 'E': /* compat XXX */
464 case 'G': /* compat XXX */
465 /* ANSI says that E,G and X behave the same way as e,g,x */
466 /* FALLTHROUGH */
467 case 'e':
468 case 'f':
469 case 'g':
470 type = CT_FLOAT;
471 if (flags & VECTOR)
472 vec_read_count = 4;
473 break;
474
475 # ifdef __SPE__
476 /* treat fixed-point like %f floating point */
477 case 'r':
478 flags |= SIGNED;
479 /* fallthrough */
480 case 'R':
481 flags |= FIXEDPOINT;
482 type = CT_FLOAT;
483 break;
484 # endif
485 #endif
486
487 case 's':
488 flags &= ~VECTOR;
489 type = CT_STRING;
490 break;
491
492 case '[':
493 fmt = __sccl (ccltab, fmt);
494 flags |= NOSKIP;
495 flags &= ~VECTOR;
496 type = CT_CCL;
497 break;
498
499 case 'c':
500 flags |= NOSKIP;
501 type = CT_CHAR;
502 if (flags & VECTOR)
503 {
504 /* not allowed to have h or l with c specifier */
505 if (flags & (LONG | SHORT))
506 continue; /* invalid format don't process any further */
507 width = 0;
508 vec_read_count = 16;
509 }
510 break;
511
512 case 'p': /* pointer format is like hex */
513 flags |= POINTER | PFXOK;
514 type = CT_INT;
515 ccfn = _strtoul_r;
516 base = 16;
517 break;
518
519 case 'n':
520 if (flags & SUPPRESS) /* ??? */
521 continue;
522 flags &= ~VECTOR;
523 if (flags & SHORT)
524 {
525 sp = va_arg (ap, short *);
526 *sp = nread;
527 }
528 else if (flags & LONG)
529 {
530 lp = va_arg (ap, long *);
531 *lp = nread;
532 }
533 #ifndef _NO_LONGLONG
534 else if (flags & LONGDBL)
535 {
536 llp = va_arg (ap, long long*);
537 *llp = nread;
538 }
539 #endif
540 else
541 {
542 ip = va_arg (ap, int *);
543 *ip = nread;
544 }
545 continue;
546
547 /*
548 * Disgusting backwards compatibility hacks. XXX
549 */
550 case '\0': /* compat */
551 return EOF;
552
553 default: /* compat */
554 if (isupper (c))
555 flags |= LONG;
556 type = CT_INT;
557 ccfn = (u_long (*)())_strtol_r;
558 base = 10;
559 break;
560 }
561
562 process:
563 /*
564 * We have a conversion that requires input.
565 */
566 if (BufferEmpty)
567 goto input_failure;
568
569 /*
570 * Consume leading white space, except for formats that
571 * suppress this.
572 */
573 last_space_char = '\0';
574
575 if ((flags & NOSKIP) == 0)
576 {
577 while (isspace (*fp->_p))
578 {
579 last_space_char = *fp->_p;
580 nread++;
581 if (--fp->_r > 0)
582 fp->_p++;
583 else
584 #ifndef CYGNUS_NEC
585 if (__srefill (fp))
586 #endif
587 goto input_failure;
588 }
589 /*
590 * Note that there is at least one character in the
591 * buffer, so conversions that do not set NOSKIP ca
592 * no longer result in an input failure.
593 */
594 }
595
596 /* for vector formats process separator characters after first loop */
597 if (looped && (flags & VECTOR))
598 {
599 flags = orig_flags;
600 /* all formats other than default char have a separator char */
601 if (vec_sep != ' ' || type != CT_CHAR)
602 {
603 if (vec_sep == ' ' && last_space_char != ' ' ||
604 vec_sep != ' ' && *fp->_p != vec_sep)
605 goto match_failure;
606 if (vec_sep != ' ')
607 {
608 nread++;
609 if (--fp->_r > 0)
610 fp->_p++;
611 else
612 #ifndef CYGNUS_NEC
613 if (__srefill (fp))
614 #endif
615 goto input_failure;
616 }
617 }
618 /* after eating the separator char, we must eat any white-space
619 after the separator char that precedes the data to convert */
620 if ((flags & NOSKIP) == 0)
621 {
622 while (isspace (*fp->_p))
623 {
624 last_space_char = *fp->_p;
625 nread++;
626 if (--fp->_r > 0)
627 fp->_p++;
628 else
629 #ifndef CYGNUS_NEC
630 if (__srefill (fp))
631 #endif
632 goto input_failure;
633 }
634 }
635
636 }
637 else /* save to counter-act changes made to flags when processing */
638 orig_flags = flags;
639
640 /*
641 * Do the conversion.
642 */
643 switch (type)
644 {
645
646 case CT_CHAR:
647 /* scan arbitrary characters (sets NOSKIP) */
648 if (width == 0)
649 width = 1;
650 if (flags & SUPPRESS)
651 {
652 size_t sum = 0;
653
654 for (;;)
655 {
656 if ((n = fp->_r) < (int)width)
657 {
658 sum += n;
659 width -= n;
660 fp->_p += n;
661 #ifndef CYGNUS_NEC
662 if (__srefill (fp))
663 {
664 #endif
665 if (sum == 0)
666 goto input_failure;
667 break;
668 #ifndef CYGNUS_NEC
669 }
670 #endif
671 }
672 else
673 {
674 sum += width;
675 fp->_r -= width;
676 fp->_p += width;
677 break;
678 }
679 }
680 nread += sum;
681 }
682 else
683 {
684 int n = width;
685 if (!looped)
686 {
687 if (flags & VECTOR)
688 ch_dest = vec_buf.c;
689 else
690 ch_dest = va_arg (ap, char *);
691 }
692 #ifdef CYGNUS_NEC
693 /* Kludge city for the moment */
694 if (fp->_r == 0)
695 goto input_failure;
696
697 while (n && fp->_r)
698 {
699 *ch_dest++ = *(fp->_p++);
700 n--;
701 fp->_r--;
702 nread++;
703 }
704 #else
705 size_t r = fread (ch_dest, 1, width, fp);
706
707 if (r == 0)
708 goto input_failure;
709 nread += r;
710 ch_dest += r;
711 #endif
712 if (!(flags & VECTOR))
713 nassigned++;
714 }
715 break;
716
717 case CT_CCL:
718 /* scan a (nonempty) character class (sets NOSKIP) */
719 if (width == 0)
720 width = ~0; /* `infinity' */
721 /* take only those things in the class */
722 if (flags & SUPPRESS)
723 {
724 n = 0;
725 while (ccltab[*fp->_p])
726 {
727 n++, fp->_r--, fp->_p++;
728 if (--width == 0)
729 break;
730 if (BufferEmpty)
731 {
732 if (n == 0)
733 goto input_failure;
734 break;
735 }
736 }
737 if (n == 0)
738 goto match_failure;
739 }
740 else
741 {
742 p0 = p = va_arg (ap, char *);
743 while (ccltab[*fp->_p])
744 {
745 fp->_r--;
746 *p++ = *fp->_p++;
747 if (--width == 0)
748 break;
749 if (BufferEmpty)
750 {
751 if (p == p0)
752 goto input_failure;
753 break;
754 }
755 }
756 n = p - p0;
757 if (n == 0)
758 goto match_failure;
759 *p = 0;
760 nassigned++;
761 }
762 nread += n;
763 break;
764
765 case CT_STRING:
766 /* like CCL, but zero-length string OK, & no NOSKIP */
767 if (width == 0)
768 width = ~0;
769 if (flags & SUPPRESS)
770 {
771 n = 0;
772 while (!isspace (*fp->_p))
773 {
774 n++, fp->_r--, fp->_p++;
775 if (--width == 0)
776 break;
777 if (BufferEmpty)
778 break;
779 }
780 nread += n;
781 }
782 else
783 {
784 p0 = p = va_arg (ap, char *);
785 while (!isspace (*fp->_p))
786 {
787 fp->_r--;
788 *p++ = *fp->_p++;
789 if (--width == 0)
790 break;
791 if (BufferEmpty)
792 break;
793 }
794 *p = 0;
795 nread += p - p0;
796 nassigned++;
797 }
798 continue;
799
800 case CT_INT:
801 {
802 unsigned int_width_left = 0;
803 int skips = 0;
804 int_width = width;
805 #ifdef hardway
806 if (int_width == 0 || int_width > sizeof (buf) - 1)
807 #else
808 /* size_t is unsigned, hence this optimisation */
809 if (int_width - 1 > sizeof (buf) - 2)
810 #endif
811 {
812 int_width_left = width - (sizeof (buf) - 1);
813 int_width = sizeof (buf) - 1;
814 }
815 flags |= SIGNOK | NDIGITS | NZDIGITS | NNZDIGITS;
816 for (p = buf; int_width; int_width--)
817 {
818 c = *fp->_p;
819 /*
820 * Switch on the character; `goto ok' if we
821 * accept it as a part of number.
822 */
823 switch (c)
824 {
825 /*
826 * The digit 0 is always legal, but is special.
827 * For %i conversions, if no digits (zero or nonzero)
828 * have been scanned (only signs), we will have base==0.
829 * In that case, we should set it to 8 and enable 0x
830 * prefixing. Also, if we have not scanned zero digits
831 * before this, do not turn off prefixing (someone else
832 * will turn it off if we have scanned any nonzero digits).
833 */
834 case '0':
835 if (! (flags & NNZDIGITS))
836 goto ok;
837 if (base == 0)
838 {
839 base = 8;
840 flags |= PFXOK;
841 }
842 if (flags & NZDIGITS)
843 {
844 flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
845 goto ok;
846 }
847 flags &= ~(SIGNOK | PFXOK | NDIGITS);
848 if (int_width_left)
849 {
850 int_width_left--;
851 int_width++;
852 }
853 ++skips;
854 goto skip;
855
856 /* 1 through 7 always legal */
857 case '1':
858 case '2':
859 case '3':
860 case '4':
861 case '5':
862 case '6':
863 case '7':
864 base = basefix[base];
865 flags &= ~(SIGNOK | PFXOK | NDIGITS | NNZDIGITS);
866 goto ok;
867
868 /* digits 8 and 9 ok iff decimal or hex */
869 case '8':
870 case '9':
871 base = basefix[base];
872 if (base <= 8)
873 break; /* not legal here */
874 flags &= ~(SIGNOK | PFXOK | NDIGITS | NNZDIGITS);
875 goto ok;
876
877 /* letters ok iff hex */
878 case 'A':
879 case 'B':
880 case 'C':
881 case 'D':
882 case 'E':
883 case 'F':
884 case 'a':
885 case 'b':
886 case 'c':
887 case 'd':
888 case 'e':
889 case 'f':
890 /* no need to fix base here */
891 if (base <= 10)
892 break; /* not legal here */
893 flags &= ~(SIGNOK | PFXOK | NDIGITS | NNZDIGITS);
894 goto ok;
895
896 /* sign ok only as first character */
897 case '+':
898 case '-':
899 if (flags & SIGNOK)
900 {
901 flags &= ~SIGNOK;
902 goto ok;
903 }
904 break;
905
906 /* x ok iff flag still set & 2nd char */
907 case 'x':
908 case 'X':
909 if (flags & PFXOK && p == buf + 1)
910 {
911 base = 16;/* if %i */
912 flags &= ~PFXOK;
913 /* We must reset the NZDIGITS and NDIGITS
914 flags that would have been unset by seeing
915 the zero that preceded the X or x. */
916 flags |= NZDIGITS | NDIGITS;
917 goto ok;
918 }
919 break;
920 }
921
922 /*
923 * If we got here, c is not a legal character
924 * for a number. Stop accumulating digits.
925 */
926 break;
927 ok:
928 /*
929 * c is legal: store it and look at the next.
930 */
931 *p++ = c;
932 skip:
933 if (--fp->_r > 0)
934 fp->_p++;
935 else
936 #ifndef CYGNUS_NEC
937 if (__srefill (fp))
938 #endif
939 break; /* EOF */
940 }
941 /*
942 * If we had only a sign, it is no good; push back the sign.
943 * If the number ends in `x', it was [sign] '0' 'x', so push back
944 * the x and treat it as [sign] '0'.
945 */
946 if (flags & NDIGITS)
947 {
948 if (p > buf)
949 _CAST_VOID ungetc (*(u_char *)-- p, fp);
950 goto match_failure;
951 }
952 c = ((u_char *) p)[-1];
953 if (c == 'x' || c == 'X')
954 {
955 --p;
956 /*(void)*/ ungetc (c, fp);
957 }
958 if ((flags & SUPPRESS) == 0)
959 {
960 u_long res;
961
962 *p = 0;
963 res = (*ccfn) (rptr, buf, (char **) NULL, base);
964 if ((flags & POINTER) && !(flags & VECTOR))
965 *(va_arg (ap, _PTR *)) = (_PTR) (unsigned _POINTER_INT) res;
966 else if (flags & SHORT)
967 {
968 if (!(flags & VECTOR))
969 sp = va_arg (ap, short *);
970 else if (!looped)
971 sp = vec_buf.h;
972 *sp++ = res;
973 }
974 else if (flags & LONG)
975 {
976 if (!(flags & VECTOR))
977 lp = va_arg (ap, long *);
978 else if (!looped)
979 lp = vec_buf.l;
980 *lp++ = res;
981 }
982 #ifndef _NO_LONGLONG
983 else if (flags & LONGDBL)
984 {
985 u_long_long resll;
986 if (ccfn == _strtoul_r)
987 resll = _strtoull_r (rptr, buf, (char **) NULL, base);
988 else
989 resll = _strtoll_r (rptr, buf, (char **) NULL, base);
990 llp = va_arg (ap, long long*);
991 *llp = resll;
992 }
993 #endif
994 else
995 {
996 if (!(flags & VECTOR))
997 {
998 ip = va_arg (ap, int *);
999 *ip++ = res;
1000 }
1001 else
1002 {
1003 if (!looped)
1004 ch_dest = vec_buf.c;
1005 *ch_dest++ = (char)res;
1006 }
1007 }
1008 if (!(flags & VECTOR))
1009 nassigned++;
1010 }
1011 nread += p - buf + skips;
1012 break;
1013 }
1014
1015 #ifdef FLOATING_POINT
1016 case CT_FLOAT:
1017 {
1018 /* scan a floating point number as if by strtod */
1019 /* This code used to assume that the number of digits is reasonable.
1020 However, ANSI / ISO C makes no such stipulation; we have to get
1021 exact results even when there is an unreasonable amount of
1022 leading zeroes. */
1023 long leading_zeroes = 0;
1024 long zeroes, exp_adjust;
1025 char *exp_start = NULL;
1026 unsigned fl_width = width;
1027 unsigned width_left = 0;
1028 #ifdef hardway
1029 if (fl_width == 0 || fl_width > sizeof (buf) - 1)
1030 #else
1031 /* size_t is unsigned, hence this optimisation */
1032 if (fl_width - 1 > sizeof (buf) - 2)
1033 #endif
1034 {
1035 width_left = fl_width - (sizeof (buf) - 1);
1036 fl_width = sizeof (buf) - 1;
1037 }
1038 flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
1039 zeroes = 0;
1040 exp_adjust = 0;
1041 for (p = buf; fl_width; )
1042 {
1043 c = *fp->_p;
1044 /*
1045 * This code mimicks the integer conversion
1046 * code, but is much simpler.
1047 */
1048 switch (c)
1049 {
1050
1051 case '0':
1052 if (flags & NDIGITS)
1053 {
1054 flags &= ~SIGNOK;
1055 zeroes++;
1056 if (width_left)
1057 {
1058 width_left--;
1059 fl_width++;
1060 }
1061 goto fskip;
1062 }
1063 /* Fall through. */
1064 case '1':
1065 case '2':
1066 case '3':
1067 case '4':
1068 case '5':
1069 case '6':
1070 case '7':
1071 case '8':
1072 case '9':
1073 flags &= ~(SIGNOK | NDIGITS);
1074 goto fok;
1075
1076 case '+':
1077 case '-':
1078 if (flags & SIGNOK)
1079 {
1080 flags &= ~SIGNOK;
1081 goto fok;
1082 }
1083 break;
1084 case '.':
1085 if (flags & DPTOK)
1086 {
1087 flags &= ~(SIGNOK | DPTOK);
1088 leading_zeroes = zeroes;
1089 goto fok;
1090 }
1091 break;
1092 case 'e':
1093 case 'E':
1094 /* no exponent without some digits */
1095 if ((flags & (NDIGITS | EXPOK)) == EXPOK
1096 || ((flags & EXPOK) && zeroes))
1097 {
1098 if (! (flags & DPTOK))
1099 {
1100 exp_adjust = zeroes - leading_zeroes;
1101 exp_start = p;
1102 }
1103 flags =
1104 (flags & ~(EXPOK | DPTOK)) |
1105 SIGNOK | NDIGITS;
1106 zeroes = 0;
1107 goto fok;
1108 }
1109 break;
1110 }
1111 break;
1112 fok:
1113 *p++ = c;
1114 fskip:
1115 fl_width--;
1116 ++nread;
1117 if (--fp->_r > 0)
1118 fp->_p++;
1119 else
1120 #ifndef CYGNUS_NEC
1121 if (__srefill (fp))
1122 #endif
1123 break; /* EOF */
1124 }
1125 if (zeroes)
1126 flags &= ~NDIGITS;
1127 /*
1128 * If no digits, might be missing exponent digits
1129 * (just give back the exponent) or might be missing
1130 * regular digits, but had sign and/or decimal point.
1131 */
1132 if (flags & NDIGITS)
1133 {
1134 if (flags & EXPOK)
1135 {
1136 /* no digits at all */
1137 while (p > buf)
1138 {
1139 ungetc (*(u_char *)-- p, fp);
1140 --nread;
1141 }
1142 goto match_failure;
1143 }
1144 /* just a bad exponent (e and maybe sign) */
1145 c = *(u_char *)-- p;
1146 --nread;
1147 if (c != 'e' && c != 'E')
1148 {
1149 _CAST_VOID ungetc (c, fp); /* sign */
1150 c = *(u_char *)-- p;
1151 --nread;
1152 }
1153 _CAST_VOID ungetc (c, fp);
1154 }
1155 if ((flags & SUPPRESS) == 0)
1156 {
1157 #ifdef _NO_LONGDBL
1158 double res;
1159 #else /* !_NO_LONG_DBL */
1160 long double res;
1161 #endif /* !_NO_LONG_DBL */
1162 long new_exp = 0;
1163
1164 *p = 0;
1165 if ((flags & (DPTOK | EXPOK)) == EXPOK)
1166 {
1167 exp_adjust = zeroes - leading_zeroes;
1168 new_exp = -exp_adjust;
1169 exp_start = p;
1170 }
1171 else if (exp_adjust)
1172 new_exp = _strtol_r (rptr, (exp_start + 1), NULL, 10) - exp_adjust;
1173 if (exp_adjust)
1174 {
1175
1176 /* If there might not be enough space for the new exponent,
1177 truncate some trailing digits to make room. */
1178 if (exp_start >= buf + sizeof (buf) - MAX_LONG_LEN)
1179 exp_start = buf + sizeof (buf) - MAX_LONG_LEN - 1;
1180 sprintf (exp_start, "e%ld", new_exp);
1181 }
1182 #ifdef __SPE__
1183 if (flags & FIXEDPOINT)
1184 {
1185 __uint64_t ufix64;
1186 if (flags & SIGNED)
1187 ufix64 = (__uint64_t)_strtosfix64_r (rptr, buf, NULL);
1188 else
1189 ufix64 = _strtoufix64_r (rptr, buf, NULL);
1190 if (flags & SHORT)
1191 {
1192 __uint16_t *sp = va_arg (ap, __uint16_t *);
1193 *sp = (__uint16_t)(ufix64 >> 48);
1194 }
1195 else if (flags & LONG)
1196 {
1197 __uint64_t *llp = va_arg (ap, __uint64_t *);
1198 *llp = ufix64;
1199 }
1200 else
1201 {
1202 __uint32_t *lp = va_arg (ap, __uint32_t *);
1203 *lp = (__uint32_t)(ufix64 >> 32);
1204 }
1205 nassigned++;
1206 break;
1207 }
1208
1209 #endif /* __SPE__ */
1210 #ifdef _NO_LONGDBL
1211 res = _strtod_r (rptr, buf, NULL);
1212 #else /* !_NO_LONGDBL */
1213 res = _strtold_r (rptr, buf, NULL);
1214 #endif /* !_NO_LONGDBL */
1215 if (flags & LONG)
1216 {
1217 dp = va_arg (ap, double *);
1218 *dp = res;
1219 }
1220 else if (flags & LONGDBL)
1221 {
1222 ldp = va_arg (ap, _LONG_DOUBLE *);
1223 *ldp = res;
1224 }
1225 else
1226 {
1227 if (!(flags & VECTOR))
1228 flp = va_arg (ap, float *);
1229 else if (!looped)
1230 flp = vec_buf.f;
1231 *flp++ = res;
1232 }
1233 if (!(flags & VECTOR))
1234 nassigned++;
1235 }
1236 break;
1237 }
1238 #endif /* FLOATING_POINT */
1239 }
1240 if (vec_read_count-- > 1)
1241 {
1242 looped = 1;
1243 goto process;
1244 }
1245 if (flags & VECTOR)
1246 {
1247 int i;
1248 unsigned long *vp = va_arg (ap, unsigned long *);
1249 for (i = 0; i < 4; ++i)
1250 *vp++ = vec_buf.l[i];
1251 nassigned++;
1252 }
1253 }
1254 input_failure:
1255 return nassigned ? nassigned : -1;
1256 match_failure:
1257 return nassigned;
1258 }
1259
1260