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