Subversion Repositories Kolibri OS

Rev

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