source: trunk/libs/newlib/src/newlib/libc/stdio/vfwscanf.c @ 450

Last change on this file since 450 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

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