fixes for host gcc 4.6.1
[zpugcc/jano.git] / toolchain / gcc / newlib / libc / machine / powerpc / vfscanf.c
blob37d2da7fe3dbc02c2c15a639950cc4b8d9fa4dd7
1 /*
2 FUNCTION
3 <<vscanf>>, <<vfscanf>>, <<vsscanf>>---format argument list
5 INDEX
6 vscanf
7 INDEX
8 vfscanf
9 INDEX
10 vsscanf
12 ANSI_SYNOPSIS
13 #include <stdio.h>
14 #include <stdarg.h>
15 int vscanf(const char *<[fmt]>, va_list <[list]>);
16 int vfscanf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
17 int vsscanf(const char *<[str]>, const char *<[fmt]>, va_list <[list]>);
19 int _vscanf_r(void *<[reent]>, const char *<[fmt]>,
20 va_list <[list]>);
21 int _vfscanf_r(void *<[reent]>, FILE *<[fp]>, const char *<[fmt]>,
22 va_list <[list]>);
23 int _vsscanf_r(void *<[reent]>, const char *<[str]>, const char *<[fmt]>,
24 va_list <[list]>);
26 TRAD_SYNOPSIS
27 #include <stdio.h>
28 #include <varargs.h>
29 int vscanf( <[fmt]>, <[ist]>)
30 char *<[fmt]>;
31 va_list <[list]>;
33 int vfscanf( <[fp]>, <[fmt]>, <[list]>)
34 FILE *<[fp]>;
35 char *<[fmt]>;
36 va_list <[list]>;
38 int vsscanf( <[str]>, <[fmt]>, <[list]>)
39 char *<[str]>;
40 char *<[fmt]>;
41 va_list <[list]>;
43 int _vscanf_r( <[reent]>, <[fmt]>, <[ist]>)
44 char *<[reent]>;
45 char *<[fmt]>;
46 va_list <[list]>;
48 int _vfscanf_r( <[reent]>, <[fp]>, <[fmt]>, <[list]>)
49 char *<[reent]>;
50 FILE *<[fp]>;
51 char *<[fmt]>;
52 va_list <[list]>;
54 int _vsscanf_r( <[reent]>, <[str]>, <[fmt]>, <[list]>)
55 char *<[reent]>;
56 char *<[str]>;
57 char *<[fmt]>;
58 va_list <[list]>;
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.
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.
73 If <<vscanf>> attempts to read at end-of-file, the return value
74 is <<EOF>>.
76 If no fields were stored, the return value is <<0>>.
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.
82 PORTABILITY
83 These are GNU extensions.
85 Supporting OS subroutines required:
88 /*-
89 * Copyright (c) 1990 The Regents of the University of California.
90 * All rights reserved.
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.
105 #include <_ansi.h>
106 #include <ctype.h>
107 #include <stdio.h>
108 #include <stdlib.h>
109 #include <limits.h>
110 #include <wchar.h>
111 #include <string.h>
112 #ifdef _HAVE_STDC
113 #include <stdarg.h>
114 #else
115 #include <varargs.h>
116 #endif
117 #include "local.h"
119 #ifndef NO_FLOATING_POINT
120 #define FLOATING_POINT
121 #endif
123 #ifdef FLOATING_POINT
124 #include <float.h>
126 /* Currently a test is made to see if long double processing is warranted.
127 This could be changed in the future should the _ldtoa_r code be
128 preferred over _dtoa_r. */
129 #define _NO_LONGDBL
130 #if defined WANT_IO_LONG_DBL && (LDBL_MANT_DIG > DBL_MANT_DIG)
131 #undef _NO_LONGDBL
132 extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr));
133 #endif
135 #define _NO_LONGLONG
136 #if defined WANT_PRINTF_LONG_LONG && defined __GNUC__
137 # undef _NO_LONGLONG
138 #endif
140 #include "floatio.h"
141 #define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */
142 /* An upper bound for how long a long prints in decimal. 4 / 13 approximates
143 log (2). Add one char for roundoff compensation and one for the sign. */
144 #define MAX_LONG_LEN ((CHAR_BIT * sizeof (long) - 1) * 4 / 13 + 2)
145 #else
146 #define BUF 40
147 #endif
150 * Flags used during conversion.
153 #define LONG 0x01 /* l: long or double */
154 #define LONGDBL 0x02 /* L: long double or long long */
155 #define SHORT 0x04 /* h: short */
156 #define SUPPRESS 0x08 /* suppress assignment */
157 #define POINTER 0x10 /* weird %p pointer (`fake hex') */
158 #define NOSKIP 0x20 /* do not skip blanks */
161 * The following are used in numeric conversions only:
162 * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
163 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
166 #define SIGNOK 0x40 /* +/- is (still) legal */
167 #define NDIGITS 0x80 /* no digits detected */
169 #define DPTOK 0x100 /* (float) decimal point is still legal */
170 #define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */
172 #define PFXOK 0x100 /* 0x prefix is (still) legal */
173 #define NZDIGITS 0x200 /* no zero digits detected */
175 #define VECTOR 0x400 /* v: vector */
176 #define FIXEDPOINT 0x800 /* r/R: fixed-point */
177 #define SIGNED 0x1000 /* r: signed fixed-point */
180 * Conversion types.
183 #define CT_CHAR 0 /* %c conversion */
184 #define CT_CCL 1 /* %[...] conversion */
185 #define CT_STRING 2 /* %s conversion */
186 #define CT_INT 3 /* integer, i.e., strtol or strtoul */
187 #define CT_FLOAT 4 /* floating, i.e., strtod */
189 #if 0
190 #define u_char unsigned char
191 #endif
192 #define u_char char
193 #define u_long unsigned long
195 #ifndef _NO_LONGLONG
196 typedef unsigned long long u_long_long;
197 #endif
199 typedef union
201 char c[16] __attribute__ ((__aligned__ (16)));
202 short h[8];
203 long l[4];
204 int i[4];
205 float f[4];
206 } vec_union;
208 /*static*/ u_char *__sccl ();
211 * vfscanf
214 #define BufferEmpty (fp->_r <= 0 && __srefill(fp))
216 #ifndef _REENT_ONLY
219 _DEFUN (vfscanf, (fp, fmt, ap),
220 register FILE *fp _AND
221 _CONST char *fmt _AND
222 va_list ap)
224 CHECK_INIT(fp);
225 return __svfscanf_r (fp->_data, fp, fmt, ap);
229 __svfscanf (fp, fmt0, ap)
230 register FILE *fp;
231 char _CONST *fmt0;
232 va_list ap;
234 return __svfscanf_r (_REENT, fp, fmt0, ap);
237 #endif /* !_REENT_ONLY */
240 _DEFUN (_vfscanf_r, (data, fp, fmt, ap),
241 struct _reent *data _AND
242 register FILE *fp _AND
243 _CONST char *fmt _AND
244 va_list ap)
246 return __svfscanf_r (data, fp, fmt, ap);
251 __svfscanf_r (rptr, fp, fmt0, ap)
252 struct _reent *rptr;
253 register FILE *fp;
254 char _CONST *fmt0;
255 va_list ap;
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
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
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};
302 nassigned = 0;
303 nread = 0;
304 for (;;)
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))
317 for (;;)
319 if (BufferEmpty)
320 return nassigned;
321 if (!isspace (*fp->_p))
322 break;
323 nread++, fp->_r--, fp->_p++;
325 continue;
327 if (wc != '%')
328 goto literal;
329 width = 0;
330 flags = 0;
331 vec_sep = ' ';
332 vec_read_count = 0;
333 looped = 0;
336 * switch on the format. continue if done; break once format
337 * type is derived.
340 again:
341 c = *fmt++;
343 switch (c)
345 case '%':
346 literal:
347 lptr = fmt - nbytes;
348 for (n = 0; n < nbytes; ++n)
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;
358 continue;
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)
375 flags &= ~LONG;
376 flags &= ~VECTOR;
377 flags |= LONGDBL;
379 else
381 flags |= LONG;
382 if (flags & VECTOR)
383 vec_read_count = 4;
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;
417 * Conversions. Those marked `compat' are for
418 * 4.[123]BSD compatibility.
420 * (According to ANSI, E and X formats are supposed to
421 * the same as e and x. Sorry about that.)
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;
433 case 'i':
434 type = CT_INT;
435 ccfn = (u_long (*)())_strtol_r;
436 base = 0;
437 break;
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;
448 case 'u':
449 type = CT_INT;
450 ccfn = _strtoul_r;
451 base = 10;
452 break;
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;
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;
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
487 case 's':
488 flags &= ~VECTOR;
489 type = CT_STRING;
490 break;
492 case '[':
493 fmt = __sccl (ccltab, fmt);
494 flags |= NOSKIP;
495 flags &= ~VECTOR;
496 type = CT_CCL;
497 break;
499 case 'c':
500 flags |= NOSKIP;
501 type = CT_CHAR;
502 if (flags & VECTOR)
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;
510 break;
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;
519 case 'n':
520 if (flags & SUPPRESS) /* ??? */
521 continue;
522 flags &= ~VECTOR;
523 if (flags & SHORT)
525 sp = va_arg (ap, short *);
526 *sp = nread;
528 else if (flags & LONG)
530 lp = va_arg (ap, long *);
531 *lp = nread;
533 #ifndef _NO_LONGLONG
534 else if (flags & LONGDBL)
536 llp = va_arg (ap, long long*);
537 *llp = nread;
539 #endif
540 else
542 ip = va_arg (ap, int *);
543 *ip = nread;
545 continue;
548 * Disgusting backwards compatibility hacks. XXX
550 case '\0': /* compat */
551 return EOF;
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;
562 process:
564 * We have a conversion that requires input.
566 if (BufferEmpty)
567 goto input_failure;
570 * Consume leading white space, except for formats that
571 * suppress this.
573 last_space_char = '\0';
575 if ((flags & NOSKIP) == 0)
577 while (isspace (*fp->_p))
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;
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.
596 /* for vector formats process separator characters after first loop */
597 if (looped && (flags & VECTOR))
599 flags = orig_flags;
600 /* all formats other than default char have a separator char */
601 if (vec_sep != ' ' || type != CT_CHAR)
603 if (vec_sep == ' ' && last_space_char != ' ' ||
604 vec_sep != ' ' && *fp->_p != vec_sep)
605 goto match_failure;
606 if (vec_sep != ' ')
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;
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)
622 while (isspace (*fp->_p))
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;
637 else /* save to counter-act changes made to flags when processing */
638 orig_flags = flags;
641 * Do the conversion.
643 switch (type)
646 case CT_CHAR:
647 /* scan arbitrary characters (sets NOSKIP) */
648 if (width == 0)
649 width = 1;
650 if (flags & SUPPRESS)
652 size_t sum = 0;
654 for (;;)
656 if ((n = fp->_r) < (int)width)
658 sum += n;
659 width -= n;
660 fp->_p += n;
661 #ifndef CYGNUS_NEC
662 if (__srefill (fp))
664 #endif
665 if (sum == 0)
666 goto input_failure;
667 break;
668 #ifndef CYGNUS_NEC
670 #endif
672 else
674 sum += width;
675 fp->_r -= width;
676 fp->_p += width;
677 break;
680 nread += sum;
682 else
684 int n = width;
685 if (!looped)
687 if (flags & VECTOR)
688 ch_dest = vec_buf.c;
689 else
690 ch_dest = va_arg (ap, char *);
692 #ifdef CYGNUS_NEC
693 /* Kludge city for the moment */
694 if (fp->_r == 0)
695 goto input_failure;
697 while (n && fp->_r)
699 *ch_dest++ = *(fp->_p++);
700 n--;
701 fp->_r--;
702 nread++;
704 #else
705 size_t r = fread (ch_dest, 1, width, fp);
707 if (r == 0)
708 goto input_failure;
709 nread += r;
710 ch_dest += r;
711 #endif
712 if (!(flags & VECTOR))
713 nassigned++;
715 break;
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)
724 n = 0;
725 while (ccltab[*fp->_p])
727 n++, fp->_r--, fp->_p++;
728 if (--width == 0)
729 break;
730 if (BufferEmpty)
732 if (n == 0)
733 goto input_failure;
734 break;
737 if (n == 0)
738 goto match_failure;
740 else
742 p0 = p = va_arg (ap, char *);
743 while (ccltab[*fp->_p])
745 fp->_r--;
746 *p++ = *fp->_p++;
747 if (--width == 0)
748 break;
749 if (BufferEmpty)
751 if (p == p0)
752 goto input_failure;
753 break;
756 n = p - p0;
757 if (n == 0)
758 goto match_failure;
759 *p = 0;
760 nassigned++;
762 nread += n;
763 break;
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)
771 n = 0;
772 while (!isspace (*fp->_p))
774 n++, fp->_r--, fp->_p++;
775 if (--width == 0)
776 break;
777 if (BufferEmpty)
778 break;
780 nread += n;
782 else
784 p0 = p = va_arg (ap, char *);
785 while (!isspace (*fp->_p))
787 fp->_r--;
788 *p++ = *fp->_p++;
789 if (--width == 0)
790 break;
791 if (BufferEmpty)
792 break;
794 *p = 0;
795 nread += p - p0;
796 nassigned++;
798 continue;
800 case CT_INT:
801 /* scan an integer as if by strtol/strtoul */
802 int_width = width;
803 #ifdef hardway
804 if (int_width == 0 || int_width > sizeof (buf) - 1)
805 int_width = sizeof (buf) - 1;
806 #else
807 /* size_t is unsigned, hence this optimisation */
808 if (--int_width > sizeof (buf) - 2)
809 int_width = sizeof (buf) - 2;
810 int_width++;
811 #endif
812 flags |= SIGNOK | NDIGITS | NZDIGITS;
813 for (p = buf; int_width; int_width--)
815 c = *fp->_p;
817 * Switch on the character; `goto ok' if we
818 * accept it as a part of number.
820 switch (c)
823 * The digit 0 is always legal, but is special.
824 * For %i conversions, if no digits (zero or nonzero)
825 * have been scanned (only signs), we will have base==0.
826 * In that case, we should set it to 8 and enable 0x
827 * prefixing. Also, if we have not scanned zero digits
828 * before this, do not turn off prefixing (someone else
829 * will turn it off if we have scanned any nonzero digits).
831 case '0':
832 if (base == 0)
834 base = 8;
835 flags |= PFXOK;
837 if (flags & NZDIGITS)
838 flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
839 else
840 flags &= ~(SIGNOK | PFXOK | NDIGITS);
841 goto ok;
843 /* 1 through 7 always legal */
844 case '1':
845 case '2':
846 case '3':
847 case '4':
848 case '5':
849 case '6':
850 case '7':
851 base = basefix[base];
852 flags &= ~(SIGNOK | PFXOK | NDIGITS);
853 goto ok;
855 /* digits 8 and 9 ok iff decimal or hex */
856 case '8':
857 case '9':
858 base = basefix[base];
859 if (base <= 8)
860 break; /* not legal here */
861 flags &= ~(SIGNOK | PFXOK | NDIGITS);
862 goto ok;
864 /* letters ok iff hex */
865 case 'A':
866 case 'B':
867 case 'C':
868 case 'D':
869 case 'E':
870 case 'F':
871 case 'a':
872 case 'b':
873 case 'c':
874 case 'd':
875 case 'e':
876 case 'f':
877 /* no need to fix base here */
878 if (base <= 10)
879 break; /* not legal here */
880 flags &= ~(SIGNOK | PFXOK | NDIGITS);
881 goto ok;
883 /* sign ok only as first character */
884 case '+':
885 case '-':
886 if (flags & SIGNOK)
888 flags &= ~SIGNOK;
889 goto ok;
891 break;
893 /* x ok iff flag still set & 2nd char */
894 case 'x':
895 case 'X':
896 if (flags & PFXOK && p == buf + 1)
898 base = 16;/* if %i */
899 flags &= ~PFXOK;
900 goto ok;
902 break;
906 * If we got here, c is not a legal character
907 * for a number. Stop accumulating digits.
909 break;
912 * c is legal: store it and look at the next.
914 *p++ = c;
915 if (--fp->_r > 0)
916 fp->_p++;
917 else
918 #ifndef CYGNUS_NEC
919 if (__srefill (fp))
920 #endif
921 break; /* EOF */
924 * If we had only a sign, it is no good; push back the sign.
925 * If the number ends in `x', it was [sign] '0' 'x', so push back
926 * the x and treat it as [sign] '0'.
928 if (flags & NDIGITS)
930 if (p > buf)
931 _CAST_VOID ungetc (*(u_char *)-- p, fp);
932 goto match_failure;
934 c = ((u_char *) p)[-1];
935 if (c == 'x' || c == 'X')
937 --p;
938 /*(void)*/ ungetc (c, fp);
940 if ((flags & SUPPRESS) == 0)
942 u_long res;
944 *p = 0;
945 res = (*ccfn) (rptr, buf, (char **) NULL, base);
946 if ((flags & POINTER) && !(flags & VECTOR))
947 *(va_arg (ap, _PTR *)) = (_PTR) (unsigned _POINTER_INT) res;
948 else if (flags & SHORT)
950 if (!(flags & VECTOR))
951 sp = va_arg (ap, short *);
952 else if (!looped)
953 sp = vec_buf.h;
954 *sp++ = res;
956 else if (flags & LONG)
958 if (!(flags & VECTOR))
959 lp = va_arg (ap, long *);
960 else if (!looped)
961 lp = vec_buf.l;
962 *lp++ = res;
964 #ifndef _NO_LONGLONG
965 else if (flags & LONGDBL)
967 u_long_long resll;
968 if (ccfn == _strtoul_r)
969 resll = _strtoull_r (rptr, buf, (char **) NULL, base);
970 else
971 resll = _strtoll_r (rptr, buf, (char **) NULL, base);
972 llp = va_arg (ap, long long*);
973 *llp = resll;
975 #endif
976 else
978 if (!(flags & VECTOR))
980 ip = va_arg (ap, int *);
981 *ip++ = res;
983 else
985 if (!looped)
986 ch_dest = vec_buf.c;
987 *ch_dest++ = (char)res;
990 if (!(flags & VECTOR))
991 nassigned++;
993 nread += p - buf;
994 break;
996 #ifdef FLOATING_POINT
997 case CT_FLOAT:
999 /* scan a floating point number as if by strtod */
1000 /* This code used to assume that the number of digits is reasonable.
1001 However, ANSI / ISO C makes no such stipulation; we have to get
1002 exact results even when there is an unreasonable amount of
1003 leading zeroes. */
1004 long leading_zeroes = 0;
1005 long zeroes, exp_adjust;
1006 char *exp_start = NULL;
1007 int fl_width = width;
1008 #ifdef hardway
1009 if (fl_width == 0 || fl_width > sizeof (buf) - 1)
1010 fl_width = sizeof (buf) - 1;
1011 #else
1012 /* size_t is unsigned, hence this optimisation */
1013 if (--fl_width > sizeof (buf) - 2)
1014 fl_width = sizeof (buf) - 2;
1015 fl_width++;
1016 #endif
1017 flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
1018 zeroes = 0;
1019 exp_adjust = 0;
1020 for (p = buf; fl_width; )
1022 c = *fp->_p;
1024 * This code mimicks the integer conversion
1025 * code, but is much simpler.
1027 switch (c)
1030 case '0':
1031 if (flags & NDIGITS)
1033 flags &= ~SIGNOK;
1034 zeroes++;
1035 goto fskip;
1037 /* Fall through. */
1038 case '1':
1039 case '2':
1040 case '3':
1041 case '4':
1042 case '5':
1043 case '6':
1044 case '7':
1045 case '8':
1046 case '9':
1047 flags &= ~(SIGNOK | NDIGITS);
1048 goto fok;
1050 case '+':
1051 case '-':
1052 if (flags & SIGNOK)
1054 flags &= ~SIGNOK;
1055 goto fok;
1057 break;
1058 case '.':
1059 if (flags & DPTOK)
1061 flags &= ~(SIGNOK | DPTOK);
1062 leading_zeroes = zeroes;
1063 goto fok;
1065 break;
1066 case 'e':
1067 case 'E':
1068 /* no exponent without some digits */
1069 if ((flags & (NDIGITS | EXPOK)) == EXPOK
1070 || ((flags & EXPOK) && zeroes))
1072 if (! (flags & DPTOK))
1074 exp_adjust = zeroes - leading_zeroes;
1075 exp_start = p;
1077 flags =
1078 (flags & ~(EXPOK | DPTOK)) |
1079 SIGNOK | NDIGITS;
1080 zeroes = 0;
1081 goto fok;
1083 break;
1085 break;
1086 fok:
1087 *p++ = c;
1088 fskip:
1089 fl_width--;
1090 ++nread;
1091 if (--fp->_r > 0)
1092 fp->_p++;
1093 else
1094 #ifndef CYGNUS_NEC
1095 if (__srefill (fp))
1096 #endif
1097 break; /* EOF */
1099 if (zeroes)
1100 flags &= ~NDIGITS;
1102 * If no digits, might be missing exponent digits
1103 * (just give back the exponent) or might be missing
1104 * regular digits, but had sign and/or decimal point.
1106 if (flags & NDIGITS)
1108 if (flags & EXPOK)
1110 /* no digits at all */
1111 while (p > buf)
1113 ungetc (*(u_char *)-- p, fp);
1114 --nread;
1116 goto match_failure;
1118 /* just a bad exponent (e and maybe sign) */
1119 c = *(u_char *)-- p;
1120 --nread;
1121 if (c != 'e' && c != 'E')
1123 _CAST_VOID ungetc (c, fp); /* sign */
1124 c = *(u_char *)-- p;
1125 --nread;
1127 _CAST_VOID ungetc (c, fp);
1129 if ((flags & SUPPRESS) == 0)
1131 #ifdef _NO_LONGDBL
1132 double res;
1133 #else /* !_NO_LONG_DBL */
1134 long double res;
1135 #endif /* !_NO_LONG_DBL */
1136 long new_exp = 0;
1138 *p = 0;
1139 if ((flags & (DPTOK | EXPOK)) == EXPOK)
1141 exp_adjust = zeroes - leading_zeroes;
1142 new_exp = -exp_adjust;
1143 exp_start = p;
1145 else if (exp_adjust)
1146 new_exp = _strtol_r (rptr, (exp_start + 1), NULL, 10) - exp_adjust;
1147 if (exp_adjust)
1150 /* If there might not be enough space for the new exponent,
1151 truncate some trailing digits to make room. */
1152 if (exp_start >= buf + sizeof (buf) - MAX_LONG_LEN)
1153 exp_start = buf + sizeof (buf) - MAX_LONG_LEN - 1;
1154 sprintf (exp_start, "e%ld", new_exp);
1156 #ifdef __SPE__
1157 if (flags & FIXEDPOINT)
1159 __uint64_t ufix64;
1160 if (flags & SIGNED)
1161 ufix64 = (__uint64_t)_strtosfix64_r (rptr, buf, NULL);
1162 else
1163 ufix64 = _strtoufix64_r (rptr, buf, NULL);
1164 if (flags & SHORT)
1166 __uint16_t *sp = va_arg (ap, __uint16_t *);
1167 *sp = (__uint16_t)(ufix64 >> 48);
1169 else if (flags & LONG)
1171 __uint64_t *llp = va_arg (ap, __uint64_t *);
1172 *llp = ufix64;
1174 else
1176 __uint32_t *lp = va_arg (ap, __uint32_t *);
1177 *lp = (__uint32_t)(ufix64 >> 32);
1179 nassigned++;
1180 break;
1183 #endif /* __SPE__ */
1184 #ifdef _NO_LONGDBL
1185 res = _strtod_r (rptr, buf, NULL);
1186 #else /* !_NO_LONGDBL */
1187 res = _strtold (buf, NULL);
1188 #endif /* !_NO_LONGDBL */
1189 if (flags & LONG)
1191 dp = va_arg (ap, double *);
1192 *dp = res;
1194 else if (flags & LONGDBL)
1196 ldp = va_arg (ap, _LONG_DOUBLE *);
1197 *ldp = res;
1199 else
1201 if (!(flags & VECTOR))
1202 flp = va_arg (ap, float *);
1203 else if (!looped)
1204 flp = vec_buf.f;
1205 *flp++ = res;
1207 if (!(flags & VECTOR))
1208 nassigned++;
1210 break;
1212 #endif /* FLOATING_POINT */
1214 if (vec_read_count-- > 1)
1216 looped = 1;
1217 goto process;
1219 if (flags & VECTOR)
1221 int i;
1222 unsigned long *vp = va_arg (ap, unsigned long *);
1223 for (i = 0; i < 4; ++i)
1224 *vp++ = vec_buf.l[i];
1225 nassigned++;
1228 input_failure:
1229 return nassigned ? nassigned : -1;
1230 match_failure:
1231 return nassigned;
1235 * Fill in the given table from the scanset at the given format
1236 * (just after `['). Return a pointer to the character past the
1237 * closing `]'. The table has a 1 wherever characters should be
1238 * considered part of the scanset.
1241 /*static*/
1242 u_char *
1243 __sccl (tab, fmt)
1244 register char *tab;
1245 register u_char *fmt;
1247 register int c, n, v;
1249 /* first `clear' the whole table */
1250 c = *fmt++; /* first char hat => negated scanset */
1251 if (c == '^')
1253 v = 1; /* default => accept */
1254 c = *fmt++; /* get new first char */
1256 else
1257 v = 0; /* default => reject */
1258 /* should probably use memset here */
1259 for (n = 0; n < 256; n++)
1260 tab[n] = v;
1261 if (c == 0)
1262 return fmt - 1; /* format ended before closing ] */
1265 * Now set the entries corresponding to the actual scanset to the
1266 * opposite of the above.
1268 * The first character may be ']' (or '-') without being special; the
1269 * last character may be '-'.
1272 v = 1 - v;
1273 for (;;)
1275 tab[c] = v; /* take character c */
1276 doswitch:
1277 n = *fmt++; /* and examine the next */
1278 switch (n)
1281 case 0: /* format ended too soon */
1282 return fmt - 1;
1284 case '-':
1286 * A scanset of the form [01+-] is defined as `the digit 0, the
1287 * digit 1, the character +, the character -', but the effect of a
1288 * scanset such as [a-zA-Z0-9] is implementation defined. The V7
1289 * Unix scanf treats `a-z' as `the letters a through z', but treats
1290 * `a-a' as `the letter a, the character -, and the letter a'.
1292 * For compatibility, the `-' is not considerd to define a range if
1293 * the character following it is either a close bracket (required by
1294 * ANSI) or is not numerically greater than the character we just
1295 * stored in the table (c).
1297 n = *fmt;
1298 if (n == ']' || n < c)
1300 c = '-';
1301 break; /* resume the for(;;) */
1303 fmt++;
1305 { /* fill in the range */
1306 tab[++c] = v;
1308 while (c < n);
1309 #if 1 /* XXX another disgusting compatibility hack */
1311 * Alas, the V7 Unix scanf also treats formats such
1312 * as [a-c-e] as `the letters a through e'. This too
1313 * is permitted by the standard....
1315 goto doswitch;
1316 #else
1317 c = *fmt++;
1318 if (c == 0)
1319 return fmt - 1;
1320 if (c == ']')
1321 return fmt;
1322 #endif
1324 break;
1327 case ']': /* end of scanset */
1328 return fmt;
1330 default: /* just another character */
1331 c = n;
1332 break;
1335 /* NOTREACHED */