xref: /dflybsd-src/lib/libc/stdio/vfwscanf.c (revision 839f7d6207d1654b664a46f2905d559773779bc3)
162f08720SJoerg Sonnenberger /*-
262f08720SJoerg Sonnenberger  * Copyright (c) 1990, 1993
362f08720SJoerg Sonnenberger  *	The Regents of the University of California.  All rights reserved.
462f08720SJoerg Sonnenberger  *
562f08720SJoerg Sonnenberger  * This code is derived from software contributed to Berkeley by
662f08720SJoerg Sonnenberger  * Chris Torek.
762f08720SJoerg Sonnenberger  *
80d5acd74SJohn Marino  * Copyright (c) 2011 The FreeBSD Foundation
90d5acd74SJohn Marino  * All rights reserved.
100d5acd74SJohn Marino  * Portions of this software were developed by David Chisnall
110d5acd74SJohn Marino  * under sponsorship from the FreeBSD Foundation.
120d5acd74SJohn Marino  *
1362f08720SJoerg Sonnenberger  * Redistribution and use in source and binary forms, with or without
1462f08720SJoerg Sonnenberger  * modification, are permitted provided that the following conditions
1562f08720SJoerg Sonnenberger  * are met:
1662f08720SJoerg Sonnenberger  * 1. Redistributions of source code must retain the above copyright
1762f08720SJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer.
1862f08720SJoerg Sonnenberger  * 2. Redistributions in binary form must reproduce the above copyright
1962f08720SJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer in the
2062f08720SJoerg Sonnenberger  *    documentation and/or other materials provided with the distribution.
21dc71b7abSJustin C. Sherrill  * 3. Neither the name of the University nor the names of its contributors
2262f08720SJoerg Sonnenberger  *    may be used to endorse or promote products derived from this software
2362f08720SJoerg Sonnenberger  *    without specific prior written permission.
2462f08720SJoerg Sonnenberger  *
2562f08720SJoerg Sonnenberger  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2662f08720SJoerg Sonnenberger  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2762f08720SJoerg Sonnenberger  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2862f08720SJoerg Sonnenberger  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2962f08720SJoerg Sonnenberger  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3062f08720SJoerg Sonnenberger  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3162f08720SJoerg Sonnenberger  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3262f08720SJoerg Sonnenberger  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3362f08720SJoerg Sonnenberger  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3462f08720SJoerg Sonnenberger  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3562f08720SJoerg Sonnenberger  * SUCH DAMAGE.
36e0f95098SPeter Avalos  *
37e0f95098SPeter Avalos  * @(#)vfscanf.c	8.1 (Berkeley) 6/4/93
380d5acd74SJohn Marino  * $FreeBSD: head/lib/libc/stdio/vfwscanf.c 249808 2013-04-23 13:33:13Z emaste $
3962f08720SJoerg Sonnenberger  */
4062f08720SJoerg Sonnenberger 
4162f08720SJoerg Sonnenberger #include "namespace.h"
4262f08720SJoerg Sonnenberger #include <ctype.h>
4362f08720SJoerg Sonnenberger #include <inttypes.h>
44e0f95098SPeter Avalos #include <limits.h>
4562f08720SJoerg Sonnenberger #include <stdio.h>
4662f08720SJoerg Sonnenberger #include <stdlib.h>
4762f08720SJoerg Sonnenberger #include <stddef.h>
4862f08720SJoerg Sonnenberger #include <stdarg.h>
4962f08720SJoerg Sonnenberger #include <string.h>
5062f08720SJoerg Sonnenberger #include <wchar.h>
5162f08720SJoerg Sonnenberger #include <wctype.h>
5262f08720SJoerg Sonnenberger #include "un-namespace.h"
5362f08720SJoerg Sonnenberger 
5462f08720SJoerg Sonnenberger #include "libc_private.h"
5562f08720SJoerg Sonnenberger #include "local.h"
560d5acd74SJohn Marino #include "xlocale_private.h"
5762f08720SJoerg Sonnenberger 
5862f08720SJoerg Sonnenberger #define	BUF		513	/* Maximum length of numeric string. */
5962f08720SJoerg Sonnenberger 
6062f08720SJoerg Sonnenberger /*
6162f08720SJoerg Sonnenberger  * Flags used during conversion.
6262f08720SJoerg Sonnenberger  */
6362f08720SJoerg Sonnenberger #define	LONG		0x01	/* l: long or double */
6462f08720SJoerg Sonnenberger #define	LONGDBL		0x02	/* L: long double */
6562f08720SJoerg Sonnenberger #define	SHORT		0x04	/* h: short */
6662f08720SJoerg Sonnenberger #define	SUPPRESS	0x08	/* *: suppress assignment */
6762f08720SJoerg Sonnenberger #define	POINTER		0x10	/* p: void * (as hex) */
6862f08720SJoerg Sonnenberger #define	NOSKIP		0x20	/* [ or c: do not skip blanks */
69*839f7d62SSascha Wildner #ifdef __DragonFly__ /* Non-standard extension: L and ll are equivalent */
70*839f7d62SSascha Wildner #define	LONGLONG	LONGDBL	/* ll/L: long long, long double */
71*839f7d62SSascha Wildner 				/* (+ deprecated q: quad) */
72*839f7d62SSascha Wildner #else
73e0f95098SPeter Avalos #define	LONGLONG	0x400	/* ll: long long (+ deprecated q: quad) */
74*839f7d62SSascha Wildner #endif
7562f08720SJoerg Sonnenberger #define	INTMAXT		0x800	/* j: intmax_t */
7662f08720SJoerg Sonnenberger #define	PTRDIFFT	0x1000	/* t: ptrdiff_t */
7762f08720SJoerg Sonnenberger #define	SIZET		0x2000	/* z: size_t */
7862f08720SJoerg Sonnenberger #define	SHORTSHORT	0x4000	/* hh: char */
7962f08720SJoerg Sonnenberger #define	UNSIGNED	0x8000	/* %[oupxX] conversions */
8062f08720SJoerg Sonnenberger 
8162f08720SJoerg Sonnenberger /*
8262f08720SJoerg Sonnenberger  * The following are used in integral conversions only:
8362f08720SJoerg Sonnenberger  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS
8462f08720SJoerg Sonnenberger  */
8562f08720SJoerg Sonnenberger #define	SIGNOK		0x40	/* +/- is (still) legal */
8662f08720SJoerg Sonnenberger #define	NDIGITS		0x80	/* no digits detected */
8762f08720SJoerg Sonnenberger #define	PFXOK		0x100	/* 0x prefix is (still) legal */
8862f08720SJoerg Sonnenberger #define	NZDIGITS	0x200	/* no zero digits detected */
8962f08720SJoerg Sonnenberger #define	HAVESIGN	0x10000	/* sign detected */
9062f08720SJoerg Sonnenberger 
9162f08720SJoerg Sonnenberger /*
9262f08720SJoerg Sonnenberger  * Conversion types.
9362f08720SJoerg Sonnenberger  */
9462f08720SJoerg Sonnenberger #define	CT_CHAR		0	/* %c conversion */
9562f08720SJoerg Sonnenberger #define	CT_CCL		1	/* %[...] conversion */
9662f08720SJoerg Sonnenberger #define	CT_STRING	2	/* %s conversion */
9762f08720SJoerg Sonnenberger #define	CT_INT		3	/* %[dioupxX] conversion */
9862f08720SJoerg Sonnenberger #define	CT_FLOAT	4	/* %[efgEFG] conversion */
9962f08720SJoerg Sonnenberger 
100e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
1010d5acd74SJohn Marino static int parsefloat(FILE *, wchar_t *, wchar_t *, locale_t);
102e0f95098SPeter Avalos #endif
10362f08720SJoerg Sonnenberger 
1040d5acd74SJohn Marino struct ccl {
1050d5acd74SJohn Marino 	const wchar_t *start;	/* character class start */
1060d5acd74SJohn Marino 	const wchar_t *end;	/* character class end */
1070d5acd74SJohn Marino 	int compl;		/* ccl is complemented? */
1080d5acd74SJohn Marino };
1090d5acd74SJohn Marino 
1100d5acd74SJohn Marino static __inline int
inccl(const struct ccl * ccl,wint_t wi)1110d5acd74SJohn Marino inccl(const struct ccl *ccl, wint_t wi)
1120d5acd74SJohn Marino {
1130d5acd74SJohn Marino 
1140d5acd74SJohn Marino 	if (ccl->compl) {
1150d5acd74SJohn Marino 		return (wmemchr(ccl->start, wi, ccl->end - ccl->start)
1160d5acd74SJohn Marino 		    == NULL);
1170d5acd74SJohn Marino 	} else {
1180d5acd74SJohn Marino 		return (wmemchr(ccl->start, wi, ccl->end - ccl->start) != NULL);
1190d5acd74SJohn Marino 	}
1200d5acd74SJohn Marino }
1210d5acd74SJohn Marino 
1220d5acd74SJohn Marino /*
1230d5acd74SJohn Marino  * Conversion functions are passed a pointer to this object instead of
1240d5acd74SJohn Marino  * a real parameter to indicate that the assignment-suppression (*)
1250d5acd74SJohn Marino  * flag was specified.  We could use a NULL pointer to indicate this,
1260d5acd74SJohn Marino  * but that would mask bugs in applications that call scanf() with a
1270d5acd74SJohn Marino  * NULL pointer.
1280d5acd74SJohn Marino  */
1290d5acd74SJohn Marino static const int suppress;
1300d5acd74SJohn Marino #define	SUPPRESS_PTR	((void *)&suppress)
131e0f95098SPeter Avalos 
132e0f95098SPeter Avalos static const mbstate_t initial_mbs;
13362f08720SJoerg Sonnenberger 
13462f08720SJoerg Sonnenberger /*
1350d5acd74SJohn Marino  * The following conversion functions return the number of characters consumed,
1360d5acd74SJohn Marino  * or -1 on input failure.  Character class conversion returns 0 on match
1370d5acd74SJohn Marino  * failure.
1380d5acd74SJohn Marino  */
1390d5acd74SJohn Marino 
1400d5acd74SJohn Marino static __inline int
convert_char(FILE * fp,char * mbp,int width,locale_t locale)1410d5acd74SJohn Marino convert_char(FILE *fp, char * mbp, int width, locale_t locale)
1420d5acd74SJohn Marino {
1430d5acd74SJohn Marino 	mbstate_t mbs;
1440d5acd74SJohn Marino 	size_t nconv;
1450d5acd74SJohn Marino 	wint_t wi;
1460d5acd74SJohn Marino 	int n;
1470d5acd74SJohn Marino 
1480d5acd74SJohn Marino 	n = 0;
1490d5acd74SJohn Marino 	mbs = initial_mbs;
1500d5acd74SJohn Marino 	while (width-- != 0 && (wi = __fgetwc(fp, locale)) != WEOF) {
1510d5acd74SJohn Marino 		if (mbp != SUPPRESS_PTR) {
1520d5acd74SJohn Marino 			nconv = wcrtomb(mbp, wi, &mbs);
1530d5acd74SJohn Marino 			if (nconv == (size_t)-1)
1540d5acd74SJohn Marino 				return (-1);
1550d5acd74SJohn Marino 			mbp += nconv;
1560d5acd74SJohn Marino 		}
1570d5acd74SJohn Marino 		n++;
1580d5acd74SJohn Marino 	}
1590d5acd74SJohn Marino 	if (n == 0)
1600d5acd74SJohn Marino 		return (-1);
1610d5acd74SJohn Marino 	return (n);
1620d5acd74SJohn Marino }
1630d5acd74SJohn Marino 
1640d5acd74SJohn Marino static __inline int
convert_wchar(FILE * fp,wchar_t * wcp,int width,locale_t locale)1650d5acd74SJohn Marino convert_wchar(FILE *fp, wchar_t *wcp, int width, locale_t locale)
1660d5acd74SJohn Marino {
1670d5acd74SJohn Marino 	wint_t wi;
1680d5acd74SJohn Marino 	int n;
1690d5acd74SJohn Marino 
1700d5acd74SJohn Marino 	n = 0;
1710d5acd74SJohn Marino 	while (width-- != 0 && (wi = __fgetwc(fp, locale)) != WEOF) {
1720d5acd74SJohn Marino 		if (wcp != SUPPRESS_PTR)
1730d5acd74SJohn Marino 			*wcp++ = (wchar_t)wi;
1740d5acd74SJohn Marino 		n++;
1750d5acd74SJohn Marino 	}
1760d5acd74SJohn Marino 	if (n == 0)
1770d5acd74SJohn Marino 		return (-1);
1780d5acd74SJohn Marino 	return (n);
1790d5acd74SJohn Marino }
1800d5acd74SJohn Marino 
1810d5acd74SJohn Marino static __inline int
convert_ccl(FILE * fp,char * mbp,int width,const struct ccl * ccl,locale_t locale)1820d5acd74SJohn Marino convert_ccl(FILE *fp, char * mbp, int width, const struct ccl *ccl,
1830d5acd74SJohn Marino     locale_t locale)
1840d5acd74SJohn Marino {
1850d5acd74SJohn Marino 	mbstate_t mbs;
1860d5acd74SJohn Marino 	size_t nconv;
1870d5acd74SJohn Marino 	wint_t wi;
1880d5acd74SJohn Marino 	int n;
1890d5acd74SJohn Marino 
1900d5acd74SJohn Marino 	n = 0;
1910d5acd74SJohn Marino 	mbs = initial_mbs;
1920d5acd74SJohn Marino 	while ((wi = __fgetwc(fp, locale)) != WEOF &&
1930d5acd74SJohn Marino 	    width-- != 0 && inccl(ccl, wi)) {
1940d5acd74SJohn Marino 		if (mbp != SUPPRESS_PTR) {
1950d5acd74SJohn Marino 			nconv = wcrtomb(mbp, wi, &mbs);
1960d5acd74SJohn Marino 			if (nconv == (size_t)-1)
1970d5acd74SJohn Marino 				return (-1);
1980d5acd74SJohn Marino 			mbp += nconv;
1990d5acd74SJohn Marino 		}
2000d5acd74SJohn Marino 		n++;
2010d5acd74SJohn Marino 	}
2020d5acd74SJohn Marino 	if (wi != WEOF)
2030d5acd74SJohn Marino 		__ungetwc(wi, fp, locale);
2040d5acd74SJohn Marino 	if (mbp != SUPPRESS_PTR)
2050d5acd74SJohn Marino 		*mbp = 0;
2060d5acd74SJohn Marino 	return (n);
2070d5acd74SJohn Marino }
2080d5acd74SJohn Marino 
2090d5acd74SJohn Marino static __inline int
convert_wccl(FILE * fp,wchar_t * wcp,int width,const struct ccl * ccl,locale_t locale)2100d5acd74SJohn Marino convert_wccl(FILE *fp, wchar_t *wcp, int width, const struct ccl *ccl,
2110d5acd74SJohn Marino     locale_t locale)
2120d5acd74SJohn Marino {
2130d5acd74SJohn Marino 	wchar_t *wcp0;
2140d5acd74SJohn Marino 	wint_t wi;
2150d5acd74SJohn Marino 	int n;
2160d5acd74SJohn Marino 
2170d5acd74SJohn Marino 	if (wcp == SUPPRESS_PTR) {
2180d5acd74SJohn Marino 		n = 0;
2190d5acd74SJohn Marino 		while ((wi = __fgetwc(fp, locale)) != WEOF &&
2200d5acd74SJohn Marino 		    width-- != 0 && inccl(ccl, wi))
2210d5acd74SJohn Marino 			n++;
2220d5acd74SJohn Marino 		if (wi != WEOF)
2230d5acd74SJohn Marino 			__ungetwc(wi, fp, locale);
2240d5acd74SJohn Marino 	} else {
2250d5acd74SJohn Marino 		wcp0 = wcp;
2260d5acd74SJohn Marino 		while ((wi = __fgetwc(fp, locale)) != WEOF &&
2270d5acd74SJohn Marino 		    width-- != 0 && inccl(ccl, wi))
2280d5acd74SJohn Marino 			*wcp++ = (wchar_t)wi;
2290d5acd74SJohn Marino 		if (wi != WEOF)
2300d5acd74SJohn Marino 			__ungetwc(wi, fp, locale);
2310d5acd74SJohn Marino 		n = wcp - wcp0;
2320d5acd74SJohn Marino 		if (n == 0)
2330d5acd74SJohn Marino 			return (0);
2340d5acd74SJohn Marino 		*wcp = 0;
2350d5acd74SJohn Marino 	}
2360d5acd74SJohn Marino 	return (n);
2370d5acd74SJohn Marino }
2380d5acd74SJohn Marino 
2390d5acd74SJohn Marino static __inline int
convert_string(FILE * fp,char * mbp,int width,locale_t locale)2400d5acd74SJohn Marino convert_string(FILE *fp, char * mbp, int width, locale_t locale)
2410d5acd74SJohn Marino {
2420d5acd74SJohn Marino 	mbstate_t mbs;
2430d5acd74SJohn Marino 	size_t nconv;
2440d5acd74SJohn Marino 	wint_t wi;
2450d5acd74SJohn Marino 	int nread;
2460d5acd74SJohn Marino 
2470d5acd74SJohn Marino 	mbs = initial_mbs;
2480d5acd74SJohn Marino 	nread = 0;
2490d5acd74SJohn Marino 	while ((wi = __fgetwc(fp, locale)) != WEOF && width-- != 0 &&
2500d5acd74SJohn Marino 	    !iswspace(wi)) {
2510d5acd74SJohn Marino 		if (mbp != SUPPRESS_PTR) {
2520d5acd74SJohn Marino 			nconv = wcrtomb(mbp, wi, &mbs);
2530d5acd74SJohn Marino 			if (nconv == (size_t)-1)
2540d5acd74SJohn Marino 				return (-1);
2550d5acd74SJohn Marino 			mbp += nconv;
2560d5acd74SJohn Marino 		}
2570d5acd74SJohn Marino 		nread++;
2580d5acd74SJohn Marino 	}
2590d5acd74SJohn Marino 	if (wi != WEOF)
2600d5acd74SJohn Marino 		__ungetwc(wi, fp, locale);
2610d5acd74SJohn Marino 	if (mbp != SUPPRESS_PTR)
2620d5acd74SJohn Marino 		*mbp = 0;
2630d5acd74SJohn Marino 	return (nread);
2640d5acd74SJohn Marino }
2650d5acd74SJohn Marino 
2660d5acd74SJohn Marino static __inline int
convert_wstring(FILE * fp,wchar_t * wcp,int width,locale_t locale)2670d5acd74SJohn Marino convert_wstring(FILE *fp, wchar_t *wcp, int width, locale_t locale)
2680d5acd74SJohn Marino {
269cf515c3aSJohn Marino 	wchar_t *wcp0 __unused;
2700d5acd74SJohn Marino 	wint_t wi;
2710d5acd74SJohn Marino 	int nread;
2720d5acd74SJohn Marino 
2730d5acd74SJohn Marino 	nread = 0;
2740d5acd74SJohn Marino 	if (wcp == SUPPRESS_PTR) {
2750d5acd74SJohn Marino 		while ((wi = __fgetwc(fp, locale)) != WEOF &&
2760d5acd74SJohn Marino 		    width-- != 0 && !iswspace(wi))
2770d5acd74SJohn Marino 			nread++;
2780d5acd74SJohn Marino 		if (wi != WEOF)
2790d5acd74SJohn Marino 			__ungetwc(wi, fp, locale);
2800d5acd74SJohn Marino 	} else {
2810d5acd74SJohn Marino 		wcp0 = wcp;
2820d5acd74SJohn Marino 		while ((wi = __fgetwc(fp, locale)) != WEOF &&
2830d5acd74SJohn Marino 		    width-- != 0 && !iswspace(wi)) {
2840d5acd74SJohn Marino 			*wcp++ = (wchar_t)wi;
2850d5acd74SJohn Marino 			nread++;
2860d5acd74SJohn Marino 		}
2870d5acd74SJohn Marino 		if (wi != WEOF)
2880d5acd74SJohn Marino 			__ungetwc(wi, fp, locale);
2890d5acd74SJohn Marino 		*wcp = '\0';
2900d5acd74SJohn Marino 	}
2910d5acd74SJohn Marino 	return (nread);
2920d5acd74SJohn Marino }
2930d5acd74SJohn Marino 
2940d5acd74SJohn Marino /*
2950d5acd74SJohn Marino  * Read an integer, storing it in buf.  The only relevant bit in the
2960d5acd74SJohn Marino  * flags argument is PFXOK.
2970d5acd74SJohn Marino  *
2980d5acd74SJohn Marino  * Return 0 on a match failure, and the number of characters read
2990d5acd74SJohn Marino  * otherwise.
3000d5acd74SJohn Marino  */
3010d5acd74SJohn Marino static __inline int
parseint(FILE * fp,wchar_t * buf,int width,int base,int flags,locale_t locale)3020d5acd74SJohn Marino parseint(FILE *fp, wchar_t *buf, int width, int base, int flags,
3030d5acd74SJohn Marino     locale_t locale)
3040d5acd74SJohn Marino {
3050d5acd74SJohn Marino 	/* `basefix' is used to avoid `if' tests */
3060d5acd74SJohn Marino 	static const short basefix[17] =
3070d5acd74SJohn Marino 		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
3080d5acd74SJohn Marino 	wchar_t *wcp;
3090d5acd74SJohn Marino 	int c;
3100d5acd74SJohn Marino 
3110d5acd74SJohn Marino 	flags |= SIGNOK | NDIGITS | NZDIGITS;
3120d5acd74SJohn Marino 	for (wcp = buf; width; width--) {
3130d5acd74SJohn Marino 		c = __fgetwc(fp, locale);
3140d5acd74SJohn Marino 		/*
3150d5acd74SJohn Marino 		 * Switch on the character; `goto ok' if we accept it
3160d5acd74SJohn Marino 		 * as a part of number.
3170d5acd74SJohn Marino 		 */
3180d5acd74SJohn Marino 		switch (c) {
3190d5acd74SJohn Marino 
3200d5acd74SJohn Marino 		/*
3210d5acd74SJohn Marino 		 * The digit 0 is always legal, but is special.  For
3220d5acd74SJohn Marino 		 * %i conversions, if no digits (zero or nonzero) have
3230d5acd74SJohn Marino 		 * been scanned (only signs), we will have base==0.
3240d5acd74SJohn Marino 		 * In that case, we should set it to 8 and enable 0x
3250d5acd74SJohn Marino 		 * prefixing.  Also, if we have not scanned zero
3260d5acd74SJohn Marino 		 * digits before this, do not turn off prefixing
3270d5acd74SJohn Marino 		 * (someone else will turn it off if we have scanned
3280d5acd74SJohn Marino 		 * any nonzero digits).
3290d5acd74SJohn Marino 		 */
3300d5acd74SJohn Marino 		case '0':
3310d5acd74SJohn Marino 			if (base == 0) {
3320d5acd74SJohn Marino 				base = 8;
3330d5acd74SJohn Marino 				flags |= PFXOK;
3340d5acd74SJohn Marino 			}
3350d5acd74SJohn Marino 			if (flags & NZDIGITS)
3360d5acd74SJohn Marino 				flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
3370d5acd74SJohn Marino 			else
3380d5acd74SJohn Marino 				flags &= ~(SIGNOK|PFXOK|NDIGITS);
3390d5acd74SJohn Marino 			goto ok;
3400d5acd74SJohn Marino 
3410d5acd74SJohn Marino 		/* 1 through 7 always legal */
3420d5acd74SJohn Marino 		case '1': case '2': case '3':
3430d5acd74SJohn Marino 		case '4': case '5': case '6': case '7':
3440d5acd74SJohn Marino 			base = basefix[base];
3450d5acd74SJohn Marino 			flags &= ~(SIGNOK | PFXOK | NDIGITS);
3460d5acd74SJohn Marino 			goto ok;
3470d5acd74SJohn Marino 
3480d5acd74SJohn Marino 		/* digits 8 and 9 ok iff decimal or hex */
3490d5acd74SJohn Marino 		case '8': case '9':
3500d5acd74SJohn Marino 			base = basefix[base];
3510d5acd74SJohn Marino 			if (base <= 8)
3520d5acd74SJohn Marino 				break;	/* not legal here */
3530d5acd74SJohn Marino 			flags &= ~(SIGNOK | PFXOK | NDIGITS);
3540d5acd74SJohn Marino 			goto ok;
3550d5acd74SJohn Marino 
3560d5acd74SJohn Marino 		/* letters ok iff hex */
3570d5acd74SJohn Marino 		case 'A': case 'B': case 'C':
3580d5acd74SJohn Marino 		case 'D': case 'E': case 'F':
3590d5acd74SJohn Marino 		case 'a': case 'b': case 'c':
3600d5acd74SJohn Marino 		case 'd': case 'e': case 'f':
3610d5acd74SJohn Marino 			/* no need to fix base here */
3620d5acd74SJohn Marino 			if (base <= 10)
3630d5acd74SJohn Marino 				break;	/* not legal here */
3640d5acd74SJohn Marino 			flags &= ~(SIGNOK | PFXOK | NDIGITS);
3650d5acd74SJohn Marino 			goto ok;
3660d5acd74SJohn Marino 
3670d5acd74SJohn Marino 		/* sign ok only as first character */
3680d5acd74SJohn Marino 		case '+': case '-':
3690d5acd74SJohn Marino 			if (flags & SIGNOK) {
3700d5acd74SJohn Marino 				flags &= ~SIGNOK;
3710d5acd74SJohn Marino 				flags |= HAVESIGN;
3720d5acd74SJohn Marino 				goto ok;
3730d5acd74SJohn Marino 			}
3740d5acd74SJohn Marino 			break;
3750d5acd74SJohn Marino 
3760d5acd74SJohn Marino 		/*
3770d5acd74SJohn Marino 		 * x ok iff flag still set & 2nd char (or 3rd char if
3780d5acd74SJohn Marino 		 * we have a sign).
3790d5acd74SJohn Marino 		 */
3800d5acd74SJohn Marino 		case 'x': case 'X':
3810d5acd74SJohn Marino 			if (flags & PFXOK && wcp ==
3820d5acd74SJohn Marino 			    buf + 1 + !!(flags & HAVESIGN)) {
3830d5acd74SJohn Marino 				base = 16;	/* if %i */
3840d5acd74SJohn Marino 				flags &= ~PFXOK;
3850d5acd74SJohn Marino 				goto ok;
3860d5acd74SJohn Marino 			}
3870d5acd74SJohn Marino 			break;
3880d5acd74SJohn Marino 		}
3890d5acd74SJohn Marino 
3900d5acd74SJohn Marino 		/*
3910d5acd74SJohn Marino 		 * If we got here, c is not a legal character for a
3920d5acd74SJohn Marino 		 * number.  Stop accumulating digits.
3930d5acd74SJohn Marino 		 */
3940d5acd74SJohn Marino 		if (c != WEOF)
3950d5acd74SJohn Marino 			__ungetwc(c, fp, locale);
3960d5acd74SJohn Marino 		break;
3970d5acd74SJohn Marino 	ok:
3980d5acd74SJohn Marino 		/*
3990d5acd74SJohn Marino 		 * c is legal: store it and look at the next.
4000d5acd74SJohn Marino 		 */
4010d5acd74SJohn Marino 		*wcp++ = (wchar_t)c;
4020d5acd74SJohn Marino 	}
4030d5acd74SJohn Marino 	/*
4040d5acd74SJohn Marino 	 * If we had only a sign, it is no good; push back the sign.
4050d5acd74SJohn Marino 	 * If the number ends in `x', it was [sign] '0' 'x', so push
4060d5acd74SJohn Marino 	 * back the x and treat it as [sign] '0'.
4070d5acd74SJohn Marino 	 */
4080d5acd74SJohn Marino 	if (flags & NDIGITS) {
4090d5acd74SJohn Marino 		if (wcp > buf)
4100d5acd74SJohn Marino 			__ungetwc(*--wcp, fp, locale);
4110d5acd74SJohn Marino 		return (0);
4120d5acd74SJohn Marino 	}
4130d5acd74SJohn Marino 	c = wcp[-1];
4140d5acd74SJohn Marino 	if (c == 'x' || c == 'X') {
4150d5acd74SJohn Marino 		--wcp;
4160d5acd74SJohn Marino 		__ungetwc(c, fp, locale);
4170d5acd74SJohn Marino 	}
4180d5acd74SJohn Marino 	return (wcp - buf);
4190d5acd74SJohn Marino }
4200d5acd74SJohn Marino 
4210d5acd74SJohn Marino /*
42262f08720SJoerg Sonnenberger  * MT-safe version.
42362f08720SJoerg Sonnenberger  */
42462f08720SJoerg Sonnenberger int
vfwscanf_l(FILE * __restrict fp,locale_t locale,const wchar_t * __restrict fmt,va_list ap)4250d5acd74SJohn Marino vfwscanf_l(FILE * __restrict fp, locale_t locale,
4260d5acd74SJohn Marino 		const wchar_t * __restrict fmt, va_list ap)
42762f08720SJoerg Sonnenberger {
42862f08720SJoerg Sonnenberger 	int ret;
4290d5acd74SJohn Marino 	FIX_LOCALE(locale);
43062f08720SJoerg Sonnenberger 
43162f08720SJoerg Sonnenberger 	FLOCKFILE(fp);
432e0f95098SPeter Avalos 	ORIENT(fp, 1);
4330d5acd74SJohn Marino 	ret = __vfwscanf(fp, locale, fmt, ap);
43462f08720SJoerg Sonnenberger 	FUNLOCKFILE(fp);
43562f08720SJoerg Sonnenberger 	return (ret);
43662f08720SJoerg Sonnenberger }
4370d5acd74SJohn Marino int
vfwscanf(FILE * __restrict fp,const wchar_t * __restrict fmt,va_list ap)4380d5acd74SJohn Marino vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
4390d5acd74SJohn Marino {
4400d5acd74SJohn Marino 	return vfwscanf_l(fp, __get_locale(), fmt, ap);
4410d5acd74SJohn Marino }
44262f08720SJoerg Sonnenberger 
44362f08720SJoerg Sonnenberger /*
44462f08720SJoerg Sonnenberger  * Non-MT-safe version.
44562f08720SJoerg Sonnenberger  */
44662f08720SJoerg Sonnenberger int
__vfwscanf(FILE * __restrict fp,locale_t locale,const wchar_t * __restrict fmt,va_list ap)4470d5acd74SJohn Marino __vfwscanf(FILE * __restrict fp, locale_t locale,
4480d5acd74SJohn Marino 		const wchar_t * __restrict fmt, va_list ap)
44962f08720SJoerg Sonnenberger {
4500d5acd74SJohn Marino #define	GETARG(type)	((flags & SUPPRESS) ? SUPPRESS_PTR : va_arg(ap, type))
45162f08720SJoerg Sonnenberger 	wint_t c;		/* character from format, or conversion */
45262f08720SJoerg Sonnenberger 	size_t width;		/* field width, or 0 */
45362f08720SJoerg Sonnenberger 	int flags;		/* flags as defined above */
45462f08720SJoerg Sonnenberger 	int nassigned;		/* number of fields assigned */
45562f08720SJoerg Sonnenberger 	int nconversions;	/* number of conversions */
4560d5acd74SJohn Marino 	int nr;			/* characters read by the current conversion */
45762f08720SJoerg Sonnenberger 	int nread;		/* number of characters consumed from fp */
45862f08720SJoerg Sonnenberger 	int base;		/* base argument to conversion function */
4590d5acd74SJohn Marino 	struct ccl ccl;		/* character class info */
46062f08720SJoerg Sonnenberger 	wchar_t buf[BUF];	/* buffer for numeric conversions */
46162f08720SJoerg Sonnenberger 	wint_t wi;		/* handy wint_t */
46262f08720SJoerg Sonnenberger 
46362f08720SJoerg Sonnenberger 	nassigned = 0;
46462f08720SJoerg Sonnenberger 	nconversions = 0;
46562f08720SJoerg Sonnenberger 	nread = 0;
4660d5acd74SJohn Marino 	ccl.start = ccl.end = NULL;
46762f08720SJoerg Sonnenberger 	for (;;) {
46862f08720SJoerg Sonnenberger 		c = *fmt++;
46962f08720SJoerg Sonnenberger 		if (c == 0)
47062f08720SJoerg Sonnenberger 			return (nassigned);
47162f08720SJoerg Sonnenberger 		if (iswspace(c)) {
4720d5acd74SJohn Marino 			while ((c = __fgetwc(fp, locale)) != WEOF &&
4730d5acd74SJohn Marino 			    iswspace_l(c, locale))
4740d5acd74SJohn Marino 				nread++;
47562f08720SJoerg Sonnenberger 			if (c != WEOF)
4760d5acd74SJohn Marino 				__ungetwc(c, fp, locale);
47762f08720SJoerg Sonnenberger 			continue;
47862f08720SJoerg Sonnenberger 		}
47962f08720SJoerg Sonnenberger 		if (c != '%')
48062f08720SJoerg Sonnenberger 			goto literal;
48162f08720SJoerg Sonnenberger 		width = 0;
48262f08720SJoerg Sonnenberger 		flags = 0;
48362f08720SJoerg Sonnenberger 		/*
48462f08720SJoerg Sonnenberger 		 * switch on the format.  continue if done;
48562f08720SJoerg Sonnenberger 		 * break once format type is derived.
48662f08720SJoerg Sonnenberger 		 */
48762f08720SJoerg Sonnenberger again:		c = *fmt++;
48862f08720SJoerg Sonnenberger 		switch (c) {
48962f08720SJoerg Sonnenberger 		case '%':
49062f08720SJoerg Sonnenberger literal:
4910d5acd74SJohn Marino 			if ((wi = __fgetwc(fp, locale)) == WEOF)
49262f08720SJoerg Sonnenberger 				goto input_failure;
49362f08720SJoerg Sonnenberger 			if (wi != c) {
4940d5acd74SJohn Marino 				__ungetwc(wi, fp, locale);
49562f08720SJoerg Sonnenberger 				goto input_failure;
49662f08720SJoerg Sonnenberger 			}
49762f08720SJoerg Sonnenberger 			nread++;
49862f08720SJoerg Sonnenberger 			continue;
49962f08720SJoerg Sonnenberger 
50062f08720SJoerg Sonnenberger 		case '*':
50162f08720SJoerg Sonnenberger 			flags |= SUPPRESS;
50262f08720SJoerg Sonnenberger 			goto again;
50362f08720SJoerg Sonnenberger 		case 'j':
50462f08720SJoerg Sonnenberger 			flags |= INTMAXT;
50562f08720SJoerg Sonnenberger 			goto again;
50662f08720SJoerg Sonnenberger 		case 'l':
50762f08720SJoerg Sonnenberger 			if (flags & LONG) {
50862f08720SJoerg Sonnenberger 				flags &= ~LONG;
50962f08720SJoerg Sonnenberger 				flags |= LONGLONG;
51062f08720SJoerg Sonnenberger 			} else
51162f08720SJoerg Sonnenberger 				flags |= LONG;
51262f08720SJoerg Sonnenberger 			goto again;
51362f08720SJoerg Sonnenberger 		case 'q':
51462f08720SJoerg Sonnenberger 			flags |= LONGLONG;	/* not quite */
51562f08720SJoerg Sonnenberger 			goto again;
51662f08720SJoerg Sonnenberger 		case 't':
51762f08720SJoerg Sonnenberger 			flags |= PTRDIFFT;
51862f08720SJoerg Sonnenberger 			goto again;
51962f08720SJoerg Sonnenberger 		case 'z':
52062f08720SJoerg Sonnenberger 			flags |= SIZET;
52162f08720SJoerg Sonnenberger 			goto again;
52262f08720SJoerg Sonnenberger 		case 'L':
52362f08720SJoerg Sonnenberger 			flags |= LONGDBL;
52462f08720SJoerg Sonnenberger 			goto again;
52562f08720SJoerg Sonnenberger 		case 'h':
52662f08720SJoerg Sonnenberger 			if (flags & SHORT) {
52762f08720SJoerg Sonnenberger 				flags &= ~SHORT;
52862f08720SJoerg Sonnenberger 				flags |= SHORTSHORT;
52962f08720SJoerg Sonnenberger 			} else
53062f08720SJoerg Sonnenberger 				flags |= SHORT;
53162f08720SJoerg Sonnenberger 			goto again;
53262f08720SJoerg Sonnenberger 
53362f08720SJoerg Sonnenberger 		case '0': case '1': case '2': case '3': case '4':
53462f08720SJoerg Sonnenberger 		case '5': case '6': case '7': case '8': case '9':
53562f08720SJoerg Sonnenberger 			width = width * 10 + c - '0';
53662f08720SJoerg Sonnenberger 			goto again;
53762f08720SJoerg Sonnenberger 
53862f08720SJoerg Sonnenberger 		/*
53962f08720SJoerg Sonnenberger 		 * Conversions.
54062f08720SJoerg Sonnenberger 		 */
54162f08720SJoerg Sonnenberger 		case 'd':
54262f08720SJoerg Sonnenberger 			c = CT_INT;
54362f08720SJoerg Sonnenberger 			base = 10;
54462f08720SJoerg Sonnenberger 			break;
54562f08720SJoerg Sonnenberger 
54662f08720SJoerg Sonnenberger 		case 'i':
54762f08720SJoerg Sonnenberger 			c = CT_INT;
54862f08720SJoerg Sonnenberger 			base = 0;
54962f08720SJoerg Sonnenberger 			break;
55062f08720SJoerg Sonnenberger 
55162f08720SJoerg Sonnenberger 		case 'o':
55262f08720SJoerg Sonnenberger 			c = CT_INT;
55362f08720SJoerg Sonnenberger 			flags |= UNSIGNED;
55462f08720SJoerg Sonnenberger 			base = 8;
55562f08720SJoerg Sonnenberger 			break;
55662f08720SJoerg Sonnenberger 
55762f08720SJoerg Sonnenberger 		case 'u':
55862f08720SJoerg Sonnenberger 			c = CT_INT;
55962f08720SJoerg Sonnenberger 			flags |= UNSIGNED;
56062f08720SJoerg Sonnenberger 			base = 10;
56162f08720SJoerg Sonnenberger 			break;
56262f08720SJoerg Sonnenberger 
56362f08720SJoerg Sonnenberger 		case 'X':
56462f08720SJoerg Sonnenberger 		case 'x':
56562f08720SJoerg Sonnenberger 			flags |= PFXOK;	/* enable 0x prefixing */
56662f08720SJoerg Sonnenberger 			c = CT_INT;
56762f08720SJoerg Sonnenberger 			flags |= UNSIGNED;
56862f08720SJoerg Sonnenberger 			base = 16;
56962f08720SJoerg Sonnenberger 			break;
57062f08720SJoerg Sonnenberger 
57162f08720SJoerg Sonnenberger #ifndef NO_FLOATING_POINT
57262f08720SJoerg Sonnenberger 		case 'A': case 'E': case 'F': case 'G':
57362f08720SJoerg Sonnenberger 		case 'a': case 'e': case 'f': case 'g':
57462f08720SJoerg Sonnenberger 			c = CT_FLOAT;
57562f08720SJoerg Sonnenberger 			break;
57662f08720SJoerg Sonnenberger #endif
57762f08720SJoerg Sonnenberger 
57862f08720SJoerg Sonnenberger 		case 'S':
57962f08720SJoerg Sonnenberger 			flags |= LONG;
58062f08720SJoerg Sonnenberger 			/* FALLTHROUGH */
58162f08720SJoerg Sonnenberger 		case 's':
58262f08720SJoerg Sonnenberger 			c = CT_STRING;
58362f08720SJoerg Sonnenberger 			break;
58462f08720SJoerg Sonnenberger 
58562f08720SJoerg Sonnenberger 		case '[':
5860d5acd74SJohn Marino 			ccl.start = fmt;
58762f08720SJoerg Sonnenberger 			if (*fmt == '^') {
5880d5acd74SJohn Marino 				ccl.compl = 1;
58962f08720SJoerg Sonnenberger 				fmt++;
59062f08720SJoerg Sonnenberger 			} else
5910d5acd74SJohn Marino 				ccl.compl = 0;
59262f08720SJoerg Sonnenberger 			if (*fmt == ']')
59362f08720SJoerg Sonnenberger 				fmt++;
59462f08720SJoerg Sonnenberger 			while (*fmt != '\0' && *fmt != ']')
59562f08720SJoerg Sonnenberger 				fmt++;
5960d5acd74SJohn Marino 			ccl.end = fmt;
59762f08720SJoerg Sonnenberger 			fmt++;
59862f08720SJoerg Sonnenberger 			flags |= NOSKIP;
59962f08720SJoerg Sonnenberger 			c = CT_CCL;
60062f08720SJoerg Sonnenberger 			break;
60162f08720SJoerg Sonnenberger 
60262f08720SJoerg Sonnenberger 		case 'C':
60362f08720SJoerg Sonnenberger 			flags |= LONG;
60462f08720SJoerg Sonnenberger 			/* FALLTHROUGH */
60562f08720SJoerg Sonnenberger 		case 'c':
60662f08720SJoerg Sonnenberger 			flags |= NOSKIP;
60762f08720SJoerg Sonnenberger 			c = CT_CHAR;
60862f08720SJoerg Sonnenberger 			break;
60962f08720SJoerg Sonnenberger 
61062f08720SJoerg Sonnenberger 		case 'p':	/* pointer format is like hex */
61162f08720SJoerg Sonnenberger 			flags |= POINTER | PFXOK;
61262f08720SJoerg Sonnenberger 			c = CT_INT;		/* assumes sizeof(uintmax_t) */
61362f08720SJoerg Sonnenberger 			flags |= UNSIGNED;	/*      >= sizeof(uintptr_t) */
61462f08720SJoerg Sonnenberger 			base = 16;
61562f08720SJoerg Sonnenberger 			break;
61662f08720SJoerg Sonnenberger 
61762f08720SJoerg Sonnenberger 		case 'n':
61862f08720SJoerg Sonnenberger 			if (flags & SUPPRESS)	/* ??? */
61962f08720SJoerg Sonnenberger 				continue;
62062f08720SJoerg Sonnenberger 			if (flags & SHORTSHORT)
62162f08720SJoerg Sonnenberger 				*va_arg(ap, char *) = nread;
62262f08720SJoerg Sonnenberger 			else if (flags & SHORT)
62362f08720SJoerg Sonnenberger 				*va_arg(ap, short *) = nread;
62462f08720SJoerg Sonnenberger 			else if (flags & LONG)
62562f08720SJoerg Sonnenberger 				*va_arg(ap, long *) = nread;
62662f08720SJoerg Sonnenberger 			else if (flags & LONGLONG)
627e0f95098SPeter Avalos 				*va_arg(ap, long long *) = nread;
62862f08720SJoerg Sonnenberger 			else if (flags & INTMAXT)
62962f08720SJoerg Sonnenberger 				*va_arg(ap, intmax_t *) = nread;
63062f08720SJoerg Sonnenberger 			else if (flags & SIZET)
63162f08720SJoerg Sonnenberger 				*va_arg(ap, size_t *) = nread;
63262f08720SJoerg Sonnenberger 			else if (flags & PTRDIFFT)
63362f08720SJoerg Sonnenberger 				*va_arg(ap, ptrdiff_t *) = nread;
63462f08720SJoerg Sonnenberger 			else
63562f08720SJoerg Sonnenberger 				*va_arg(ap, int *) = nread;
63662f08720SJoerg Sonnenberger 			continue;
63762f08720SJoerg Sonnenberger 
63862f08720SJoerg Sonnenberger 		default:
63962f08720SJoerg Sonnenberger 			goto match_failure;
64062f08720SJoerg Sonnenberger 
64162f08720SJoerg Sonnenberger 		/*
64262f08720SJoerg Sonnenberger 		 * Disgusting backwards compatibility hack.	XXX
64362f08720SJoerg Sonnenberger 		 */
64462f08720SJoerg Sonnenberger 		case '\0':	/* compat */
64562f08720SJoerg Sonnenberger 			return (EOF);
64662f08720SJoerg Sonnenberger 		}
64762f08720SJoerg Sonnenberger 
64862f08720SJoerg Sonnenberger 		/*
64962f08720SJoerg Sonnenberger 		 * Consume leading white space, except for formats
65062f08720SJoerg Sonnenberger 		 * that suppress this.
65162f08720SJoerg Sonnenberger 		 */
65262f08720SJoerg Sonnenberger 		if ((flags & NOSKIP) == 0) {
6530d5acd74SJohn Marino 			while ((wi = __fgetwc(fp, locale)) != WEOF && iswspace(wi))
65462f08720SJoerg Sonnenberger 				nread++;
65562f08720SJoerg Sonnenberger 			if (wi == WEOF)
65662f08720SJoerg Sonnenberger 				goto input_failure;
6570d5acd74SJohn Marino 			__ungetwc(wi, fp, locale);
65862f08720SJoerg Sonnenberger 		}
65962f08720SJoerg Sonnenberger 
66062f08720SJoerg Sonnenberger 		/*
66162f08720SJoerg Sonnenberger 		 * Do the conversion.
66262f08720SJoerg Sonnenberger 		 */
66362f08720SJoerg Sonnenberger 		switch (c) {
66462f08720SJoerg Sonnenberger 
66562f08720SJoerg Sonnenberger 		case CT_CHAR:
66662f08720SJoerg Sonnenberger 			/* scan arbitrary characters (sets NOSKIP) */
66762f08720SJoerg Sonnenberger 			if (width == 0)
66862f08720SJoerg Sonnenberger 				width = 1;
66962f08720SJoerg Sonnenberger 			if (flags & LONG) {
6700d5acd74SJohn Marino 				nr = convert_wchar(fp, GETARG(wchar_t *), width,
6710d5acd74SJohn Marino 				    locale);
67262f08720SJoerg Sonnenberger 			} else {
6730d5acd74SJohn Marino 				nr = convert_char(fp, GETARG(char *), width,
6740d5acd74SJohn Marino 				    locale);
6750d5acd74SJohn Marino 			}
6760d5acd74SJohn Marino 			if (nr < 0)
67762f08720SJoerg Sonnenberger 				goto input_failure;
67862f08720SJoerg Sonnenberger 			break;
67962f08720SJoerg Sonnenberger 
68062f08720SJoerg Sonnenberger 		case CT_CCL:
68162f08720SJoerg Sonnenberger 			/* scan a (nonempty) character class (sets NOSKIP) */
68262f08720SJoerg Sonnenberger 			if (width == 0)
68362f08720SJoerg Sonnenberger 				width = (size_t)~0;	/* `infinity' */
68462f08720SJoerg Sonnenberger 			/* take only those things in the class */
6850d5acd74SJohn Marino 			if (flags & LONG) {
6860d5acd74SJohn Marino 				nr = convert_wccl(fp, GETARG(wchar_t *), width,
6870d5acd74SJohn Marino 				    &ccl, locale);
68862f08720SJoerg Sonnenberger 			} else {
6890d5acd74SJohn Marino 				nr = convert_ccl(fp, GETARG(char *), width,
6900d5acd74SJohn Marino 				    &ccl, locale);
6910d5acd74SJohn Marino 			}
6920d5acd74SJohn Marino 			if (nr <= 0) {
6930d5acd74SJohn Marino 				if (nr < 0)
69462f08720SJoerg Sonnenberger 					goto input_failure;
6950d5acd74SJohn Marino 				else /* nr == 0 */
6960d5acd74SJohn Marino 					goto match_failure;
69762f08720SJoerg Sonnenberger 			}
69862f08720SJoerg Sonnenberger 			break;
69962f08720SJoerg Sonnenberger 
70062f08720SJoerg Sonnenberger 		case CT_STRING:
70162f08720SJoerg Sonnenberger 			/* like CCL, but zero-length string OK, & no NOSKIP */
70262f08720SJoerg Sonnenberger 			if (width == 0)
70362f08720SJoerg Sonnenberger 				width = (size_t)~0;
7040d5acd74SJohn Marino 			if (flags & LONG) {
7050d5acd74SJohn Marino 				nr = convert_wstring(fp, GETARG(wchar_t *),
7060d5acd74SJohn Marino 				    width, locale);
7070d5acd74SJohn Marino 			} else {
7080d5acd74SJohn Marino 				nr = convert_string(fp, GETARG(char *), width,
7090d5acd74SJohn Marino 				    locale);
71062f08720SJoerg Sonnenberger 			}
7110d5acd74SJohn Marino 			if (nr < 0)
71262f08720SJoerg Sonnenberger 				goto input_failure;
71362f08720SJoerg Sonnenberger 			break;
71462f08720SJoerg Sonnenberger 
71562f08720SJoerg Sonnenberger 		case CT_INT:
71662f08720SJoerg Sonnenberger 			/* scan an integer as if by the conversion function */
71762f08720SJoerg Sonnenberger 			if (width == 0 || width > sizeof(buf) /
71862f08720SJoerg Sonnenberger 			    sizeof(*buf) - 1)
71962f08720SJoerg Sonnenberger 				width = sizeof(buf) / sizeof(*buf) - 1;
72062f08720SJoerg Sonnenberger 
7210d5acd74SJohn Marino 			nr = parseint(fp, buf, width, base, flags, locale);
7220d5acd74SJohn Marino 			if (nr == 0)
72362f08720SJoerg Sonnenberger 				goto match_failure;
72462f08720SJoerg Sonnenberger 			if ((flags & SUPPRESS) == 0) {
72562f08720SJoerg Sonnenberger 				uintmax_t res;
72662f08720SJoerg Sonnenberger 
7270d5acd74SJohn Marino 				buf[nr] = L'\0';
72862f08720SJoerg Sonnenberger 				if ((flags & UNSIGNED) == 0)
72962f08720SJoerg Sonnenberger 				    res = wcstoimax(buf, NULL, base);
73062f08720SJoerg Sonnenberger 				else
73162f08720SJoerg Sonnenberger 				    res = wcstoumax(buf, NULL, base);
73262f08720SJoerg Sonnenberger 				if (flags & POINTER)
73362f08720SJoerg Sonnenberger 					*va_arg(ap, void **) =
73462f08720SJoerg Sonnenberger 							(void *)(uintptr_t)res;
73562f08720SJoerg Sonnenberger 				else if (flags & SHORTSHORT)
736e0f95098SPeter Avalos 					*va_arg(ap, char *) = res;
73762f08720SJoerg Sonnenberger 				else if (flags & SHORT)
738e0f95098SPeter Avalos 					*va_arg(ap, short *) = res;
73962f08720SJoerg Sonnenberger 				else if (flags & LONG)
740e0f95098SPeter Avalos 					*va_arg(ap, long *) = res;
74162f08720SJoerg Sonnenberger 				else if (flags & LONGLONG)
742e0f95098SPeter Avalos 					*va_arg(ap, long long *) = res;
74362f08720SJoerg Sonnenberger 				else if (flags & INTMAXT)
74462f08720SJoerg Sonnenberger 					*va_arg(ap, intmax_t *) = res;
74562f08720SJoerg Sonnenberger 				else if (flags & PTRDIFFT)
746e0f95098SPeter Avalos 					*va_arg(ap, ptrdiff_t *) = res;
74762f08720SJoerg Sonnenberger 				else if (flags & SIZET)
748e0f95098SPeter Avalos 					*va_arg(ap, size_t *) = res;
74962f08720SJoerg Sonnenberger 				else
750e0f95098SPeter Avalos 					*va_arg(ap, int *) = res;
75162f08720SJoerg Sonnenberger 			}
75262f08720SJoerg Sonnenberger 			break;
75362f08720SJoerg Sonnenberger 
75462f08720SJoerg Sonnenberger #ifndef NO_FLOATING_POINT
75562f08720SJoerg Sonnenberger 		case CT_FLOAT:
75662f08720SJoerg Sonnenberger 			/* scan a floating point number as if by strtod */
75762f08720SJoerg Sonnenberger 			if (width == 0 || width > sizeof(buf) /
75862f08720SJoerg Sonnenberger 			    sizeof(*buf) - 1)
75962f08720SJoerg Sonnenberger 				width = sizeof(buf) / sizeof(*buf) - 1;
7600d5acd74SJohn Marino 			nr = parsefloat(fp, buf, buf + width, locale);
7610d5acd74SJohn Marino 			if (nr == 0)
76262f08720SJoerg Sonnenberger 				goto match_failure;
76362f08720SJoerg Sonnenberger 			if ((flags & SUPPRESS) == 0) {
76462f08720SJoerg Sonnenberger 				if (flags & LONGDBL) {
7650d5acd74SJohn Marino 					long double res = wcstold(buf, NULL);
76662f08720SJoerg Sonnenberger 					*va_arg(ap, long double *) = res;
767e0f95098SPeter Avalos 				} else if (flags & LONG) {
7680d5acd74SJohn Marino 					double res = wcstod(buf, NULL);
76962f08720SJoerg Sonnenberger 					*va_arg(ap, double *) = res;
77062f08720SJoerg Sonnenberger 				} else {
7710d5acd74SJohn Marino 					float res = wcstof(buf, NULL);
77262f08720SJoerg Sonnenberger 					*va_arg(ap, float *) = res;
77362f08720SJoerg Sonnenberger 				}
77462f08720SJoerg Sonnenberger 			}
77562f08720SJoerg Sonnenberger 			break;
77662f08720SJoerg Sonnenberger #endif /* !NO_FLOATING_POINT */
77762f08720SJoerg Sonnenberger 		}
7780d5acd74SJohn Marino 		if (!(flags & SUPPRESS))
7790d5acd74SJohn Marino 			nassigned++;
7800d5acd74SJohn Marino 		nread += nr;
7810d5acd74SJohn Marino 		nconversions++;
78262f08720SJoerg Sonnenberger 	}
78362f08720SJoerg Sonnenberger input_failure:
78462f08720SJoerg Sonnenberger 	return (nconversions != 0 ? nassigned : EOF);
78562f08720SJoerg Sonnenberger match_failure:
78662f08720SJoerg Sonnenberger 	return (nassigned);
78762f08720SJoerg Sonnenberger }
78862f08720SJoerg Sonnenberger 
78962f08720SJoerg Sonnenberger #ifndef NO_FLOATING_POINT
79062f08720SJoerg Sonnenberger static int
parsefloat(FILE * fp,wchar_t * buf,wchar_t * end,locale_t locale)7910d5acd74SJohn Marino parsefloat(FILE *fp, wchar_t *buf, wchar_t *end, locale_t locale)
79262f08720SJoerg Sonnenberger {
793e0f95098SPeter Avalos 	mbstate_t mbs;
794e0f95098SPeter Avalos 	size_t nconv;
79562f08720SJoerg Sonnenberger 	wchar_t *commit, *p;
79662f08720SJoerg Sonnenberger 	int infnanpos = 0;
79762f08720SJoerg Sonnenberger 	enum {
798e0f95098SPeter Avalos 		S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX,
79962f08720SJoerg Sonnenberger 		S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
80062f08720SJoerg Sonnenberger 	} state = S_START;
80162f08720SJoerg Sonnenberger 	wchar_t c;
802e0f95098SPeter Avalos 	wchar_t decpt;
803e0f95098SPeter Avalos 	_Bool gotmantdig = 0, ishex = 0;
804e0f95098SPeter Avalos 
805e0f95098SPeter Avalos 	mbs = initial_mbs;
806e0f95098SPeter Avalos 	nconv = mbrtowc(&decpt, localeconv()->decimal_point, MB_CUR_MAX, &mbs);
807e0f95098SPeter Avalos 	if (nconv == (size_t)-1 || nconv == (size_t)-2)
808e0f95098SPeter Avalos 		decpt = '.';	/* failsafe */
80962f08720SJoerg Sonnenberger 
81062f08720SJoerg Sonnenberger 	/*
81162f08720SJoerg Sonnenberger 	 * We set commit = p whenever the string we have read so far
81262f08720SJoerg Sonnenberger 	 * constitutes a valid representation of a floating point
81362f08720SJoerg Sonnenberger 	 * number by itself.  At some point, the parse will complete
81462f08720SJoerg Sonnenberger 	 * or fail, and we will ungetc() back to the last commit point.
81562f08720SJoerg Sonnenberger 	 * To ensure that the file offset gets updated properly, it is
81662f08720SJoerg Sonnenberger 	 * always necessary to read at least one character that doesn't
81762f08720SJoerg Sonnenberger 	 * match; thus, we can't short-circuit "infinity" or "nan(...)".
81862f08720SJoerg Sonnenberger 	 */
81962f08720SJoerg Sonnenberger 	commit = buf - 1;
82062f08720SJoerg Sonnenberger 	c = WEOF;
82162f08720SJoerg Sonnenberger 	for (p = buf; p < end; ) {
8220d5acd74SJohn Marino 		if ((c = __fgetwc(fp, locale)) == WEOF)
82362f08720SJoerg Sonnenberger 			break;
82462f08720SJoerg Sonnenberger reswitch:
82562f08720SJoerg Sonnenberger 		switch (state) {
82662f08720SJoerg Sonnenberger 		case S_START:
82762f08720SJoerg Sonnenberger 			state = S_GOTSIGN;
82862f08720SJoerg Sonnenberger 			if (c == '-' || c == '+')
82962f08720SJoerg Sonnenberger 				break;
83062f08720SJoerg Sonnenberger 			else
83162f08720SJoerg Sonnenberger 				goto reswitch;
83262f08720SJoerg Sonnenberger 		case S_GOTSIGN:
83362f08720SJoerg Sonnenberger 			switch (c) {
83462f08720SJoerg Sonnenberger 			case '0':
83562f08720SJoerg Sonnenberger 				state = S_MAYBEHEX;
83662f08720SJoerg Sonnenberger 				commit = p;
83762f08720SJoerg Sonnenberger 				break;
83862f08720SJoerg Sonnenberger 			case 'I':
83962f08720SJoerg Sonnenberger 			case 'i':
84062f08720SJoerg Sonnenberger 				state = S_INF;
84162f08720SJoerg Sonnenberger 				break;
84262f08720SJoerg Sonnenberger 			case 'N':
84362f08720SJoerg Sonnenberger 			case 'n':
84462f08720SJoerg Sonnenberger 				state = S_NAN;
84562f08720SJoerg Sonnenberger 				break;
84662f08720SJoerg Sonnenberger 			default:
84762f08720SJoerg Sonnenberger 				state = S_DIGITS;
84862f08720SJoerg Sonnenberger 				goto reswitch;
84962f08720SJoerg Sonnenberger 			}
85062f08720SJoerg Sonnenberger 			break;
85162f08720SJoerg Sonnenberger 		case S_INF:
85262f08720SJoerg Sonnenberger 			if (infnanpos > 6 ||
85362f08720SJoerg Sonnenberger 			    (c != "nfinity"[infnanpos] &&
85462f08720SJoerg Sonnenberger 			     c != "NFINITY"[infnanpos]))
85562f08720SJoerg Sonnenberger 				goto parsedone;
85662f08720SJoerg Sonnenberger 			if (infnanpos == 1 || infnanpos == 6)
85762f08720SJoerg Sonnenberger 				commit = p;	/* inf or infinity */
85862f08720SJoerg Sonnenberger 			infnanpos++;
85962f08720SJoerg Sonnenberger 			break;
86062f08720SJoerg Sonnenberger 		case S_NAN:
86162f08720SJoerg Sonnenberger 			switch (infnanpos) {
86262f08720SJoerg Sonnenberger 			case 0:
86362f08720SJoerg Sonnenberger 				if (c != 'A' && c != 'a')
86462f08720SJoerg Sonnenberger 					goto parsedone;
86562f08720SJoerg Sonnenberger 				break;
86662f08720SJoerg Sonnenberger 			case 1:
86762f08720SJoerg Sonnenberger 				if (c != 'N' && c != 'n')
86862f08720SJoerg Sonnenberger 					goto parsedone;
86962f08720SJoerg Sonnenberger 				else
87062f08720SJoerg Sonnenberger 					commit = p;
87162f08720SJoerg Sonnenberger 				break;
87262f08720SJoerg Sonnenberger 			case 2:
87362f08720SJoerg Sonnenberger 				if (c != '(')
87462f08720SJoerg Sonnenberger 					goto parsedone;
87562f08720SJoerg Sonnenberger 				break;
87662f08720SJoerg Sonnenberger 			default:
87762f08720SJoerg Sonnenberger 				if (c == ')') {
87862f08720SJoerg Sonnenberger 					commit = p;
879e0f95098SPeter Avalos 					state = S_DONE;
88062f08720SJoerg Sonnenberger 				} else if (!iswalnum(c) && c != '_')
88162f08720SJoerg Sonnenberger 					goto parsedone;
88262f08720SJoerg Sonnenberger 				break;
88362f08720SJoerg Sonnenberger 			}
88462f08720SJoerg Sonnenberger 			infnanpos++;
88562f08720SJoerg Sonnenberger 			break;
886e0f95098SPeter Avalos 		case S_DONE:
887e0f95098SPeter Avalos 			goto parsedone;
88862f08720SJoerg Sonnenberger 		case S_MAYBEHEX:
88962f08720SJoerg Sonnenberger 			state = S_DIGITS;
89062f08720SJoerg Sonnenberger 			if (c == 'X' || c == 'x') {
89162f08720SJoerg Sonnenberger 				ishex = 1;
89262f08720SJoerg Sonnenberger 				break;
89362f08720SJoerg Sonnenberger 			} else {	/* we saw a '0', but no 'x' */
89462f08720SJoerg Sonnenberger 				gotmantdig = 1;
89562f08720SJoerg Sonnenberger 				goto reswitch;
89662f08720SJoerg Sonnenberger 			}
89762f08720SJoerg Sonnenberger 		case S_DIGITS:
89862f08720SJoerg Sonnenberger 			if ((ishex && iswxdigit(c)) || iswdigit(c))
89962f08720SJoerg Sonnenberger 				gotmantdig = 1;
90062f08720SJoerg Sonnenberger 			else {
90162f08720SJoerg Sonnenberger 				state = S_FRAC;
90262f08720SJoerg Sonnenberger 				if (c != decpt)
90362f08720SJoerg Sonnenberger 					goto reswitch;
90462f08720SJoerg Sonnenberger 			}
90562f08720SJoerg Sonnenberger 			if (gotmantdig)
90662f08720SJoerg Sonnenberger 				commit = p;
90762f08720SJoerg Sonnenberger 			break;
90862f08720SJoerg Sonnenberger 		case S_FRAC:
90962f08720SJoerg Sonnenberger 			if (((c == 'E' || c == 'e') && !ishex) ||
91062f08720SJoerg Sonnenberger 			    ((c == 'P' || c == 'p') && ishex)) {
91162f08720SJoerg Sonnenberger 				if (!gotmantdig)
91262f08720SJoerg Sonnenberger 					goto parsedone;
91362f08720SJoerg Sonnenberger 				else
91462f08720SJoerg Sonnenberger 					state = S_EXP;
91562f08720SJoerg Sonnenberger 			} else if ((ishex && iswxdigit(c)) || iswdigit(c)) {
91662f08720SJoerg Sonnenberger 				commit = p;
91762f08720SJoerg Sonnenberger 				gotmantdig = 1;
91862f08720SJoerg Sonnenberger 			} else
91962f08720SJoerg Sonnenberger 				goto parsedone;
92062f08720SJoerg Sonnenberger 			break;
92162f08720SJoerg Sonnenberger 		case S_EXP:
92262f08720SJoerg Sonnenberger 			state = S_EXPDIGITS;
92362f08720SJoerg Sonnenberger 			if (c == '-' || c == '+')
92462f08720SJoerg Sonnenberger 				break;
92562f08720SJoerg Sonnenberger 			else
92662f08720SJoerg Sonnenberger 				goto reswitch;
92762f08720SJoerg Sonnenberger 		case S_EXPDIGITS:
92862f08720SJoerg Sonnenberger 			if (iswdigit(c))
92962f08720SJoerg Sonnenberger 				commit = p;
93062f08720SJoerg Sonnenberger 			else
93162f08720SJoerg Sonnenberger 				goto parsedone;
93262f08720SJoerg Sonnenberger 			break;
93362f08720SJoerg Sonnenberger 		default:
93462f08720SJoerg Sonnenberger 			abort();
93562f08720SJoerg Sonnenberger 		}
93662f08720SJoerg Sonnenberger 		*p++ = c;
93762f08720SJoerg Sonnenberger 		c = WEOF;
93862f08720SJoerg Sonnenberger 	}
93962f08720SJoerg Sonnenberger 
94062f08720SJoerg Sonnenberger parsedone:
94162f08720SJoerg Sonnenberger 	if (c != WEOF)
9420d5acd74SJohn Marino 		__ungetwc(c, fp, locale);
94362f08720SJoerg Sonnenberger 	while (commit < --p)
9440d5acd74SJohn Marino 		__ungetwc(*p, fp, locale);
94562f08720SJoerg Sonnenberger 	*++commit = '\0';
94662f08720SJoerg Sonnenberger 	return (commit - buf);
94762f08720SJoerg Sonnenberger }
94862f08720SJoerg Sonnenberger #endif
949