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