OSDN Git Service

9cfb658ca10e31e5f3b8fb54f87208eb0f8787d5
[pf3gnuchains/pf3gnuchains4x.git] / newlib / libc / machine / powerpc / vfscanf.c
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 *<[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]>);
18
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]>);
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 <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"
118
119 #ifndef NO_FLOATING_POINT
120 #define FLOATING_POINT
121 #endif
122
123 #ifdef FLOATING_POINT
124 #include <float.h>
125
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
134
135 #ifdef __SPE__
136 extern __int64_t _strtosfix64_r _PARAMS((struct _reent *, char *s, char **sptr));
137 extern __uint64_t _strtoufix64_r _PARAMS((struct _reent *, char *s, char **sptr));
138 #endif
139
140 #define _NO_LONGLONG
141 #if defined WANT_PRINTF_LONG_LONG && defined __GNUC__
142 # undef _NO_LONGLONG
143 #endif
144
145 #include "floatio.h"
146 #define BUF     (MAXEXP+MAXFRACT+3)     /* 3 = sign + decimal point + NUL */
147 /* An upper bound for how long a long prints in decimal.  4 / 13 approximates
148    log (2).  Add one char for roundoff compensation and one for the sign.  */
149 #define MAX_LONG_LEN ((CHAR_BIT * sizeof (long)  - 1) * 4 / 13 + 2)
150 #else
151 #define BUF     40
152 #endif
153
154 /*
155  * Flags used during conversion.
156  */
157
158 #define LONG            0x01    /* l: long or double */
159 #define LONGDBL         0x02    /* L: long double or long long */
160 #define SHORT           0x04    /* h: short */
161 #define SUPPRESS        0x08    /* suppress assignment */
162 #define POINTER         0x10    /* weird %p pointer (`fake hex') */
163 #define NOSKIP          0x20    /* do not skip blanks */
164
165 /*
166  * The following are used in numeric conversions only:
167  * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
168  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
169  */
170
171 #define SIGNOK          0x40    /* +/- is (still) legal */
172 #define NDIGITS         0x80    /* no digits detected */
173
174 #define DPTOK           0x100   /* (float) decimal point is still legal */
175 #define EXPOK           0x200   /* (float) exponent (e+3, etc) still legal */
176
177 #define PFXOK           0x100   /* 0x prefix is (still) legal */
178 #define NZDIGITS        0x200   /* no zero digits detected */
179
180 #define VECTOR          0x400   /* v: vector */
181 #define FIXEDPOINT      0x800   /* r/R: fixed-point */
182 #define SIGNED          0x1000  /* r: signed fixed-point */
183
184 /*
185  * Conversion types.
186  */
187
188 #define CT_CHAR         0       /* %c conversion */
189 #define CT_CCL          1       /* %[...] conversion */
190 #define CT_STRING       2       /* %s conversion */
191 #define CT_INT          3       /* integer, i.e., strtol or strtoul */
192 #define CT_FLOAT        4       /* floating, i.e., strtod */
193
194 #if 0
195 #define u_char unsigned char
196 #endif
197 #define u_char char
198 #define u_long unsigned long
199
200 #ifndef _NO_LONGLONG
201 typedef unsigned long long u_long_long;
202 #endif
203
204 typedef union
205 {
206   char c[16] __attribute__ ((__aligned__ (16)));
207   short h[8];
208   long l[4];
209   int i[4];
210   float f[4];
211 } vec_union;
212
213 /*static*/ u_char *__sccl ();
214
215 /*
216  * vfscanf
217  */
218
219 #define BufferEmpty (fp->_r <= 0 && __srefill(fp))
220
221 #ifndef _REENT_ONLY
222
223 int
224 _DEFUN (vfscanf, (fp, fmt, ap), 
225     register FILE *fp _AND 
226     _CONST char *fmt _AND 
227     va_list ap)
228 {
229   CHECK_INIT(fp);
230   return __svfscanf_r (fp->_data, fp, fmt, ap);
231 }
232
233 int
234 __svfscanf (fp, fmt0, ap)
235      register FILE *fp;
236      char _CONST *fmt0;
237      va_list ap;
238 {
239   return __svfscanf_r (_REENT, fp, fmt0, ap);
240 }
241
242 #endif /* !_REENT_ONLY */
243
244 int
245 _DEFUN (_vfscanf_r, (data, fp, fmt, ap),
246     struct _reent *data _AND 
247     register FILE *fp _AND 
248     _CONST char *fmt _AND 
249     va_list ap)
250 {
251   return __svfscanf_r (data, fp, fmt, ap);
252 }
253
254
255 int
256 __svfscanf_r (rptr, fp, fmt0, ap)
257      struct _reent *rptr;
258      register FILE *fp;
259      char _CONST *fmt0;
260      va_list ap;
261 {
262   register u_char *fmt = (u_char *) fmt0;
263   register int c;               /* character from format, or conversion */
264   register int type;            /* conversion type */
265   register size_t width;        /* field width, or 0 */
266   register char *p;             /* points into all kinds of strings */
267   register int n;               /* handy integer */
268   register int flags;           /* flags as defined above */
269   register char *p0;            /* saves original value of p when necessary */
270   int orig_flags;               /* saved flags used when processing vector */
271   int int_width;                /* tmp area to store width when processing int */
272   int nassigned;                /* number of fields assigned */
273   int nread;                    /* number of characters consumed from fp */
274   int base = 0;                 /* base argument to strtol/strtoul */
275   int nbytes = 1;               /* number of bytes read from fmt string */
276   wchar_t wc;                   /* wchar to use to read format string */
277   char vec_sep;                 /* vector separator char */
278   char last_space_char;         /* last white-space char eaten - needed for vec support */
279   int vec_read_count;           /* number of vector items to read separately */
280   int looped;                   /* has vector processing looped */
281   u_long (*ccfn) () = 0;        /* conversion function (strtol/strtoul) */
282   char ccltab[256];             /* character class table for %[...] */
283   char buf[BUF];                /* buffer for numeric conversions */
284   vec_union vec_buf;
285   char *lptr;                   /* literal pointer */
286 #ifdef MB_CAPABLE
287   mbstate_t state;                /* value to keep track of multibyte state */
288 #endif
289
290   char *ch_dest;
291   short *sp;
292   int *ip;
293   float *flp;
294   _LONG_DOUBLE *ldp;
295   double *dp;
296   long *lp;
297 #ifndef _NO_LONGLONG
298   long long *llp;
299 #else
300         u_long _uquad;
301 #endif
302
303   /* `basefix' is used to avoid `if' tests in the integer scanner */
304   static _CONST short basefix[17] =
305     {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
306
307   nassigned = 0;
308   nread = 0;
309   for (;;)
310     {
311 #ifndef MB_CAPABLE
312       wc = *fmt;
313 #else
314       memset (&state, '\0', sizeof (state));
315       nbytes = _mbtowc_r (rptr, &wc, fmt, MB_CUR_MAX, &state);
316 #endif
317       fmt += nbytes;
318       if (wc == 0)
319         return nassigned;
320       if (nbytes == 1 && isspace (wc))
321         {
322           for (;;)
323             {
324               if (BufferEmpty)
325                 return nassigned;
326               if (!isspace (*fp->_p))
327                 break;
328               nread++, fp->_r--, fp->_p++;
329             }
330           continue;
331         }
332       if (wc != '%')
333         goto literal;
334       width = 0;
335       flags = 0;
336       vec_sep = ' ';
337       vec_read_count = 0;
338       looped = 0;
339
340       /*
341        * switch on the format.  continue if done; break once format
342        * type is derived.
343        */
344
345     again:
346       c = *fmt++;
347
348       switch (c)
349         {
350         case '%':
351         literal:
352           lptr = fmt - nbytes;
353           for (n = 0; n < nbytes; ++n)
354             {
355               if (BufferEmpty)
356                 goto input_failure;
357               if (*fp->_p != *lptr)
358                 goto match_failure;
359               fp->_r--, fp->_p++;
360               nread++;
361               ++lptr;
362             }
363           continue;
364
365         case '*':
366           flags |= SUPPRESS;
367           goto again;
368         case ',':
369         case ';':
370         case ':':
371         case '_':
372           if (flags == SUPPRESS || flags == 0)
373             vec_sep = c;
374           goto again;
375         case 'l':
376           if (flags & SHORT)
377             continue; /* invalid format, don't process any further */
378           if (flags & LONG)
379             {
380               flags &= ~LONG;
381               flags &= ~VECTOR;
382               flags |= LONGDBL;
383             }
384           else
385             {
386               flags |= LONG;
387               if (flags & VECTOR)
388                 vec_read_count = 4;
389             }
390           goto again;
391         case 'L':
392           flags |= LONGDBL;
393           flags &= ~VECTOR;
394           goto again;
395         case 'h':
396           flags |= SHORT;
397           if (flags & LONG)
398             continue;  /* invalid format, don't process any further */
399           if (flags & VECTOR)
400             vec_read_count = 8;
401           goto again;
402 #ifdef __ALTIVEC__
403         case 'v':
404           flags |= VECTOR;
405           vec_read_count = (flags & SHORT) ? 8 : ((flags & LONG) ? 4 : 16);
406           goto again;
407 #endif
408         case '0':
409         case '1':
410         case '2':
411         case '3':
412         case '4':
413         case '5':
414         case '6':
415         case '7':
416         case '8':
417         case '9':
418           width = width * 10 + c - '0';
419           goto again;
420
421           /*
422            * Conversions. Those marked `compat' are for
423            * 4.[123]BSD compatibility.
424            *
425            * (According to ANSI, E and X formats are supposed to
426            * the same as e and x.  Sorry about that.)
427            */
428
429         case 'D':               /* compat */
430           flags |= LONG;
431           /* FALLTHROUGH */
432         case 'd':
433           type = CT_INT;
434           ccfn = (u_long (*)())_strtol_r;
435           base = 10;
436           break;
437
438         case 'i':
439           type = CT_INT;
440           ccfn = (u_long (*)())_strtol_r;
441           base = 0;
442           break;
443
444         case 'O':               /* compat */
445           flags |= LONG;
446           /* FALLTHROUGH */
447         case 'o':
448           type = CT_INT;
449           ccfn = _strtoul_r;
450           base = 8;
451           break;
452
453         case 'u':
454           type = CT_INT;
455           ccfn = _strtoul_r;
456           base = 10;
457           break;
458
459         case 'X':               /* compat   XXX */
460         case 'x':
461           flags |= PFXOK;       /* enable 0x prefixing */
462           type = CT_INT;
463           ccfn = _strtoul_r;
464           base = 16;
465           break;
466
467 #ifdef FLOATING_POINT
468         case 'E':               /* compat   XXX */
469         case 'G':               /* compat   XXX */
470 /* ANSI says that E,G and X behave the same way as e,g,x */
471           /* FALLTHROUGH */
472         case 'e':
473         case 'f':
474         case 'g':
475           type = CT_FLOAT;
476           if (flags & VECTOR)
477             vec_read_count = 4;
478           break;
479        
480 # ifdef __SPE__
481           /* treat fixed-point like %f floating point */
482         case 'r':
483           flags |= SIGNED;
484           /* fallthrough */
485         case 'R':
486           flags |= FIXEDPOINT;
487           type = CT_FLOAT;
488           break;
489 # endif
490 #endif
491
492         case 's':
493           flags &= ~VECTOR;
494           type = CT_STRING;
495           break;
496
497         case '[':
498           fmt = __sccl (ccltab, fmt);
499           flags |= NOSKIP;
500           flags &= ~VECTOR;
501           type = CT_CCL;
502           break;
503
504         case 'c':
505           flags |= NOSKIP;
506           type = CT_CHAR;
507           if (flags & VECTOR)
508             {
509               /* not allowed to have h or l with c specifier */
510               if (flags & (LONG | SHORT))
511                 continue;  /* invalid format don't process any further */
512               width = 0;
513               vec_read_count = 16;
514             }
515           break;
516
517         case 'p':               /* pointer format is like hex */
518           flags |= POINTER | PFXOK;
519           type = CT_INT;
520           ccfn = _strtoul_r;
521           base = 16;
522           break;
523
524         case 'n':
525           if (flags & SUPPRESS) /* ??? */
526             continue;
527           flags &= ~VECTOR;
528           if (flags & SHORT)
529             {
530               sp = va_arg (ap, short *);
531               *sp = nread;
532             }
533           else if (flags & LONG)
534             {
535               lp = va_arg (ap, long *);
536               *lp = nread;
537             }
538 #ifndef _NO_LONGLONG
539           else if (flags & LONGDBL)
540             {
541               llp = va_arg (ap, long long*);
542               *llp = nread;
543             }
544 #endif
545           else
546             {
547               ip = va_arg (ap, int *);
548               *ip = nread;
549             }
550           continue;
551
552           /*
553            * Disgusting backwards compatibility hacks.  XXX
554            */
555         case '\0':              /* compat */
556           return EOF;
557
558         default:                /* compat */
559           if (isupper (c))
560             flags |= LONG;
561           type = CT_INT;
562           ccfn = (u_long (*)())_strtol_r;
563           base = 10;
564           break;
565         }
566
567     process:
568       /*
569        * We have a conversion that requires input.
570        */
571       if (BufferEmpty)
572         goto input_failure;
573
574       /*
575        * Consume leading white space, except for formats that
576        * suppress this.
577        */
578       last_space_char = '\0';
579
580       if ((flags & NOSKIP) == 0)
581         {
582           while (isspace (*fp->_p))
583             {
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;
593             }
594           /*
595            * Note that there is at least one character in the
596            * buffer, so conversions that do not set NOSKIP ca
597            * no longer result in an input failure.
598            */
599         }
600
601       /* for vector formats process separator characters after first loop */
602       if (looped && (flags & VECTOR))
603         {
604           flags = orig_flags; 
605           /* all formats other than default char have a separator char */
606           if (vec_sep != ' ' || type != CT_CHAR)
607             {
608               if (vec_sep == ' ' && last_space_char != ' ' ||
609                   vec_sep != ' ' && *fp->_p != vec_sep)
610                 goto match_failure;
611               if (vec_sep != ' ')
612                 {
613                   nread++;
614                   if (--fp->_r > 0)
615                     fp->_p++;
616                   else
617 #ifndef CYGNUS_NEC
618                     if (__srefill (fp))
619 #endif
620                       goto input_failure;
621                 }
622             }
623           /* after eating the separator char, we must eat any white-space
624              after the separator char that precedes the data to convert */
625           if ((flags & NOSKIP) == 0)
626             {
627               while (isspace (*fp->_p))
628                 {
629                   last_space_char = *fp->_p;
630                   nread++;
631                   if (--fp->_r > 0)
632                     fp->_p++;
633                   else
634 #ifndef CYGNUS_NEC
635                     if (__srefill (fp))
636 #endif
637                       goto input_failure;
638                 }
639             }
640
641         }
642       else /* save to counter-act changes made to flags when processing */
643         orig_flags = flags;
644
645       /*
646        * Do the conversion.
647        */
648       switch (type)
649         {
650
651         case CT_CHAR:
652           /* scan arbitrary characters (sets NOSKIP) */
653           if (width == 0)
654             width = 1;
655           if (flags & SUPPRESS)
656             {
657               size_t sum = 0;
658
659               for (;;)
660                 {
661                   if ((n = fp->_r) < (int)width)
662                     {
663                       sum += n;
664                       width -= n;
665                       fp->_p += n;
666 #ifndef CYGNUS_NEC
667                       if (__srefill (fp))
668                         {
669 #endif
670                           if (sum == 0)
671                             goto input_failure;
672                           break;
673 #ifndef CYGNUS_NEC
674                         }
675 #endif
676                     }
677                   else
678                     {
679                       sum += width;
680                       fp->_r -= width;
681                       fp->_p += width;
682                       break;
683                     }
684                 }
685               nread += sum;
686             }
687           else
688             {
689               int n = width;
690               if (!looped)
691                 {
692                   if (flags & VECTOR)
693                     ch_dest = vec_buf.c;
694                   else
695                     ch_dest = va_arg (ap, char *);
696                 }
697 #ifdef CYGNUS_NEC
698               /* Kludge city for the moment */
699               if (fp->_r == 0)
700                 goto input_failure;
701
702               while (n && fp->_r)
703                 {
704                   *ch_dest++ = *(fp->_p++);
705                   n--;
706                   fp->_r--;
707                   nread++;
708                 }
709 #else
710               size_t r = fread (ch_dest, 1, width, fp);
711
712               if (r == 0)
713                 goto input_failure;
714               nread += r;
715               ch_dest += r;
716 #endif
717               if (!(flags & VECTOR))
718                 nassigned++;
719             }
720           break;
721
722         case CT_CCL:
723           /* scan a (nonempty) character class (sets NOSKIP) */
724           if (width == 0)
725             width = ~0;         /* `infinity' */
726           /* take only those things in the class */
727           if (flags & SUPPRESS)
728             {
729               n = 0;
730               while (ccltab[*fp->_p])
731                 {
732                   n++, fp->_r--, fp->_p++;
733                   if (--width == 0)
734                     break;
735                   if (BufferEmpty)
736                     {
737                       if (n == 0)
738                         goto input_failure;
739                       break;
740                     }
741                 }
742               if (n == 0)
743                 goto match_failure;
744             }
745           else
746             {
747               p0 = p = va_arg (ap, char *);
748               while (ccltab[*fp->_p])
749                 {
750                   fp->_r--;
751                   *p++ = *fp->_p++;
752                   if (--width == 0)
753                     break;
754                   if (BufferEmpty)
755                     {
756                       if (p == p0)
757                         goto input_failure;
758                       break;
759                     }
760                 }
761               n = p - p0;
762               if (n == 0)
763                 goto match_failure;
764               *p = 0;
765               nassigned++;
766             }
767           nread += n;
768           break;
769
770         case CT_STRING:
771           /* like CCL, but zero-length string OK, & no NOSKIP */
772           if (width == 0)
773             width = ~0;
774           if (flags & SUPPRESS)
775             {
776               n = 0;
777               while (!isspace (*fp->_p))
778                 {
779                   n++, fp->_r--, fp->_p++;
780                   if (--width == 0)
781                     break;
782                   if (BufferEmpty)
783                     break;
784                 }
785               nread += n;
786             }
787           else
788             {
789               p0 = p = va_arg (ap, char *);
790               while (!isspace (*fp->_p))
791                 {
792                   fp->_r--;
793                   *p++ = *fp->_p++;
794                   if (--width == 0)
795                     break;
796                   if (BufferEmpty)
797                     break;
798                 }
799               *p = 0;
800               nread += p - p0;
801               nassigned++;
802             }
803           continue;
804
805         case CT_INT:
806           /* scan an integer as if by strtol/strtoul */
807           int_width = width;
808 #ifdef hardway
809           if (int_width == 0 || int_width > sizeof (buf) - 1)
810             int_width = sizeof (buf) - 1;
811 #else
812           /* size_t is unsigned, hence this optimisation */
813           if (--int_width > sizeof (buf) - 2)
814             int_width = sizeof (buf) - 2;
815           int_width++;
816 #endif
817           flags |= SIGNOK | NDIGITS | NZDIGITS;
818           for (p = buf; int_width; int_width--)
819             {
820               c = *fp->_p;
821               /*
822                * Switch on the character; `goto ok' if we
823                * accept it as a part of number.
824                */
825               switch (c)
826                 {
827                   /*
828                    * The digit 0 is always legal, but is special.
829                    * For %i conversions, if no digits (zero or nonzero)
830                    * have been scanned (only signs), we will have base==0.
831                    * In that case, we should set it to 8 and enable 0x
832                    * prefixing. Also, if we have not scanned zero digits
833                    * before this, do not turn off prefixing (someone else
834                    * will turn it off if we have scanned any nonzero digits).
835                    */
836                 case '0':
837                   if (base == 0)
838                     {
839                       base = 8;
840                       flags |= PFXOK;
841                     }
842                   if (flags & NZDIGITS)
843                     flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
844                   else
845                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
846                   goto ok;
847
848                   /* 1 through 7 always legal */
849                 case '1':
850                 case '2':
851                 case '3':
852                 case '4':
853                 case '5':
854                 case '6':
855                 case '7':
856                   base = basefix[base];
857                   flags &= ~(SIGNOK | PFXOK | NDIGITS);
858                   goto ok;
859
860                   /* digits 8 and 9 ok iff decimal or hex */
861                 case '8':
862                 case '9':
863                   base = basefix[base];
864                   if (base <= 8)
865                     break;      /* not legal here */
866                   flags &= ~(SIGNOK | PFXOK | NDIGITS);
867                   goto ok;
868
869                   /* letters ok iff hex */
870                 case 'A':
871                 case 'B':
872                 case 'C':
873                 case 'D':
874                 case 'E':
875                 case 'F':
876                 case 'a':
877                 case 'b':
878                 case 'c':
879                 case 'd':
880                 case 'e':
881                 case 'f':
882                   /* no need to fix base here */
883                   if (base <= 10)
884                     break;      /* not legal here */
885                   flags &= ~(SIGNOK | PFXOK | NDIGITS);
886                   goto ok;
887
888                   /* sign ok only as first character */
889                 case '+':
890                 case '-':
891                   if (flags & SIGNOK)
892                     {
893                       flags &= ~SIGNOK;
894                       goto ok;
895                     }
896                   break;
897
898                   /* x ok iff flag still set & 2nd char */
899                 case 'x':
900                 case 'X':
901                   if (flags & PFXOK && p == buf + 1)
902                     {
903                       base = 16;/* if %i */
904                       flags &= ~PFXOK;
905                       goto ok;
906                     }
907                   break;
908                 }
909
910               /*
911                * If we got here, c is not a legal character
912                * for a number.  Stop accumulating digits.
913                */
914               break;
915             ok:
916               /*
917                * c is legal: store it and look at the next.
918                */
919               *p++ = c;
920               if (--fp->_r > 0)
921                 fp->_p++;
922               else
923 #ifndef CYGNUS_NEC
924               if (__srefill (fp))
925 #endif
926                 break;          /* EOF */
927             }
928           /*
929            * If we had only a sign, it is no good; push back the sign.
930            * If the number ends in `x', it was [sign] '0' 'x', so push back
931            * the x and treat it as [sign] '0'.
932            */
933           if (flags & NDIGITS)
934             {
935               if (p > buf)
936                 _CAST_VOID ungetc (*(u_char *)-- p, fp);
937               goto match_failure;
938             }
939           c = ((u_char *) p)[-1];
940           if (c == 'x' || c == 'X')
941             {
942               --p;
943               /*(void)*/ ungetc (c, fp);
944             }
945           if ((flags & SUPPRESS) == 0)
946             {
947               u_long res;
948
949               *p = 0;
950               res = (*ccfn) (rptr, buf, (char **) NULL, base);
951               if ((flags & POINTER) && !(flags & VECTOR))
952                 *(va_arg (ap, _PTR *)) = (_PTR) (unsigned _POINTER_INT) res;
953               else if (flags & SHORT)
954                 {
955                   if (!(flags & VECTOR))
956                     sp = va_arg (ap, short *);
957                   else if (!looped)
958                     sp = vec_buf.h;
959                   *sp++ = res;
960                 }
961               else if (flags & LONG)
962                 {
963                   if (!(flags & VECTOR))
964                     lp = va_arg (ap, long *);
965                   else if (!looped)
966                     lp = vec_buf.l;
967                   *lp++ = res;
968                 }
969 #ifndef _NO_LONGLONG
970               else if (flags & LONGDBL)
971                 {
972                   u_long_long resll;
973                   if (ccfn == _strtoul_r)
974                     resll = _strtoull_r (rptr, buf, (char **) NULL, base);
975                   else
976                     resll = _strtoll_r (rptr, buf, (char **) NULL, base);
977                   llp = va_arg (ap, long long*);
978                   *llp = resll;
979                 }
980 #endif
981               else
982                 {
983                   if (!(flags & VECTOR))
984                     {
985                       ip = va_arg (ap, int *);
986                       *ip++ = res;
987                     }
988                   else
989                     {
990                       if (!looped)
991                         ch_dest = vec_buf.c;
992                       *ch_dest++ = (char)res;
993                     }
994                 }
995               if (!(flags & VECTOR))
996                 nassigned++;
997             }
998           nread += p - buf;
999           break;
1000
1001 #ifdef FLOATING_POINT
1002         case CT_FLOAT:
1003         {
1004           /* scan a floating point number as if by strtod */
1005           /* This code used to assume that the number of digits is reasonable.
1006              However, ANSI / ISO C makes no such stipulation; we have to get
1007              exact results even when there is an unreasonable amount of
1008              leading zeroes.  */
1009           long leading_zeroes = 0;
1010           long zeroes, exp_adjust;
1011           char *exp_start = NULL;
1012           int fl_width = width;
1013 #ifdef hardway
1014           if (fl_width == 0 || fl_width > sizeof (buf) - 1)
1015             fl_width = sizeof (buf) - 1;
1016 #else
1017           /* size_t is unsigned, hence this optimisation */
1018           if (--fl_width > sizeof (buf) - 2)
1019             fl_width = sizeof (buf) - 2;
1020           fl_width++;
1021 #endif
1022           flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
1023           zeroes = 0;
1024           exp_adjust = 0;
1025           for (p = buf; fl_width; )
1026             {
1027               c = *fp->_p;
1028               /*
1029                * This code mimicks the integer conversion
1030                * code, but is much simpler.
1031                */
1032               switch (c)
1033                 {
1034
1035                 case '0':
1036                   if (flags & NDIGITS)
1037                     {
1038                       flags &= ~SIGNOK;
1039                       zeroes++;
1040                       goto fskip;
1041                     }
1042                   /* Fall through.  */
1043                 case '1':
1044                 case '2':
1045                 case '3':
1046                 case '4':
1047                 case '5':
1048                 case '6':
1049                 case '7':
1050                 case '8':
1051                 case '9':
1052                   flags &= ~(SIGNOK | NDIGITS);
1053                   goto fok;
1054
1055                 case '+':
1056                 case '-':
1057                   if (flags & SIGNOK)
1058                     {
1059                       flags &= ~SIGNOK;
1060                       goto fok;
1061                     }
1062                   break;
1063                 case '.':
1064                   if (flags & DPTOK)
1065                     {
1066                       flags &= ~(SIGNOK | DPTOK);
1067                       leading_zeroes = zeroes;
1068                       goto fok;
1069                     }
1070                   break;
1071                 case 'e':
1072                 case 'E':
1073                   /* no exponent without some digits */
1074                   if ((flags & (NDIGITS | EXPOK)) == EXPOK
1075                       || ((flags & EXPOK) && zeroes))
1076                     {
1077                       if (! (flags & DPTOK))
1078                         {
1079                           exp_adjust = zeroes - leading_zeroes;
1080                           exp_start = p;
1081                         }
1082                       flags =
1083                         (flags & ~(EXPOK | DPTOK)) |
1084                         SIGNOK | NDIGITS;
1085                       zeroes = 0;
1086                       goto fok;
1087                     }
1088                   break;
1089                 }
1090               break;
1091             fok:
1092               *p++ = c;
1093               fl_width--;
1094             fskip:
1095               ++nread;
1096               if (--fp->_r > 0)
1097                 fp->_p++;
1098               else
1099 #ifndef CYGNUS_NEC
1100               if (__srefill (fp))
1101 #endif
1102                 break;          /* EOF */
1103             }
1104           if (zeroes)
1105             flags &= ~NDIGITS;
1106           /*
1107            * If no digits, might be missing exponent digits
1108            * (just give back the exponent) or might be missing
1109            * regular digits, but had sign and/or decimal point.
1110            */
1111           if (flags & NDIGITS)
1112             {
1113               if (flags & EXPOK)
1114                 {
1115                   /* no digits at all */
1116                   while (p > buf)
1117                     {
1118                       ungetc (*(u_char *)-- p, fp);
1119                       --nread;
1120                     }
1121                   goto match_failure;
1122                 }
1123               /* just a bad exponent (e and maybe sign) */
1124               c = *(u_char *)-- p;
1125               --nread;
1126               if (c != 'e' && c != 'E')
1127                 {
1128                   _CAST_VOID ungetc (c, fp);    /* sign */
1129                   c = *(u_char *)-- p;
1130                   --nread;
1131                 }
1132               _CAST_VOID ungetc (c, fp);
1133             }
1134           if ((flags & SUPPRESS) == 0)
1135             {
1136 #ifdef _NO_LONGDBL
1137               double res;
1138 #else  /* !_NO_LONG_DBL */
1139               long double res;
1140 #endif /* !_NO_LONG_DBL */
1141               long new_exp = 0;
1142
1143               *p = 0;
1144               if ((flags & (DPTOK | EXPOK)) == EXPOK)
1145                 {
1146                   exp_adjust = zeroes - leading_zeroes;
1147                   new_exp = -exp_adjust;
1148                   exp_start = p;
1149                 }
1150               else if (exp_adjust)
1151                 new_exp = _strtol_r (rptr, (exp_start + 1), NULL, 10) - exp_adjust;
1152               if (exp_adjust)
1153                 {
1154
1155                   /* If there might not be enough space for the new exponent,
1156                      truncate some trailing digits to make room.  */
1157                   if (exp_start >= buf + sizeof (buf) - MAX_LONG_LEN)
1158                     exp_start = buf + sizeof (buf) - MAX_LONG_LEN - 1;
1159                  sprintf (exp_start, "e%ld", new_exp);
1160                 }
1161 #ifdef __SPE__
1162               if (flags & FIXEDPOINT)
1163                 {
1164                   __uint64_t ufix64;
1165                   if (flags & SIGNED)
1166                     ufix64 = (__uint64_t)_strtosfix64_r (rptr, buf, NULL);
1167                   else
1168                     ufix64 = _strtoufix64_r (rptr, buf, NULL);
1169                   if (flags & SHORT)
1170                     {
1171                       __uint16_t *sp = va_arg (ap, __uint16_t *);
1172                       *sp = (__uint16_t)(ufix64 >> 48);
1173                     }
1174                   else if (flags & LONG)
1175                     {
1176                       __uint64_t *llp = va_arg (ap, __uint64_t *);
1177                       *llp = ufix64;
1178                     }
1179                   else
1180                     {
1181                       __uint32_t *lp = va_arg (ap, __uint32_t *);
1182                       *lp = (__uint32_t)(ufix64 >> 32);
1183                     }
1184                   nassigned++;
1185                   break;
1186                 }
1187               
1188 #endif /* __SPE__ */
1189 #ifdef _NO_LONGDBL
1190               res = _strtod_r (rptr, buf, NULL);
1191 #else  /* !_NO_LONGDBL */
1192               res = _strtold (buf, NULL);
1193 #endif /* !_NO_LONGDBL */
1194               if (flags & LONG)
1195                 {
1196                   dp = va_arg (ap, double *);
1197                   *dp = res;
1198                 }
1199               else if (flags & LONGDBL)
1200                 {
1201                   ldp = va_arg (ap, _LONG_DOUBLE *);
1202                   *ldp = res;
1203                 }
1204               else
1205                 {
1206                   if (!(flags & VECTOR))
1207                     flp = va_arg (ap, float *);
1208                   else if (!looped)
1209                     flp = vec_buf.f;
1210                   *flp++ = res;
1211                 }
1212               if (!(flags & VECTOR))
1213                 nassigned++;
1214             }
1215           break;
1216         }
1217 #endif /* FLOATING_POINT */
1218         }
1219       if (vec_read_count-- > 1)
1220         {
1221           looped = 1;
1222           goto process;
1223         }
1224       if (flags & VECTOR)
1225         {
1226           int i;
1227           unsigned long *vp = va_arg (ap, unsigned long *);
1228           for (i = 0; i < 4; ++i)
1229             *vp++ = vec_buf.l[i];
1230           nassigned++;
1231         }
1232     }
1233 input_failure:
1234   return nassigned ? nassigned : -1;
1235 match_failure:
1236   return nassigned;
1237 }
1238
1239 /*
1240  * Fill in the given table from the scanset at the given format
1241  * (just after `[').  Return a pointer to the character past the
1242  * closing `]'.  The table has a 1 wherever characters should be
1243  * considered part of the scanset.
1244  */
1245
1246 /*static*/
1247 u_char *
1248 __sccl (tab, fmt)
1249      register char *tab;
1250      register u_char *fmt;
1251 {
1252   register int c, n, v;
1253
1254   /* first `clear' the whole table */
1255   c = *fmt++;                   /* first char hat => negated scanset */
1256   if (c == '^')
1257     {
1258       v = 1;                    /* default => accept */
1259       c = *fmt++;               /* get new first char */
1260     }
1261   else
1262     v = 0;                      /* default => reject */
1263   /* should probably use memset here */
1264   for (n = 0; n < 256; n++)
1265     tab[n] = v;
1266   if (c == 0)
1267     return fmt - 1;             /* format ended before closing ] */
1268
1269   /*
1270    * Now set the entries corresponding to the actual scanset to the
1271    * opposite of the above.
1272    *
1273    * The first character may be ']' (or '-') without being special; the
1274    * last character may be '-'.
1275    */
1276
1277   v = 1 - v;
1278   for (;;)
1279     {
1280       tab[c] = v;               /* take character c */
1281     doswitch:
1282       n = *fmt++;               /* and examine the next */
1283       switch (n)
1284         {
1285
1286         case 0:         /* format ended too soon */
1287           return fmt - 1;
1288
1289         case '-':
1290           /*
1291            * A scanset of the form [01+-] is defined as `the digit 0, the
1292            * digit 1, the character +, the character -', but the effect of a
1293            * scanset such as [a-zA-Z0-9] is implementation defined.  The V7
1294            * Unix scanf treats `a-z' as `the letters a through z', but treats
1295            * `a-a' as `the letter a, the character -, and the letter a'.
1296            *
1297            * For compatibility, the `-' is not considerd to define a range if
1298            * the character following it is either a close bracket (required by
1299            * ANSI) or is not numerically greater than the character we just
1300            * stored in the table (c).
1301            */
1302           n = *fmt;
1303           if (n == ']' || n < c)
1304             {
1305               c = '-';
1306               break;            /* resume the for(;;) */
1307             }
1308           fmt++;
1309           do
1310             {                   /* fill in the range */
1311               tab[++c] = v;
1312             }
1313           while (c < n);
1314 #if 1                   /* XXX another disgusting compatibility hack */
1315           /*
1316            * Alas, the V7 Unix scanf also treats formats such
1317            * as [a-c-e] as `the letters a through e'. This too
1318            * is permitted by the standard....
1319            */
1320           goto doswitch;
1321 #else
1322           c = *fmt++;
1323           if (c == 0)
1324             return fmt - 1;
1325           if (c == ']')
1326             return fmt;
1327 #endif
1328
1329           break;
1330
1331
1332         case ']':               /* end of scanset */
1333           return fmt;
1334
1335         default:                /* just another character */
1336           c = n;
1337           break;
1338         }
1339     }
1340   /* NOTREACHED */
1341 }