Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2009-03-11 14:53:22 +0300
committerCorinna Vinschen <corinna@vinschen.de>2009-03-11 14:53:22 +0300
commitd0b85c158fbe7a30d665f41c60bb5800da562ce8 (patch)
tree0a6bdcb338566b97077e802d1515f583d02f3cf7 /newlib/libc/stdio/vfwscanf.c
parente20efdda164c04d8e6731db0aed019a110699b1b (diff)
* libc/include/wchar.h (fwscanf, swscanf, vfwscanf, vswscanf, vwscanf,
wscanf): Declare. (_fwscanf_r, _swscanf_r, _vfwscanf_r, _vswscanf_r, _vwscanf_r, _wscanf_r): Declare. * libc/stdio/Makefile.am: Add new wscanf files. * libc/stdio/Makefile.in: Regenerate. * libc/stdio/fwscanf.c: New file. * libc/stdio/local.h (__svfwscanf_r, __ssvfwscanf_r, __svfiwscanf_r, __ssvfiwscanf_r): Declare. * libc/stdio/stdio.tex: Add new documentation references. * libc/stdio/swscanf.c: New file. * libc/stdio/vfwscanf.c: New file. * libc/stdio/vswscanf.c: New file. * libc/stdio/vwscanf.c: New file. * libc/stdio/wscanf.c: New file. * libc/stdio/vfscanf.c (_sungetc_r): Make externaly available. Only define if INTEGER_ONLY is defined. Declare otherwise. (__ssrefill_r): Ditto. (_sfread_r): Ditto. Remove static eofread/eofread1 functions and use __seofread function instead, throughout. * libc/stdio/local.h (__seofread): Declare. * libc/stdio/stdio.c (__seofread): Define. * libc/stdio/fgetwc.c (__fgetwc): Fix compiler warning. * libc/stdio/fgetws.c (_fgetws_r): Ditto. * libc/stdio/fread.c (_fread_r): Ditto. * libc/stdio/vfprintf.c: Ditto. * libc/stdio/vswprintf.c: Ditto.
Diffstat (limited to 'newlib/libc/stdio/vfwscanf.c')
-rw-r--r--newlib/libc/stdio/vfwscanf.c1469
1 files changed, 1469 insertions, 0 deletions
diff --git a/newlib/libc/stdio/vfwscanf.c b/newlib/libc/stdio/vfwscanf.c
new file mode 100644
index 000000000..56df93247
--- /dev/null
+++ b/newlib/libc/stdio/vfwscanf.c
@@ -0,0 +1,1469 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+FUNCTION
+<<vfwscanf>>, <<vwscanf>>, <<vswscanf>>---scan and format argument list from wide character input
+
+INDEX
+ vfwscanf
+INDEX
+ _vfwscanf
+INDEX
+ vwscanf
+INDEX
+ _vwscanf
+INDEX
+ vswscanf
+INDEX
+ _vswscanf
+
+ANSI_SYNOPSIS
+ #include <stdio.h>
+ #include <stdarg.h>
+ int vwscanf(const wchar_t *<[fmt]>, va_list <[list]>);
+ int vfwscanf(FILE *<[fp]>, const wchar_t *<[fmt]>, va_list <[list]>);
+ int vswscanf(const wchar_t *<[str]>, const wchar_t *<[fmt]>, va_list <[list]>);
+
+ int _vwscanf(struct _reent *<[reent]>, const wchar_t *<[fmt]>,
+ va_list <[list]>);
+ int _vfwscanf(struct _reent *<[reent]>, FILE *<[fp]>, const wchar_t *<[fmt]>,
+ va_list <[list]>);
+ int _vswscanf(struct _reent *<[reent]>, const wchar_t *<[str]>,
+ const wchar_t *<[fmt]>, va_list <[list]>);
+
+TRAD_SYNOPSIS
+ #include <stdio.h>
+ #include <varargs.h>
+ int vwscanf( <[fmt]>, <[ist]>)
+ wchar_t *<[fmt]>;
+ va_list <[list]>;
+
+ int vfwscanf( <[fp]>, <[fmt]>, <[list]>)
+ FILE *<[fp]>;
+ wchar_t *<[fmt]>;
+ va_list <[list]>;
+
+ int vswscanf( <[str]>, <[fmt]>, <[list]>)
+ wchar_t *<[str]>;
+ wchar_t *<[fmt]>;
+ va_list <[list]>;
+
+ int _vwscanf( <[reent]>, <[fmt]>, <[ist]>)
+ struct _reent *<[reent]>;
+ wchar_t *<[fmt]>;
+ va_list <[list]>;
+
+ int _vfwscanf( <[reent]>, <[fp]>, <[fmt]>, <[list]>)
+ struct _reent *<[reent]>;
+ FILE *<[fp]>;
+ wchar_t *<[fmt]>;
+ va_list <[list]>;
+
+ int _vswscanf( <[reent]>, <[str]>, <[fmt]>, <[list]>)
+ struct _reent *<[reent]>;
+ wchar_t *<[str]>;
+ wchar_t *<[fmt]>;
+ va_list <[list]>;
+
+DESCRIPTION
+<<vwscanf>>, <<vfwscanf>>, and <<vswscanf>> are (respectively) variants
+of <<wscanf>>, <<fwscanf>>, and <<swscanf>>. They differ only in
+allowing their caller to pass the variable argument list as a
+<<va_list>> object (initialized by <<va_start>>) rather than
+directly accepting a variable number of arguments.
+
+RETURNS
+The return values are consistent with the corresponding functions:
+<<vwscanf>> returns the number of input fields successfully scanned,
+converted, and stored; the return value does not include scanned
+fields which were not stored.
+
+If <<vwscanf>> attempts to read at end-of-file, the return value
+is <<EOF>>.
+
+If no fields were stored, the return value is <<0>>.
+
+The routines <<_vwscanf>>, <<_vfwscanf>>, and <<_vswscanf>> are
+reentrant versions which take an additional first parameter which points
+to the reentrancy structure.
+
+PORTABILITY
+C99, POSIX-1.2008
+*/
+
+#include <_ansi.h>
+#include <reent.h>
+#include <newlib.h>
+#include <ctype.h>
+#include <wctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include <wchar.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include "local.h"
+
+#ifdef INTEGER_ONLY
+#define VFWSCANF vfiwscanf
+#define _VFWSCANF_R _vfiwscanf_r
+#define __SVFWSCANF __svfiwscanf
+#ifdef STRING_ONLY
+# define __SVFWSCANF_R __ssvfiwscanf_r
+#else
+# define __SVFWSCANF_R __svfiwscanf_r
+#endif
+#else
+#define VFWSCANF vfwscanf
+#define _VFWSCANF_R _vfwscanf_r
+#define __SVFWSCANF __svfwscanf
+#ifdef STRING_ONLY
+# define __SVFWSCANF_R __ssvfwscanf_r
+#else
+# define __SVFWSCANF_R __svfwscanf_r
+#endif
+#ifndef NO_FLOATING_POINT
+#define FLOATING_POINT
+#endif
+#endif
+
+#ifdef STRING_ONLY
+#undef _flockfile
+#undef _funlockfile
+#define _flockfile(x) {}
+#define _funlockfile(x) {}
+#define _ungetwc_r _sungetwc_r
+#define __srefill_r __ssrefill_r
+#define _fgetwc_r _sfgetwc_r
+#endif
+
+#ifdef FLOATING_POINT
+#include <math.h>
+#include <float.h>
+
+/* Currently a test is made to see if long double processing is warranted.
+ This could be changed in the future should the _ldtoa_r code be
+ preferred over _dtoa_r. */
+#define _NO_LONGDBL
+#if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
+#undef _NO_LONGDBL
+extern _LONG_DOUBLE _wcstold_r _PARAMS((wchar_t *s, wchar_t **sptr));
+#endif
+
+#include "floatio.h"
+
+#if ((MAXEXP+MAXFRACT+3) > MB_LEN_MAX)
+# define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */
+#else
+# define BUF MB_LEN_MAX
+#endif
+
+/* An upper bound for how long a long prints in decimal. 4 / 13 approximates
+ log (2). Add one char for roundoff compensation and one for the sign. */
+#define MAX_LONG_LEN ((CHAR_BIT * sizeof (long) - 1) * 4 / 13 + 2)
+#else
+#define BUF 40
+#endif
+
+#define _NO_LONGLONG
+#if defined _WANT_IO_LONG_LONG \
+ && (defined __GNUC__ || __STDC_VERSION__ >= 199901L)
+# undef _NO_LONGLONG
+#endif
+
+#define _NO_POS_ARGS
+#ifdef _WANT_IO_POS_ARGS
+# undef _NO_POS_ARGS
+# ifdef NL_ARGMAX
+# define MAX_POS_ARGS NL_ARGMAX
+# else
+# define MAX_POS_ARGS 32
+# endif
+
+static void * get_arg (int, va_list *, int *, void **);
+#endif /* _WANT_IO_POS_ARGS */
+
+/*
+ * Flags used during conversion.
+ */
+
+#define LONG 0x01 /* l: long or double */
+#define LONGDBL 0x02 /* L/ll: long double or long long */
+#define SHORT 0x04 /* h: short */
+#define CHAR 0x08 /* hh: 8 bit integer */
+#define SUPPRESS 0x10 /* suppress assignment */
+#define POINTER 0x20 /* weird %p pointer (`fake hex') */
+#define NOSKIP 0x40 /* do not skip blanks */
+
+/*
+ * The following are used in numeric conversions only:
+ * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
+ * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
+ */
+
+#define SIGNOK 0x80 /* +/- is (still) legal */
+#define NDIGITS 0x100 /* no digits detected */
+
+#define DPTOK 0x200 /* (float) decimal point is still legal */
+#define EXPOK 0x400 /* (float) exponent (e+3, etc) still legal */
+
+#define PFXOK 0x200 /* 0x prefix is (still) legal */
+#define NZDIGITS 0x400 /* no zero digits detected */
+#define HAVESIGN 0x10000 /* sign detected */
+
+/*
+ * Conversion types.
+ */
+
+#define CT_CHAR 0 /* %c conversion */
+#define CT_CCL 1 /* %[...] conversion */
+#define CT_STRING 2 /* %s conversion */
+#define CT_INT 3 /* integer, i.e., wcstol or wcstoul */
+#define CT_FLOAT 4 /* floating, i.e., wcstod */
+
+#define INCCL(_c) \
+ (cclcompl ? (wmemchr(ccls, (_c), ccle - ccls) == NULL) : \
+ (wmemchr(ccls, (_c), ccle - ccls) != NULL))
+
+/*
+ * vfwscanf
+ */
+
+#ifndef STRING_ONLY
+
+#ifndef _REENT_ONLY
+
+int
+_DEFUN(VFWSCANF, (fp, fmt, ap),
+ register FILE *fp _AND
+ _CONST wchar_t *fmt _AND
+ va_list ap)
+{
+ CHECK_INIT(_REENT, fp);
+ return __SVFWSCANF_R (_REENT, fp, fmt, ap);
+}
+
+int
+_DEFUN(__SVFWSCANF, (fp, fmt0, ap),
+ register FILE *fp _AND
+ wchar_t _CONST *fmt0 _AND
+ va_list ap)
+{
+ return __SVFWSCANF_R (_REENT, fp, fmt0, ap);
+}
+
+#endif /* !_REENT_ONLY */
+
+int
+_DEFUN(_VFWSCANF_R, (data, fp, fmt, ap),
+ struct _reent *data _AND
+ register FILE *fp _AND
+ _CONST wchar_t *fmt _AND
+ va_list ap)
+{
+ CHECK_INIT(data, fp);
+ return __SVFWSCANF_R (data, fp, fmt, ap);
+}
+#endif /* !STRING_ONLY */
+
+#ifdef STRING_ONLY
+/* When dealing with the swscanf family, we don't want to use the
+ * regular ungetwc which will drag in file I/O items we don't need.
+ * So, we create our own trimmed-down version. */
+static wint_t
+_DEFUN(_sungetwc_r, (data, fp, ch),
+ struct _reent *data _AND
+ wint_t wc _AND
+ register FILE *fp)
+{
+ if (wc == WEOF)
+ return (WEOF);
+
+ /* After ungetc, we won't be at eof anymore */
+ fp->_flags &= ~__SEOF;
+
+ /*
+ * If we are in the middle of ungetwc'ing, just continue.
+ * This may require expanding the current ungetc buffer.
+ */
+
+ if (HASUB (fp))
+ {
+ if (fp->_r >= fp->_ub._size && __submore (data, fp))
+ {
+ return EOF;
+ }
+ fp->_p -= sizeof (wchar_t);
+ *fp->_p = (wchar_t) wc;
+ fp->_r += sizeof (wchar_t);
+ return wc;
+ }
+
+ /*
+ * If we can handle this by simply backing up, do so,
+ * but never replace the original character.
+ * (This makes swscanf() work when scanning `const' data.)
+ */
+
+ if (fp->_bf._base != NULL && fp->_p > fp->_bf._base
+ && ((wchar_t *)fp->_p)[-1] == wc)
+ {
+ fp->_p -= sizeof (wchar_t);
+ fp->_r += sizeof (wchar_t);
+ return wc;
+ }
+
+ /*
+ * Create an ungetc buffer.
+ * Initially, we will use the `reserve' buffer.
+ */
+
+ fp->_ur = fp->_r;
+ fp->_up = fp->_p;
+ fp->_ub._base = fp->_ubuf;
+ fp->_ub._size = sizeof (fp->_ubuf);
+ fp->_p = &fp->_ubuf[sizeof (fp->_ubuf) - sizeof (wchar_t)];
+ *(wchar_t *) fp->_p = wc;
+ fp->_r = 2;
+ return wc;
+}
+
+extern int __ssrefill_r _PARAMS ((struct _reent *ptr, register FILE * fp));
+
+static size_t
+_DEFUN(_sfgetwc_r, (ptr, fp),
+ struct _reent * ptr _AND
+ FILE * fp)
+{
+ wchar_t wc;
+
+ if (fp->_r <= 0 && __ssrefill_r (ptr, fp))
+ return (WEOF);
+ wc = *(wchar_t *) fp->_p;
+ fp->_p += sizeof (wchar_t);
+ fp->_r -= sizeof (wchar_t);
+ return (wc);
+}
+#endif /* STRING_ONLY */
+
+int
+_DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
+ struct _reent *rptr _AND
+ register FILE *fp _AND
+ wchar_t _CONST *fmt0 _AND
+ va_list ap)
+{
+ register wchar_t *fmt = (wchar_t *) fmt0;
+ register wint_t c; /* character from format, or conversion */
+ register size_t width; /* field width, or 0 */
+ register wchar_t *p = NULL; /* points into all kinds of strings */
+ register int n; /* handy integer */
+ register int flags; /* flags as defined above */
+ register wchar_t *p0; /* saves original value of p when necessary */
+ int nassigned; /* number of fields assigned */
+ int nread; /* number of characters consumed from fp */
+#ifndef _NO_POS_ARGS
+ int N; /* arg number */
+ int arg_index = 0; /* index into args processed directly */
+ int numargs = 0; /* number of varargs read */
+ void *args[MAX_POS_ARGS]; /* positional args read */
+ int is_pos_arg; /* is current format positional? */
+#endif
+ int base = 0; /* base argument to wcstol/wcstoul */
+
+ mbstate_t mbs; /* value to keep track of multibyte state */
+
+ #define CCFN_PARAMS _PARAMS((struct _reent *, const wchar_t *, wchar_t **, int))
+ unsigned long (*ccfn)CCFN_PARAMS=0; /* conversion function (wcstol/wcstoul) */
+ wchar_t buf[BUF]; /* buffer for numeric conversions */
+ const wchar_t *ccls; /* character class start */
+ const wchar_t *ccle; /* character class end */
+ int cclcompl = 0; /* ccl is complemented? */
+ wint_t wi; /* handy wint_t */
+ char *mbp = NULL; /* multibyte string pointer for %c %s %[ */
+ size_t nconv; /* number of bytes in mb. conversion */
+ char mbbuf[MB_LEN_MAX]; /* temporary mb. character buffer */
+
+ char *cp;
+ short *sp;
+ int *ip;
+#ifdef FLOATING_POINT
+ float *flp;
+ _LONG_DOUBLE *ldp;
+ double *dp;
+#endif
+ long *lp;
+#ifndef _NO_LONGLONG
+ long long *llp;
+#endif
+
+ /* `basefix' is used to avoid `if' tests in the integer scanner */
+ static _CONST short basefix[17] =
+ {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+
+ /* Macro to support positional arguments */
+#ifndef _NO_POS_ARGS
+# define GET_ARG(n, ap, type) \
+ ((type) (is_pos_arg \
+ ? (n < numargs \
+ ? args[n] \
+ : get_arg (n, &ap, &numargs, args)) \
+ : (arg_index++ < numargs \
+ ? args[n] \
+ : (numargs < MAX_POS_ARGS \
+ ? args[numargs++] = va_arg (ap, void *) \
+ : va_arg (ap, void *)))))
+#else
+# define GET_ARG(n, ap, type) (va_arg (ap, type))
+#endif
+
+ __sfp_lock_acquire ();
+ _flockfile (fp);
+
+ ORIENT (fp, 1);
+
+ nassigned = 0;
+ nread = 0;
+ ccls = ccle = NULL;
+ for (;;)
+ {
+ c = *fmt++;
+ if (c == L'\0')
+ goto all_done;
+ if (iswspace (c))
+ {
+ while ((c = _fgetwc_r (rptr, fp)) != WEOF && iswspace(c))
+ ;
+ if (c != WEOF)
+ _ungetwc_r (rptr, c, fp);
+ continue;
+ }
+ if (c != L'%')
+ goto literal;
+ width = 0;
+ flags = 0;
+#ifndef _NO_POS_ARGS
+ N = arg_index;
+ is_pos_arg = 0;
+#endif
+
+ /*
+ * switch on the format. continue if done; break once format
+ * type is derived.
+ */
+
+ again:
+ c = *fmt++;
+
+ switch (c)
+ {
+ case L'%':
+ literal:
+ if ((wi = _fgetwc_r (rptr, fp)) == WEOF)
+ goto input_failure;
+ if (wi != c)
+ {
+ _ungetwc_r (rptr, wi, fp);
+ goto input_failure;
+ }
+ nread++;
+ continue;
+
+ case L'*':
+ flags |= SUPPRESS;
+ goto again;
+ case L'l':
+#if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
+ if (*fmt == L'l') /* Check for 'll' = long long (SUSv3) */
+ {
+ ++fmt;
+ flags |= LONGDBL;
+ }
+ else
+#endif
+ flags |= LONG;
+ goto again;
+ case L'L':
+ flags |= LONGDBL;
+ goto again;
+ case L'h':
+#ifdef _WANT_IO_C99_FORMATS
+ if (*fmt == 'h') /* Check for 'hh' = char int (SUSv3) */
+ {
+ ++fmt;
+ flags |= CHAR;
+ }
+ else
+#endif
+ flags |= SHORT;
+ goto again;
+#ifdef _WANT_IO_C99_FORMATS
+ case L'j': /* intmax_t */
+ if (sizeof (intmax_t) == sizeof (long))
+ flags |= LONG;
+ else
+ flags |= LONGDBL;
+ goto again;
+ case L't': /* ptrdiff_t */
+ if (sizeof (ptrdiff_t) < sizeof (int))
+ /* POSIX states ptrdiff_t is 16 or more bits, as
+ is short. */
+ flags |= SHORT;
+ else if (sizeof (ptrdiff_t) == sizeof (int))
+ /* no flag needed */;
+ else if (sizeof (ptrdiff_t) <= sizeof (long))
+ flags |= LONG;
+ else
+ /* POSIX states that at least one programming
+ environment must support ptrdiff_t no wider than
+ long, but that means other environments can
+ have ptrdiff_t as wide as long long. */
+ flags |= LONGDBL;
+ goto again;
+ case L'z': /* size_t */
+ if (sizeof (size_t) < sizeof (int))
+ /* POSIX states size_t is 16 or more bits, as is short. */
+ flags |= SHORT;
+ else if (sizeof (size_t) == sizeof (int))
+ /* no flag needed */;
+ else if (sizeof (size_t) <= sizeof (long))
+ flags |= LONG;
+ else
+ /* POSIX states that at least one programming
+ environment must support size_t no wider than
+ long, but that means other environments can
+ have size_t as wide as long long. */
+ flags |= LONGDBL;
+ goto again;
+#endif /* _WANT_IO_C99_FORMATS */
+
+ case L'0':
+ case L'1':
+ case L'2':
+ case L'3':
+ case L'4':
+ case L'5':
+ case L'6':
+ case L'7':
+ case L'8':
+ case L'9':
+ width = width * 10 + c - L'0';
+ goto again;
+
+#ifndef _NO_POS_ARGS
+ case L'$':
+ if (width <= MAX_POS_ARGS)
+ {
+ N = width - 1;
+ is_pos_arg = 1;
+ width = 0;
+ goto again;
+ }
+ rptr->_errno = EINVAL;
+ goto input_failure;
+#endif /* !_NO_POS_ARGS */
+
+ case L'd':
+ c = CT_INT;
+ ccfn = (unsigned long (*)CCFN_PARAMS)_wcstol_r;
+ base = 10;
+ break;
+
+ case L'i':
+ c = CT_INT;
+ ccfn = (unsigned long (*)CCFN_PARAMS)_wcstol_r;
+ base = 0;
+ break;
+
+ case L'o':
+ c = CT_INT;
+ ccfn = _wcstoul_r;
+ base = 8;
+ break;
+
+ case L'u':
+ c = CT_INT;
+ ccfn = _wcstoul_r;
+ base = 10;
+ break;
+
+ case L'X':
+ case L'x':
+ flags |= PFXOK; /* enable 0x prefixing */
+ c = CT_INT;
+ ccfn = _wcstoul_r;
+ base = 16;
+ break;
+
+#ifdef FLOATING_POINT
+# ifdef _WANT_IO_C99_FORMATS
+ case L'A':
+ case L'a':
+ case L'F':
+# endif
+ case L'E':
+ case L'G':
+ case L'e':
+ case L'f':
+ case L'g':
+ c = CT_FLOAT;
+ break;
+#endif
+
+#ifdef _WANT_IO_C99_FORMATS
+ case L'S':
+ flags |= LONG;
+ /* FALLTHROUGH */
+#endif
+
+ case L's':
+ c = CT_STRING;
+ break;
+
+ case L'[':
+ ccls = fmt;
+ if (*fmt == '^')
+ {
+ cclcompl = 1;
+ ++fmt;
+ }
+ else
+ cclcompl = 0;
+ if (*fmt == ']')
+ fmt++;
+ while (*fmt != '\0' && *fmt != ']')
+ fmt++;
+ ccle = fmt;
+ fmt++;
+ flags |= NOSKIP;
+ c = CT_CCL;
+ break;
+
+#ifdef _WANT_IO_C99_FORMATS
+ case 'C':
+ flags |= LONG;
+ /* FALLTHROUGH */
+#endif
+
+ case 'c':
+ flags |= NOSKIP;
+ c = CT_CHAR;
+ break;
+
+ case 'p': /* pointer format is like hex */
+ flags |= POINTER | PFXOK;
+ c = CT_INT;
+ ccfn = _wcstoul_r;
+ base = 16;
+ break;
+
+ case 'n':
+ if (flags & SUPPRESS) /* ??? */
+ continue;
+#ifdef _WANT_IO_C99_FORMATS
+ if (flags & CHAR)
+ {
+ cp = GET_ARG (N, ap, char *);
+ *cp = nread;
+ }
+ else
+#endif
+ if (flags & SHORT)
+ {
+ sp = GET_ARG (N, ap, short *);
+ *sp = nread;
+ }
+ else if (flags & LONG)
+ {
+ lp = GET_ARG (N, ap, long *);
+ *lp = nread;
+ }
+#ifndef _NO_LONGLONG
+ else if (flags & LONGDBL)
+ {
+ llp = GET_ARG (N, ap, long long*);
+ *llp = nread;
+ }
+#endif
+ else
+ {
+ ip = GET_ARG (N, ap, int *);
+ *ip = nread;
+ }
+ continue;
+
+ /*
+ * Disgusting backwards compatibility hacks. XXX
+ */
+ case L'\0': /* compat */
+ _funlockfile (fp);
+ __sfp_lock_release ();
+ return EOF;
+
+ default: /* compat */
+ goto match_failure;
+ }
+
+ /*
+ * Consume leading white space, except for formats that
+ * suppress this.
+ */
+ if ((flags & NOSKIP) == 0)
+ {
+ while ((wi = _fgetwc_r (rptr, fp)) != WEOF && iswspace (wi))
+ nread++;
+ if (wi == WEOF)
+ goto input_failure;
+ _ungetwc_r (rptr, wi, fp);
+ }
+
+ /*
+ * Do the conversion.
+ */
+ switch (c)
+ {
+
+ case CT_CHAR:
+ /* scan arbitrary characters (sets NOSKIP) */
+ if (width == 0)
+ width = 1;
+ if (flags & LONG)
+ {
+ if (!(flags & SUPPRESS))
+ p = va_arg(ap, wchar_t *);
+ n = 0;
+ while (width-- != 0 && (wi = _fgetwc_r (rptr, fp)) != WEOF)
+ {
+ if (!(flags & SUPPRESS))
+ *p++ = (wchar_t) wi;
+ n++;
+ }
+ if (n == 0)
+ goto input_failure;
+ nread += n;
+ if (!(flags & SUPPRESS))
+ nassigned++;
+ }
+ else
+ {
+ if (!(flags & SUPPRESS))
+ mbp = va_arg(ap, char *);
+ n = 0;
+ memset ((_PTR)&mbs, '\0', sizeof (mbstate_t));
+ while (width != 0 && (wi = _fgetwc_r (rptr, fp)) != WEOF)
+ {
+ if (width >= MB_CUR_MAX && !(flags & SUPPRESS))
+ {
+ nconv = _wcrtomb_r (rptr, mbp, wi, &mbs);
+ if (nconv == (size_t) -1)
+ goto input_failure;
+ }
+ else
+ {
+ nconv = _wcrtomb_r (rptr, mbbuf, wi, &mbs);
+ if (nconv == (size_t) -1)
+ goto input_failure;
+ if (nconv > width)
+ {
+ _ungetwc_r (rptr, wi, fp);
+ break;
+ }
+ if (!(flags & SUPPRESS))
+ memcpy(mbp, mbbuf, nconv);
+ }
+ if (!(flags & SUPPRESS))
+ mbp += nconv;
+ width -= nconv;
+ n++;
+ }
+ if (n == 0)
+ goto input_failure;
+ nread += n;
+ if (!(flags & SUPPRESS))
+ nassigned++;
+ }
+ break;
+
+ case CT_CCL:
+ /* scan a (nonempty) character class (sets NOSKIP) */
+ if (width == 0)
+ width = (size_t) ~0; /* `infinity' */
+ /* take only those things in the class */
+ if ((flags & SUPPRESS) && (flags & LONG))
+ {
+ n = 0;
+ while ((wi = _fgetwc_r (rptr, fp)) != WEOF
+ && width-- != 0 && INCCL (wi))
+ n++;
+ if (wi != WEOF)
+ _ungetwc_r (rptr, wi, fp);
+ if (n == 0)
+ goto match_failure;
+ }
+ else if (flags & LONG)
+ {
+ p0 = p = va_arg(ap, wchar_t *);
+ while ((wi = _fgetwc_r (rptr, fp)) != WEOF
+ && width-- != 0 && INCCL (wi))
+ *p++ = (wchar_t) wi;
+ if (wi != WEOF)
+ _ungetwc_r (rptr, wi, fp);
+ n = p - p0;
+ if (n == 0)
+ goto match_failure;
+ }
+ else
+ {
+ if (!(flags & SUPPRESS))
+ mbp = va_arg(ap, char *);
+ n = 0;
+ memset ((_PTR) &mbs, '\0', sizeof (mbstate_t));
+ while ((wi = _fgetwc_r (rptr, fp)) != WEOF
+ && width-- != 0 && INCCL (wi))
+ {
+ if (width >= MB_CUR_MAX && !(flags & SUPPRESS))
+ {
+ nconv = _wcrtomb_r (rptr, mbp, wi, &mbs);
+ if (nconv == (size_t) -1)
+ goto input_failure;
+ }
+ else
+ {
+ nconv = wcrtomb(mbbuf, wi, &mbs);
+ if (nconv == (size_t) -1)
+ goto input_failure;
+ if (nconv > width)
+ break;
+ if (!(flags & SUPPRESS))
+ memcpy(mbp, mbbuf, nconv);
+ }
+ if (!(flags & SUPPRESS))
+ mbp += nconv;
+ width -= nconv;
+ n++;
+ }
+ if (wi != WEOF)
+ _ungetwc_r (rptr, wi, fp);
+ if (!(flags & SUPPRESS))
+ {
+ *mbp = 0;
+ nassigned++;
+ }
+ }
+ nread += n;
+ break;
+
+ case CT_STRING:
+ /* like CCL, but zero-length string OK, & no NOSKIP */
+ if (width == 0)
+ width = (size_t)~0;
+ if ((flags & SUPPRESS) && (flags & LONG))
+ {
+ while ((wi = _fgetwc_r (rptr, fp)) != WEOF
+ && width-- != 0 && !iswspace (wi))
+ nread++;
+ if (wi != WEOF)
+ _ungetwc_r (rptr, wi, fp);
+ }
+ else if (flags & LONG)
+ {
+ p0 = p = va_arg(ap, wchar_t *);
+ while ((wi = _fgetwc_r (rptr, fp)) != WEOF
+ && width-- != 0 && !iswspace (wi))
+ {
+ *p++ = (wchar_t) wi;
+ nread++;
+ }
+ if (wi != WEOF)
+ _ungetwc_r (rptr, wi, fp);
+ *p = '\0';
+ nassigned++;
+ }
+ else
+ {
+ if (!(flags & SUPPRESS))
+ mbp = va_arg(ap, char *);
+ memset ((_PTR) &mbs, '\0', sizeof (mbstate_t));
+ while ((wi = _fgetwc_r (rptr, fp)) != WEOF
+ && width != 0 && !iswspace (wi))
+ {
+ if (width >= MB_CUR_MAX && !(flags & SUPPRESS))
+ {
+ nconv = wcrtomb(mbp, wi, &mbs);
+ if (nconv == (size_t)-1)
+ goto input_failure;
+ }
+ else
+ {
+ nconv = wcrtomb(mbbuf, wi, &mbs);
+ if (nconv == (size_t)-1)
+ goto input_failure;
+ if (nconv > width)
+ break;
+ if (!(flags & SUPPRESS))
+ memcpy(mbp, mbbuf, nconv);
+ }
+ if (!(flags & SUPPRESS))
+ mbp += nconv;
+ width -= nconv;
+ nread++;
+ }
+ if (wi != WEOF)
+ _ungetwc_r (rptr, wi, fp);
+ if (!(flags & SUPPRESS))
+ {
+ *mbp = 0;
+ nassigned++;
+ }
+ }
+ continue;
+
+ case CT_INT:
+ {
+ /* scan an integer as if by wcstol/wcstoul */
+ if (width == 0 || width > sizeof (buf) / sizeof (*buf) - 1)
+ width = sizeof(buf) / sizeof (*buf) - 1;
+ flags |= SIGNOK | NDIGITS | NZDIGITS;
+ for (p = buf; width; width--)
+ {
+ c = _fgetwc_r (rptr, fp);
+ /*
+ * Switch on the character; `goto ok' if we
+ * accept it as a part of number.
+ */
+ switch (c)
+ {
+ /*
+ * The digit 0 is always legal, but is special.
+ * For %i conversions, if no digits (zero or nonzero)
+ * have been scanned (only signs), we will have base==0.
+ * In that case, we should set it to 8 and enable 0x
+ * prefixing. Also, if we have not scanned zero digits
+ * before this, do not turn off prefixing (someone else
+ * will turn it off if we have scanned any nonzero digits).
+ */
+ case L'0':
+ if (base == 0)
+ {
+ base = 8;
+ flags |= PFXOK;
+ }
+ if (flags & NZDIGITS)
+ flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
+ else
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* 1 through 7 always legal */
+ case L'1':
+ case L'2':
+ case L'3':
+ case L'4':
+ case L'5':
+ case L'6':
+ case L'7':
+ base = basefix[base];
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* digits 8 and 9 ok iff decimal or hex */
+ case L'8':
+ case L'9':
+ base = basefix[base];
+ if (base <= 8)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* letters ok iff hex */
+ case L'A':
+ case L'B':
+ case L'C':
+ case L'D':
+ case L'E':
+ case L'F':
+ case L'a':
+ case L'b':
+ case L'c':
+ case L'd':
+ case L'e':
+ case L'f':
+ /* no need to fix base here */
+ if (base <= 10)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* sign ok only as first character */
+ case L'+':
+ case L'-':
+ if (flags & SIGNOK)
+ {
+ flags &= ~SIGNOK;
+ flags |= HAVESIGN;
+ goto ok;
+ }
+ break;
+
+ /* x ok iff flag still set & single 0 seen */
+ case L'x':
+ case L'X':
+ if ((flags & PFXOK) && p == buf + 1 + !!(flags & HAVESIGN))
+ {
+ base = 16;/* if %i */
+ flags &= ~PFXOK;
+ goto ok;
+ }
+ break;
+ }
+
+ /*
+ * If we got here, c is not a legal character
+ * for a number. Stop accumulating digits.
+ */
+ if (c != WEOF)
+ _ungetwc_r (rptr, c, fp);
+ break;
+ ok:
+ /*
+ * c is legal: store it and look at the next.
+ */
+ *p++ = (wchar_t) c;
+ }
+ /*
+ * If we had only a sign, it is no good; push back the sign.
+ * If the number ends in `x', it was [sign] '0' 'x', so push back
+ * the x and treat it as [sign] '0'.
+ * Use of ungetc here and below assumes ASCII encoding; we are only
+ * pushing back 7-bit characters, so casting to unsigned char is
+ * not necessary.
+ */
+ if (flags & NDIGITS)
+ {
+ if (p > buf)
+ _ungetwc_r (rptr, *--p, fp); /* [-+xX] */
+ goto match_failure;
+ }
+ c = p[-1];
+ if (c == L'x' || c == L'X')
+ {
+ --p;
+ _ungetwc_r (rptr, c, fp);
+ }
+ if ((flags & SUPPRESS) == 0)
+ {
+ unsigned long res;
+
+ *p = 0;
+ res = (*ccfn) (rptr, buf, (wchar_t **) NULL, base);
+ if (flags & POINTER)
+ {
+ void **vp = GET_ARG (N, ap, void **);
+#ifndef _NO_LONGLONG
+ if (sizeof (uintptr_t) > sizeof (unsigned long))
+ {
+ unsigned long long resll;
+ resll = _wcstoull_r (rptr, buf, (wchar_t **) NULL, base);
+ *vp = (void *) (uintptr_t) resll;
+ }
+ else
+#endif /* !_NO_LONGLONG */
+ *vp = (void *) (uintptr_t) res;
+ }
+#ifdef _WANT_IO_C99_FORMATS
+ else if (flags & CHAR)
+ {
+ cp = GET_ARG (N, ap, char *);
+ *cp = res;
+ }
+#endif
+ else if (flags & SHORT)
+ {
+ sp = GET_ARG (N, ap, short *);
+ *sp = res;
+ }
+ else if (flags & LONG)
+ {
+ lp = GET_ARG (N, ap, long *);
+ *lp = res;
+ }
+#ifndef _NO_LONGLONG
+ else if (flags & LONGDBL)
+ {
+ unsigned long long resll;
+ if (ccfn == _wcstoul_r)
+ resll = _wcstoull_r (rptr, buf, (wchar_t **) NULL, base);
+ else
+ resll = _wcstoll_r (rptr, buf, (wchar_t **) NULL, base);
+ llp = GET_ARG (N, ap, long long*);
+ *llp = resll;
+ }
+#endif
+ else
+ {
+ ip = GET_ARG (N, ap, int *);
+ *ip = res;
+ }
+ nassigned++;
+ }
+ nread += p - buf;
+ break;
+ }
+#ifdef FLOATING_POINT
+ case CT_FLOAT:
+ {
+ /* scan a floating point number as if by wcstod */
+ /* This code used to assume that the number of digits is reasonable.
+ However, ANSI / ISO C makes no such stipulation; we have to get
+ exact results even when there is an unreasonable amount of
+ leading zeroes. */
+ long leading_zeroes = 0;
+ long zeroes, exp_adjust;
+ wchar_t *exp_start = NULL;
+ unsigned width_left = 0;
+ char nancount = 0;
+ char infcount = 0;
+#ifdef hardway
+ if (width == 0 || width > sizeof (buf) - 1)
+#else
+ /* size_t is unsigned, hence this optimisation */
+ if (width - 1 > sizeof (buf) - 2)
+#endif
+ {
+ width_left = width - (sizeof (buf) - 1);
+ width = sizeof (buf) - 1;
+ }
+ flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
+ zeroes = 0;
+ exp_adjust = 0;
+ for (p = buf; width; )
+ {
+ c = _fgetwc_r (rptr, fp);
+ /*
+ * This code mimicks the integer conversion
+ * code, but is much simpler.
+ */
+ switch (c)
+ {
+ case L'0':
+ if (flags & NDIGITS)
+ {
+ flags &= ~SIGNOK;
+ zeroes++;
+ if (width_left)
+ {
+ width_left--;
+ width++;
+ }
+ goto fskip;
+ }
+ /* Fall through. */
+ case L'1':
+ case L'2':
+ case L'3':
+ case L'4':
+ case L'5':
+ case L'6':
+ case L'7':
+ case L'8':
+ case L'9':
+ if (nancount + infcount == 0)
+ {
+ flags &= ~(SIGNOK | NDIGITS);
+ goto fok;
+ }
+ break;
+
+ case L'+':
+ case L'-':
+ if (flags & SIGNOK)
+ {
+ flags &= ~SIGNOK;
+ goto fok;
+ }
+ break;
+ case L'n':
+ case L'N':
+ if (nancount == 0 && zeroes == 0
+ && (flags & (NDIGITS | DPTOK | EXPOK)) ==
+ (NDIGITS | DPTOK | EXPOK))
+ {
+ flags &= ~(SIGNOK | DPTOK | EXPOK | NDIGITS);
+ nancount = 1;
+ goto fok;
+ }
+ if (nancount == 2)
+ {
+ nancount = 3;
+ goto fok;
+ }
+ if (infcount == 1 || infcount == 4)
+ {
+ infcount++;
+ goto fok;
+ }
+ break;
+ case L'a':
+ case L'A':
+ if (nancount == 1)
+ {
+ nancount = 2;
+ goto fok;
+ }
+ break;
+ case L'i':
+ if (infcount == 0 && zeroes == 0
+ && (flags & (NDIGITS | DPTOK | EXPOK)) ==
+ (NDIGITS | DPTOK | EXPOK))
+ {
+ flags &= ~(SIGNOK | DPTOK | EXPOK | NDIGITS);
+ infcount = 1;
+ goto fok;
+ }
+ if (infcount == 3 || infcount == 5)
+ {
+ infcount++;
+ goto fok;
+ }
+ break;
+ case L'f':
+ case L'F':
+ if (infcount == 2)
+ {
+ infcount = 3;
+ goto fok;
+ }
+ break;
+ case L't':
+ case L'T':
+ if (infcount == 6)
+ {
+ infcount = 7;
+ goto fok;
+ }
+ break;
+ case L'y':
+ case L'Y':
+ if (infcount == 7)
+ {
+ infcount = 8;
+ goto fok;
+ }
+ break;
+ case L'.':
+ if (flags & DPTOK)
+ {
+ flags &= ~(SIGNOK | DPTOK);
+ leading_zeroes = zeroes;
+ goto fok;
+ }
+ break;
+ case L'e':
+ case L'E':
+ /* no exponent without some digits */
+ if ((flags & (NDIGITS | EXPOK)) == EXPOK
+ || ((flags & EXPOK) && zeroes))
+ {
+ if (! (flags & DPTOK))
+ {
+ exp_adjust = zeroes - leading_zeroes;
+ exp_start = p;
+ }
+ flags =
+ (flags & ~(EXPOK | DPTOK)) |
+ SIGNOK | NDIGITS;
+ zeroes = 0;
+ goto fok;
+ }
+ break;
+ }
+ if (c != WEOF)
+ _ungetwc_r (rptr, c, fp);
+ break;
+ fok:
+ *p++ = c;
+ fskip:
+ width--;
+ ++nread;
+ }
+ if (zeroes)
+ flags &= ~NDIGITS;
+ /* We may have a 'N' or possibly even [sign] 'N' 'a' as the
+ start of 'NaN', only to run out of chars before it was
+ complete (or having encountered a non-matching char). So
+ check here if we have an outstanding nancount, and if so
+ put back the chars we did swallow and treat as a failed
+ match.
+
+ FIXME - we still don't handle NAN([0xdigits]). */
+ if (nancount - 1U < 2U) /* nancount && nancount < 3 */
+ {
+ /* Newlib's ungetc works even if we called __srefill in
+ the middle of a partial parse, but POSIX does not
+ guarantee that in all implementations of ungetc. */
+ while (p > buf)
+ {
+ _ungetwc_r (rptr, *--p, fp); /* [-+nNaA] */
+ --nread;
+ }
+ goto match_failure;
+ }
+ /* Likewise for 'inf' and 'infinity'. But be careful that
+ 'infinite' consumes only 3 characters, leaving the stream
+ at the second 'i'. */
+ if (infcount - 1U < 7U) /* infcount && infcount < 8 */
+ {
+ if (infcount >= 3) /* valid 'inf', but short of 'infinity' */
+ while (infcount-- > 3)
+ {
+ _ungetwc_r (rptr, *--p, fp); /* [iInNtT] */
+ --nread;
+ }
+ else
+ {
+ while (p > buf)
+ {
+ _ungetwc_r (rptr, *--p, fp); /* [-+iInN] */
+ --nread;
+ }
+ goto match_failure;
+ }
+ }
+ /*
+ * If no digits, might be missing exponent digits
+ * (just give back the exponent) or might be missing
+ * regular digits, but had sign and/or decimal point.
+ */
+ if (flags & NDIGITS)
+ {
+ if (flags & EXPOK)
+ {
+ /* no digits at all */
+ while (p > buf)
+ {
+ _ungetwc_r (rptr, *--p, fp); /* [-+.] */
+ --nread;
+ }
+ goto match_failure;
+ }
+ /* just a bad exponent (e and maybe sign) */
+ c = *--p;
+ --nread;
+ if (c != L'e' && c != L'E')
+ {
+ _ungetwc_r (rptr, c, fp); /* [-+] */
+ c = *--p;
+ --nread;
+ }
+ _ungetwc_r (rptr, c, fp); /* [eE] */
+ }
+ if ((flags & SUPPRESS) == 0)
+ {
+ double res = 0;
+#ifdef _NO_LONGDBL
+#define QUAD_RES res;
+#else /* !_NO_LONG_DBL */
+ long double qres = 0;
+#define QUAD_RES qres;
+#endif /* !_NO_LONG_DBL */
+ long new_exp = 0;
+
+ *p = 0;
+ if ((flags & (DPTOK | EXPOK)) == EXPOK)
+ {
+ exp_adjust = zeroes - leading_zeroes;
+ new_exp = -exp_adjust;
+ exp_start = p;
+ }
+ else if (exp_adjust)
+ new_exp = _wcstol_r (rptr, (exp_start + 1), NULL, 10) - exp_adjust;
+ if (exp_adjust)
+ {
+
+ /* If there might not be enough space for the new exponent,
+ truncate some trailing digits to make room. */
+ if (exp_start >= buf + sizeof (buf) - MAX_LONG_LEN)
+ exp_start = buf + sizeof (buf) - MAX_LONG_LEN - 1;
+ swprintf (exp_start, MAX_LONG_LEN, L"e%ld", new_exp);
+ }
+
+ /* FIXME: We don't have wcstold yet. */
+#if 0//ndef _NO_LONGDBL /* !_NO_LONGDBL */
+ if (flags & LONGDBL)
+ qres = _wcstold_r (rptr, buf, NULL);
+ else
+#endif
+ res = _wcstod_r (rptr, buf, NULL);
+
+ if (flags & LONG)
+ {
+ dp = GET_ARG (N, ap, double *);
+ *dp = res;
+ }
+ else if (flags & LONGDBL)
+ {
+ ldp = GET_ARG (N, ap, _LONG_DOUBLE *);
+ *ldp = QUAD_RES;
+ }
+ else
+ {
+ flp = GET_ARG (N, ap, float *);
+ if (isnan (res))
+ *flp = nanf (NULL);
+ else
+ *flp = res;
+ }
+ nassigned++;
+ }
+ break;
+ }
+#endif /* FLOATING_POINT */
+ }
+ }
+input_failure:
+ /* On read failure, return EOF failure regardless of matches; errno
+ should have been set prior to here. On EOF failure (including
+ invalid format string), return EOF if no matches yet, else number
+ of matches made prior to failure. */
+ _funlockfile (fp);
+ __sfp_lock_release ();
+ return nassigned && !(fp->_flags & __SERR) ? nassigned : EOF;
+match_failure:
+all_done:
+ /* Return number of matches, which can be 0 on match failure. */
+ _funlockfile (fp);
+ __sfp_lock_release ();
+ return nassigned;
+}
+
+#ifndef _NO_POS_ARGS
+/* Process all intermediate arguments. Fortunately, with wscanf, all
+ intermediate arguments are sizeof(void*), so we don't need to scan
+ ahead in the format string. */
+static void *
+get_arg (int n, va_list *ap, int *numargs_p, void **args)
+{
+ int numargs = *numargs_p;
+ while (n >= numargs)
+ args[numargs++] = va_arg (*ap, void *);
+ *numargs_p = numargs;
+ return args[n];
+}
+#endif /* !_NO_POS_ARGS */