Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / stdio / vfwscanf.c
blobd2f91dde2ba2ac3538fac200f27d8b74aa2a9016
1 /*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
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.
19 FUNCTION
20 <<vfwscanf>>, <<vwscanf>>, <<vswscanf>>---scan and format argument list from wide character input
22 INDEX
23 vfwscanf
24 INDEX
25 _vfwscanf
26 INDEX
27 vwscanf
28 INDEX
29 _vwscanf
30 INDEX
31 vswscanf
32 INDEX
33 _vswscanf
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]>);
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]>);
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.
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.
64 If <<vwscanf>> attempts to read at end-of-file, the return value
65 is <<EOF>>.
67 If no fields were stored, the return value is <<0>>.
69 The routines <<_vwscanf>>, <<_vfwscanf>>, and <<_vswscanf>> are
70 reentrant versions which take an additional first parameter which points
71 to the reentrancy structure.
73 PORTABILITY
74 C99, POSIX-1.2008
77 #include <_ansi.h>
78 #include <reent.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"
92 #ifdef INTEGER_ONLY
93 #define VFWSCANF vfiwscanf
94 #define _VFWSCANF_R _vfiwscanf_r
95 #define __SVFWSCANF __svfiwscanf
96 #ifdef STRING_ONLY
97 # define __SVFWSCANF_R __ssvfiwscanf_r
98 #else
99 # define __SVFWSCANF_R __svfiwscanf_r
100 #endif
101 #else
102 #define VFWSCANF vfwscanf
103 #define _VFWSCANF_R _vfwscanf_r
104 #define __SVFWSCANF __svfwscanf
105 #ifdef STRING_ONLY
106 # define __SVFWSCANF_R __ssvfwscanf_r
107 #else
108 # define __SVFWSCANF_R __svfwscanf_r
109 #endif
110 #ifndef NO_FLOATING_POINT
111 #define FLOATING_POINT
112 #endif
113 #endif
115 #ifdef STRING_ONLY
116 #undef _newlib_flockfile_start
117 #undef _newlib_flockfile_exit
118 #undef _newlib_flockfile_end
119 #define _newlib_flockfile_start(x) {}
120 #define _newlib_flockfile_exit(x) {}
121 #define _newlib_flockfile_end(x) {}
122 #define _ungetwc_r _sungetwc_r
123 #define __srefill_r __ssrefill_r
124 #define _fgetwc_r _sfgetwc_r
125 #endif
127 #ifdef FLOATING_POINT
128 #include <math.h>
129 #include <float.h>
130 #include <locale.h>
131 #ifdef __HAVE_LOCALE_INFO_EXTENDED__
132 #include "../locale/setlocale.h"
133 #endif
135 /* Currently a test is made to see if long double processing is warranted.
136 This could be changed in the future should the _ldtoa_r code be
137 preferred over _dtoa_r. */
138 #define _NO_LONGDBL
139 #if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
140 #undef _NO_LONGDBL
141 extern _LONG_DOUBLE _wcstold_r (wchar_t *s, wchar_t **sptr);
142 #endif
144 #include "floatio.h"
146 #if ((MAXEXP+MAXFRACT+3) > MB_LEN_MAX)
147 # define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */
148 #else
149 # define BUF MB_LEN_MAX
150 #endif
152 /* An upper bound for how long a long prints in decimal. 4 / 13 approximates
153 log (2). Add one char for roundoff compensation and one for the sign. */
154 #define MAX_LONG_LEN ((CHAR_BIT * sizeof (long) - 1) * 4 / 13 + 2)
155 #else
156 #define BUF 40
157 #endif
159 #define _NO_LONGLONG
160 #if defined _WANT_IO_LONG_LONG \
161 && (defined __GNUC__ || __STDC_VERSION__ >= 199901L)
162 # undef _NO_LONGLONG
163 #endif
165 #define _NO_POS_ARGS
166 #ifdef _WANT_IO_POS_ARGS
167 # undef _NO_POS_ARGS
168 # ifdef NL_ARGMAX
169 # define MAX_POS_ARGS NL_ARGMAX
170 # else
171 # define MAX_POS_ARGS 32
172 # endif
174 static void * get_arg (int, va_list *, int *, void **);
175 #endif /* _WANT_IO_POS_ARGS */
178 * Flags used during conversion.
181 #define LONG 0x01 /* l: long or double */
182 #define LONGDBL 0x02 /* L/ll: long double or long long */
183 #define SHORT 0x04 /* h: short */
184 #define CHAR 0x08 /* hh: 8 bit integer */
185 #define SUPPRESS 0x10 /* suppress assignment */
186 #define POINTER 0x20 /* weird %p pointer (`fake hex') */
187 #define NOSKIP 0x40 /* do not skip blanks */
188 #define MALLOC 0x80 /* handle 'm' modifier */
191 * The following are used in numeric conversions only:
192 * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
193 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
196 #define SIGNOK 0x80 /* +/- is (still) legal */
197 #define NDIGITS 0x100 /* no digits detected */
199 #define DPTOK 0x200 /* (float) decimal point is still legal */
200 #define EXPOK 0x400 /* (float) exponent (e+3, etc) still legal */
202 #define PFXOK 0x200 /* 0x prefix is (still) legal */
203 #define NZDIGITS 0x400 /* no zero digits detected */
204 #define HAVESIGN 0x10000 /* sign detected */
207 * Conversion types.
210 #define CT_CHAR 0 /* %c conversion */
211 #define CT_CCL 1 /* %[...] conversion */
212 #define CT_STRING 2 /* %s conversion */
213 #define CT_INT 3 /* integer, i.e., wcstol or wcstoul */
214 #define CT_FLOAT 4 /* floating, i.e., wcstod */
216 #define INCCL(_c) \
217 (cclcompl ? (wmemchr(ccls, (_c), ccle - ccls) == NULL) : \
218 (wmemchr(ccls, (_c), ccle - ccls) != NULL))
221 * vfwscanf
224 #ifndef STRING_ONLY
226 #ifndef _REENT_ONLY
229 VFWSCANF (register FILE *__restrict fp,
230 const wchar_t *__restrict fmt,
231 va_list ap)
233 struct _reent *reent = _REENT;
235 CHECK_INIT(reent, fp);
236 return __SVFWSCANF_R (reent, fp, fmt, ap);
240 __SVFWSCANF (register FILE *fp,
241 wchar_t const *fmt0,
242 va_list ap)
244 return __SVFWSCANF_R (_REENT, fp, fmt0, ap);
247 #endif /* !_REENT_ONLY */
250 _VFWSCANF_R (struct _reent *data,
251 register FILE *fp,
252 const wchar_t *fmt,
253 va_list ap)
255 CHECK_INIT(data, fp);
256 return __SVFWSCANF_R (data, fp, fmt, ap);
258 #endif /* !STRING_ONLY */
260 #ifdef STRING_ONLY
261 /* When dealing with the swscanf family, we don't want to use the
262 * regular ungetwc which will drag in file I/O items we don't need.
263 * So, we create our own trimmed-down version. */
264 static wint_t
265 _sungetwc_r (struct _reent *data,
266 wint_t wc,
267 register FILE *fp)
269 if (wc == WEOF)
270 return (WEOF);
272 /* After ungetc, we won't be at eof anymore */
273 fp->_flags &= ~__SEOF;
275 /* All ungetwc usage in scanf un-gets the current character, so
276 * just back up over the string if we aren't at the start
278 if (fp->_bf._base != NULL && fp->_p > fp->_bf._base)
280 fp->_p -= sizeof (wchar_t);
281 fp->_r += sizeof (wchar_t);
284 return wc;
287 extern int __ssrefill_r (struct _reent *ptr, register FILE * fp);
289 static size_t
290 _sfgetwc_r (struct _reent * ptr,
291 FILE * fp)
293 wchar_t wc;
295 if (fp->_r <= 0 && __ssrefill_r (ptr, fp))
296 return (WEOF);
297 wc = *(wchar_t *) fp->_p;
298 fp->_p += sizeof (wchar_t);
299 fp->_r -= sizeof (wchar_t);
300 return (wc);
302 #endif /* STRING_ONLY */
305 __SVFWSCANF_R (struct _reent *rptr,
306 register FILE *fp,
307 wchar_t const *fmt0,
308 va_list ap)
310 register wchar_t *fmt = (wchar_t *) fmt0;
311 register wint_t c; /* character from format, or conversion */
312 register size_t width; /* field width, or 0 */
313 register wchar_t *p = NULL; /* points into all kinds of strings */
314 register int n; /* handy integer */
315 register int flags; /* flags as defined above */
316 register wchar_t *p0; /* saves original value of p when necessary */
317 int nassigned; /* number of fields assigned */
318 int nread; /* number of characters consumed from fp */
319 #ifndef _NO_POS_ARGS
320 int N; /* arg number */
321 int arg_index = 0; /* index into args processed directly */
322 int numargs = 0; /* number of varargs read */
323 void *args[MAX_POS_ARGS]; /* positional args read */
324 int is_pos_arg; /* is current format positional? */
325 #endif
326 int base = 0; /* base argument to wcstol/wcstoul */
328 mbstate_t mbs; /* value to keep track of multibyte state */
330 #define CCFN_PARAMS (struct _reent *, const wchar_t *, wchar_t **, int)
331 unsigned long (*ccfn)CCFN_PARAMS=0; /* conversion function (wcstol/wcstoul) */
332 wchar_t buf[BUF]; /* buffer for numeric conversions */
333 const wchar_t *ccls; /* character class start */
334 const wchar_t *ccle; /* character class end */
335 int cclcompl = 0; /* ccl is complemented? */
336 wint_t wi; /* handy wint_t */
337 char *mbp = NULL; /* multibyte string pointer for %c %s %[ */
338 size_t nconv; /* number of bytes in mb. conversion */
339 char mbbuf[MB_LEN_MAX]; /* temporary mb. character buffer */
341 char *cp;
342 short *sp;
343 int *ip;
344 #ifdef FLOATING_POINT
345 float *flp;
346 _LONG_DOUBLE *ldp;
347 double *dp;
348 wchar_t decpt;
349 #endif
350 long *lp;
351 #ifndef _NO_LONGLONG
352 long long *llp;
353 #endif
354 #ifdef _WANT_IO_C99_FORMATS
355 #define _WANT_IO_POSIX_EXTENSIONS
356 #endif
357 #ifdef _WANT_IO_POSIX_EXTENSIONS
358 /* POSIX requires that fwscanf frees all allocated strings from 'm'
359 conversions in case it returns EOF. m_ptr is used to keep track.
360 It will be allocated on the stack the first time an 'm' conversion
361 takes place, and it will be free'd on return from the function.
362 This implementation tries to save space by only allocating 8
363 pointer slots at a time. Most scenarios should never have to call
364 realloc again. This implementation allows only up to 65528 'm'
365 conversions per fwscanf invocation for now. That should be enough
366 for almost all scenarios, right? */
367 struct m_ptrs {
368 void ***m_arr; /* Array of pointer args to 'm' conversion */
369 uint16_t m_siz; /* Number of slots in m_arr */
370 uint16_t m_cnt; /* Number of valid entries in m_arr */
371 } *m_ptr = NULL;
372 #define init_m_ptr() \
373 do \
375 if (!m_ptr) \
377 m_ptr = (struct m_ptrs *) alloca (sizeof *m_ptr); \
378 m_ptr->m_arr = NULL; \
379 m_ptr->m_siz = 0; \
380 m_ptr->m_cnt = 0; \
383 while (0)
384 #define push_m_ptr(arg) \
385 do \
387 if (m_ptr->m_cnt >= m_ptr->m_siz) \
389 void ***n = NULL; \
391 if (m_ptr->m_siz + 8 > 0 && m_ptr->m_siz + 8 < UINT16_MAX) \
392 n = (void ***) realloc (m_ptr->m_arr, \
393 (m_ptr->m_siz + 8) * \
394 sizeof (void **)); \
395 if (!n) \
397 nassigned = EOF; \
398 goto match_failure; \
400 m_ptr->m_arr = n; \
401 m_ptr->m_siz += 8; \
403 m_ptr->m_arr[m_ptr->m_cnt++] = (void **) (arg); \
405 while (0)
406 #define alloc_m_ptr(_type, _p, _p0, _p_p, _w) \
407 ({ \
408 _p_p = GET_ARG (N, ap, _type **); \
409 if (!_p_p) \
410 goto match_failure; \
411 _p0 = (_type *) malloc ((_w) * sizeof (_type)); \
412 if (!_p0) \
414 nassigned = EOF; \
415 goto match_failure; \
417 *_p_p = _p0; \
418 push_m_ptr (_p_p); \
419 _p = _p0; \
420 _w; \
422 /* For char output, check if there's room for at least MB_CUR_MAX
423 characters. */
424 #define realloc_m_ptr(_type, _p, _p0, _p_p, _w) \
425 ({ \
426 size_t _nw = (_w); \
427 ptrdiff_t _dif = _p - _p0; \
428 if (_p_p && \
429 ((sizeof (_type) == 1 && _dif >= _nw - MB_CUR_MAX) \
430 || _dif >= _nw)) \
432 _p0 = (_type *) realloc (_p0, (_nw << 1) * sizeof (_type)); \
433 if (!_p0) \
435 nassigned = EOF; \
436 goto match_failure; \
438 _p = _p0 + _dif; \
439 *_p_p = _p0; \
440 _nw <<= 1; \
442 _nw; \
444 #define shrink_m_ptr(_type, _p_p, _w, _cw) \
445 ({ \
446 size_t _nw = (_w); \
447 if (_p_p && _nw < _cw) \
449 _type *_np_p = (_type *) \
450 realloc (*_p_p, _nw * sizeof (_type)); \
451 if (_np_p) \
452 *_p_p = _np_p; \
455 #define free_m_ptr() \
456 do \
458 if (m_ptr) \
460 if (nassigned == EOF) \
462 int i; \
463 for (i = 0; i < m_ptr->m_cnt; ++i) \
465 free (*m_ptr->m_arr[i]); \
466 *m_ptr->m_arr[i] = NULL; \
469 if (m_ptr->m_arr) \
470 free (m_ptr->m_arr); \
473 while (0)
474 #endif
476 /* `basefix' is used to avoid `if' tests in the integer scanner */
477 static const short basefix[17] =
478 {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
480 /* Macro to support positional arguments */
481 #ifndef _NO_POS_ARGS
482 # define GET_ARG(n, ap, type) \
483 ((type) (is_pos_arg \
484 ? (n < numargs \
485 ? args[n] \
486 : get_arg (n, &ap, &numargs, args)) \
487 : (arg_index++ < numargs \
488 ? args[n] \
489 : (numargs < MAX_POS_ARGS \
490 ? args[numargs++] = va_arg (ap, void *) \
491 : va_arg (ap, void *)))))
492 #else
493 # define GET_ARG(n, ap, type) (va_arg (ap, type))
494 #endif
496 #ifdef FLOATING_POINT
497 #ifdef _MB_CAPABLE
498 #ifdef __HAVE_LOCALE_INFO_EXTENDED__
499 decpt = *__get_current_numeric_locale ()->wdecimal_point;
500 #else
502 size_t nconv;
504 memset (&mbs, '\0', sizeof (mbs));
505 nconv = _mbrtowc_r (rptr, &decpt,
506 _localeconv_r (rptr)->decimal_point,
507 MB_CUR_MAX, &mbs);
508 if (nconv == (size_t) -1 || nconv == (size_t) -2)
509 decpt = L'.';
511 #endif /* !__HAVE_LOCALE_INFO_EXTENDED__ */
512 #else
513 decpt = (wchar_t) *_localeconv_r (rptr)->decimal_point;
514 #endif /* !_MB_CAPABLE */
515 #endif /* FLOATING_POINT */
517 _newlib_flockfile_start (fp);
519 if (ORIENT (fp, 1) != 1)
521 nassigned = EOF;
522 goto all_done;
525 nassigned = 0;
526 nread = 0;
527 ccls = ccle = NULL;
528 for (;;)
530 c = *fmt++;
531 if (c == L'\0')
532 goto all_done;
533 if (iswspace (c))
535 while ((c = _fgetwc_r (rptr, fp)) != WEOF && iswspace(c))
537 if (c != WEOF)
538 _ungetwc_r (rptr, c, fp);
539 continue;
541 if (c != L'%')
542 goto literal;
543 width = 0;
544 flags = 0;
545 #ifndef _NO_POS_ARGS
546 N = arg_index;
547 is_pos_arg = 0;
548 #endif
551 * switch on the format. continue if done; break once format
552 * type is derived.
555 again:
556 c = *fmt++;
558 switch (c)
560 case L'%':
561 literal:
562 if ((wi = _fgetwc_r (rptr, fp)) == WEOF)
563 goto input_failure;
564 if (wi != c)
566 _ungetwc_r (rptr, wi, fp);
567 goto input_failure;
569 nread++;
570 continue;
572 case L'*':
573 if ((flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS | MALLOC))
574 || width)
575 goto match_failure;
576 flags |= SUPPRESS;
577 goto again;
578 case L'l':
579 if (flags & (CHAR | SHORT | LONG | LONGDBL))
580 goto match_failure;
581 #if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
582 if (*fmt == L'l') /* Check for 'll' = long long (SUSv3) */
584 ++fmt;
585 flags |= LONGDBL;
587 else
588 #endif
589 flags |= LONG;
590 goto again;
591 case L'L':
592 if (flags & (CHAR | SHORT | LONG | LONGDBL))
593 goto match_failure;
594 flags |= LONGDBL;
595 goto again;
596 case L'h':
597 #ifdef _WANT_IO_C99_FORMATS
598 if (flags & (CHAR | SHORT | LONG | LONGDBL))
599 goto match_failure;
600 if (*fmt == 'h') /* Check for 'hh' = char int (SUSv3) */
602 ++fmt;
603 flags |= CHAR;
605 else
606 #endif
607 flags |= SHORT;
608 goto again;
609 #ifdef _WANT_IO_C99_FORMATS
610 case L'j': /* intmax_t */
611 if (flags & (CHAR | SHORT | LONG | LONGDBL))
612 goto match_failure;
613 if (sizeof (intmax_t) == sizeof (long))
614 flags |= LONG;
615 else
616 flags |= LONGDBL;
617 goto again;
618 case L't': /* ptrdiff_t */
619 if (flags & (CHAR | SHORT | LONG | LONGDBL))
620 goto match_failure;
621 if (sizeof (ptrdiff_t) < sizeof (int))
622 /* POSIX states ptrdiff_t is 16 or more bits, as
623 is short. */
624 flags |= SHORT;
625 else if (sizeof (ptrdiff_t) == sizeof (int))
626 /* no flag needed */;
627 else if (sizeof (ptrdiff_t) <= sizeof (long))
628 flags |= LONG;
629 else
630 /* POSIX states that at least one programming
631 environment must support ptrdiff_t no wider than
632 long, but that means other environments can
633 have ptrdiff_t as wide as long long. */
634 flags |= LONGDBL;
635 goto again;
636 case L'z': /* size_t */
637 if (flags & (CHAR | SHORT | LONG | LONGDBL))
638 goto match_failure;
639 if (sizeof (size_t) < sizeof (int))
640 /* POSIX states size_t is 16 or more bits, as is short. */
641 flags |= SHORT;
642 else if (sizeof (size_t) == sizeof (int))
643 /* no flag needed */;
644 else if (sizeof (size_t) <= sizeof (long))
645 flags |= LONG;
646 else
647 /* POSIX states that at least one programming
648 environment must support size_t no wider than
649 long, but that means other environments can
650 have size_t as wide as long long. */
651 flags |= LONGDBL;
652 goto again;
653 #endif /* _WANT_IO_C99_FORMATS */
654 #ifdef _WANT_IO_POSIX_EXTENSIONS
655 case 'm':
656 if (flags & (CHAR | SHORT | LONG | LONGDBL | MALLOC))
657 goto match_failure;
658 init_m_ptr ();
659 flags |= MALLOC;
660 goto again;
661 #endif
663 case L'0':
664 case L'1':
665 case L'2':
666 case L'3':
667 case L'4':
668 case L'5':
669 case L'6':
670 case L'7':
671 case L'8':
672 case L'9':
673 if (flags & (CHAR | SHORT | LONG | LONGDBL | MALLOC))
674 goto match_failure;
675 width = width * 10 + c - L'0';
676 goto again;
678 #ifndef _NO_POS_ARGS
679 case L'$':
680 if (flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS | MALLOC))
681 goto match_failure;
682 if (width <= MAX_POS_ARGS)
684 N = width - 1;
685 is_pos_arg = 1;
686 width = 0;
687 goto again;
689 _REENT_ERRNO(rptr) = EINVAL;
690 goto input_failure;
691 #endif /* !_NO_POS_ARGS */
693 case L'd':
694 c = CT_INT;
695 ccfn = (unsigned long (*)CCFN_PARAMS)_wcstol_r;
696 base = 10;
697 break;
699 case L'i':
700 c = CT_INT;
701 ccfn = (unsigned long (*)CCFN_PARAMS)_wcstol_r;
702 base = 0;
703 break;
705 case L'o':
706 c = CT_INT;
707 ccfn = _wcstoul_r;
708 base = 8;
709 break;
711 case L'u':
712 c = CT_INT;
713 ccfn = _wcstoul_r;
714 base = 10;
715 break;
717 case L'X':
718 case L'x':
719 flags |= PFXOK; /* enable 0x prefixing */
720 c = CT_INT;
721 ccfn = _wcstoul_r;
722 base = 16;
723 break;
725 #ifdef FLOATING_POINT
726 # ifdef _WANT_IO_C99_FORMATS
727 case L'A':
728 case L'a':
729 case L'F':
730 # endif
731 case L'E':
732 case L'G':
733 case L'e':
734 case L'f':
735 case L'g':
736 c = CT_FLOAT;
737 break;
738 #endif
740 #ifdef _WANT_IO_C99_FORMATS
741 case L'S':
742 flags |= LONG;
743 /* FALLTHROUGH */
744 #endif
746 case L's':
747 c = CT_STRING;
748 break;
750 case L'[':
751 if (*fmt == '^')
753 cclcompl = 1;
754 ++fmt;
756 else
757 cclcompl = 0;
758 ccls = fmt;
759 if (*fmt == ']')
760 fmt++;
761 while (*fmt != '\0' && *fmt != ']')
762 fmt++;
763 ccle = fmt;
764 fmt++;
765 flags |= NOSKIP;
766 c = CT_CCL;
767 break;
769 #ifdef _WANT_IO_C99_FORMATS
770 case 'C':
771 flags |= LONG;
772 /* FALLTHROUGH */
773 #endif
775 case 'c':
776 flags |= NOSKIP;
777 c = CT_CHAR;
778 break;
780 case 'p': /* pointer format is like hex */
781 flags |= POINTER | PFXOK;
782 c = CT_INT;
783 ccfn = _wcstoul_r;
784 base = 16;
785 break;
787 case 'n':
788 if (flags & SUPPRESS) /* ??? */
789 continue;
790 #ifdef _WANT_IO_C99_FORMATS
791 if (flags & CHAR)
793 cp = GET_ARG (N, ap, char *);
794 *cp = nread;
796 else
797 #endif
798 if (flags & SHORT)
800 sp = GET_ARG (N, ap, short *);
801 *sp = nread;
803 else if (flags & LONG)
805 lp = GET_ARG (N, ap, long *);
806 *lp = nread;
808 #ifndef _NO_LONGLONG
809 else if (flags & LONGDBL)
811 llp = GET_ARG (N, ap, long long*);
812 *llp = nread;
814 #endif
815 else
817 ip = GET_ARG (N, ap, int *);
818 *ip = nread;
820 continue;
822 default:
823 goto match_failure;
827 * Consume leading white space, except for formats that
828 * suppress this.
830 if ((flags & NOSKIP) == 0)
832 while ((wi = _fgetwc_r (rptr, fp)) != WEOF && iswspace (wi))
833 nread++;
834 if (wi == WEOF)
835 goto input_failure;
836 _ungetwc_r (rptr, wi, fp);
840 * Do the conversion.
842 switch (c)
845 case CT_CHAR:
846 /* scan arbitrary characters (sets NOSKIP) */
847 if (width == 0)
848 width = 1;
849 if (flags & LONG)
851 #ifdef _WANT_IO_POSIX_EXTENSIONS
852 wchar_t **p_p = NULL;
853 wchar_t *p0 = NULL;
854 size_t p_siz = 0;
855 #endif
857 if (flags & SUPPRESS)
859 #ifdef _WANT_IO_POSIX_EXTENSIONS
860 else if (flags & MALLOC)
861 p_siz = alloc_m_ptr (wchar_t, p, p0, p_p, 32);
862 #endif
863 else
864 p = GET_ARG(N, ap, wchar_t *);
865 n = 0;
866 while (width-- != 0 && (wi = _fgetwc_r (rptr, fp)) != WEOF)
868 if (!(flags & SUPPRESS))
870 #ifdef _WANT_IO_POSIX_EXTENSIONS
871 /* Check before ++ because we never add a \0 */
872 p_siz = realloc_m_ptr (wchar_t, p, p0, p_p, p_siz);
873 #endif
874 *p++ = (wchar_t) wi;
876 n++;
878 if (n == 0)
879 goto input_failure;
880 nread += n;
881 #ifdef _WANT_IO_POSIX_EXTENSIONS
882 shrink_m_ptr (wchar_t, p_p, p - p0, p_siz);
883 #endif
884 if (!(flags & SUPPRESS))
885 nassigned++;
887 else
889 #ifdef _WANT_IO_POSIX_EXTENSIONS
890 char **mbp_p = NULL;
891 char *mbp0 = NULL;
892 size_t mbp_siz = 0;
893 #endif
895 if (flags & SUPPRESS)
896 mbp = mbbuf;
897 #ifdef _WANT_IO_POSIX_EXTENSIONS
898 else if (flags & MALLOC)
899 mbp_siz = alloc_m_ptr (char, mbp, mbp0, mbp_p, 32);
900 #endif
901 else
902 mbp = GET_ARG(N, ap, char *);
903 n = 0;
904 memset ((void *)&mbs, '\0', sizeof (mbstate_t));
905 while (width != 0 && (wi = _fgetwc_r (rptr, fp)) != WEOF)
907 nconv = _wcrtomb_r (rptr, mbp, wi, &mbs);
908 if (nconv == (size_t) -1)
909 goto input_failure;
910 /* Ignore high surrogate in width counting */
911 if (nconv != 0 || mbs.__count != -4)
912 width--;
913 if (!(flags & SUPPRESS))
915 #ifdef _WANT_IO_POSIX_EXTENSIONS
916 mbp_siz = realloc_m_ptr (char, mbp, mbp0, mbp_p, mbp_siz);
917 #endif
918 mbp += nconv;
920 n++;
922 if (n == 0)
923 goto input_failure;
924 nread += n;
925 #ifdef _WANT_IO_POSIX_EXTENSIONS
926 shrink_m_ptr (char, mbp_p, mbp - mbp0, mbp_siz);
927 #endif
928 if (!(flags & SUPPRESS))
929 nassigned++;
931 break;
933 case CT_CCL:
934 /* scan a (nonempty) character class (sets NOSKIP) */
935 if (width == 0)
936 width = SIZE_MAX; /* `infinity' */
937 /* take only those things in the class */
938 if ((flags & SUPPRESS) && (flags & LONG))
940 n = 0;
941 while ((wi = _fgetwc_r (rptr, fp)) != WEOF
942 && width-- != 0 && INCCL (wi))
943 n++;
944 if (wi != WEOF)
945 _ungetwc_r (rptr, wi, fp);
946 if (n == 0)
947 goto match_failure;
949 else if (flags & LONG)
951 #ifdef _WANT_IO_POSIX_EXTENSIONS
952 wchar_t **p_p = NULL;
953 size_t p_siz = 0;
955 if (flags & MALLOC)
956 p_siz = alloc_m_ptr (wchar_t, p, p0, p_p, 32);
957 else
958 #endif
959 p0 = p = GET_ARG(N, ap, wchar_t *);
960 while ((wi = _fgetwc_r (rptr, fp)) != WEOF
961 && width-- != 0 && INCCL (wi))
963 *p++ = (wchar_t) wi;
964 #ifdef _WANT_IO_POSIX_EXTENSIONS
965 p_siz = realloc_m_ptr (wchar_t, p, p0, p_p, p_siz);
966 #endif
968 if (wi != WEOF)
969 _ungetwc_r (rptr, wi, fp);
970 n = p - p0;
971 if (n == 0)
972 goto match_failure;
973 *p = L'\0';
974 #ifdef _WANT_IO_POSIX_EXTENSIONS
975 shrink_m_ptr (wchar_t, p_p, n + 1, p_siz);
976 #endif
977 nassigned++;
979 else
981 #ifdef _WANT_IO_POSIX_EXTENSIONS
982 char **mbp_p = NULL;
983 char *mbp0 = NULL;
984 size_t mbp_siz = 0;
985 #endif
987 if (flags & SUPPRESS)
988 mbp = mbbuf;
989 #ifdef _WANT_IO_POSIX_EXTENSIONS
990 else if (flags & MALLOC)
991 mbp_siz = alloc_m_ptr (char, mbp, mbp0, mbp_p, 32);
992 #endif
993 else
994 mbp = GET_ARG(N, ap, char *);
995 n = 0;
996 memset ((void *) &mbs, '\0', sizeof (mbstate_t));
997 while ((wi = _fgetwc_r (rptr, fp)) != WEOF
998 && width != 0 && INCCL (wi))
1000 nconv = _wcrtomb_r (rptr, mbp, wi, &mbs);
1001 if (nconv == (size_t) -1)
1002 goto input_failure;
1003 /* Ignore high surrogate in width counting */
1004 if (nconv != 0 || mbs.__count != -4)
1005 width--;
1006 if (!(flags & SUPPRESS))
1008 mbp += nconv;
1009 #ifdef _WANT_IO_POSIX_EXTENSIONS
1010 mbp_siz = realloc_m_ptr (char, mbp, mbp0, mbp_p, mbp_siz);
1011 #endif
1013 n++;
1015 if (wi != WEOF)
1016 _ungetwc_r (rptr, wi, fp);
1017 if (!(flags & SUPPRESS))
1019 *mbp = 0;
1020 #ifdef _WANT_IO_POSIX_EXTENSIONS
1021 shrink_m_ptr (char, mbp_p, mbp - mbp0 + 1, mbp_siz);
1022 #endif
1023 nassigned++;
1026 nread += n;
1027 break;
1029 case CT_STRING:
1030 /* like CCL, but zero-length string OK, & no NOSKIP */
1031 if (width == 0)
1032 width = SIZE_MAX;
1033 if ((flags & SUPPRESS) && (flags & LONG))
1035 while ((wi = _fgetwc_r (rptr, fp)) != WEOF
1036 && width-- != 0 && !iswspace (wi))
1037 nread++;
1038 if (wi != WEOF)
1039 _ungetwc_r (rptr, wi, fp);
1041 else if (flags & LONG)
1043 #ifdef _WANT_IO_POSIX_EXTENSIONS
1044 wchar_t **p_p = NULL;
1045 size_t p_siz = 0;
1047 if (flags & MALLOC)
1048 p_siz = alloc_m_ptr (wchar_t, p, p0, p_p, 32);
1049 else
1050 #endif
1051 p0 = p = GET_ARG(N, ap, wchar_t *);
1052 while ((wi = _fgetwc_r (rptr, fp)) != WEOF
1053 && width-- != 0 && !iswspace (wi))
1055 *p++ = (wchar_t) wi;
1056 #ifdef _WANT_IO_POSIX_EXTENSIONS
1057 p_siz = realloc_m_ptr (wchar_t, p, p0, p_p, p_siz);
1058 #endif
1059 nread++;
1061 if (wi != WEOF)
1062 _ungetwc_r (rptr, wi, fp);
1063 *p = L'\0';
1064 #ifdef _WANT_IO_POSIX_EXTENSIONS
1065 shrink_m_ptr (wchar_t, p_p, p - p0 + 1, p_siz);
1066 #endif
1067 nassigned++;
1069 else
1071 #ifdef _WANT_IO_POSIX_EXTENSIONS
1072 char **mbp_p = NULL;
1073 char *mbp0 = NULL;
1074 size_t mbp_siz = 0;
1075 #endif
1077 if (flags & SUPPRESS)
1078 mbp = mbbuf;
1079 #ifdef _WANT_IO_POSIX_EXTENSIONS
1080 else if (flags & MALLOC)
1081 mbp_siz = alloc_m_ptr (char, mbp, mbp0, mbp_p, 32);
1082 #endif
1083 else
1084 mbp = GET_ARG(N, ap, char *);
1085 memset ((void *) &mbs, '\0', sizeof (mbstate_t));
1086 while ((wi = _fgetwc_r (rptr, fp)) != WEOF
1087 && width != 0 && !iswspace (wi))
1089 nconv = wcrtomb(mbp, wi, &mbs);
1090 if (nconv == (size_t)-1)
1091 goto input_failure;
1092 /* Ignore high surrogate in width counting */
1093 if (nconv != 0 || mbs.__count != -4)
1094 width--;
1095 if (!(flags & SUPPRESS))
1097 mbp += nconv;
1098 #ifdef _WANT_IO_POSIX_EXTENSIONS
1099 mbp_siz = realloc_m_ptr (char, mbp, mbp0, mbp_p, mbp_siz);
1100 #endif
1102 nread++;
1104 if (wi != WEOF)
1105 _ungetwc_r (rptr, wi, fp);
1106 if (!(flags & SUPPRESS))
1108 *mbp = 0;
1109 #ifdef _WANT_IO_POSIX_EXTENSIONS
1110 shrink_m_ptr (char, mbp_p, mbp - mbp0 + 1, mbp_siz);
1111 #endif
1112 nassigned++;
1115 continue;
1117 case CT_INT:
1119 /* scan an integer as if by wcstol/wcstoul */
1120 if (width == 0 || width > sizeof (buf) / sizeof (*buf) - 1)
1121 width = sizeof(buf) / sizeof (*buf) - 1;
1122 flags |= SIGNOK | NDIGITS | NZDIGITS;
1123 for (p = buf; width; width--)
1125 c = _fgetwc_r (rptr, fp);
1127 * Switch on the character; `goto ok' if we
1128 * accept it as a part of number.
1130 switch (c)
1133 * The digit 0 is always legal, but is special.
1134 * For %i conversions, if no digits (zero or nonzero)
1135 * have been scanned (only signs), we will have base==0.
1136 * In that case, we should set it to 8 and enable 0x
1137 * prefixing. Also, if we have not scanned zero digits
1138 * before this, do not turn off prefixing (someone else
1139 * will turn it off if we have scanned any nonzero digits).
1141 case L'0':
1142 if (base == 0)
1144 base = 8;
1145 flags |= PFXOK;
1147 if (flags & NZDIGITS)
1148 flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
1149 else
1150 flags &= ~(SIGNOK | PFXOK | NDIGITS);
1151 goto ok;
1153 /* 1 through 7 always legal */
1154 case L'1':
1155 case L'2':
1156 case L'3':
1157 case L'4':
1158 case L'5':
1159 case L'6':
1160 case L'7':
1161 base = basefix[base];
1162 flags &= ~(SIGNOK | PFXOK | NDIGITS);
1163 goto ok;
1165 /* digits 8 and 9 ok iff decimal or hex */
1166 case L'8':
1167 case L'9':
1168 base = basefix[base];
1169 if (base <= 8)
1170 break; /* not legal here */
1171 flags &= ~(SIGNOK | PFXOK | NDIGITS);
1172 goto ok;
1174 /* letters ok iff hex */
1175 case L'A':
1176 case L'B':
1177 case L'C':
1178 case L'D':
1179 case L'E':
1180 case L'F':
1181 case L'a':
1182 case L'b':
1183 case L'c':
1184 case L'd':
1185 case L'e':
1186 case L'f':
1187 /* no need to fix base here */
1188 if (base <= 10)
1189 break; /* not legal here */
1190 flags &= ~(SIGNOK | PFXOK | NDIGITS);
1191 goto ok;
1193 /* sign ok only as first character */
1194 case L'+':
1195 case L'-':
1196 if (flags & SIGNOK)
1198 flags &= ~SIGNOK;
1199 flags |= HAVESIGN;
1200 goto ok;
1202 break;
1204 /* x ok iff flag still set & single 0 seen */
1205 case L'x':
1206 case L'X':
1207 if ((flags & PFXOK) && p == buf + 1 + !!(flags & HAVESIGN))
1209 base = 16;/* if %i */
1210 flags &= ~PFXOK;
1211 goto ok;
1213 break;
1217 * If we got here, c is not a legal character
1218 * for a number. Stop accumulating digits.
1220 if (c != WEOF)
1221 _ungetwc_r (rptr, c, fp);
1222 break;
1225 * c is legal: store it and look at the next.
1227 *p++ = (wchar_t) c;
1230 * If we had only a sign, it is no good; push back the sign.
1231 * If the number ends in `x', it was [sign] '0' 'x', so push back
1232 * the x and treat it as [sign] '0'.
1233 * Use of ungetc here and below assumes ASCII encoding; we are only
1234 * pushing back 7-bit characters, so casting to unsigned char is
1235 * not necessary.
1237 if (flags & NDIGITS)
1239 if (p > buf)
1240 _ungetwc_r (rptr, *--p, fp); /* [-+xX] */
1241 goto match_failure;
1243 c = p[-1];
1244 if (c == L'x' || c == L'X')
1246 --p;
1247 _ungetwc_r (rptr, c, fp);
1249 if ((flags & SUPPRESS) == 0)
1251 unsigned long res;
1253 *p = 0;
1254 res = (*ccfn) (rptr, buf, (wchar_t **) NULL, base);
1255 if (flags & POINTER)
1257 void **vp = GET_ARG (N, ap, void **);
1258 #ifndef _NO_LONGLONG
1259 if (sizeof (uintptr_t) > sizeof (unsigned long))
1261 unsigned long long resll;
1262 resll = _wcstoull_r (rptr, buf, (wchar_t **) NULL, base);
1263 *vp = (void *) (uintptr_t) resll;
1265 else
1266 #endif /* !_NO_LONGLONG */
1267 *vp = (void *) (uintptr_t) res;
1269 #ifdef _WANT_IO_C99_FORMATS
1270 else if (flags & CHAR)
1272 cp = GET_ARG (N, ap, char *);
1273 *cp = res;
1275 #endif
1276 else if (flags & SHORT)
1278 sp = GET_ARG (N, ap, short *);
1279 *sp = res;
1281 else if (flags & LONG)
1283 lp = GET_ARG (N, ap, long *);
1284 *lp = res;
1286 #ifndef _NO_LONGLONG
1287 else if (flags & LONGDBL)
1289 unsigned long long resll;
1290 if (ccfn == _wcstoul_r)
1291 resll = _wcstoull_r (rptr, buf, (wchar_t **) NULL, base);
1292 else
1293 resll = _wcstoll_r (rptr, buf, (wchar_t **) NULL, base);
1294 llp = GET_ARG (N, ap, long long*);
1295 *llp = resll;
1297 #endif
1298 else
1300 ip = GET_ARG (N, ap, int *);
1301 *ip = res;
1303 nassigned++;
1305 nread += p - buf;
1306 break;
1308 #ifdef FLOATING_POINT
1309 case CT_FLOAT:
1311 /* scan a floating point number as if by wcstod */
1312 /* This code used to assume that the number of digits is reasonable.
1313 However, ANSI / ISO C makes no such stipulation; we have to get
1314 exact results even when there is an unreasonable amount of
1315 leading zeroes. */
1316 long leading_zeroes = 0;
1317 long zeroes, exp_adjust;
1318 wchar_t *exp_start = NULL;
1319 unsigned width_left = 0;
1320 char nancount = 0;
1321 char infcount = 0;
1322 #ifdef hardway
1323 if (width == 0 || width > sizeof (buf) / sizeof (*buf) - 1)
1324 #else
1325 /* size_t is unsigned, hence this optimisation */
1326 if (width - 1 > sizeof (buf) / sizeof (*buf) - 2)
1327 #endif
1329 width_left = width - (sizeof (buf) / sizeof (*buf) - 1);
1330 width = sizeof (buf) / sizeof (*buf) - 1;
1332 flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
1333 zeroes = 0;
1334 exp_adjust = 0;
1335 for (p = buf; width; )
1337 c = _fgetwc_r (rptr, fp);
1339 * This code mimicks the integer conversion
1340 * code, but is much simpler.
1342 switch (c)
1344 case L'0':
1345 if (flags & NDIGITS)
1347 flags &= ~SIGNOK;
1348 zeroes++;
1349 if (width_left)
1351 width_left--;
1352 width++;
1354 goto fskip;
1356 /* Fall through. */
1357 case L'1':
1358 case L'2':
1359 case L'3':
1360 case L'4':
1361 case L'5':
1362 case L'6':
1363 case L'7':
1364 case L'8':
1365 case L'9':
1366 if (nancount + infcount == 0)
1368 flags &= ~(SIGNOK | NDIGITS);
1369 goto fok;
1371 break;
1373 case L'+':
1374 case L'-':
1375 if (flags & SIGNOK)
1377 flags &= ~SIGNOK;
1378 goto fok;
1380 break;
1381 case L'n':
1382 case L'N':
1383 if (nancount == 0 && zeroes == 0
1384 && (flags & (NDIGITS | DPTOK | EXPOK)) ==
1385 (NDIGITS | DPTOK | EXPOK))
1387 flags &= ~(SIGNOK | DPTOK | EXPOK | NDIGITS);
1388 nancount = 1;
1389 goto fok;
1391 if (nancount == 2)
1393 nancount = 3;
1394 goto fok;
1396 if (infcount == 1 || infcount == 4)
1398 infcount++;
1399 goto fok;
1401 break;
1402 case L'a':
1403 case L'A':
1404 if (nancount == 1)
1406 nancount = 2;
1407 goto fok;
1409 break;
1410 case L'i':
1411 if (infcount == 0 && zeroes == 0
1412 && (flags & (NDIGITS | DPTOK | EXPOK)) ==
1413 (NDIGITS | DPTOK | EXPOK))
1415 flags &= ~(SIGNOK | DPTOK | EXPOK | NDIGITS);
1416 infcount = 1;
1417 goto fok;
1419 if (infcount == 3 || infcount == 5)
1421 infcount++;
1422 goto fok;
1424 break;
1425 case L'f':
1426 case L'F':
1427 if (infcount == 2)
1429 infcount = 3;
1430 goto fok;
1432 break;
1433 case L't':
1434 case L'T':
1435 if (infcount == 6)
1437 infcount = 7;
1438 goto fok;
1440 break;
1441 case L'y':
1442 case L'Y':
1443 if (infcount == 7)
1445 infcount = 8;
1446 goto fok;
1448 break;
1449 case L'e':
1450 case L'E':
1451 /* no exponent without some digits */
1452 if ((flags & (NDIGITS | EXPOK)) == EXPOK
1453 || ((flags & EXPOK) && zeroes))
1455 if (! (flags & DPTOK))
1457 exp_adjust = zeroes - leading_zeroes;
1458 exp_start = p;
1460 flags =
1461 (flags & ~(EXPOK | DPTOK)) |
1462 SIGNOK | NDIGITS;
1463 zeroes = 0;
1464 goto fok;
1466 break;
1467 default:
1468 if ((wchar_t) c == decpt && (flags & DPTOK))
1470 flags &= ~(SIGNOK | DPTOK);
1471 leading_zeroes = zeroes;
1472 goto fok;
1474 break;
1476 if (c != WEOF)
1477 _ungetwc_r (rptr, c, fp);
1478 break;
1479 fok:
1480 *p++ = c;
1481 fskip:
1482 width--;
1483 ++nread;
1485 if (zeroes)
1486 flags &= ~NDIGITS;
1487 /* We may have a 'N' or possibly even [sign] 'N' 'a' as the
1488 start of 'NaN', only to run out of chars before it was
1489 complete (or having encountered a non-matching char). So
1490 check here if we have an outstanding nancount, and if so
1491 put back the chars we did swallow and treat as a failed
1492 match.
1494 FIXME - we still don't handle NAN([0xdigits]). */
1495 if (nancount - 1U < 2U) /* nancount && nancount < 3 */
1497 /* Newlib's ungetc works even if we called __srefill in
1498 the middle of a partial parse, but POSIX does not
1499 guarantee that in all implementations of ungetc. */
1500 while (p > buf)
1502 _ungetwc_r (rptr, *--p, fp); /* [-+nNaA] */
1503 --nread;
1505 goto match_failure;
1507 /* Likewise for 'inf' and 'infinity'. But be careful that
1508 'infinite' consumes only 3 characters, leaving the stream
1509 at the second 'i'. */
1510 if (infcount - 1U < 7U) /* infcount && infcount < 8 */
1512 if (infcount >= 3) /* valid 'inf', but short of 'infinity' */
1513 while (infcount-- > 3)
1515 _ungetwc_r (rptr, *--p, fp); /* [iInNtT] */
1516 --nread;
1518 else
1520 while (p > buf)
1522 _ungetwc_r (rptr, *--p, fp); /* [-+iInN] */
1523 --nread;
1525 goto match_failure;
1529 * If no digits, might be missing exponent digits
1530 * (just give back the exponent) or might be missing
1531 * regular digits, but had sign and/or decimal point.
1533 if (flags & NDIGITS)
1535 if (flags & EXPOK)
1537 /* no digits at all */
1538 while (p > buf)
1540 _ungetwc_r (rptr, *--p, fp); /* [-+.] */
1541 --nread;
1543 goto match_failure;
1545 /* just a bad exponent (e and maybe sign) */
1546 c = *--p;
1547 --nread;
1548 if (c != L'e' && c != L'E')
1550 _ungetwc_r (rptr, c, fp); /* [-+] */
1551 c = *--p;
1552 --nread;
1554 _ungetwc_r (rptr, c, fp); /* [eE] */
1556 if ((flags & SUPPRESS) == 0)
1558 double res = 0;
1559 #ifdef _NO_LONGDBL
1560 #define QUAD_RES res;
1561 #else /* !_NO_LONG_DBL */
1562 long double qres = 0;
1563 #define QUAD_RES qres;
1564 #endif /* !_NO_LONG_DBL */
1565 long new_exp = 0;
1567 *p = 0;
1568 if ((flags & (DPTOK | EXPOK)) == EXPOK)
1570 exp_adjust = zeroes - leading_zeroes;
1571 new_exp = -exp_adjust;
1572 exp_start = p;
1574 else if (exp_adjust)
1575 new_exp = _wcstol_r (rptr, (exp_start + 1), NULL, 10) - exp_adjust;
1576 if (exp_adjust)
1579 /* If there might not be enough space for the new exponent,
1580 truncate some trailing digits to make room. */
1581 if (exp_start >= buf + sizeof (buf) / sizeof (*buf)
1582 - MAX_LONG_LEN)
1583 exp_start = buf + sizeof (buf) / sizeof (*buf)
1584 - MAX_LONG_LEN - 1;
1585 swprintf (exp_start, MAX_LONG_LEN, L"e%ld", new_exp);
1588 /* FIXME: We don't have wcstold yet. */
1589 #if 0//ndef _NO_LONGDBL /* !_NO_LONGDBL */
1590 if (flags & LONGDBL)
1591 qres = _wcstold_r (rptr, buf, NULL);
1592 else
1593 #endif
1594 res = _wcstod_r (rptr, buf, NULL);
1596 if (flags & LONG)
1598 dp = GET_ARG (N, ap, double *);
1599 *dp = res;
1601 else if (flags & LONGDBL)
1603 ldp = GET_ARG (N, ap, _LONG_DOUBLE *);
1604 *ldp = QUAD_RES;
1606 else
1608 flp = GET_ARG (N, ap, float *);
1609 if (isnan (res))
1610 *flp = nanf ("");
1611 else
1612 *flp = res;
1614 nassigned++;
1616 break;
1618 #endif /* FLOATING_POINT */
1621 input_failure:
1622 /* On read failure, return EOF failure regardless of matches; errno
1623 should have been set prior to here. On EOF failure (including
1624 invalid format string), return EOF if no matches yet, else number
1625 of matches made prior to failure. */
1626 nassigned = nassigned && !(fp->_flags & __SERR) ? nassigned : EOF;
1627 match_failure:
1628 all_done:
1629 /* Return number of matches, which can be 0 on match failure. */
1630 _newlib_flockfile_end (fp);
1631 #ifdef _WANT_IO_POSIX_EXTENSIONS
1632 free_m_ptr ();
1633 #endif
1634 return nassigned;
1637 #ifndef _NO_POS_ARGS
1638 /* Process all intermediate arguments. Fortunately, with wscanf, all
1639 intermediate arguments are sizeof(void*), so we don't need to scan
1640 ahead in the format string. */
1641 static void *
1642 get_arg (int n, va_list *ap, int *numargs_p, void **args)
1644 int numargs = *numargs_p;
1645 while (n >= numargs)
1646 args[numargs++] = va_arg (*ap, void *);
1647 *numargs_p = numargs;
1648 return args[n];
1650 #endif /* !_NO_POS_ARGS */