Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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