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