source: trunk/libs/newlib/src/newlib/libc/stdio/vfscanf.c

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

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

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