OSDN Git Service

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