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