xref: /freebsd/lib/libc/stdio/vfscanf.c (revision dc36d6f9bb1753f3808552f3afd30eda9a7b206a)
158f0484fSRodney W. Grimes /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
458f0484fSRodney W. Grimes  * Copyright (c) 1990, 1993
558f0484fSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
658f0484fSRodney W. Grimes  *
73c87aa1dSDavid Chisnall  * Copyright (c) 2011 The FreeBSD Foundation
85b5fa75aSEd Maste  *
9d9dc1603SDag-Erling Smørgrav  * Copyright (c) 2023 Dag-Erling Smørgrav
10d9dc1603SDag-Erling Smørgrav  *
113c87aa1dSDavid Chisnall  * Portions of this software were developed by David Chisnall
123c87aa1dSDavid Chisnall  * under sponsorship from the FreeBSD Foundation.
133c87aa1dSDavid Chisnall  *
1458f0484fSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
1558f0484fSRodney W. Grimes  * Chris Torek.
1658f0484fSRodney W. Grimes  *
1758f0484fSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
1858f0484fSRodney W. Grimes  * modification, are permitted provided that the following conditions
1958f0484fSRodney W. Grimes  * are met:
2058f0484fSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
2158f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
2258f0484fSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
2358f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
2458f0484fSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
251d8053c5SEd Maste  * 3. Neither the name of the University nor the names of its contributors
2658f0484fSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
2758f0484fSRodney W. Grimes  *    without specific prior written permission.
2858f0484fSRodney W. Grimes  *
2958f0484fSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3058f0484fSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3158f0484fSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3258f0484fSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3358f0484fSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3458f0484fSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3558f0484fSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3658f0484fSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3758f0484fSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3858f0484fSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3958f0484fSRodney W. Grimes  * SUCH DAMAGE.
4058f0484fSRodney W. Grimes  */
4158f0484fSRodney W. Grimes 
42d201fe46SDaniel Eischen #include "namespace.h"
43946b2d00SBill Fenner #include <ctype.h>
44946b2d00SBill Fenner #include <inttypes.h>
4558f0484fSRodney W. Grimes #include <stdio.h>
4658f0484fSRodney W. Grimes #include <stdlib.h>
47946b2d00SBill Fenner #include <stddef.h>
4858f0484fSRodney W. Grimes #include <stdarg.h>
49ea295661SAndrey A. Chernov #include <string.h>
504712aa3bSTim J. Robbins #include <wchar.h>
514712aa3bSTim J. Robbins #include <wctype.h>
52d201fe46SDaniel Eischen #include "un-namespace.h"
53ea295661SAndrey A. Chernov 
541daad8f5SAndrey A. Chernov #include "collate.h"
55d201fe46SDaniel Eischen #include "libc_private.h"
5658f0484fSRodney W. Grimes #include "local.h"
573c87aa1dSDavid Chisnall #include "xlocale_private.h"
5858f0484fSRodney W. Grimes 
598de9e897SDavid Schultz #ifndef NO_FLOATING_POINT
60a2a135c9SAndrey A. Chernov #include <locale.h>
61a2a135c9SAndrey A. Chernov #endif
62a2a135c9SAndrey A. Chernov 
6358f0484fSRodney W. Grimes #define	BUF		513	/* Maximum length of numeric string. */
6458f0484fSRodney W. Grimes 
6558f0484fSRodney W. Grimes /*
6658f0484fSRodney W. Grimes  * Flags used during conversion.
6758f0484fSRodney W. Grimes  */
6858f0484fSRodney W. Grimes #define	LONG		0x01	/* l: long or double */
698fddd060SBruce Evans #define	LONGDBL		0x02	/* L: long double */
7058f0484fSRodney W. Grimes #define	SHORT		0x04	/* h: short */
71946b2d00SBill Fenner #define	SUPPRESS	0x08	/* *: suppress assignment */
72946b2d00SBill Fenner #define	POINTER		0x10	/* p: void * (as hex) */
73946b2d00SBill Fenner #define	NOSKIP		0x20	/* [ or c: do not skip blanks */
74*bce0bef3SDag-Erling Smørgrav #define FASTINT		0x200	/* wfN: int_fastN_t */
75946b2d00SBill Fenner #define	LONGLONG	0x400	/* ll: long long (+ deprecated q: quad) */
76946b2d00SBill Fenner #define	INTMAXT		0x800	/* j: intmax_t */
77946b2d00SBill Fenner #define	PTRDIFFT	0x1000	/* t: ptrdiff_t */
78946b2d00SBill Fenner #define	SIZET		0x2000	/* z: size_t */
79946b2d00SBill Fenner #define	SHORTSHORT	0x4000	/* hh: char */
80946b2d00SBill Fenner #define	UNSIGNED	0x8000	/* %[oupxX] conversions */
8158f0484fSRodney W. Grimes 
8258f0484fSRodney W. Grimes /*
8358f0484fSRodney W. Grimes  * Conversion types.
8458f0484fSRodney W. Grimes  */
8558f0484fSRodney W. Grimes #define	CT_CHAR		0	/* %c conversion */
8658f0484fSRodney W. Grimes #define	CT_CCL		1	/* %[...] conversion */
8758f0484fSRodney W. Grimes #define	CT_STRING	2	/* %s conversion */
88946b2d00SBill Fenner #define	CT_INT		3	/* %[dioupxX] conversion */
89946b2d00SBill Fenner #define	CT_FLOAT	4	/* %[efgEFG] conversion */
9058f0484fSRodney W. Grimes 
91946b2d00SBill Fenner static const u_char *__sccl(char *, const u_char *);
9275239a01SPoul-Henning Kamp #ifndef NO_FLOATING_POINT
933c87aa1dSDavid Chisnall static int parsefloat(FILE *, char *, char *, locale_t);
9475239a01SPoul-Henning Kamp #endif
95370077c7SDavid Schultz 
96af1c9c0eSTim J. Robbins __weak_reference(__vfscanf, vfscanf);
97af1c9c0eSTim J. Robbins 
9858f0484fSRodney W. Grimes /*
9951300896SDavid Schultz  * Conversion functions are passed a pointer to this object instead of
10051300896SDavid Schultz  * a real parameter to indicate that the assignment-suppression (*)
10151300896SDavid Schultz  * flag was specified.  We could use a NULL pointer to indicate this,
10251300896SDavid Schultz  * but that would mask bugs in applications that call scanf() with a
10351300896SDavid Schultz  * NULL pointer.
10451300896SDavid Schultz  */
10551300896SDavid Schultz static const int suppress;
10651300896SDavid Schultz #define	SUPPRESS_PTR	((void *)&suppress)
10751300896SDavid Schultz 
10851300896SDavid Schultz static const mbstate_t initial_mbs;
10951300896SDavid Schultz 
11051300896SDavid Schultz /*
11151300896SDavid Schultz  * The following conversion functions return the number of characters consumed,
11251300896SDavid Schultz  * or -1 on input failure.  Character class conversion returns 0 on match
11351300896SDavid Schultz  * failure.
11451300896SDavid Schultz  */
11551300896SDavid Schultz 
11651300896SDavid Schultz static __inline int
convert_char(FILE * fp,char * p,int width)117671c0336SJean-Sébastien Pédron convert_char(FILE *fp, char * p, int width)
11851300896SDavid Schultz {
119d7af8cf1SDavid Schultz 	int n;
12051300896SDavid Schultz 
12151300896SDavid Schultz 	if (p == SUPPRESS_PTR) {
12251300896SDavid Schultz 		size_t sum = 0;
12351300896SDavid Schultz 		for (;;) {
12451300896SDavid Schultz 			if ((n = fp->_r) < width) {
12551300896SDavid Schultz 				sum += n;
12651300896SDavid Schultz 				width -= n;
12751300896SDavid Schultz 				fp->_p += n;
12851300896SDavid Schultz 				if (__srefill(fp)) {
12951300896SDavid Schultz 					if (sum == 0)
13051300896SDavid Schultz 						return (-1);
13151300896SDavid Schultz 					break;
13251300896SDavid Schultz 				}
13351300896SDavid Schultz 			} else {
13451300896SDavid Schultz 				sum += width;
13551300896SDavid Schultz 				fp->_r -= width;
13651300896SDavid Schultz 				fp->_p += width;
13751300896SDavid Schultz 				break;
13851300896SDavid Schultz 			}
13951300896SDavid Schultz 		}
140d7af8cf1SDavid Schultz 		return (sum);
14151300896SDavid Schultz 	} else {
14251300896SDavid Schultz 		size_t r = __fread(p, 1, width, fp);
14351300896SDavid Schultz 
14451300896SDavid Schultz 		if (r == 0)
14551300896SDavid Schultz 			return (-1);
146d7af8cf1SDavid Schultz 		return (r);
14751300896SDavid Schultz 	}
14851300896SDavid Schultz }
14951300896SDavid Schultz 
15051300896SDavid Schultz static __inline int
convert_wchar(FILE * fp,wchar_t * wcp,int width,locale_t locale)151d7af8cf1SDavid Schultz convert_wchar(FILE *fp, wchar_t *wcp, int width, locale_t locale)
15251300896SDavid Schultz {
15351300896SDavid Schultz 	mbstate_t mbs;
15451300896SDavid Schultz 	int n, nread;
155d7af8cf1SDavid Schultz 	wint_t wi;
15651300896SDavid Schultz 
15751300896SDavid Schultz 	mbs = initial_mbs;
15851300896SDavid Schultz 	n = 0;
159d7af8cf1SDavid Schultz 	while (width-- != 0 &&
160d7af8cf1SDavid Schultz 	    (wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF) {
161d7af8cf1SDavid Schultz 		if (wcp != SUPPRESS_PTR)
162d7af8cf1SDavid Schultz 			*wcp++ = (wchar_t)wi;
163d7af8cf1SDavid Schultz 		n += nread;
16451300896SDavid Schultz 	}
165d7af8cf1SDavid Schultz 	if (n == 0)
16651300896SDavid Schultz 		return (-1);
167d7af8cf1SDavid Schultz 	return (n);
16851300896SDavid Schultz }
16951300896SDavid Schultz 
17051300896SDavid Schultz static __inline int
convert_ccl(FILE * fp,char * p,int width,const char * ccltab)171671c0336SJean-Sébastien Pédron convert_ccl(FILE *fp, char * p, int width, const char *ccltab)
17251300896SDavid Schultz {
17351300896SDavid Schultz 	char *p0;
17451300896SDavid Schultz 	int n;
17551300896SDavid Schultz 
17651300896SDavid Schultz 	if (p == SUPPRESS_PTR) {
17751300896SDavid Schultz 		n = 0;
17851300896SDavid Schultz 		while (ccltab[*fp->_p]) {
17951300896SDavid Schultz 			n++, fp->_r--, fp->_p++;
18051300896SDavid Schultz 			if (--width == 0)
18151300896SDavid Schultz 				break;
18251300896SDavid Schultz 			if (fp->_r <= 0 && __srefill(fp)) {
18351300896SDavid Schultz 				if (n == 0)
18451300896SDavid Schultz 					return (-1);
18551300896SDavid Schultz 				break;
18651300896SDavid Schultz 			}
18751300896SDavid Schultz 		}
18851300896SDavid Schultz 	} else {
18951300896SDavid Schultz 		p0 = p;
19051300896SDavid Schultz 		while (ccltab[*fp->_p]) {
19151300896SDavid Schultz 			fp->_r--;
19251300896SDavid Schultz 			*p++ = *fp->_p++;
19351300896SDavid Schultz 			if (--width == 0)
19451300896SDavid Schultz 				break;
19551300896SDavid Schultz 			if (fp->_r <= 0 && __srefill(fp)) {
19651300896SDavid Schultz 				if (p == p0)
19751300896SDavid Schultz 					return (-1);
19851300896SDavid Schultz 				break;
19951300896SDavid Schultz 			}
20051300896SDavid Schultz 		}
20151300896SDavid Schultz 		n = p - p0;
20251300896SDavid Schultz 		if (n == 0)
20351300896SDavid Schultz 			return (0);
20451300896SDavid Schultz 		*p = 0;
20551300896SDavid Schultz 	}
20651300896SDavid Schultz 	return (n);
20751300896SDavid Schultz }
20851300896SDavid Schultz 
20951300896SDavid Schultz static __inline int
convert_wccl(FILE * fp,wchar_t * wcp,int width,const char * ccltab,locale_t locale)210d7af8cf1SDavid Schultz convert_wccl(FILE *fp, wchar_t *wcp, int width, const char *ccltab,
211d7af8cf1SDavid Schultz     locale_t locale)
21251300896SDavid Schultz {
21351300896SDavid Schultz 	mbstate_t mbs;
214d7af8cf1SDavid Schultz 	wint_t wi;
215d7af8cf1SDavid Schultz 	int n, nread;
21651300896SDavid Schultz 
21751300896SDavid Schultz 	mbs = initial_mbs;
21851300896SDavid Schultz 	n = 0;
219d7af8cf1SDavid Schultz 	if (wcp == SUPPRESS_PTR) {
220d7af8cf1SDavid Schultz 		while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
221d7af8cf1SDavid Schultz 		    width-- != 0 && ccltab[wctob(wi)])
222d7af8cf1SDavid Schultz 			n += nread;
223d7af8cf1SDavid Schultz 		if (wi != WEOF)
224d7af8cf1SDavid Schultz 			__ungetwc(wi, fp, __get_locale());
225d7af8cf1SDavid Schultz 	} else {
226d7af8cf1SDavid Schultz 		while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
227d7af8cf1SDavid Schultz 		    width-- != 0 && ccltab[wctob(wi)]) {
228d7af8cf1SDavid Schultz 			*wcp++ = (wchar_t)wi;
229d7af8cf1SDavid Schultz 			n += nread;
23051300896SDavid Schultz 		}
231d7af8cf1SDavid Schultz 		if (wi != WEOF)
232d7af8cf1SDavid Schultz 			__ungetwc(wi, fp, __get_locale());
233d7af8cf1SDavid Schultz 		if (n == 0)
23451300896SDavid Schultz 			return (0);
235d7af8cf1SDavid Schultz 		*wcp = 0;
236d7af8cf1SDavid Schultz 	}
237d7af8cf1SDavid Schultz 	return (n);
23851300896SDavid Schultz }
23951300896SDavid Schultz 
24051300896SDavid Schultz static __inline int
convert_string(FILE * fp,char * p,int width)241671c0336SJean-Sébastien Pédron convert_string(FILE *fp, char * p, int width)
24251300896SDavid Schultz {
24351300896SDavid Schultz 	char *p0;
24451300896SDavid Schultz 	int n;
24551300896SDavid Schultz 
24651300896SDavid Schultz 	if (p == SUPPRESS_PTR) {
24751300896SDavid Schultz 		n = 0;
24851300896SDavid Schultz 		while (!isspace(*fp->_p)) {
24951300896SDavid Schultz 			n++, fp->_r--, fp->_p++;
25051300896SDavid Schultz 			if (--width == 0)
25151300896SDavid Schultz 				break;
25251300896SDavid Schultz 			if (fp->_r <= 0 && __srefill(fp))
25351300896SDavid Schultz 				break;
25451300896SDavid Schultz 		}
25551300896SDavid Schultz 	} else {
25651300896SDavid Schultz 		p0 = p;
25751300896SDavid Schultz 		while (!isspace(*fp->_p)) {
25851300896SDavid Schultz 			fp->_r--;
25951300896SDavid Schultz 			*p++ = *fp->_p++;
26051300896SDavid Schultz 			if (--width == 0)
26151300896SDavid Schultz 				break;
26251300896SDavid Schultz 			if (fp->_r <= 0 && __srefill(fp))
26351300896SDavid Schultz 				break;
26451300896SDavid Schultz 		}
26551300896SDavid Schultz 		*p = 0;
26651300896SDavid Schultz 		n = p - p0;
26751300896SDavid Schultz 	}
26851300896SDavid Schultz 	return (n);
26951300896SDavid Schultz }
27051300896SDavid Schultz 
27151300896SDavid Schultz static __inline int
convert_wstring(FILE * fp,wchar_t * wcp,int width,locale_t locale)272d7af8cf1SDavid Schultz convert_wstring(FILE *fp, wchar_t *wcp, int width, locale_t locale)
27351300896SDavid Schultz {
27451300896SDavid Schultz 	mbstate_t mbs;
275d7af8cf1SDavid Schultz 	wint_t wi;
276d7af8cf1SDavid Schultz 	int n, nread;
27751300896SDavid Schultz 
27851300896SDavid Schultz 	mbs = initial_mbs;
27951300896SDavid Schultz 	n = 0;
280d7af8cf1SDavid Schultz 	if (wcp == SUPPRESS_PTR) {
281d7af8cf1SDavid Schultz 		while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
282d7af8cf1SDavid Schultz 		    width-- != 0 && !iswspace(wi))
283d7af8cf1SDavid Schultz 			n += nread;
284d7af8cf1SDavid Schultz 		if (wi != WEOF)
285d7af8cf1SDavid Schultz 			__ungetwc(wi, fp, __get_locale());
286d7af8cf1SDavid Schultz 	} else {
287d7af8cf1SDavid Schultz 		while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
288d7af8cf1SDavid Schultz 		    width-- != 0 && !iswspace(wi)) {
289d7af8cf1SDavid Schultz 			*wcp++ = (wchar_t)wi;
290d7af8cf1SDavid Schultz 			n += nread;
29151300896SDavid Schultz 		}
292d7af8cf1SDavid Schultz 		if (wi != WEOF)
293d7af8cf1SDavid Schultz 			__ungetwc(wi, fp, __get_locale());
294d7af8cf1SDavid Schultz 		*wcp = '\0';
29551300896SDavid Schultz 	}
296d7af8cf1SDavid Schultz 	return (n);
29751300896SDavid Schultz }
29851300896SDavid Schultz 
299d9dc1603SDag-Erling Smørgrav enum parseint_state {
300d9dc1603SDag-Erling Smørgrav 	begin,
301d9dc1603SDag-Erling Smørgrav 	havesign,
302d9dc1603SDag-Erling Smørgrav 	havezero,
303d9dc1603SDag-Erling Smørgrav 	haveprefix,
304d9dc1603SDag-Erling Smørgrav 	any,
305d9dc1603SDag-Erling Smørgrav };
306d9dc1603SDag-Erling Smørgrav 
307d9dc1603SDag-Erling Smørgrav static __inline int
parseint_fsm(int c,enum parseint_state * state,int * base)308d9dc1603SDag-Erling Smørgrav parseint_fsm(int c, enum parseint_state *state, int *base)
309d9dc1603SDag-Erling Smørgrav {
310d9dc1603SDag-Erling Smørgrav 	switch (c) {
311d9dc1603SDag-Erling Smørgrav 	case '+':
312d9dc1603SDag-Erling Smørgrav 	case '-':
313d9dc1603SDag-Erling Smørgrav 		if (*state == begin) {
314d9dc1603SDag-Erling Smørgrav 			*state = havesign;
315d9dc1603SDag-Erling Smørgrav 			return 1;
316d9dc1603SDag-Erling Smørgrav 		}
317d9dc1603SDag-Erling Smørgrav 		break;
318d9dc1603SDag-Erling Smørgrav 	case '0':
319d9dc1603SDag-Erling Smørgrav 		if (*state == begin || *state == havesign) {
320d9dc1603SDag-Erling Smørgrav 			*state = havezero;
321d9dc1603SDag-Erling Smørgrav 		} else {
322d9dc1603SDag-Erling Smørgrav 			*state = any;
323d9dc1603SDag-Erling Smørgrav 		}
324d9dc1603SDag-Erling Smørgrav 		return 1;
325d9dc1603SDag-Erling Smørgrav 	case '1':
326d9dc1603SDag-Erling Smørgrav 	case '2':
327d9dc1603SDag-Erling Smørgrav 	case '3':
328d9dc1603SDag-Erling Smørgrav 	case '4':
329d9dc1603SDag-Erling Smørgrav 	case '5':
330d9dc1603SDag-Erling Smørgrav 	case '6':
331d9dc1603SDag-Erling Smørgrav 	case '7':
332d9dc1603SDag-Erling Smørgrav 		if (*state == havezero && *base == 0) {
333d9dc1603SDag-Erling Smørgrav 			*base = 8;
334d9dc1603SDag-Erling Smørgrav 		}
335d9dc1603SDag-Erling Smørgrav 		/* FALL THROUGH */
336d9dc1603SDag-Erling Smørgrav 	case '8':
337d9dc1603SDag-Erling Smørgrav 	case '9':
338d9dc1603SDag-Erling Smørgrav 		if (*state == begin ||
339d9dc1603SDag-Erling Smørgrav 		    *state == havesign) {
340d9dc1603SDag-Erling Smørgrav 			if (*base == 0) {
341d9dc1603SDag-Erling Smørgrav 				*base = 10;
342d9dc1603SDag-Erling Smørgrav 			}
343d9dc1603SDag-Erling Smørgrav 		}
344d9dc1603SDag-Erling Smørgrav 		if (*state == begin ||
345d9dc1603SDag-Erling Smørgrav 		    *state == havesign ||
346d9dc1603SDag-Erling Smørgrav 		    *state == havezero ||
347d9dc1603SDag-Erling Smørgrav 		    *state == haveprefix ||
348d9dc1603SDag-Erling Smørgrav 		    *state == any) {
349d9dc1603SDag-Erling Smørgrav 			if (*base > c - '0') {
350d9dc1603SDag-Erling Smørgrav 				*state = any;
351d9dc1603SDag-Erling Smørgrav 				return 1;
352d9dc1603SDag-Erling Smørgrav 			}
353d9dc1603SDag-Erling Smørgrav 		}
354d9dc1603SDag-Erling Smørgrav 		break;
355d9dc1603SDag-Erling Smørgrav 	case 'b':
356d9dc1603SDag-Erling Smørgrav 		if (*state == havezero) {
357d9dc1603SDag-Erling Smørgrav 			if (*base == 0 || *base == 2) {
358d9dc1603SDag-Erling Smørgrav 				*state = haveprefix;
359d9dc1603SDag-Erling Smørgrav 				*base = 2;
360d9dc1603SDag-Erling Smørgrav 				return 1;
361d9dc1603SDag-Erling Smørgrav 			}
362d9dc1603SDag-Erling Smørgrav 		}
363d9dc1603SDag-Erling Smørgrav 		/* FALL THROUGH */
364d9dc1603SDag-Erling Smørgrav 	case 'a':
365d9dc1603SDag-Erling Smørgrav 	case 'c':
366d9dc1603SDag-Erling Smørgrav 	case 'd':
367d9dc1603SDag-Erling Smørgrav 	case 'e':
368d9dc1603SDag-Erling Smørgrav 	case 'f':
369d9dc1603SDag-Erling Smørgrav 		if (*state == begin ||
370d9dc1603SDag-Erling Smørgrav 		    *state == havesign ||
371d9dc1603SDag-Erling Smørgrav 		    *state == havezero ||
372d9dc1603SDag-Erling Smørgrav 		    *state == haveprefix ||
373d9dc1603SDag-Erling Smørgrav 		    *state == any) {
374d9dc1603SDag-Erling Smørgrav 			if (*base > c - 'a' + 10) {
375d9dc1603SDag-Erling Smørgrav 				*state = any;
376d9dc1603SDag-Erling Smørgrav 				return 1;
377d9dc1603SDag-Erling Smørgrav 			}
378d9dc1603SDag-Erling Smørgrav 		}
379d9dc1603SDag-Erling Smørgrav 		break;
380d9dc1603SDag-Erling Smørgrav 	case 'B':
381d9dc1603SDag-Erling Smørgrav 		if (*state == havezero) {
382d9dc1603SDag-Erling Smørgrav 			if (*base == 0 || *base == 2) {
383d9dc1603SDag-Erling Smørgrav 				*state = haveprefix;
384d9dc1603SDag-Erling Smørgrav 				*base = 2;
385d9dc1603SDag-Erling Smørgrav 				return 1;
386d9dc1603SDag-Erling Smørgrav 			}
387d9dc1603SDag-Erling Smørgrav 		}
388d9dc1603SDag-Erling Smørgrav 		/* FALL THROUGH */
389d9dc1603SDag-Erling Smørgrav 	case 'A':
390d9dc1603SDag-Erling Smørgrav 	case 'C':
391d9dc1603SDag-Erling Smørgrav 	case 'D':
392d9dc1603SDag-Erling Smørgrav 	case 'E':
393d9dc1603SDag-Erling Smørgrav 	case 'F':
394d9dc1603SDag-Erling Smørgrav 		if (*state == begin ||
395d9dc1603SDag-Erling Smørgrav 		    *state == havesign ||
396d9dc1603SDag-Erling Smørgrav 		    *state == havezero ||
397d9dc1603SDag-Erling Smørgrav 		    *state == haveprefix ||
398d9dc1603SDag-Erling Smørgrav 		    *state == any) {
399d9dc1603SDag-Erling Smørgrav 			if (*base > c - 'A' + 10) {
400d9dc1603SDag-Erling Smørgrav 				*state = any;
401d9dc1603SDag-Erling Smørgrav 				return 1;
402d9dc1603SDag-Erling Smørgrav 			}
403d9dc1603SDag-Erling Smørgrav 		}
404d9dc1603SDag-Erling Smørgrav 		break;
405d9dc1603SDag-Erling Smørgrav 	case 'x':
406d9dc1603SDag-Erling Smørgrav 	case 'X':
407d9dc1603SDag-Erling Smørgrav 		if (*state == havezero) {
408d9dc1603SDag-Erling Smørgrav 			if (*base == 0 || *base == 16) {
409d9dc1603SDag-Erling Smørgrav 				*state = haveprefix;
410d9dc1603SDag-Erling Smørgrav 				*base = 16;
411d9dc1603SDag-Erling Smørgrav 				return 1;
412d9dc1603SDag-Erling Smørgrav 			}
413d9dc1603SDag-Erling Smørgrav 		}
414d9dc1603SDag-Erling Smørgrav 		break;
415d9dc1603SDag-Erling Smørgrav 	}
416d9dc1603SDag-Erling Smørgrav 	return 0;
417d9dc1603SDag-Erling Smørgrav }
418d9dc1603SDag-Erling Smørgrav 
41951300896SDavid Schultz /*
420d9dc1603SDag-Erling Smørgrav  * Read an integer, storing it in buf.
42151300896SDavid Schultz  *
42251300896SDavid Schultz  * Return 0 on a match failure, and the number of characters read
42351300896SDavid Schultz  * otherwise.
42451300896SDavid Schultz  */
42551300896SDavid Schultz static __inline int
parseint(FILE * fp,char * __restrict buf,int width,int base)426d9dc1603SDag-Erling Smørgrav parseint(FILE *fp, char * __restrict buf, int width, int base)
42751300896SDavid Schultz {
428d9dc1603SDag-Erling Smørgrav 	enum parseint_state state = begin;
42951300896SDavid Schultz 	char *p;
43051300896SDavid Schultz 	int c;
43151300896SDavid Schultz 
43251300896SDavid Schultz 	for (p = buf; width; width--) {
433d9dc1603SDag-Erling Smørgrav 		c = __sgetc(fp);
434d9dc1603SDag-Erling Smørgrav 		if (c == EOF)
43551300896SDavid Schultz 			break;
436d9dc1603SDag-Erling Smørgrav 		if (!parseint_fsm(c, &state, &base))
43751300896SDavid Schultz 			break;
43851300896SDavid Schultz 		*p++ = c;
43951300896SDavid Schultz 	}
44051300896SDavid Schultz 	/*
441d9dc1603SDag-Erling Smørgrav 	 * If we only had a sign, push it back.  If we only had a 0b or 0x
442d9dc1603SDag-Erling Smørgrav 	 * prefix (possibly preceded by a sign), we view it as "0" and
443d9dc1603SDag-Erling Smørgrav 	 * push back the letter.  In all other cases, if we stopped
444d9dc1603SDag-Erling Smørgrav 	 * because we read a non-number character, push it back.
44551300896SDavid Schultz 	 */
446d9dc1603SDag-Erling Smørgrav 	if (state == havesign) {
447d9dc1603SDag-Erling Smørgrav 		p--;
448d9dc1603SDag-Erling Smørgrav 		(void) __ungetc(*(u_char *)p, fp);
449d9dc1603SDag-Erling Smørgrav 	} else if (state == haveprefix) {
450d9dc1603SDag-Erling Smørgrav 		p--;
451d9dc1603SDag-Erling Smørgrav 		(void) __ungetc(c, fp);
452aca3bd16SDag-Erling Smørgrav 	} else if (width && c != EOF) {
45351300896SDavid Schultz 		(void) __ungetc(c, fp);
45451300896SDavid Schultz 	}
45551300896SDavid Schultz 	return (p - buf);
45651300896SDavid Schultz }
45751300896SDavid Schultz 
45851300896SDavid Schultz /*
459d201fe46SDaniel Eischen  * __vfscanf - MT-safe version
46058f0484fSRodney W. Grimes  */
461ce51cf03SJames Raynard int
__vfscanf(FILE * fp,char const * fmt0,va_list ap)462d201fe46SDaniel Eischen __vfscanf(FILE *fp, char const *fmt0, va_list ap)
46358f0484fSRodney W. Grimes {
464d201fe46SDaniel Eischen 	int ret;
465d201fe46SDaniel Eischen 
466fda0a14fSKonstantin Belousov 	FLOCKFILE_CANCELSAFE(fp);
4673c87aa1dSDavid Chisnall 	ret = __svfscanf(fp, __get_locale(), fmt0, ap);
468fda0a14fSKonstantin Belousov 	FUNLOCKFILE_CANCELSAFE();
4693c87aa1dSDavid Chisnall 	return (ret);
4703c87aa1dSDavid Chisnall }
4713c87aa1dSDavid Chisnall int
vfscanf_l(FILE * fp,locale_t locale,char const * fmt0,va_list ap)4723c87aa1dSDavid Chisnall vfscanf_l(FILE *fp, locale_t locale, char const *fmt0, va_list ap)
4733c87aa1dSDavid Chisnall {
4743c87aa1dSDavid Chisnall 	int ret;
4753c87aa1dSDavid Chisnall 	FIX_LOCALE(locale);
4763c87aa1dSDavid Chisnall 
477fda0a14fSKonstantin Belousov 	FLOCKFILE_CANCELSAFE(fp);
4783c87aa1dSDavid Chisnall 	ret = __svfscanf(fp, locale, fmt0, ap);
479fda0a14fSKonstantin Belousov 	FUNLOCKFILE_CANCELSAFE();
480d201fe46SDaniel Eischen 	return (ret);
481d201fe46SDaniel Eischen }
482d201fe46SDaniel Eischen 
483d201fe46SDaniel Eischen /*
484d201fe46SDaniel Eischen  * __svfscanf - non-MT-safe version of __vfscanf
485d201fe46SDaniel Eischen  */
486d201fe46SDaniel Eischen int
__svfscanf(FILE * fp,locale_t locale,const char * fmt0,va_list ap)4873c87aa1dSDavid Chisnall __svfscanf(FILE *fp, locale_t locale, const char *fmt0, va_list ap)
488d201fe46SDaniel Eischen {
48951300896SDavid Schultz #define	GETARG(type)	((flags & SUPPRESS) ? SUPPRESS_PTR : va_arg(ap, type))
490946b2d00SBill Fenner 	const u_char *fmt = (const u_char *)fmt0;
491d201fe46SDaniel Eischen 	int c;			/* character from format, or conversion */
492d201fe46SDaniel Eischen 	size_t width;		/* field width, or 0 */
493d201fe46SDaniel Eischen 	int flags;		/* flags as defined above */
49458f0484fSRodney W. Grimes 	int nassigned;		/* number of fields assigned */
495e836e480SBruce Evans 	int nconversions;	/* number of conversions */
49651300896SDavid Schultz 	int nr;			/* characters read by the current conversion */
49758f0484fSRodney W. Grimes 	int nread;		/* number of characters consumed from fp */
498946b2d00SBill Fenner 	int base;		/* base argument to conversion function */
49958f0484fSRodney W. Grimes 	char ccltab[256];	/* character class table for %[...] */
50051300896SDavid Schultz 	char buf[BUF];		/* buffer for numeric conversions */
50158f0484fSRodney W. Grimes 
502e74101e4STim J. Robbins 	ORIENT(fp, -1);
503e74101e4STim J. Robbins 
50458f0484fSRodney W. Grimes 	nassigned = 0;
505e836e480SBruce Evans 	nconversions = 0;
50658f0484fSRodney W. Grimes 	nread = 0;
50758f0484fSRodney W. Grimes 	for (;;) {
50858f0484fSRodney W. Grimes 		c = *fmt++;
50958f0484fSRodney W. Grimes 		if (c == 0)
51058f0484fSRodney W. Grimes 			return (nassigned);
51158f0484fSRodney W. Grimes 		if (isspace(c)) {
5125846581cSDavid E. O'Brien 			while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p))
51358f0484fSRodney W. Grimes 				nread++, fp->_r--, fp->_p++;
51458f0484fSRodney W. Grimes 			continue;
51558f0484fSRodney W. Grimes 		}
51658f0484fSRodney W. Grimes 		if (c != '%')
51758f0484fSRodney W. Grimes 			goto literal;
51858f0484fSRodney W. Grimes 		width = 0;
51958f0484fSRodney W. Grimes 		flags = 0;
52058f0484fSRodney W. Grimes 		/*
52158f0484fSRodney W. Grimes 		 * switch on the format.  continue if done;
52258f0484fSRodney W. Grimes 		 * break once format type is derived.
52358f0484fSRodney W. Grimes 		 */
52458f0484fSRodney W. Grimes again:		c = *fmt++;
52558f0484fSRodney W. Grimes 		switch (c) {
52658f0484fSRodney W. Grimes 		case '%':
52758f0484fSRodney W. Grimes literal:
52858f0484fSRodney W. Grimes 			if (fp->_r <= 0 && __srefill(fp))
52958f0484fSRodney W. Grimes 				goto input_failure;
53058f0484fSRodney W. Grimes 			if (*fp->_p != c)
53158f0484fSRodney W. Grimes 				goto match_failure;
53258f0484fSRodney W. Grimes 			fp->_r--, fp->_p++;
53358f0484fSRodney W. Grimes 			nread++;
53458f0484fSRodney W. Grimes 			continue;
53558f0484fSRodney W. Grimes 
53658f0484fSRodney W. Grimes 		case '*':
53758f0484fSRodney W. Grimes 			flags |= SUPPRESS;
53858f0484fSRodney W. Grimes 			goto again;
539946b2d00SBill Fenner 		case 'j':
540946b2d00SBill Fenner 			flags |= INTMAXT;
541946b2d00SBill Fenner 			goto again;
54258f0484fSRodney W. Grimes 		case 'l':
543946b2d00SBill Fenner 			if (flags & LONG) {
544946b2d00SBill Fenner 				flags &= ~LONG;
545946b2d00SBill Fenner 				flags |= LONGLONG;
546946b2d00SBill Fenner 			} else
54758f0484fSRodney W. Grimes 				flags |= LONG;
54858f0484fSRodney W. Grimes 			goto again;
5495e17038fSJordan K. Hubbard 		case 'q':
550946b2d00SBill Fenner 			flags |= LONGLONG;	/* not quite */
551946b2d00SBill Fenner 			goto again;
552946b2d00SBill Fenner 		case 't':
553946b2d00SBill Fenner 			flags |= PTRDIFFT;
554946b2d00SBill Fenner 			goto again;
555*bce0bef3SDag-Erling Smørgrav 		case 'w':
556*bce0bef3SDag-Erling Smørgrav 			/*
557*bce0bef3SDag-Erling Smørgrav 			 * Fixed-width integer types.  On all platforms we
558*bce0bef3SDag-Erling Smørgrav 			 * support, int8_t is equivalent to char, int16_t
559*bce0bef3SDag-Erling Smørgrav 			 * is equivalent to short, int32_t is equivalent
560*bce0bef3SDag-Erling Smørgrav 			 * to int, int64_t is equivalent to long long int.
561*bce0bef3SDag-Erling Smørgrav 			 * Furthermore, int_fast8_t, int_fast16_t and
562*bce0bef3SDag-Erling Smørgrav 			 * int_fast32_t are equivalent to int, and
563*bce0bef3SDag-Erling Smørgrav 			 * int_fast64_t is equivalent to long long int.
564*bce0bef3SDag-Erling Smørgrav 			 */
565*bce0bef3SDag-Erling Smørgrav 			flags &= ~(SHORTSHORT|SHORT|LONG|LONGLONG|SIZET|INTMAXT|PTRDIFFT);
566*bce0bef3SDag-Erling Smørgrav 			if (fmt[0] == 'f') {
567*bce0bef3SDag-Erling Smørgrav 				flags |= FASTINT;
568*bce0bef3SDag-Erling Smørgrav 				fmt++;
569*bce0bef3SDag-Erling Smørgrav 			} else {
570*bce0bef3SDag-Erling Smørgrav 				flags &= ~FASTINT;
571*bce0bef3SDag-Erling Smørgrav 			}
572*bce0bef3SDag-Erling Smørgrav 			if (fmt[0] == '8') {
573*bce0bef3SDag-Erling Smørgrav 				if (!(flags & FASTINT))
574*bce0bef3SDag-Erling Smørgrav 					flags |= SHORTSHORT;
575*bce0bef3SDag-Erling Smørgrav 				else
576*bce0bef3SDag-Erling Smørgrav 					/* no flag set = 32 */ ;
577*bce0bef3SDag-Erling Smørgrav 				fmt += 1;
578*bce0bef3SDag-Erling Smørgrav 			} else if (fmt[0] == '1' && fmt[1] == '6') {
579*bce0bef3SDag-Erling Smørgrav 				if (!(flags & FASTINT))
580*bce0bef3SDag-Erling Smørgrav 					flags |= SHORT;
581*bce0bef3SDag-Erling Smørgrav 				else
582*bce0bef3SDag-Erling Smørgrav 					/* no flag set = 32 */ ;
583*bce0bef3SDag-Erling Smørgrav 				fmt += 2;
584*bce0bef3SDag-Erling Smørgrav 			} else if (fmt[0] == '3' && fmt[1] == '2') {
585*bce0bef3SDag-Erling Smørgrav 				/* no flag set = 32 */ ;
586*bce0bef3SDag-Erling Smørgrav 				fmt += 2;
587*bce0bef3SDag-Erling Smørgrav 			} else if (fmt[0] == '6' && fmt[1] == '4') {
588*bce0bef3SDag-Erling Smørgrav 				flags |= LONGLONG;
589*bce0bef3SDag-Erling Smørgrav 				fmt += 2;
590*bce0bef3SDag-Erling Smørgrav 			} else {
591*bce0bef3SDag-Erling Smørgrav 				goto match_failure;
592*bce0bef3SDag-Erling Smørgrav 			}
593*bce0bef3SDag-Erling Smørgrav 			goto again;
594946b2d00SBill Fenner 		case 'z':
595946b2d00SBill Fenner 			flags |= SIZET;
5965e17038fSJordan K. Hubbard 			goto again;
59758f0484fSRodney W. Grimes 		case 'L':
59858f0484fSRodney W. Grimes 			flags |= LONGDBL;
59958f0484fSRodney W. Grimes 			goto again;
60058f0484fSRodney W. Grimes 		case 'h':
601946b2d00SBill Fenner 			if (flags & SHORT) {
602946b2d00SBill Fenner 				flags &= ~SHORT;
603946b2d00SBill Fenner 				flags |= SHORTSHORT;
604946b2d00SBill Fenner 			} else
60558f0484fSRodney W. Grimes 				flags |= SHORT;
60658f0484fSRodney W. Grimes 			goto again;
60758f0484fSRodney W. Grimes 
60858f0484fSRodney W. Grimes 		case '0': case '1': case '2': case '3': case '4':
60958f0484fSRodney W. Grimes 		case '5': case '6': case '7': case '8': case '9':
61058f0484fSRodney W. Grimes 			width = width * 10 + c - '0';
61158f0484fSRodney W. Grimes 			goto again;
61258f0484fSRodney W. Grimes 
61358f0484fSRodney W. Grimes 		/*
61458f0484fSRodney W. Grimes 		 * Conversions.
61558f0484fSRodney W. Grimes 		 */
616d9dc1603SDag-Erling Smørgrav 		case 'B':
617d9dc1603SDag-Erling Smørgrav 		case 'b':
618d9dc1603SDag-Erling Smørgrav 			c = CT_INT;
619d9dc1603SDag-Erling Smørgrav 			flags |= UNSIGNED;
620d9dc1603SDag-Erling Smørgrav 			base = 2;
621d9dc1603SDag-Erling Smørgrav 			break;
622d9dc1603SDag-Erling Smørgrav 
62358f0484fSRodney W. Grimes 		case 'd':
62458f0484fSRodney W. Grimes 			c = CT_INT;
62558f0484fSRodney W. Grimes 			base = 10;
62658f0484fSRodney W. Grimes 			break;
62758f0484fSRodney W. Grimes 
62858f0484fSRodney W. Grimes 		case 'i':
62958f0484fSRodney W. Grimes 			c = CT_INT;
63058f0484fSRodney W. Grimes 			base = 0;
63158f0484fSRodney W. Grimes 			break;
63258f0484fSRodney W. Grimes 
63358f0484fSRodney W. Grimes 		case 'o':
63458f0484fSRodney W. Grimes 			c = CT_INT;
635946b2d00SBill Fenner 			flags |= UNSIGNED;
63658f0484fSRodney W. Grimes 			base = 8;
63758f0484fSRodney W. Grimes 			break;
63858f0484fSRodney W. Grimes 
63958f0484fSRodney W. Grimes 		case 'u':
64058f0484fSRodney W. Grimes 			c = CT_INT;
641946b2d00SBill Fenner 			flags |= UNSIGNED;
64258f0484fSRodney W. Grimes 			base = 10;
64358f0484fSRodney W. Grimes 			break;
64458f0484fSRodney W. Grimes 
645946b2d00SBill Fenner 		case 'X':
64658f0484fSRodney W. Grimes 		case 'x':
64758f0484fSRodney W. Grimes 			c = CT_INT;
648946b2d00SBill Fenner 			flags |= UNSIGNED;
64958f0484fSRodney W. Grimes 			base = 16;
65058f0484fSRodney W. Grimes 			break;
65158f0484fSRodney W. Grimes 
6528de9e897SDavid Schultz #ifndef NO_FLOATING_POINT
653370077c7SDavid Schultz 		case 'A': case 'E': case 'F': case 'G':
654370077c7SDavid Schultz 		case 'a': case 'e': case 'f': case 'g':
65558f0484fSRodney W. Grimes 			c = CT_FLOAT;
65658f0484fSRodney W. Grimes 			break;
65758f0484fSRodney W. Grimes #endif
65858f0484fSRodney W. Grimes 
659946b2d00SBill Fenner 		case 'S':
660946b2d00SBill Fenner 			flags |= LONG;
661946b2d00SBill Fenner 			/* FALLTHROUGH */
66258f0484fSRodney W. Grimes 		case 's':
66358f0484fSRodney W. Grimes 			c = CT_STRING;
66458f0484fSRodney W. Grimes 			break;
66558f0484fSRodney W. Grimes 
66658f0484fSRodney W. Grimes 		case '[':
66758f0484fSRodney W. Grimes 			fmt = __sccl(ccltab, fmt);
66858f0484fSRodney W. Grimes 			flags |= NOSKIP;
66958f0484fSRodney W. Grimes 			c = CT_CCL;
67058f0484fSRodney W. Grimes 			break;
67158f0484fSRodney W. Grimes 
672946b2d00SBill Fenner 		case 'C':
673946b2d00SBill Fenner 			flags |= LONG;
674946b2d00SBill Fenner 			/* FALLTHROUGH */
67558f0484fSRodney W. Grimes 		case 'c':
67658f0484fSRodney W. Grimes 			flags |= NOSKIP;
67758f0484fSRodney W. Grimes 			c = CT_CHAR;
67858f0484fSRodney W. Grimes 			break;
67958f0484fSRodney W. Grimes 
68058f0484fSRodney W. Grimes 		case 'p':	/* pointer format is like hex */
681d9dc1603SDag-Erling Smørgrav 			flags |= POINTER;
682946b2d00SBill Fenner 			c = CT_INT;		/* assumes sizeof(uintmax_t) */
683946b2d00SBill Fenner 			flags |= UNSIGNED;	/*      >= sizeof(uintptr_t) */
68458f0484fSRodney W. Grimes 			base = 16;
68558f0484fSRodney W. Grimes 			break;
68658f0484fSRodney W. Grimes 
68758f0484fSRodney W. Grimes 		case 'n':
68858f0484fSRodney W. Grimes 			if (flags & SUPPRESS)	/* ??? */
68958f0484fSRodney W. Grimes 				continue;
690946b2d00SBill Fenner 			if (flags & SHORTSHORT)
691946b2d00SBill Fenner 				*va_arg(ap, char *) = nread;
692946b2d00SBill Fenner 			else if (flags & SHORT)
69358f0484fSRodney W. Grimes 				*va_arg(ap, short *) = nread;
69458f0484fSRodney W. Grimes 			else if (flags & LONG)
69558f0484fSRodney W. Grimes 				*va_arg(ap, long *) = nread;
696946b2d00SBill Fenner 			else if (flags & LONGLONG)
697946b2d00SBill Fenner 				*va_arg(ap, long long *) = nread;
698946b2d00SBill Fenner 			else if (flags & INTMAXT)
699946b2d00SBill Fenner 				*va_arg(ap, intmax_t *) = nread;
700946b2d00SBill Fenner 			else if (flags & SIZET)
701946b2d00SBill Fenner 				*va_arg(ap, size_t *) = nread;
702946b2d00SBill Fenner 			else if (flags & PTRDIFFT)
703946b2d00SBill Fenner 				*va_arg(ap, ptrdiff_t *) = nread;
70458f0484fSRodney W. Grimes 			else
70558f0484fSRodney W. Grimes 				*va_arg(ap, int *) = nread;
70658f0484fSRodney W. Grimes 			continue;
70758f0484fSRodney W. Grimes 
708946b2d00SBill Fenner 		default:
709946b2d00SBill Fenner 			goto match_failure;
710946b2d00SBill Fenner 
71158f0484fSRodney W. Grimes 		/*
712946b2d00SBill Fenner 		 * Disgusting backwards compatibility hack.	XXX
71358f0484fSRodney W. Grimes 		 */
71458f0484fSRodney W. Grimes 		case '\0':	/* compat */
71558f0484fSRodney W. Grimes 			return (EOF);
71658f0484fSRodney W. Grimes 		}
71758f0484fSRodney W. Grimes 
71858f0484fSRodney W. Grimes 		/*
71958f0484fSRodney W. Grimes 		 * We have a conversion that requires input.
72058f0484fSRodney W. Grimes 		 */
72158f0484fSRodney W. Grimes 		if (fp->_r <= 0 && __srefill(fp))
72258f0484fSRodney W. Grimes 			goto input_failure;
72358f0484fSRodney W. Grimes 
72458f0484fSRodney W. Grimes 		/*
72558f0484fSRodney W. Grimes 		 * Consume leading white space, except for formats
72658f0484fSRodney W. Grimes 		 * that suppress this.
72758f0484fSRodney W. Grimes 		 */
72858f0484fSRodney W. Grimes 		if ((flags & NOSKIP) == 0) {
72958f0484fSRodney W. Grimes 			while (isspace(*fp->_p)) {
73058f0484fSRodney W. Grimes 				nread++;
73158f0484fSRodney W. Grimes 				if (--fp->_r > 0)
73258f0484fSRodney W. Grimes 					fp->_p++;
73358f0484fSRodney W. Grimes 				else if (__srefill(fp))
73458f0484fSRodney W. Grimes 					goto input_failure;
73558f0484fSRodney W. Grimes 			}
73658f0484fSRodney W. Grimes 			/*
73758f0484fSRodney W. Grimes 			 * Note that there is at least one character in
73858f0484fSRodney W. Grimes 			 * the buffer, so conversions that do not set NOSKIP
73958f0484fSRodney W. Grimes 			 * ca no longer result in an input failure.
74058f0484fSRodney W. Grimes 			 */
74158f0484fSRodney W. Grimes 		}
74258f0484fSRodney W. Grimes 
74358f0484fSRodney W. Grimes 		/*
74458f0484fSRodney W. Grimes 		 * Do the conversion.
74558f0484fSRodney W. Grimes 		 */
74658f0484fSRodney W. Grimes 		switch (c) {
74758f0484fSRodney W. Grimes 
74858f0484fSRodney W. Grimes 		case CT_CHAR:
74958f0484fSRodney W. Grimes 			/* scan arbitrary characters (sets NOSKIP) */
75058f0484fSRodney W. Grimes 			if (width == 0)
75158f0484fSRodney W. Grimes 				width = 1;
75235739e07STim J. Robbins 			if (flags & LONG) {
75351300896SDavid Schultz 				nr = convert_wchar(fp, GETARG(wchar_t *),
754d7af8cf1SDavid Schultz 				    width, locale);
75558f0484fSRodney W. Grimes 			} else {
75651300896SDavid Schultz 				nr = convert_char(fp, GETARG(char *), width);
75758f0484fSRodney W. Grimes 			}
75851300896SDavid Schultz 			if (nr < 0)
75958f0484fSRodney W. Grimes 				goto input_failure;
76058f0484fSRodney W. Grimes 			break;
76158f0484fSRodney W. Grimes 
76258f0484fSRodney W. Grimes 		case CT_CCL:
76358f0484fSRodney W. Grimes 			/* scan a (nonempty) character class (sets NOSKIP) */
76458f0484fSRodney W. Grimes 			if (width == 0)
765ce51cf03SJames Raynard 				width = (size_t)~0;	/* `infinity' */
76635739e07STim J. Robbins 			if (flags & LONG) {
76751300896SDavid Schultz 				nr = convert_wccl(fp, GETARG(wchar_t *), width,
768d7af8cf1SDavid Schultz 				    ccltab, locale);
76958f0484fSRodney W. Grimes 			} else {
77051300896SDavid Schultz 				nr = convert_ccl(fp, GETARG(char *), width,
77151300896SDavid Schultz 				    ccltab);
77251300896SDavid Schultz 			}
77351300896SDavid Schultz 			if (nr <= 0) {
77451300896SDavid Schultz 				if (nr < 0)
77558f0484fSRodney W. Grimes 					goto input_failure;
77651300896SDavid Schultz 				else /* nr == 0 */
77758f0484fSRodney W. Grimes 					goto match_failure;
77858f0484fSRodney W. Grimes 			}
77958f0484fSRodney W. Grimes 			break;
78058f0484fSRodney W. Grimes 
78158f0484fSRodney W. Grimes 		case CT_STRING:
78258f0484fSRodney W. Grimes 			/* like CCL, but zero-length string OK, & no NOSKIP */
78358f0484fSRodney W. Grimes 			if (width == 0)
784ce51cf03SJames Raynard 				width = (size_t)~0;
78535739e07STim J. Robbins 			if (flags & LONG) {
78651300896SDavid Schultz 				nr = convert_wstring(fp, GETARG(wchar_t *),
787d7af8cf1SDavid Schultz 				    width, locale);
78858f0484fSRodney W. Grimes 			} else {
78951300896SDavid Schultz 				nr = convert_string(fp, GETARG(char *), width);
79058f0484fSRodney W. Grimes 			}
79151300896SDavid Schultz 			if (nr < 0)
79251300896SDavid Schultz 				goto input_failure;
79351300896SDavid Schultz 			break;
79458f0484fSRodney W. Grimes 
79558f0484fSRodney W. Grimes 		case CT_INT:
796946b2d00SBill Fenner 			/* scan an integer as if by the conversion function */
79758f0484fSRodney W. Grimes #ifdef hardway
79858f0484fSRodney W. Grimes 			if (width == 0 || width > sizeof(buf) - 1)
79958f0484fSRodney W. Grimes 				width = sizeof(buf) - 1;
80058f0484fSRodney W. Grimes #else
80158f0484fSRodney W. Grimes 			/* size_t is unsigned, hence this optimisation */
80258f0484fSRodney W. Grimes 			if (--width > sizeof(buf) - 2)
80358f0484fSRodney W. Grimes 				width = sizeof(buf) - 2;
80458f0484fSRodney W. Grimes 			width++;
80558f0484fSRodney W. Grimes #endif
806d9dc1603SDag-Erling Smørgrav 			nr = parseint(fp, buf, width, base);
80751300896SDavid Schultz 			if (nr == 0)
80858f0484fSRodney W. Grimes 				goto match_failure;
80958f0484fSRodney W. Grimes 			if ((flags & SUPPRESS) == 0) {
810946b2d00SBill Fenner 				uintmax_t res;
81158f0484fSRodney W. Grimes 
81251300896SDavid Schultz 				buf[nr] = '\0';
813946b2d00SBill Fenner 				if ((flags & UNSIGNED) == 0)
8143c87aa1dSDavid Chisnall 				    res = strtoimax_l(buf, (char **)NULL, base, locale);
815946b2d00SBill Fenner 				else
8163c87aa1dSDavid Chisnall 				    res = strtoumax_l(buf, (char **)NULL, base, locale);
81758f0484fSRodney W. Grimes 				if (flags & POINTER)
8185e17038fSJordan K. Hubbard 					*va_arg(ap, void **) =
819946b2d00SBill Fenner 							(void *)(uintptr_t)res;
820946b2d00SBill Fenner 				else if (flags & SHORTSHORT)
821946b2d00SBill Fenner 					*va_arg(ap, char *) = res;
82258f0484fSRodney W. Grimes 				else if (flags & SHORT)
82358f0484fSRodney W. Grimes 					*va_arg(ap, short *) = res;
82458f0484fSRodney W. Grimes 				else if (flags & LONG)
82558f0484fSRodney W. Grimes 					*va_arg(ap, long *) = res;
826946b2d00SBill Fenner 				else if (flags & LONGLONG)
827946b2d00SBill Fenner 					*va_arg(ap, long long *) = res;
828946b2d00SBill Fenner 				else if (flags & INTMAXT)
829946b2d00SBill Fenner 					*va_arg(ap, intmax_t *) = res;
830946b2d00SBill Fenner 				else if (flags & PTRDIFFT)
831946b2d00SBill Fenner 					*va_arg(ap, ptrdiff_t *) = res;
832946b2d00SBill Fenner 				else if (flags & SIZET)
833946b2d00SBill Fenner 					*va_arg(ap, size_t *) = res;
83458f0484fSRodney W. Grimes 				else
83558f0484fSRodney W. Grimes 					*va_arg(ap, int *) = res;
83658f0484fSRodney W. Grimes 			}
83758f0484fSRodney W. Grimes 			break;
83858f0484fSRodney W. Grimes 
8398de9e897SDavid Schultz #ifndef NO_FLOATING_POINT
84058f0484fSRodney W. Grimes 		case CT_FLOAT:
84158f0484fSRodney W. Grimes 			/* scan a floating point number as if by strtod */
84258f0484fSRodney W. Grimes 			if (width == 0 || width > sizeof(buf) - 1)
84358f0484fSRodney W. Grimes 				width = sizeof(buf) - 1;
84451300896SDavid Schultz 			nr = parsefloat(fp, buf, buf + width, locale);
84551300896SDavid Schultz 			if (nr == 0)
84658f0484fSRodney W. Grimes 				goto match_failure;
84758f0484fSRodney W. Grimes 			if ((flags & SUPPRESS) == 0) {
848370077c7SDavid Schultz 				if (flags & LONGDBL) {
84951300896SDavid Schultz 					long double res = strtold_l(buf, NULL,
85051300896SDavid Schultz 					    locale);
8518fddd060SBruce Evans 					*va_arg(ap, long double *) = res;
852370077c7SDavid Schultz 				} else if (flags & LONG) {
85351300896SDavid Schultz 					double res = strtod_l(buf, NULL,
85451300896SDavid Schultz 					    locale);
85558f0484fSRodney W. Grimes 					*va_arg(ap, double *) = res;
856370077c7SDavid Schultz 				} else {
85751300896SDavid Schultz 					float res = strtof_l(buf, NULL, locale);
85858f0484fSRodney W. Grimes 					*va_arg(ap, float *) = res;
859370077c7SDavid Schultz 				}
86058f0484fSRodney W. Grimes 			}
86158f0484fSRodney W. Grimes 			break;
8628de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */
86358f0484fSRodney W. Grimes 		}
86451300896SDavid Schultz 		if (!(flags & SUPPRESS))
86551300896SDavid Schultz 			nassigned++;
86651300896SDavid Schultz 		nread += nr;
86751300896SDavid Schultz 		nconversions++;
86858f0484fSRodney W. Grimes 	}
86958f0484fSRodney W. Grimes input_failure:
870e836e480SBruce Evans 	return (nconversions != 0 ? nassigned : EOF);
87158f0484fSRodney W. Grimes match_failure:
87258f0484fSRodney W. Grimes 	return (nassigned);
87358f0484fSRodney W. Grimes }
87458f0484fSRodney W. Grimes 
87558f0484fSRodney W. Grimes /*
87658f0484fSRodney W. Grimes  * Fill in the given table from the scanset at the given format
87758f0484fSRodney W. Grimes  * (just after `[').  Return a pointer to the character past the
87858f0484fSRodney W. Grimes  * closing `]'.  The table has a 1 wherever characters should be
87958f0484fSRodney W. Grimes  * considered part of the scanset.
88058f0484fSRodney W. Grimes  */
881946b2d00SBill Fenner static const u_char *
__sccl(char * tab,const u_char * fmt)88225070501SCraig Rodrigues __sccl(char *tab, const u_char *fmt)
88358f0484fSRodney W. Grimes {
8841daad8f5SAndrey A. Chernov 	int c, n, v, i;
8851daad8f5SAndrey A. Chernov 	struct xlocale_collate *table =
8861daad8f5SAndrey A. Chernov 		(struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
88758f0484fSRodney W. Grimes 
88858f0484fSRodney W. Grimes 	/* first `clear' the whole table */
88958f0484fSRodney W. Grimes 	c = *fmt++;		/* first char hat => negated scanset */
89058f0484fSRodney W. Grimes 	if (c == '^') {
89158f0484fSRodney W. Grimes 		v = 1;		/* default => accept */
89258f0484fSRodney W. Grimes 		c = *fmt++;	/* get new first char */
89358f0484fSRodney W. Grimes 	} else
89458f0484fSRodney W. Grimes 		v = 0;		/* default => reject */
895628abd1bSAndrey A. Chernov 
896628abd1bSAndrey A. Chernov 	/* XXX: Will not work if sizeof(tab*) > sizeof(char) */
897ea295661SAndrey A. Chernov 	(void) memset(tab, v, 256);
898628abd1bSAndrey A. Chernov 
89958f0484fSRodney W. Grimes 	if (c == 0)
90058f0484fSRodney W. Grimes 		return (fmt - 1);/* format ended before closing ] */
90158f0484fSRodney W. Grimes 
90258f0484fSRodney W. Grimes 	/*
90358f0484fSRodney W. Grimes 	 * Now set the entries corresponding to the actual scanset
90458f0484fSRodney W. Grimes 	 * to the opposite of the above.
90558f0484fSRodney W. Grimes 	 *
90658f0484fSRodney W. Grimes 	 * The first character may be ']' (or '-') without being special;
90758f0484fSRodney W. Grimes 	 * the last character may be '-'.
90858f0484fSRodney W. Grimes 	 */
90958f0484fSRodney W. Grimes 	v = 1 - v;
91058f0484fSRodney W. Grimes 	for (;;) {
91158f0484fSRodney W. Grimes 		tab[c] = v;		/* take character c */
91258f0484fSRodney W. Grimes doswitch:
91358f0484fSRodney W. Grimes 		n = *fmt++;		/* and examine the next */
91458f0484fSRodney W. Grimes 		switch (n) {
91558f0484fSRodney W. Grimes 
91658f0484fSRodney W. Grimes 		case 0:			/* format ended too soon */
91758f0484fSRodney W. Grimes 			return (fmt - 1);
91858f0484fSRodney W. Grimes 
91958f0484fSRodney W. Grimes 		case '-':
92058f0484fSRodney W. Grimes 			/*
92158f0484fSRodney W. Grimes 			 * A scanset of the form
92258f0484fSRodney W. Grimes 			 *	[01+-]
92358f0484fSRodney W. Grimes 			 * is defined as `the digit 0, the digit 1,
92458f0484fSRodney W. Grimes 			 * the character +, the character -', but
92558f0484fSRodney W. Grimes 			 * the effect of a scanset such as
92658f0484fSRodney W. Grimes 			 *	[a-zA-Z0-9]
92758f0484fSRodney W. Grimes 			 * is implementation defined.  The V7 Unix
92858f0484fSRodney W. Grimes 			 * scanf treats `a-z' as `the letters a through
92958f0484fSRodney W. Grimes 			 * z', but treats `a-a' as `the letter a, the
93058f0484fSRodney W. Grimes 			 * character -, and the letter a'.
93158f0484fSRodney W. Grimes 			 *
93232223c1bSPedro F. Giffuni 			 * For compatibility, the `-' is not considered
93358f0484fSRodney W. Grimes 			 * to define a range if the character following
93458f0484fSRodney W. Grimes 			 * it is either a close bracket (required by ANSI)
93558f0484fSRodney W. Grimes 			 * or is not numerically greater than the character
93658f0484fSRodney W. Grimes 			 * we just stored in the table (c).
93758f0484fSRodney W. Grimes 			 */
93858f0484fSRodney W. Grimes 			n = *fmt;
9391daad8f5SAndrey A. Chernov 			if (n == ']'
9401daad8f5SAndrey A. Chernov 			    || (table->__collate_load_error ? n < c :
94112eae8c8SAndrey A. Chernov 				__collate_range_cmp(n, c) < 0
9421daad8f5SAndrey A. Chernov 			       )
9431daad8f5SAndrey A. Chernov 			   ) {
94458f0484fSRodney W. Grimes 				c = '-';
94558f0484fSRodney W. Grimes 				break;	/* resume the for(;;) */
94658f0484fSRodney W. Grimes 			}
94758f0484fSRodney W. Grimes 			fmt++;
9481daad8f5SAndrey A. Chernov 			/* fill in the range */
9491daad8f5SAndrey A. Chernov 			if (table->__collate_load_error) {
9501daad8f5SAndrey A. Chernov 				do {
951350498c5SAndrey A. Chernov 					tab[++c] = v;
952350498c5SAndrey A. Chernov 				} while (c < n);
9531daad8f5SAndrey A. Chernov 			} else {
9541daad8f5SAndrey A. Chernov 				for (i = 0; i < 256; i ++)
95512eae8c8SAndrey A. Chernov 					if (__collate_range_cmp(c, i) <= 0 &&
95612eae8c8SAndrey A. Chernov 					    __collate_range_cmp(i, n) <= 0
9571daad8f5SAndrey A. Chernov 					   )
9581daad8f5SAndrey A. Chernov 						tab[i] = v;
9591daad8f5SAndrey A. Chernov 			}
96058f0484fSRodney W. Grimes #if 1	/* XXX another disgusting compatibility hack */
9611daad8f5SAndrey A. Chernov 			c = n;
96258f0484fSRodney W. Grimes 			/*
96358f0484fSRodney W. Grimes 			 * Alas, the V7 Unix scanf also treats formats
96458f0484fSRodney W. Grimes 			 * such as [a-c-e] as `the letters a through e'.
96558f0484fSRodney W. Grimes 			 * This too is permitted by the standard....
96658f0484fSRodney W. Grimes 			 */
96758f0484fSRodney W. Grimes 			goto doswitch;
96858f0484fSRodney W. Grimes #else
96958f0484fSRodney W. Grimes 			c = *fmt++;
97058f0484fSRodney W. Grimes 			if (c == 0)
97158f0484fSRodney W. Grimes 				return (fmt - 1);
97258f0484fSRodney W. Grimes 			if (c == ']')
97358f0484fSRodney W. Grimes 				return (fmt);
97458f0484fSRodney W. Grimes #endif
97558f0484fSRodney W. Grimes 			break;
97658f0484fSRodney W. Grimes 
97758f0484fSRodney W. Grimes 		case ']':		/* end of scanset */
97858f0484fSRodney W. Grimes 			return (fmt);
97958f0484fSRodney W. Grimes 
98058f0484fSRodney W. Grimes 		default:		/* just another character */
98158f0484fSRodney W. Grimes 			c = n;
98258f0484fSRodney W. Grimes 			break;
98358f0484fSRodney W. Grimes 		}
98458f0484fSRodney W. Grimes 	}
98558f0484fSRodney W. Grimes 	/* NOTREACHED */
98658f0484fSRodney W. Grimes }
987370077c7SDavid Schultz 
9888de9e897SDavid Schultz #ifndef NO_FLOATING_POINT
989370077c7SDavid Schultz static int
parsefloat(FILE * fp,char * buf,char * end,locale_t locale)9903c87aa1dSDavid Chisnall parsefloat(FILE *fp, char *buf, char *end, locale_t locale)
991370077c7SDavid Schultz {
992370077c7SDavid Schultz 	char *commit, *p;
993f8f57193SDavid Schultz 	int infnanpos = 0, decptpos = 0;
994370077c7SDavid Schultz 	enum {
995f8f57193SDavid Schultz 		S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX,
996f8f57193SDavid Schultz 		S_DIGITS, S_DECPT, S_FRAC, S_EXP, S_EXPDIGITS
997370077c7SDavid Schultz 	} state = S_START;
998370077c7SDavid Schultz 	unsigned char c;
9993c87aa1dSDavid Chisnall 	const char *decpt = localeconv_l(locale)->decimal_point;
1000370077c7SDavid Schultz 	_Bool gotmantdig = 0, ishex = 0;
1001370077c7SDavid Schultz 
1002370077c7SDavid Schultz 	/*
1003370077c7SDavid Schultz 	 * We set commit = p whenever the string we have read so far
1004370077c7SDavid Schultz 	 * constitutes a valid representation of a floating point
1005370077c7SDavid Schultz 	 * number by itself.  At some point, the parse will complete
1006370077c7SDavid Schultz 	 * or fail, and we will ungetc() back to the last commit point.
1007370077c7SDavid Schultz 	 * To ensure that the file offset gets updated properly, it is
1008370077c7SDavid Schultz 	 * always necessary to read at least one character that doesn't
1009370077c7SDavid Schultz 	 * match; thus, we can't short-circuit "infinity" or "nan(...)".
1010370077c7SDavid Schultz 	 */
1011370077c7SDavid Schultz 	commit = buf - 1;
1012370077c7SDavid Schultz 	for (p = buf; p < end; ) {
1013370077c7SDavid Schultz 		c = *fp->_p;
1014370077c7SDavid Schultz reswitch:
1015370077c7SDavid Schultz 		switch (state) {
1016370077c7SDavid Schultz 		case S_START:
1017370077c7SDavid Schultz 			state = S_GOTSIGN;
1018370077c7SDavid Schultz 			if (c == '-' || c == '+')
1019370077c7SDavid Schultz 				break;
1020370077c7SDavid Schultz 			else
1021370077c7SDavid Schultz 				goto reswitch;
1022370077c7SDavid Schultz 		case S_GOTSIGN:
1023370077c7SDavid Schultz 			switch (c) {
1024370077c7SDavid Schultz 			case '0':
1025370077c7SDavid Schultz 				state = S_MAYBEHEX;
1026370077c7SDavid Schultz 				commit = p;
1027370077c7SDavid Schultz 				break;
1028370077c7SDavid Schultz 			case 'I':
1029370077c7SDavid Schultz 			case 'i':
1030370077c7SDavid Schultz 				state = S_INF;
1031370077c7SDavid Schultz 				break;
1032370077c7SDavid Schultz 			case 'N':
1033370077c7SDavid Schultz 			case 'n':
1034370077c7SDavid Schultz 				state = S_NAN;
1035370077c7SDavid Schultz 				break;
1036370077c7SDavid Schultz 			default:
1037370077c7SDavid Schultz 				state = S_DIGITS;
1038370077c7SDavid Schultz 				goto reswitch;
1039370077c7SDavid Schultz 			}
1040370077c7SDavid Schultz 			break;
1041370077c7SDavid Schultz 		case S_INF:
1042370077c7SDavid Schultz 			if (infnanpos > 6 ||
1043370077c7SDavid Schultz 			    (c != "nfinity"[infnanpos] &&
1044370077c7SDavid Schultz 			     c != "NFINITY"[infnanpos]))
1045370077c7SDavid Schultz 				goto parsedone;
1046370077c7SDavid Schultz 			if (infnanpos == 1 || infnanpos == 6)
1047370077c7SDavid Schultz 				commit = p;	/* inf or infinity */
1048370077c7SDavid Schultz 			infnanpos++;
1049370077c7SDavid Schultz 			break;
1050370077c7SDavid Schultz 		case S_NAN:
1051370077c7SDavid Schultz 			switch (infnanpos) {
1052370077c7SDavid Schultz 			case 0:
1053370077c7SDavid Schultz 				if (c != 'A' && c != 'a')
1054370077c7SDavid Schultz 					goto parsedone;
1055370077c7SDavid Schultz 				break;
1056370077c7SDavid Schultz 			case 1:
1057370077c7SDavid Schultz 				if (c != 'N' && c != 'n')
1058370077c7SDavid Schultz 					goto parsedone;
1059370077c7SDavid Schultz 				else
1060370077c7SDavid Schultz 					commit = p;
1061370077c7SDavid Schultz 				break;
1062370077c7SDavid Schultz 			case 2:
1063370077c7SDavid Schultz 				if (c != '(')
1064370077c7SDavid Schultz 					goto parsedone;
1065370077c7SDavid Schultz 				break;
1066370077c7SDavid Schultz 			default:
1067370077c7SDavid Schultz 				if (c == ')') {
1068370077c7SDavid Schultz 					commit = p;
1069f8f57193SDavid Schultz 					state = S_DONE;
1070370077c7SDavid Schultz 				} else if (!isalnum(c) && c != '_')
1071370077c7SDavid Schultz 					goto parsedone;
1072370077c7SDavid Schultz 				break;
1073370077c7SDavid Schultz 			}
1074370077c7SDavid Schultz 			infnanpos++;
1075370077c7SDavid Schultz 			break;
1076f8f57193SDavid Schultz 		case S_DONE:
1077f8f57193SDavid Schultz 			goto parsedone;
1078370077c7SDavid Schultz 		case S_MAYBEHEX:
1079370077c7SDavid Schultz 			state = S_DIGITS;
1080370077c7SDavid Schultz 			if (c == 'X' || c == 'x') {
1081370077c7SDavid Schultz 				ishex = 1;
1082370077c7SDavid Schultz 				break;
1083370077c7SDavid Schultz 			} else {	/* we saw a '0', but no 'x' */
1084370077c7SDavid Schultz 				gotmantdig = 1;
1085370077c7SDavid Schultz 				goto reswitch;
1086370077c7SDavid Schultz 			}
1087370077c7SDavid Schultz 		case S_DIGITS:
1088f8f57193SDavid Schultz 			if ((ishex && isxdigit(c)) || isdigit(c)) {
1089370077c7SDavid Schultz 				gotmantdig = 1;
1090370077c7SDavid Schultz 				commit = p;
1091370077c7SDavid Schultz 				break;
1092f8f57193SDavid Schultz 			} else {
1093f8f57193SDavid Schultz 				state = S_DECPT;
1094f8f57193SDavid Schultz 				goto reswitch;
1095f8f57193SDavid Schultz 			}
1096f8f57193SDavid Schultz 		case S_DECPT:
1097f8f57193SDavid Schultz 			if (c == decpt[decptpos]) {
1098f8f57193SDavid Schultz 				if (decpt[++decptpos] == '\0') {
1099f8f57193SDavid Schultz 					/* We read the complete decpt seq. */
1100f8f57193SDavid Schultz 					state = S_FRAC;
1101f8f57193SDavid Schultz 					if (gotmantdig)
1102f8f57193SDavid Schultz 						commit = p;
1103f8f57193SDavid Schultz 				}
1104f8f57193SDavid Schultz 				break;
1105f8f57193SDavid Schultz 			} else if (!decptpos) {
1106f8f57193SDavid Schultz 				/* We didn't read any decpt characters. */
1107f8f57193SDavid Schultz 				state = S_FRAC;
1108f8f57193SDavid Schultz 				goto reswitch;
1109f8f57193SDavid Schultz 			} else {
1110f8f57193SDavid Schultz 				/*
1111f8f57193SDavid Schultz 				 * We read part of a multibyte decimal point,
1112f8f57193SDavid Schultz 				 * but the rest is invalid, so bail.
1113f8f57193SDavid Schultz 				 */
1114f8f57193SDavid Schultz 				goto parsedone;
1115f8f57193SDavid Schultz 			}
1116370077c7SDavid Schultz 		case S_FRAC:
111727a97dffSJacques Vidrine 			if (((c == 'E' || c == 'e') && !ishex) ||
111827a97dffSJacques Vidrine 			    ((c == 'P' || c == 'p') && ishex)) {
1119370077c7SDavid Schultz 				if (!gotmantdig)
1120370077c7SDavid Schultz 					goto parsedone;
1121370077c7SDavid Schultz 				else
1122370077c7SDavid Schultz 					state = S_EXP;
112327a97dffSJacques Vidrine 			} else if ((ishex && isxdigit(c)) || isdigit(c)) {
1124370077c7SDavid Schultz 				commit = p;
1125370077c7SDavid Schultz 				gotmantdig = 1;
1126370077c7SDavid Schultz 			} else
1127370077c7SDavid Schultz 				goto parsedone;
1128370077c7SDavid Schultz 			break;
1129370077c7SDavid Schultz 		case S_EXP:
1130370077c7SDavid Schultz 			state = S_EXPDIGITS;
1131370077c7SDavid Schultz 			if (c == '-' || c == '+')
1132370077c7SDavid Schultz 				break;
1133370077c7SDavid Schultz 			else
1134370077c7SDavid Schultz 				goto reswitch;
1135370077c7SDavid Schultz 		case S_EXPDIGITS:
1136370077c7SDavid Schultz 			if (isdigit(c))
1137370077c7SDavid Schultz 				commit = p;
1138370077c7SDavid Schultz 			else
1139370077c7SDavid Schultz 				goto parsedone;
1140370077c7SDavid Schultz 			break;
1141370077c7SDavid Schultz 		default:
1142370077c7SDavid Schultz 			abort();
1143370077c7SDavid Schultz 		}
1144370077c7SDavid Schultz 		*p++ = c;
1145370077c7SDavid Schultz 		if (--fp->_r > 0)
1146370077c7SDavid Schultz 			fp->_p++;
1147370077c7SDavid Schultz 		else if (__srefill(fp))
1148370077c7SDavid Schultz 			break;	/* EOF */
1149370077c7SDavid Schultz 	}
1150370077c7SDavid Schultz 
1151370077c7SDavid Schultz parsedone:
1152370077c7SDavid Schultz 	while (commit < --p)
1153370077c7SDavid Schultz 		__ungetc(*(u_char *)p, fp);
1154370077c7SDavid Schultz 	*++commit = '\0';
1155370077c7SDavid Schultz 	return (commit - buf);
1156370077c7SDavid Schultz }
1157370077c7SDavid Schultz #endif
1158