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  * and/or 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 <<vfwscanf>>, <<vwscanf>>, <<vswscanf>>---scan and format argument list from wide character input
21 
22 INDEX
23 	vfwscanf
24 INDEX
25 	_vfwscanf
26 INDEX
27 	vwscanf
28 INDEX
29 	_vwscanf
30 INDEX
31 	vswscanf
32 INDEX
33 	_vswscanf
34 
35 SYNOPSIS
36 	#include <stdio.h>
37 	#include <stdarg.h>
38 	int vwscanf(const wchar_t *__restrict <[fmt]>, va_list <[list]>);
39 	int vfwscanf(FILE *__restrict <[fp]>,
40                      const wchar_t *__restrict <[fmt]>, va_list <[list]>);
41 	int vswscanf(const wchar_t *__restrict <[str]>,
42                      const wchar_t *__restrict <[fmt]>, va_list <[list]>);
43 
44 	int _vwscanf(struct _reent *<[reent]>, const wchar_t *<[fmt]>,
45                        va_list <[list]>);
46 	int _vfwscanf(struct _reent *<[reent]>, FILE *<[fp]>,
47                       const wchar_t *<[fmt]>, va_list <[list]>);
48 	int _vswscanf(struct _reent *<[reent]>, const wchar_t *<[str]>,
49                        const wchar_t *<[fmt]>, va_list <[list]>);
50 
51 DESCRIPTION
52 <<vwscanf>>, <<vfwscanf>>, and <<vswscanf>> are (respectively) variants
53 of <<wscanf>>, <<fwscanf>>, and <<swscanf>>.  They differ only in
54 allowing their caller to pass the variable argument list as a
55 <<va_list>> object (initialized by <<va_start>>) rather than
56 directly accepting a variable number of arguments.
57 
58 RETURNS
59 The return values are consistent with the corresponding functions:
60 <<vwscanf>> returns the number of input fields successfully scanned,
61 converted, and stored; the return value does not include scanned
62 fields which were not stored.
63 
64 If <<vwscanf>> attempts to read at end-of-file, the return value
65 is <<EOF>>.
66 
67 If no fields were stored, the return value is <<0>>.
68 
69 The routines <<_vwscanf>>, <<_vfwscanf>>, and <<_vswscanf>> are
70 reentrant versions which take an additional first parameter which points
71 to the reentrancy structure.
72 
73 PORTABILITY
74 C99, POSIX-1.2008
75 */
76 
77 #define _DEFAULT_SOURCE
78 #include <_ansi.h>
79 #include <newlib.h>
80 #include <ctype.h>
81 #include <wctype.h>
82 #include <stdio.h>
83 #include <stdlib.h>
84 #include <stdint.h>
85 #include <limits.h>
86 #include <wchar.h>
87 #include <string.h>
88 #include <stdarg.h>
89 #include <errno.h>
90 #include "local.h"
91 
92 #ifdef INTEGER_ONLY
93 #define VFWSCANF vfiwscanf
94 #ifdef STRING_ONLY
95 #  define _SVFWSCANF _ssvfiwscanf
96 #else
97 #  define _SVFWSCANF _svfiwscanf
98 #endif
99 #else
100 #define VFWSCANF vfwscanf
101 #ifdef STRING_ONLY
102 #  define _SVFWSCANF _ssvfwscanf
103 #else
104 #  define _SVFWSCANF _svfwscanf
105 #endif
106 #ifndef NO_FLOATING_POINT
107 #define FLOATING_POINT
108 #endif
109 #endif
110 
111 #ifdef STRING_ONLY
112 #undef _newlib_flockfile_start
113 #undef _newlib_flockfile_exit
114 #undef _newlib_flockfile_end
115 #define _newlib_flockfile_start(x) {}
116 #define _newlib_flockfile_exit(x) {}
117 #define _newlib_flockfile_end(x) {}
118 #define ungetwc sungetwc
119 #define _srefill _ssrefill
120 #define fgetwc sfgetwc
121 #endif
122 
123 #ifdef FLOATING_POINT
124 #include <math.h>
125 #include <float.h>
126 #include <locale.h>
127 #ifdef __HAVE_LOCALE_INFO_EXTENDED__
128 #include "../locale/setlocale.h"
129 #endif
130 
131 /* Currently a test is made to see if long double processing is warranted.
132    This could be changed in the future should the __ldtoa code be
133    preferred over __dtoa.  */
134 #define _NO_LONGDBL
135 #if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
136 #undef _NO_LONGDBL
137 #endif
138 
139 #include "floatio.h"
140 
141 #if ((MAXEXP+MAXFRACT+3) > MB_LEN_MAX)
142 #  define BUF (MAXEXP+MAXFRACT+3)        /* 3 = sign + decimal point + NUL */
143 #else
144 #  define BUF MB_LEN_MAX
145 #endif
146 
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 #define _NO_LONGLONG
155 #if defined _WANT_IO_LONG_LONG \
156 	&& (defined __GNUC__ || __STDC_VERSION__ >= 199901L)
157 # undef _NO_LONGLONG
158 #endif
159 
160 #define _NO_POS_ARGS
161 #ifdef _WANT_IO_POS_ARGS
162 # undef _NO_POS_ARGS
163 # ifdef NL_ARGMAX
164 #  define MAX_POS_ARGS NL_ARGMAX
165 # else
166 #  define MAX_POS_ARGS 32
167 # endif
168 
169 static void * get_arg (int, va_list *, int *, void **);
170 #endif /* _WANT_IO_POS_ARGS */
171 
172 /*
173  * Flags used during conversion.
174  */
175 
176 #define	LONG		0x01	/* l: long or double */
177 #define	LONGDBL		0x02	/* L/ll: long double or long long */
178 #define	SHORT		0x04	/* h: short */
179 #define CHAR		0x08	/* hh: 8 bit integer */
180 #define	SUPPRESS	0x10	/* suppress assignment */
181 #define	POINTER		0x20	/* weird %p pointer (`fake hex') */
182 #define	NOSKIP		0x40	/* do not skip blanks */
183 #define	MALLOC		0x80	/* handle 'm' modifier */
184 
185 /*
186  * The following are used in numeric conversions only:
187  * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
188  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
189  */
190 
191 #define	SIGNOK		0x80	/* +/- is (still) legal */
192 #define	NDIGITS		0x100	/* no digits detected */
193 
194 #define	DPTOK		0x200	/* (float) decimal point is still legal */
195 #define	EXPOK		0x400	/* (float) exponent (e+3, etc) still legal */
196 
197 #define	PFXOK		0x200	/* 0x prefix is (still) legal */
198 #define	NZDIGITS	0x400	/* no zero digits detected */
199 #define HAVESIGN        0x10000 /* sign detected */
200 
201 /*
202  * Conversion types.
203  */
204 
205 #define	CT_CHAR		0	/* %c conversion */
206 #define	CT_CCL		1	/* %[...] conversion */
207 #define	CT_STRING	2	/* %s conversion */
208 #define	CT_INT		3	/* integer, i.e., wcstol or wcstoul */
209 #define	CT_FLOAT	4	/* floating, i.e., wcstod */
210 
211 #define INCCL(_c)       \
212 	(cclcompl ? (wmemchr(ccls, (_c), ccle - ccls) == NULL) : \
213 	(wmemchr(ccls, (_c), ccle - ccls) != NULL))
214 
215 /*
216  * vfwscanf
217  */
218 
219 #ifndef STRING_ONLY
220 
221 int
VFWSCANF(register FILE * fp,const wchar_t * fmt,va_list ap)222 VFWSCANF (
223        register FILE *fp,
224        const wchar_t *fmt,
225        va_list ap)
226 {
227   CHECK_INIT(data, fp);
228   return _SVFWSCANF (fp, fmt, ap);
229 }
230 #endif /* !STRING_ONLY */
231 
232 #ifdef STRING_ONLY
233 /* When dealing with the swscanf family, we don't want to use the
234  * regular ungetwc which will drag in file I/O items we don't need.
235  * So, we create our own trimmed-down version.  */
236 static wint_t
sungetwc(wint_t wc,register FILE * fp)237 sungetwc (
238 	wint_t wc,
239 	register FILE *fp)
240 {
241   if (wc == WEOF)
242     return (WEOF);
243 
244   /* After ungetc, we won't be at eof anymore */
245   fp->_flags &= ~__SEOF;
246 
247   /* All ungetwc usage in scanf un-gets the current character, so
248    * just back up over the string if we aren't at the start
249    */
250   if (fp->_bf._base != NULL && fp->_p > fp->_bf._base)
251     {
252       fp->_p -= sizeof (wchar_t);
253       fp->_r += sizeof (wchar_t);
254     }
255 
256   return wc;
257 }
258 
259 extern int _ssrefill ( register FILE * fp);
260 
261 static size_t
sfgetwc(FILE * fp)262 sfgetwc (
263        FILE * fp)
264 {
265   wchar_t wc;
266 
267   if (fp->_r <= 0 && _ssrefill ( fp))
268     return (WEOF);
269   wc = *(wchar_t *) fp->_p;
270   fp->_p += sizeof (wchar_t);
271   fp->_r -= sizeof (wchar_t);
272   return (wc);
273 }
274 #endif /* STRING_ONLY */
275 
276 int
_SVFWSCANF(register FILE * fp,wchar_t const * fmt0,va_list ap)277 _SVFWSCANF (
278        register FILE *fp,
279        wchar_t const *fmt0,
280        va_list ap)
281 {
282   register wchar_t *fmt = (wchar_t *) fmt0;
283   register wint_t c;            /* character from format, or conversion */
284   register size_t width;	/* field width, or 0 */
285   register wchar_t *p = NULL;	/* points into all kinds of strings */
286   register int n;		/* handy integer */
287   register int flags;		/* flags as defined above */
288   register wchar_t *p0;		/* saves original value of p when necessary */
289   int nassigned;		/* number of fields assigned */
290   int nread;			/* number of characters consumed from fp */
291 #ifndef _NO_POS_ARGS
292   int N;			/* arg number */
293   int arg_index = 0;		/* index into args processed directly */
294   int numargs = 0;		/* number of varargs read */
295   void *args[MAX_POS_ARGS];	/* positional args read */
296   int is_pos_arg;		/* is current format positional? */
297 #endif
298   int base = 0;			/* base argument to wcstol/wcstoul */
299 
300   mbstate_t mbs;                /* value to keep track of multibyte state */
301 
302   #define CCFN_PARAMS	(const wchar_t *, wchar_t **, int)
303   unsigned long (*ccfn)CCFN_PARAMS=0;	/* conversion function (wcstol/wcstoul) */
304   wchar_t buf[BUF];		/* buffer for numeric conversions */
305   const wchar_t *ccls;          /* character class start */
306   const wchar_t *ccle;          /* character class end */
307   int cclcompl = 0;             /* ccl is complemented? */
308   wint_t wi;                    /* handy wint_t */
309   char *mbp = NULL;             /* multibyte string pointer for %c %s %[ */
310   size_t nconv;                 /* number of bytes in mb. conversion */
311   char mbbuf[MB_LEN_MAX];	/* temporary mb. character buffer */
312 
313   char *cp;
314   short *sp;
315   int *ip;
316 #ifdef FLOATING_POINT
317   float *flp;
318   _LONG_DOUBLE *ldp;
319   double *dp;
320   wchar_t decpt;
321 #endif
322   long *lp;
323 #ifndef _NO_LONGLONG
324   long long *llp;
325 #endif
326 #ifdef _WANT_IO_C99_FORMATS
327 #define _WANT_IO_POSIX_EXTENSIONS
328 #endif
329 #ifdef _WANT_IO_POSIX_EXTENSIONS
330   /* POSIX requires that fwscanf frees all allocated strings from 'm'
331      conversions in case it returns EOF.  m_ptr is used to keep track.
332      It will be allocated on the stack the first time an 'm' conversion
333      takes place, and it will be free'd on return from the function.
334      This implementation tries to save space by only allocating 8
335      pointer slots at a time.  Most scenarios should never have to call
336      realloc again.  This implementation allows only up to 65528 'm'
337      conversions per fwscanf invocation for now.  That should be enough
338      for almost all scenarios, right? */
339   struct m_ptrs {
340     void ***m_arr;		/* Array of pointer args to 'm' conversion */
341     uint16_t m_siz;		/* Number of slots in m_arr */
342     uint16_t m_cnt;		/* Number of valid entries in m_arr */
343   } *m_ptr = NULL, m_store;
344   #define init_m_ptr()							\
345     do									\
346       {									\
347 	if (!m_ptr)							\
348 	  {								\
349 	    m_ptr = &m_store;		                                \
350 	    m_ptr->m_arr = NULL;					\
351 	    m_ptr->m_siz = 0;						\
352 	    m_ptr->m_cnt = 0;						\
353 	  }								\
354       }									\
355     while (0)
356   #define push_m_ptr(arg)						\
357     do									\
358       {									\
359 	if (m_ptr->m_cnt >= m_ptr->m_siz)				\
360 	  {								\
361 	    void ***n = NULL;						\
362 									\
363 	    if (m_ptr->m_siz + 8 > 0 && m_ptr->m_siz + 8 < UINT16_MAX)	\
364 	      n = (void ***) realloc (m_ptr->m_arr,			\
365 				      (m_ptr->m_siz + 8) *		\
366 				      sizeof (void **));		\
367 	    if (!n)							\
368 	      {								\
369 		nassigned = EOF;					\
370 		goto match_failure;					\
371 	      }								\
372 	    m_ptr->m_arr = n;						\
373 	    m_ptr->m_siz += 8;						\
374 	  }								\
375 	m_ptr->m_arr[m_ptr->m_cnt++] = (void **) (arg);				\
376       }									\
377     while (0)
378   #define alloc_m_ptr(_type, _p, _p0, _p_p, _w)				\
379     ({									\
380       _p_p = GET_ARG (N, ap, _type **);					\
381       if (!_p_p)							\
382 	goto match_failure;						\
383       _p0 = (_type *) malloc ((_w) * sizeof (_type));			\
384       if (!_p0)								\
385 	{								\
386 	  nassigned = EOF;						\
387 	  goto match_failure;						\
388 	}								\
389       *_p_p = _p0;							\
390       push_m_ptr (_p_p);						\
391       _p = _p0;								\
392       _w;								\
393     })
394   /* For char output, check if there's room for at least MB_CUR_MAX
395      characters. */
396   #define realloc_m_ptr(_type, _p, _p0, _p_p, _w)			\
397     ({									\
398       size_t _nw = (_w);						\
399       ptrdiff_t _dif = _p - _p0;					\
400       if (_p_p &&							\
401 	  ((sizeof (_type) == 1 && (size_t) _dif >= _nw - MB_CUR_MAX)   \
402 	   || (size_t) _dif >= _nw))                                    \
403 	{								\
404 	  _p0 = (_type *) realloc (_p0, (_nw << 1) * sizeof (_type));	\
405 	  if (!_p0)							\
406 	    {								\
407 	      nassigned = EOF;						\
408 	      goto match_failure;					\
409 	    }								\
410 	  _p = _p0 + _dif;						\
411 	  *_p_p = _p0;							\
412 	  _nw <<= 1;							\
413 	}								\
414       _nw;								\
415     })
416   #define shrink_m_ptr(_type, _p_p, _w, _cw)				\
417     ({									\
418 	size_t _nw = (_w);						\
419 	if (_p_p && _nw < _cw)						\
420 	  {								\
421 	    _type *_np_p = (_type *)					\
422 			   realloc (*_p_p, _nw * sizeof (_type));	\
423 	    if (_np_p)							\
424 	      *_p_p = _np_p;						\
425 	  }								\
426     })
427   #define free_m_ptr()							\
428     do									\
429       {									\
430 	if (m_ptr)							\
431 	  {								\
432 	    if (nassigned == EOF)					\
433 	      {								\
434                 unsigned i;                                             \
435 		for (i = 0; i < m_ptr->m_cnt; ++i)			\
436 		  {							\
437 		    free (*m_ptr->m_arr[i]);				\
438 		    *m_ptr->m_arr[i] = NULL;				\
439 		  }							\
440 	      }								\
441 	    if (m_ptr->m_arr)						\
442 	      free (m_ptr->m_arr);					\
443 	  }								\
444       }									\
445     while (0)
446 #endif
447 
448   /* `basefix' is used to avoid `if' tests in the integer scanner */
449   static const short basefix[17] =
450     {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
451 
452   /* Macro to support positional arguments */
453 #ifndef _NO_POS_ARGS
454 # define GET_ARG(n, ap, type)					\
455   ((type) (is_pos_arg						\
456 	   ? (n < numargs					\
457 	      ? args[n]						\
458 	      : get_arg (n, &ap, &numargs, args))		\
459 	   : (arg_index++ < numargs				\
460 	      ? args[n]						\
461 	      : (numargs < MAX_POS_ARGS				\
462 		 ? args[numargs++] = va_arg (ap, void *)	\
463 		 : va_arg (ap, void *)))))
464 #else
465 # define GET_ARG(n, ap, type) (va_arg (ap, type))
466 #endif
467 
468 #ifdef FLOATING_POINT
469 #ifdef _MB_CAPABLE
470 #ifdef __HAVE_LOCALE_INFO_EXTENDED__
471 	  decpt = *__get_current_numeric_locale ()->wdecimal_point;
472 #else
473 	  {
474 	    size_t nconv;
475 
476 	    memset (&mbs, '\0', sizeof (mbs));
477 	    nconv = mbrtowc (&decpt,
478 				localeconv ()->decimal_point,
479 				MB_CUR_MAX, &mbs);
480 	    if (nconv == (size_t) -1 || nconv == (size_t) -2)
481 	      decpt = L'.';
482 	  }
483 #endif /* !__HAVE_LOCALE_INFO_EXTENDED__ */
484 #else
485 	  decpt = (wchar_t) *localeconv ()->decimal_point;
486 #endif /* !_MB_CAPABLE */
487 #endif /* FLOATING_POINT */
488 
489   _newlib_flockfile_start (fp);
490 
491   ORIENT (fp, 1);
492 
493   nassigned = 0;
494   nread = 0;
495   ccls = ccle = NULL;
496   for (;;)
497     {
498       c = *fmt++;
499       if (c == L'\0')
500 	goto all_done;
501       if (iswspace (c))
502 	{
503 	  while ((c = fgetwc ( fp)) != WEOF && iswspace(c))
504 	    ;
505 	  if (c != WEOF)
506 	    ungetwc ( c, fp);
507 	  continue;
508 	}
509       if (c != L'%')
510 	goto literal;
511       width = 0;
512       flags = 0;
513 #ifndef _NO_POS_ARGS
514       N = arg_index;
515       is_pos_arg = 0;
516 #endif
517 
518       /*
519        * switch on the format.  continue if done; break once format
520        * type is derived.
521        */
522 
523     again:
524       c = *fmt++;
525 
526       switch (c)
527 	{
528 	case L'%':
529 	literal:
530 	  if ((wi = fgetwc ( fp)) == WEOF)
531 	    goto input_failure;
532 	  if (wi != c)
533 	    {
534 	      ungetwc ( wi, fp);
535 	      goto input_failure;
536 	    }
537 	  nread++;
538 	  continue;
539 
540 	case L'*':
541 	  if ((flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS | MALLOC))
542 	      || width)
543 	    goto match_failure;
544 	  flags |= SUPPRESS;
545 	  goto again;
546 	case L'l':
547 	  if (flags & (CHAR | SHORT | LONG | LONGDBL))
548 	    goto match_failure;
549 #if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
550 	  if (*fmt == L'l')	/* Check for 'll' = long long (SUSv3) */
551 	    {
552 	      ++fmt;
553 	      flags |= LONGDBL;
554 	    }
555 	  else
556 #endif
557 	    flags |= LONG;
558 	  goto again;
559 	case L'L':
560 	  if (flags & (CHAR | SHORT | LONG | LONGDBL))
561 	    goto match_failure;
562 	  flags |= LONGDBL;
563 	  goto again;
564 	case L'h':
565 #ifdef _WANT_IO_C99_FORMATS
566 	  if (flags & (CHAR | SHORT | LONG | LONGDBL))
567 	    goto match_failure;
568 	  if (*fmt == 'h')	/* Check for 'hh' = char int (SUSv3) */
569 	    {
570 	      ++fmt;
571 	      flags |= CHAR;
572 	    }
573 	  else
574 #endif
575 	    flags |= SHORT;
576 	  goto again;
577 #ifdef _WANT_IO_C99_FORMATS
578 	case L'j': /* intmax_t */
579 	  if (flags & (CHAR | SHORT | LONG | LONGDBL))
580 	    goto match_failure;
581 	  if (sizeof (intmax_t) == sizeof (long))
582 	    flags |= LONG;
583 	  else
584 	    flags |= LONGDBL;
585 	  goto again;
586 	case L't': /* ptrdiff_t */
587 	  if (flags & (CHAR | SHORT | LONG | LONGDBL))
588 	    goto match_failure;
589 	  if (sizeof (ptrdiff_t) < sizeof (int))
590 	    /* POSIX states ptrdiff_t is 16 or more bits, as
591 	       is short.  */
592 	    flags |= SHORT;
593 	  else if (sizeof (ptrdiff_t) == sizeof (int))
594 	    /* no flag needed */;
595 	  else if (sizeof (ptrdiff_t) <= sizeof (long))
596 	    flags |= LONG;
597 	  else
598 	    /* POSIX states that at least one programming
599 	       environment must support ptrdiff_t no wider than
600 	       long, but that means other environments can
601 	       have ptrdiff_t as wide as long long.  */
602 	    flags |= LONGDBL;
603 	  goto again;
604 	case L'z': /* size_t */
605 	  if (flags & (CHAR | SHORT | LONG | LONGDBL))
606 	    goto match_failure;
607 	  if (sizeof (size_t) < sizeof (int))
608 	    /* POSIX states size_t is 16 or more bits, as is short.  */
609 	    flags |= SHORT;
610 	  else if (sizeof (size_t) == sizeof (int))
611 	    /* no flag needed */;
612 	  else if (sizeof (size_t) <= sizeof (long))
613 	    flags |= LONG;
614 	  else
615 	    /* POSIX states that at least one programming
616 	       environment must support size_t no wider than
617 	       long, but that means other environments can
618 	       have size_t as wide as long long.  */
619 	    flags |= LONGDBL;
620 	  goto again;
621 #endif /* _WANT_IO_C99_FORMATS */
622 #ifdef _WANT_IO_POSIX_EXTENSIONS
623 	case 'm':
624 	  if (flags & (CHAR | SHORT | LONG | LONGDBL | MALLOC))
625 	    goto match_failure;
626 	  init_m_ptr ();
627 	  flags |= MALLOC;
628 	  goto again;
629 #endif
630 
631 	case L'0':
632 	case L'1':
633 	case L'2':
634 	case L'3':
635 	case L'4':
636 	case L'5':
637 	case L'6':
638 	case L'7':
639 	case L'8':
640 	case L'9':
641 	  if (flags & (CHAR | SHORT | LONG | LONGDBL | MALLOC))
642 	    goto match_failure;
643 	  width = width * 10 + c - L'0';
644 	  goto again;
645 
646 #ifndef _NO_POS_ARGS
647 	case L'$':
648 	  if (flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS | MALLOC))
649 	    goto match_failure;
650 	  if (width <= MAX_POS_ARGS)
651 	    {
652 	      N = width - 1;
653 	      is_pos_arg = 1;
654 	      width = 0;
655 	      goto again;
656 	    }
657 	  _REENT_ERRNO(rptr) = EINVAL;
658 	  goto input_failure;
659 #endif /* !_NO_POS_ARGS */
660 
661 	case L'd':
662 	  c = CT_INT;
663 	  ccfn = (unsigned long (*)CCFN_PARAMS)wcstol;
664 	  base = 10;
665 	  break;
666 
667 	case L'i':
668 	  c = CT_INT;
669 	  ccfn = (unsigned long (*)CCFN_PARAMS)wcstol;
670 	  base = 0;
671 	  break;
672 
673 	case L'o':
674 	  c = CT_INT;
675 	  ccfn = wcstoul;
676 	  base = 8;
677 	  break;
678 
679 	case L'u':
680 	  c = CT_INT;
681 	  ccfn = wcstoul;
682 	  base = 10;
683 	  break;
684 
685 	case L'X':
686 	case L'x':
687 	  flags |= PFXOK;	/* enable 0x prefixing */
688 	  c = CT_INT;
689 	  ccfn = wcstoul;
690 	  base = 16;
691 	  break;
692 
693 #ifdef FLOATING_POINT
694 # ifdef _WANT_IO_C99_FORMATS
695 	case L'A':
696 	case L'a':
697 	case L'F':
698 # endif
699 	case L'E':
700 	case L'G':
701 	case L'e':
702 	case L'f':
703 	case L'g':
704 	  c = CT_FLOAT;
705 	  break;
706 #endif
707 
708 #ifdef _WANT_IO_C99_FORMATS
709 	case L'S':
710 	  flags |= LONG;
711           FALLTHROUGH;
712 #endif
713 
714 	case L's':
715 	  c = CT_STRING;
716 	  break;
717 
718 	case L'[':
719 	  if (*fmt == '^')
720 	    {
721 	      cclcompl = 1;
722 	      ++fmt;
723 	    }
724 	  else
725 	    cclcompl = 0;
726 	  ccls = fmt;
727 	  if (*fmt == ']')
728 	    fmt++;
729 	  while (*fmt != '\0' && *fmt != ']')
730 	    fmt++;
731 	  ccle = fmt;
732 	  fmt++;
733 	  flags |= NOSKIP;
734 	  c = CT_CCL;
735 	  break;
736 
737 #ifdef _WANT_IO_C99_FORMATS
738 	case 'C':
739 	  flags |= LONG;
740           FALLTHROUGH;
741 #endif
742 
743 	case 'c':
744 	  flags |= NOSKIP;
745 	  c = CT_CHAR;
746 	  break;
747 
748 	case 'p':		/* pointer format is like hex */
749 	  flags |= POINTER | PFXOK;
750 	  c = CT_INT;
751 	  ccfn = wcstoul;
752 	  base = 16;
753 	  break;
754 
755 	case 'n':
756 	  if (flags & SUPPRESS)	/* ??? */
757 	    continue;
758 #ifdef _WANT_IO_C99_FORMATS
759 	  if (flags & CHAR)
760 	    {
761 	      cp = GET_ARG (N, ap, char *);
762 	      *cp = nread;
763 	    }
764 	  else
765 #endif
766 	  if (flags & SHORT)
767 	    {
768 	      sp = GET_ARG (N, ap, short *);
769 	      *sp = nread;
770 	    }
771 	  else if (flags & LONG)
772 	    {
773 	      lp = GET_ARG (N, ap, long *);
774 	      *lp = nread;
775 	    }
776 #ifndef _NO_LONGLONG
777 	  else if (flags & LONGDBL)
778 	    {
779 	      llp = GET_ARG (N, ap, long long*);
780 	      *llp = nread;
781 	    }
782 #endif
783 	  else
784 	    {
785 	      ip = GET_ARG (N, ap, int *);
786 	      *ip = nread;
787 	    }
788 	  continue;
789 
790 	default:
791 	  goto match_failure;
792 	}
793 
794       /*
795        * Consume leading white space, except for formats that
796        * suppress this.
797        */
798       if ((flags & NOSKIP) == 0)
799 	{
800 	  while ((wi = fgetwc ( fp)) != WEOF && iswspace (wi))
801 	    nread++;
802 	  if (wi == WEOF)
803 	    goto input_failure;
804 	  ungetwc ( wi, fp);
805 	}
806 
807       /*
808        * Do the conversion.
809        */
810       switch (c)
811 	{
812 
813 	case CT_CHAR:
814 	  /* scan arbitrary characters (sets NOSKIP) */
815 	  if (width == 0)
816 	    width = 1;
817           if (flags & LONG)
818 	    {
819 #ifdef _WANT_IO_POSIX_EXTENSIONS
820 	      wchar_t **p_p = NULL;
821 	      wchar_t *p0 = NULL;
822 	      size_t p_siz = 0;
823 #endif
824 
825 	      if (flags & SUPPRESS)
826 		;
827 #ifdef _WANT_IO_POSIX_EXTENSIONS
828 	      else if (flags & MALLOC)
829 		p_siz = alloc_m_ptr (wchar_t, p, p0, p_p, 32);
830 #endif
831 	      else
832 		p = GET_ARG(N, ap, wchar_t *);
833 	      n = 0;
834 	      while (width-- != 0 && (wi = fgetwc ( fp)) != WEOF)
835 		{
836 		  if (!(flags & SUPPRESS))
837 		    {
838 #ifdef _WANT_IO_POSIX_EXTENSIONS
839 		      /* Check before ++ because we never add a \0 */
840 		      p_siz = realloc_m_ptr (wchar_t, p, p0, p_p, p_siz);
841 #endif
842 		      *p++ = (wchar_t) wi;
843 		    }
844 		  n++;
845 		}
846 	      if (n == 0)
847 		goto input_failure;
848 	      nread += n;
849 #ifdef _WANT_IO_POSIX_EXTENSIONS
850 	      shrink_m_ptr (wchar_t, p_p, p - p0, p_siz);
851 #endif
852 	      if (!(flags & SUPPRESS))
853 		nassigned++;
854 	    }
855 	  else
856 	    {
857 #ifdef _WANT_IO_POSIX_EXTENSIONS
858 	      char **mbp_p = NULL;
859 	      char *mbp0 = NULL;
860 	      size_t mbp_siz = 0;
861 #endif
862 
863 	      if (flags & SUPPRESS)
864 		mbp = mbbuf;
865 #ifdef _WANT_IO_POSIX_EXTENSIONS
866 	      else if (flags & MALLOC)
867 		mbp_siz = alloc_m_ptr (char, mbp, mbp0, mbp_p, 32);
868 #endif
869 	      else
870 		mbp = GET_ARG(N, ap, char *);
871 	      n = 0;
872 	      memset ((void *)&mbs, '\0', sizeof (mbstate_t));
873 	      while (width != 0 && (wi = fgetwc ( fp)) != WEOF)
874 		{
875 		  nconv = wcrtomb (mbp, wi, &mbs);
876 		  if (nconv == (size_t) -1)
877 		    goto input_failure;
878 		  /* Ignore high surrogate in width counting */
879 		  if (nconv != 0 || mbs.__count != -4)
880 		    width--;
881 		  if (!(flags & SUPPRESS))
882 		    {
883 #ifdef _WANT_IO_POSIX_EXTENSIONS
884 		      mbp_siz = realloc_m_ptr (char, mbp, mbp0, mbp_p, mbp_siz);
885 #endif
886 		      mbp += nconv;
887 		    }
888 		  n++;
889 		}
890 	      if (n == 0)
891 		goto input_failure;
892 	      nread += n;
893 #ifdef _WANT_IO_POSIX_EXTENSIONS
894 	      shrink_m_ptr (char, mbp_p, mbp - mbp0, mbp_siz);
895 #endif
896 	      if (!(flags & SUPPRESS))
897 		nassigned++;
898 	    }
899 	  break;
900 
901 	case CT_CCL:
902 	  /* scan a (nonempty) character class (sets NOSKIP) */
903 	  if (width == 0)
904 	    width = SIZE_MAX;		/* `infinity' */
905 	  /* take only those things in the class */
906 	  if ((flags & SUPPRESS) && (flags & LONG))
907 	    {
908 	      n = 0;
909 	      while ((wi = fgetwc ( fp)) != WEOF
910 		     && width-- != 0 && INCCL (wi))
911 		n++;
912 	      if (wi != WEOF)
913 		ungetwc ( wi, fp);
914 	      if (n == 0)
915 		goto match_failure;
916 	    }
917 	  else if (flags & LONG)
918 	    {
919 #ifdef _WANT_IO_POSIX_EXTENSIONS
920 	      wchar_t **p_p = NULL;
921 	      size_t p_siz = 0;
922 
923 	      if (flags & MALLOC)
924 		p_siz = alloc_m_ptr (wchar_t, p, p0, p_p, 32);
925 	      else
926 #endif
927 		p0 = p = GET_ARG(N, ap, wchar_t *);
928 	      while ((wi = fgetwc ( fp)) != WEOF
929 		     && width-- != 0 && INCCL (wi))
930 		{
931 		  *p++ = (wchar_t) wi;
932 #ifdef _WANT_IO_POSIX_EXTENSIONS
933 		  p_siz = realloc_m_ptr (wchar_t, p, p0, p_p, p_siz);
934 #endif
935 		}
936 	      if (wi != WEOF)
937 		ungetwc ( wi, fp);
938 	      n = p - p0;
939 	      if (n == 0)
940 		goto match_failure;
941 	      *p = L'\0';
942 #ifdef _WANT_IO_POSIX_EXTENSIONS
943 	      shrink_m_ptr (wchar_t, p_p, n + 1, p_siz);
944 #endif
945 	      nassigned++;
946 	    }
947 	  else
948 	    {
949 #ifdef _WANT_IO_POSIX_EXTENSIONS
950 	      char **mbp_p = NULL;
951 	      char *mbp0 = NULL;
952 	      size_t mbp_siz = 0;
953 #endif
954 
955 	      if (flags & SUPPRESS)
956 		mbp = mbbuf;
957 #ifdef _WANT_IO_POSIX_EXTENSIONS
958 	      else if (flags & MALLOC)
959 		mbp_siz = alloc_m_ptr (char, mbp, mbp0, mbp_p, 32);
960 #endif
961 	      else
962 		mbp = GET_ARG(N, ap, char *);
963 	      n = 0;
964 	      memset ((void *) &mbs, '\0', sizeof (mbstate_t));
965 	      while ((wi = fgetwc ( fp)) != WEOF
966 		     && width != 0 && INCCL (wi))
967 		{
968 		  nconv = wcrtomb (mbp, wi, &mbs);
969 		  if (nconv == (size_t) -1)
970 		    goto input_failure;
971 		  /* Ignore high surrogate in width counting */
972 		  if (nconv != 0 || mbs.__count != -4)
973 		    width--;
974 		  if (!(flags & SUPPRESS))
975 		    {
976 		      mbp += nconv;
977 #ifdef _WANT_IO_POSIX_EXTENSIONS
978 		      mbp_siz = realloc_m_ptr (char, mbp, mbp0, mbp_p, mbp_siz);
979 #endif
980 		    }
981 		  n++;
982 		}
983 	      if (wi != WEOF)
984 		ungetwc ( wi, fp);
985 	      if (!(flags & SUPPRESS))
986 		{
987 		  *mbp = 0;
988 #ifdef _WANT_IO_POSIX_EXTENSIONS
989 		  shrink_m_ptr (char, mbp_p, mbp - mbp0 + 1, mbp_siz);
990 #endif
991 		  nassigned++;
992 		}
993 	    }
994 	  nread += n;
995 	  break;
996 
997 	case CT_STRING:
998 	  /* like CCL, but zero-length string OK, & no NOSKIP */
999 	  if (width == 0)
1000             width = SIZE_MAX;
1001 	  if ((flags & SUPPRESS) && (flags & LONG))
1002 	    {
1003 	      while ((wi = fgetwc ( fp)) != WEOF
1004 		     && width-- != 0 && !iswspace (wi))
1005 		nread++;
1006 	      if (wi != WEOF)
1007 		ungetwc ( wi, fp);
1008 	    }
1009 	  else if (flags & LONG)
1010 	    {
1011 #ifdef _WANT_IO_POSIX_EXTENSIONS
1012               wchar_t **p_p = NULL;
1013               size_t p_siz = 0;
1014 
1015               if (flags & MALLOC)
1016                 p_siz = alloc_m_ptr (wchar_t, p, p0, p_p, 32);
1017               else
1018 #endif
1019 		p0 = p = GET_ARG(N, ap, wchar_t *);
1020 	      while ((wi = fgetwc ( fp)) != WEOF
1021 		     && width-- != 0 && !iswspace (wi))
1022 		{
1023 		  *p++ = (wchar_t) wi;
1024 #ifdef _WANT_IO_POSIX_EXTENSIONS
1025 		  p_siz = realloc_m_ptr (wchar_t, p, p0, p_p, p_siz);
1026 #endif
1027 		  nread++;
1028 		}
1029 	      if (wi != WEOF)
1030 		ungetwc ( wi, fp);
1031 	      *p = L'\0';
1032 #ifdef _WANT_IO_POSIX_EXTENSIONS
1033 	      shrink_m_ptr (wchar_t, p_p, p - p0 + 1, p_siz);
1034 #endif
1035 	      nassigned++;
1036 	    }
1037 	  else
1038 	    {
1039 #ifdef _WANT_IO_POSIX_EXTENSIONS
1040 	      char **mbp_p = NULL;
1041 	      char *mbp0 = NULL;
1042 	      size_t mbp_siz = 0;
1043 #endif
1044 
1045 	      if (flags & SUPPRESS)
1046 		mbp = mbbuf;
1047 #ifdef _WANT_IO_POSIX_EXTENSIONS
1048 	      else if (flags & MALLOC)
1049 		mbp_siz = alloc_m_ptr (char, mbp, mbp0, mbp_p, 32);
1050 #endif
1051 	      else
1052 		mbp = GET_ARG(N, ap, char *);
1053 	      memset ((void *) &mbs, '\0', sizeof (mbstate_t));
1054 	      while ((wi = fgetwc ( fp)) != WEOF
1055 		     && width != 0 && !iswspace (wi))
1056 		{
1057 		  nconv = wcrtomb(mbp, wi, &mbs);
1058 		  if (nconv == (size_t)-1)
1059 		    goto input_failure;
1060 		  /* Ignore high surrogate in width counting */
1061 		  if (nconv != 0 || mbs.__count != -4)
1062 		    width--;
1063 		  if (!(flags & SUPPRESS))
1064 		    {
1065 		      mbp += nconv;
1066 #ifdef _WANT_IO_POSIX_EXTENSIONS
1067 		      mbp_siz = realloc_m_ptr (char, mbp, mbp0, mbp_p, mbp_siz);
1068 #endif
1069 		    }
1070 		  nread++;
1071 		}
1072 	      if (wi != WEOF)
1073 		ungetwc ( wi, fp);
1074 	      if (!(flags & SUPPRESS))
1075 		{
1076 		  *mbp = 0;
1077 #ifdef _WANT_IO_POSIX_EXTENSIONS
1078 		  shrink_m_ptr (char, mbp_p, mbp - mbp0 + 1, mbp_siz);
1079 #endif
1080 		  nassigned++;
1081 		}
1082 	    }
1083 	  continue;
1084 
1085 	case CT_INT:
1086 	{
1087 	  /* scan an integer as if by wcstol/wcstoul */
1088 	  if (width == 0 || width > sizeof (buf) / sizeof (*buf) - 1)
1089 	    width = sizeof(buf) / sizeof (*buf) - 1;
1090 	  flags |= SIGNOK | NDIGITS | NZDIGITS;
1091 	  for (p = buf; width; width--)
1092 	    {
1093 	      c = fgetwc ( fp);
1094 	      /*
1095 	       * Switch on the character; `goto ok' if we
1096 	       * accept it as a part of number.
1097 	       */
1098 	      switch (c)
1099 		{
1100 		  /*
1101 		   * The digit 0 is always legal, but is special.
1102 		   * For %i conversions, if no digits (zero or nonzero)
1103 		   * have been scanned (only signs), we will have base==0.
1104 		   * In that case, we should set it to 8 and enable 0x
1105 		   * prefixing. Also, if we have not scanned zero digits
1106 		   * before this, do not turn off prefixing (someone else
1107 		   * will turn it off if we have scanned any nonzero digits).
1108 		   */
1109 		case L'0':
1110 		  if (base == 0)
1111 		    {
1112 		      base = 8;
1113 		      flags |= PFXOK;
1114 		    }
1115 		  if (flags & NZDIGITS)
1116 		    flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
1117 		  else
1118 		    flags &= ~(SIGNOK | PFXOK | NDIGITS);
1119 		  goto ok;
1120 
1121 		  /* 1 through 7 always legal */
1122 		case L'1':
1123 		case L'2':
1124 		case L'3':
1125 		case L'4':
1126 		case L'5':
1127 		case L'6':
1128 		case L'7':
1129 		  base = basefix[base];
1130 		  flags &= ~(SIGNOK | PFXOK | NDIGITS);
1131 		  goto ok;
1132 
1133 		  /* digits 8 and 9 ok iff decimal or hex */
1134 		case L'8':
1135 		case L'9':
1136 		  base = basefix[base];
1137 		  if (base <= 8)
1138 		    break;	/* not legal here */
1139 		  flags &= ~(SIGNOK | PFXOK | NDIGITS);
1140 		  goto ok;
1141 
1142 		  /* letters ok iff hex */
1143 		case L'A':
1144 		case L'B':
1145 		case L'C':
1146 		case L'D':
1147 		case L'E':
1148 		case L'F':
1149 		case L'a':
1150 		case L'b':
1151 		case L'c':
1152 		case L'd':
1153 		case L'e':
1154 		case L'f':
1155 		  /* no need to fix base here */
1156 		  if (base <= 10)
1157 		    break;	/* not legal here */
1158 		  flags &= ~(SIGNOK | PFXOK | NDIGITS);
1159 		  goto ok;
1160 
1161 		  /* sign ok only as first character */
1162 		case L'+':
1163 		case L'-':
1164 		  if (flags & SIGNOK)
1165 		    {
1166 		      flags &= ~SIGNOK;
1167 		      flags |= HAVESIGN;
1168 		      goto ok;
1169 		    }
1170 		  break;
1171 
1172 		  /* x ok iff flag still set & single 0 seen */
1173 		case L'x':
1174 		case L'X':
1175 		  if ((flags & PFXOK) && p == buf + 1 + !!(flags & HAVESIGN))
1176 		    {
1177 		      base = 16;/* if %i */
1178 		      flags &= ~PFXOK;
1179 		      goto ok;
1180 		    }
1181 		  break;
1182 		}
1183 
1184 	      /*
1185 	       * If we got here, c is not a legal character
1186 	       * for a number.  Stop accumulating digits.
1187 	       */
1188 	      if (c != WEOF)
1189 		ungetwc ( c, fp);
1190 	      break;
1191 	    ok:
1192 	      /*
1193 	       * c is legal: store it and look at the next.
1194 	       */
1195 	      *p++ = (wchar_t) c;
1196 	    }
1197 	  /*
1198 	   * If we had only a sign, it is no good; push back the sign.
1199 	   * If the number ends in `x', it was [sign] '0' 'x', so push back
1200 	   * the x and treat it as [sign] '0'.
1201 	   * Use of ungetc here and below assumes ASCII encoding; we are only
1202 	   * pushing back 7-bit characters, so casting to unsigned char is
1203 	   * not necessary.
1204 	   */
1205 	  if (flags & NDIGITS)
1206 	    {
1207 	      if (p > buf)
1208 		ungetwc ( *--p, fp); /* [-+xX] */
1209 	      goto match_failure;
1210 	    }
1211 	  c = p[-1];
1212 	  if (c == L'x' || c == L'X')
1213 	    {
1214 	      --p;
1215 	      ungetwc ( c, fp);
1216 	    }
1217 	  if ((flags & SUPPRESS) == 0)
1218 	    {
1219 	      unsigned long res;
1220 
1221 	      *p = 0;
1222 	      res = (*ccfn) (buf, (wchar_t **) NULL, base);
1223 	      if (flags & POINTER)
1224 		{
1225 		  void **vp = GET_ARG (N, ap, void **);
1226 #ifndef _NO_LONGLONG
1227 		  if (sizeof (uintptr_t) > sizeof (unsigned long))
1228 		    {
1229 		      unsigned long long resll;
1230 		      resll = wcstoull (buf, (wchar_t **) NULL, base);
1231 		      *vp = (void *) (uintptr_t) resll;
1232 		    }
1233 		  else
1234 #endif /* !_NO_LONGLONG */
1235 		    *vp = (void *) (uintptr_t) res;
1236 		}
1237 #ifdef _WANT_IO_C99_FORMATS
1238 	      else if (flags & CHAR)
1239 		{
1240 		  cp = GET_ARG (N, ap, char *);
1241 		  *cp = res;
1242 		}
1243 #endif
1244 	      else if (flags & SHORT)
1245 		{
1246 		  sp = GET_ARG (N, ap, short *);
1247 		  *sp = res;
1248 		}
1249 	      else if (flags & LONG)
1250 		{
1251 		  lp = GET_ARG (N, ap, long *);
1252 		  *lp = res;
1253 		}
1254 #ifndef _NO_LONGLONG
1255 	      else if (flags & LONGDBL)
1256 		{
1257 		  unsigned long long resll;
1258 		  if (ccfn == wcstoul)
1259 		    resll = wcstoull (buf, (wchar_t **) NULL, base);
1260 		  else
1261 		    resll = wcstoll (buf, (wchar_t **) NULL, base);
1262 		  llp = GET_ARG (N, ap, long long*);
1263 		  *llp = resll;
1264 		}
1265 #endif
1266 	      else
1267 		{
1268 		  ip = GET_ARG (N, ap, int *);
1269 		  *ip = res;
1270 		}
1271 	      nassigned++;
1272 	    }
1273 	  nread += p - buf;
1274 	  break;
1275 	}
1276 #ifdef FLOATING_POINT
1277 	case CT_FLOAT:
1278 	{
1279 	  /* scan a floating point number as if by wcstod */
1280 	  /* This code used to assume that the number of digits is reasonable.
1281 	     However, ANSI / ISO C makes no such stipulation; we have to get
1282 	     exact results even when there is an unreasonable amount of
1283 	     leading zeroes.  */
1284 	  long leading_zeroes = 0;
1285 	  long zeroes, exp_adjust;
1286 	  wchar_t *exp_start = NULL;
1287 	  unsigned width_left = 0;
1288 	  char nancount = 0;
1289 	  char infcount = 0;
1290 #ifdef hardway
1291 	  if (width == 0 || width > sizeof (buf) / sizeof (*buf) - 1)
1292 #else
1293 	  /* size_t is unsigned, hence this optimisation */
1294 	  if (width - 1 > sizeof (buf) / sizeof (*buf) - 2)
1295 #endif
1296 	    {
1297 	      width_left = width - (sizeof (buf) / sizeof (*buf) - 1);
1298 	      width = sizeof (buf) / sizeof (*buf) - 1;
1299 	    }
1300 	  flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
1301 	  zeroes = 0;
1302 	  exp_adjust = 0;
1303 	  for (p = buf; width; )
1304 	    {
1305 	      c = fgetwc ( fp);
1306 	      /*
1307 	       * This code mimicks the integer conversion
1308 	       * code, but is much simpler.
1309 	       */
1310 	      switch (c)
1311 		{
1312 		case L'0':
1313 		  if (flags & NDIGITS)
1314 		    {
1315 		      flags &= ~SIGNOK;
1316 		      zeroes++;
1317 		      if (width_left)
1318 			{
1319 			  width_left--;
1320 			  width++;
1321 			}
1322 		      goto fskip;
1323 		    }
1324 		  /* Fall through.  */
1325 		case L'1':
1326 		case L'2':
1327 		case L'3':
1328 		case L'4':
1329 		case L'5':
1330 		case L'6':
1331 		case L'7':
1332 		case L'8':
1333 		case L'9':
1334 		  if (nancount + infcount == 0)
1335 		    {
1336 		      flags &= ~(SIGNOK | NDIGITS);
1337 		      goto fok;
1338 		    }
1339 		  break;
1340 
1341 		case L'+':
1342 		case L'-':
1343 		  if (flags & SIGNOK)
1344 		    {
1345 		      flags &= ~SIGNOK;
1346 		      goto fok;
1347 		    }
1348 		  break;
1349 		case L'n':
1350 		case L'N':
1351 		  if (nancount == 0 && zeroes == 0
1352 		      && (flags & (NDIGITS | DPTOK | EXPOK)) ==
1353 				  (NDIGITS | DPTOK | EXPOK))
1354 		    {
1355 		      flags &= ~(SIGNOK | DPTOK | EXPOK | NDIGITS);
1356 		      nancount = 1;
1357 		      goto fok;
1358 		    }
1359 		  if (nancount == 2)
1360 		    {
1361 		      nancount = 3;
1362 		      goto fok;
1363 		    }
1364 		  if (infcount == 1 || infcount == 4)
1365 		    {
1366 		      infcount++;
1367 		      goto fok;
1368 		    }
1369 		  break;
1370 		case L'a':
1371 		case L'A':
1372 		  if (nancount == 1)
1373 		    {
1374 		      nancount = 2;
1375 		      goto fok;
1376 		    }
1377 		  break;
1378 		case L'i':
1379 		  if (infcount == 0 && zeroes == 0
1380 		      && (flags & (NDIGITS | DPTOK | EXPOK)) ==
1381 				  (NDIGITS | DPTOK | EXPOK))
1382 		    {
1383 		      flags &= ~(SIGNOK | DPTOK | EXPOK | NDIGITS);
1384 		      infcount = 1;
1385 		      goto fok;
1386 		    }
1387 		  if (infcount == 3 || infcount == 5)
1388 		    {
1389 		      infcount++;
1390 		      goto fok;
1391 		    }
1392 		  break;
1393 		case L'f':
1394 		case L'F':
1395 		  if (infcount == 2)
1396 		    {
1397 		      infcount = 3;
1398 		      goto fok;
1399 		    }
1400 		  break;
1401 		case L't':
1402 		case L'T':
1403 		  if (infcount == 6)
1404 		    {
1405 		      infcount = 7;
1406 		      goto fok;
1407 		    }
1408 		  break;
1409 		case L'y':
1410 		case L'Y':
1411 		  if (infcount == 7)
1412 		    {
1413 		      infcount = 8;
1414 		      goto fok;
1415 		    }
1416 		  break;
1417 		case L'e':
1418 		case L'E':
1419 		  /* no exponent without some digits */
1420 		  if ((flags & (NDIGITS | EXPOK)) == EXPOK
1421 		      || ((flags & EXPOK) && zeroes))
1422 		    {
1423 		      if (! (flags & DPTOK))
1424 			{
1425 			  exp_adjust = zeroes - leading_zeroes;
1426 			  exp_start = p;
1427 			}
1428 		      flags =
1429 			(flags & ~(EXPOK | DPTOK)) |
1430 			SIGNOK | NDIGITS;
1431 		      zeroes = 0;
1432 		      goto fok;
1433 		    }
1434 		  break;
1435 		default:
1436 		  if ((wchar_t) c == decpt && (flags & DPTOK))
1437 		    {
1438 		      flags &= ~(SIGNOK | DPTOK);
1439 		      leading_zeroes = zeroes;
1440 		      goto fok;
1441 		    }
1442 		  break;
1443 		}
1444 	      if (c != WEOF)
1445 		ungetwc ( c, fp);
1446 	      break;
1447 	    fok:
1448 	      *p++ = c;
1449 	    fskip:
1450 	      width--;
1451 	      ++nread;
1452 	    }
1453 	  if (zeroes)
1454 	    flags &= ~NDIGITS;
1455 	  /* We may have a 'N' or possibly even [sign] 'N' 'a' as the
1456 	     start of 'NaN', only to run out of chars before it was
1457 	     complete (or having encountered a non-matching char).  So
1458 	     check here if we have an outstanding nancount, and if so
1459 	     put back the chars we did swallow and treat as a failed
1460 	     match.
1461 
1462 	     FIXME - we still don't handle NAN([0xdigits]).  */
1463 	  if (nancount - 1U < 2U) /* nancount && nancount < 3 */
1464 	    {
1465 	      /* Newlib's ungetc works even if we called __srefill in
1466 		 the middle of a partial parse, but POSIX does not
1467 		 guarantee that in all implementations of ungetc.  */
1468 	      while (p > buf)
1469 		{
1470 		  ungetwc ( *--p, fp); /* [-+nNaA] */
1471 		  --nread;
1472 		}
1473 	      goto match_failure;
1474 	    }
1475 	  /* Likewise for 'inf' and 'infinity'.	 But be careful that
1476 	     'infinite' consumes only 3 characters, leaving the stream
1477 	     at the second 'i'.	 */
1478 	  if (infcount - 1U < 7U) /* infcount && infcount < 8 */
1479 	    {
1480 	      if (infcount >= 3) /* valid 'inf', but short of 'infinity' */
1481 		while (infcount-- > 3)
1482 		  {
1483 		    ungetwc ( *--p, fp); /* [iInNtT] */
1484 		    --nread;
1485 		  }
1486 	      else
1487 		{
1488 		  while (p > buf)
1489 		    {
1490 		      ungetwc ( *--p, fp); /* [-+iInN] */
1491 		      --nread;
1492 		    }
1493 		  goto match_failure;
1494 		}
1495 	    }
1496 	  /*
1497 	   * If no digits, might be missing exponent digits
1498 	   * (just give back the exponent) or might be missing
1499 	   * regular digits, but had sign and/or decimal point.
1500 	   */
1501 	  if (flags & NDIGITS)
1502 	    {
1503 	      if (flags & EXPOK)
1504 		{
1505 		  /* no digits at all */
1506 		  while (p > buf)
1507 		    {
1508 		      ungetwc ( *--p, fp); /* [-+.] */
1509 		      --nread;
1510 		    }
1511 		  goto match_failure;
1512 		}
1513 	      /* just a bad exponent (e and maybe sign) */
1514 	      c = *--p;
1515 	      --nread;
1516 	      if (c != L'e' && c != L'E')
1517 		{
1518 		  ungetwc ( c, fp); /* [-+] */
1519 		  c = *--p;
1520 		  --nread;
1521 		}
1522 	      ungetwc ( c, fp); /* [eE] */
1523 	    }
1524 	  if ((flags & SUPPRESS) == 0)
1525 	    {
1526 	      double res = 0;
1527 #ifdef _NO_LONGDBL
1528 #define QUAD_RES res;
1529 #else  /* !_NO_LONG_DBL */
1530 	      long double qres = 0;
1531 #define QUAD_RES qres;
1532 #endif /* !_NO_LONG_DBL */
1533 	      long new_exp = 0;
1534 
1535 	      *p = 0;
1536 	      if ((flags & (DPTOK | EXPOK)) == EXPOK)
1537 		{
1538 		  exp_adjust = zeroes - leading_zeroes;
1539 		  new_exp = -exp_adjust;
1540 		  exp_start = p;
1541 		}
1542 	      else if (exp_adjust)
1543                 new_exp = wcstol ((exp_start + 1), NULL, 10) - exp_adjust;
1544 	      if (exp_adjust)
1545 		{
1546 
1547 		  /* If there might not be enough space for the new exponent,
1548 		     truncate some trailing digits to make room.  */
1549 		  if (exp_start >= buf + sizeof (buf) / sizeof (*buf)
1550 				   - MAX_LONG_LEN)
1551 		    exp_start = buf + sizeof (buf) / sizeof (*buf)
1552 				- MAX_LONG_LEN - 1;
1553                  swprintf (exp_start, MAX_LONG_LEN, L"e%ld", new_exp);
1554 		}
1555 
1556 	      /* FIXME: We don't have wcstold yet. */
1557 #if 0//ndef _NO_LONGDBL /* !_NO_LONGDBL */
1558 	      if (flags & LONGDBL)
1559 		qres = wcstold (buf, NULL);
1560 	      else
1561 #endif
1562 	        res = wcstod (buf, NULL);
1563 
1564 	      if (flags & LONG)
1565 		{
1566 		  dp = GET_ARG (N, ap, double *);
1567 		  *dp = res;
1568 		}
1569 	      else if (flags & LONGDBL)
1570 		{
1571 		  ldp = GET_ARG (N, ap, _LONG_DOUBLE *);
1572 		  *ldp = (_LONG_DOUBLE) QUAD_RES;
1573 		}
1574 	      else
1575 		{
1576 		  flp = GET_ARG (N, ap, float *);
1577 		  if (isnan (res))
1578 		    *flp = nanf ("");
1579 		  else
1580 		    *flp = res;
1581 		}
1582 	      nassigned++;
1583 	    }
1584 	  break;
1585 	}
1586 #endif /* FLOATING_POINT */
1587 	}
1588     }
1589 input_failure:
1590   /* On read failure, return EOF failure regardless of matches; errno
1591      should have been set prior to here.  On EOF failure (including
1592      invalid format string), return EOF if no matches yet, else number
1593      of matches made prior to failure.  */
1594   nassigned = nassigned && !(fp->_flags & __SERR) ? nassigned : EOF;
1595 match_failure:
1596 all_done:
1597   /* Return number of matches, which can be 0 on match failure.  */
1598   _newlib_flockfile_end (fp);
1599 #ifdef _WANT_IO_POSIX_EXTENSIONS
1600   free_m_ptr ();
1601 #endif
1602   return nassigned;
1603 }
1604 
1605 #ifndef _NO_POS_ARGS
1606 /* Process all intermediate arguments.  Fortunately, with wscanf, all
1607    intermediate arguments are sizeof(void*), so we don't need to scan
1608    ahead in the format string.  */
1609 static void *
get_arg(int n,va_list * ap,int * numargs_p,void ** args)1610 get_arg (int n, va_list *ap, int *numargs_p, void **args)
1611 {
1612   int numargs = *numargs_p;
1613   while (n >= numargs)
1614     args[numargs++] = va_arg (*ap, void *);
1615   *numargs_p = numargs;
1616   return args[n];
1617 }
1618 #endif /* !_NO_POS_ARGS */
1619