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