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