1/*-
2 * Copyright (c) 1990, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Copyright (c) 2011 The FreeBSD Foundation
6 * All rights reserved.
7 * Portions of this software were developed by David Chisnall
8 * under sponsorship from the FreeBSD Foundation.
9 *
10 * This code is derived from software contributed to Berkeley by
11 * Chris Torek.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38#if defined(LIBC_SCCS) && !defined(lint)
39static char sccsid[] = "@(#)vfscanf.c	8.1 (Berkeley) 6/4/93";
40#endif /* LIBC_SCCS and not lint */
41#include <sys/cdefs.h>
42__FBSDID("$FreeBSD: stable/11/lib/libc/stdio/vfscanf.c 320942 2017-07-13 09:27:11Z kib $");
43
44#include "namespace.h"
45#include <ctype.h>
46#include <inttypes.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <stddef.h>
50#include <stdarg.h>
51#include <string.h>
52#include <wchar.h>
53#include <wctype.h>
54#include "un-namespace.h"
55
56#include "collate.h"
57#include "libc_private.h"
58#include "local.h"
59#include "xlocale_private.h"
60
61#ifndef NO_FLOATING_POINT
62#include <locale.h>
63#endif
64
65#define	BUF		513	/* Maximum length of numeric string. */
66
67/*
68 * Flags used during conversion.
69 */
70#define	LONG		0x01	/* l: long or double */
71#define	LONGDBL		0x02	/* L: long double */
72#define	SHORT		0x04	/* h: short */
73#define	SUPPRESS	0x08	/* *: suppress assignment */
74#define	POINTER		0x10	/* p: void * (as hex) */
75#define	NOSKIP		0x20	/* [ or c: do not skip blanks */
76#define	LONGLONG	0x400	/* ll: long long (+ deprecated q: quad) */
77#define	INTMAXT		0x800	/* j: intmax_t */
78#define	PTRDIFFT	0x1000	/* t: ptrdiff_t */
79#define	SIZET		0x2000	/* z: size_t */
80#define	SHORTSHORT	0x4000	/* hh: char */
81#define	UNSIGNED	0x8000	/* %[oupxX] conversions */
82
83/*
84 * The following are used in integral conversions only:
85 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS
86 */
87#define	SIGNOK		0x40	/* +/- is (still) legal */
88#define	NDIGITS		0x80	/* no digits detected */
89#define	PFXOK		0x100	/* 0x prefix is (still) legal */
90#define	NZDIGITS	0x200	/* no zero digits detected */
91#define	HAVESIGN	0x10000	/* sign detected */
92
93/*
94 * Conversion types.
95 */
96#define	CT_CHAR		0	/* %c conversion */
97#define	CT_CCL		1	/* %[...] conversion */
98#define	CT_STRING	2	/* %s conversion */
99#define	CT_INT		3	/* %[dioupxX] conversion */
100#define	CT_FLOAT	4	/* %[efgEFG] conversion */
101
102static const u_char *__sccl(char *, const u_char *);
103#ifndef NO_FLOATING_POINT
104static int parsefloat(FILE *, char *, char *, locale_t);
105#endif
106
107__weak_reference(__vfscanf, vfscanf);
108
109/*
110 * Conversion functions are passed a pointer to this object instead of
111 * a real parameter to indicate that the assignment-suppression (*)
112 * flag was specified.  We could use a NULL pointer to indicate this,
113 * but that would mask bugs in applications that call scanf() with a
114 * NULL pointer.
115 */
116static const int suppress;
117#define	SUPPRESS_PTR	((void *)&suppress)
118
119static const mbstate_t initial_mbs;
120
121/*
122 * The following conversion functions return the number of characters consumed,
123 * or -1 on input failure.  Character class conversion returns 0 on match
124 * failure.
125 */
126
127static __inline int
128convert_char(FILE *fp, char * p, int width)
129{
130	int n;
131
132	if (p == SUPPRESS_PTR) {
133		size_t sum = 0;
134		for (;;) {
135			if ((n = fp->_r) < width) {
136				sum += n;
137				width -= n;
138				fp->_p += n;
139				if (__srefill(fp)) {
140					if (sum == 0)
141						return (-1);
142					break;
143				}
144			} else {
145				sum += width;
146				fp->_r -= width;
147				fp->_p += width;
148				break;
149			}
150		}
151		return (sum);
152	} else {
153		size_t r = __fread(p, 1, width, fp);
154
155		if (r == 0)
156			return (-1);
157		return (r);
158	}
159}
160
161static __inline int
162convert_wchar(FILE *fp, wchar_t *wcp, int width, locale_t locale)
163{
164	mbstate_t mbs;
165	int n, nread;
166	wint_t wi;
167
168	mbs = initial_mbs;
169	n = 0;
170	while (width-- != 0 &&
171	    (wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF) {
172		if (wcp != SUPPRESS_PTR)
173			*wcp++ = (wchar_t)wi;
174		n += nread;
175	}
176	if (n == 0)
177		return (-1);
178	return (n);
179}
180
181static __inline int
182convert_ccl(FILE *fp, char * p, int width, const char *ccltab)
183{
184	char *p0;
185	int n;
186
187	if (p == SUPPRESS_PTR) {
188		n = 0;
189		while (ccltab[*fp->_p]) {
190			n++, fp->_r--, fp->_p++;
191			if (--width == 0)
192				break;
193			if (fp->_r <= 0 && __srefill(fp)) {
194				if (n == 0)
195					return (-1);
196				break;
197			}
198		}
199	} else {
200		p0 = p;
201		while (ccltab[*fp->_p]) {
202			fp->_r--;
203			*p++ = *fp->_p++;
204			if (--width == 0)
205				break;
206			if (fp->_r <= 0 && __srefill(fp)) {
207				if (p == p0)
208					return (-1);
209				break;
210			}
211		}
212		n = p - p0;
213		if (n == 0)
214			return (0);
215		*p = 0;
216	}
217	return (n);
218}
219
220static __inline int
221convert_wccl(FILE *fp, wchar_t *wcp, int width, const char *ccltab,
222    locale_t locale)
223{
224	mbstate_t mbs;
225	wint_t wi;
226	int n, nread;
227
228	mbs = initial_mbs;
229	n = 0;
230	if (wcp == SUPPRESS_PTR) {
231		while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
232		    width-- != 0 && ccltab[wctob(wi)])
233			n += nread;
234		if (wi != WEOF)
235			__ungetwc(wi, fp, __get_locale());
236	} else {
237		while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
238		    width-- != 0 && ccltab[wctob(wi)]) {
239			*wcp++ = (wchar_t)wi;
240			n += nread;
241		}
242		if (wi != WEOF)
243			__ungetwc(wi, fp, __get_locale());
244		if (n == 0)
245			return (0);
246		*wcp = 0;
247	}
248	return (n);
249}
250
251static __inline int
252convert_string(FILE *fp, char * p, int width)
253{
254	char *p0;
255	int n;
256
257	if (p == SUPPRESS_PTR) {
258		n = 0;
259		while (!isspace(*fp->_p)) {
260			n++, fp->_r--, fp->_p++;
261			if (--width == 0)
262				break;
263			if (fp->_r <= 0 && __srefill(fp))
264				break;
265		}
266	} else {
267		p0 = p;
268		while (!isspace(*fp->_p)) {
269			fp->_r--;
270			*p++ = *fp->_p++;
271			if (--width == 0)
272				break;
273			if (fp->_r <= 0 && __srefill(fp))
274				break;
275		}
276		*p = 0;
277		n = p - p0;
278	}
279	return (n);
280}
281
282static __inline int
283convert_wstring(FILE *fp, wchar_t *wcp, int width, locale_t locale)
284{
285	mbstate_t mbs;
286	wint_t wi;
287	int n, nread;
288
289	mbs = initial_mbs;
290	n = 0;
291	if (wcp == SUPPRESS_PTR) {
292		while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
293		    width-- != 0 && !iswspace(wi))
294			n += nread;
295		if (wi != WEOF)
296			__ungetwc(wi, fp, __get_locale());
297	} else {
298		while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
299		    width-- != 0 && !iswspace(wi)) {
300			*wcp++ = (wchar_t)wi;
301			n += nread;
302		}
303		if (wi != WEOF)
304			__ungetwc(wi, fp, __get_locale());
305		*wcp = '\0';
306	}
307	return (n);
308}
309
310/*
311 * Read an integer, storing it in buf.  The only relevant bit in the
312 * flags argument is PFXOK.
313 *
314 * Return 0 on a match failure, and the number of characters read
315 * otherwise.
316 */
317static __inline int
318parseint(FILE *fp, char * __restrict buf, int width, int base, int flags)
319{
320	/* `basefix' is used to avoid `if' tests */
321	static const short basefix[17] =
322		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
323	char *p;
324	int c;
325
326	flags |= SIGNOK | NDIGITS | NZDIGITS;
327	for (p = buf; width; width--) {
328		c = *fp->_p;
329		/*
330		 * Switch on the character; `goto ok' if we accept it
331		 * as a part of number.
332		 */
333		switch (c) {
334
335		/*
336		 * The digit 0 is always legal, but is special.  For
337		 * %i conversions, if no digits (zero or nonzero) have
338		 * been scanned (only signs), we will have base==0.
339		 * In that case, we should set it to 8 and enable 0x
340		 * prefixing.  Also, if we have not scanned zero
341		 * digits before this, do not turn off prefixing
342		 * (someone else will turn it off if we have scanned
343		 * any nonzero digits).
344		 */
345		case '0':
346			if (base == 0) {
347				base = 8;
348				flags |= PFXOK;
349			}
350			if (flags & NZDIGITS)
351				flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
352			else
353				flags &= ~(SIGNOK|PFXOK|NDIGITS);
354			goto ok;
355
356		/* 1 through 7 always legal */
357		case '1': case '2': case '3':
358		case '4': case '5': case '6': case '7':
359			base = basefix[base];
360			flags &= ~(SIGNOK | PFXOK | NDIGITS);
361			goto ok;
362
363		/* digits 8 and 9 ok iff decimal or hex */
364		case '8': case '9':
365			base = basefix[base];
366			if (base <= 8)
367				break;	/* not legal here */
368			flags &= ~(SIGNOK | PFXOK | NDIGITS);
369			goto ok;
370
371		/* letters ok iff hex */
372		case 'A': case 'B': case 'C':
373		case 'D': case 'E': case 'F':
374		case 'a': case 'b': case 'c':
375		case 'd': case 'e': case 'f':
376			/* no need to fix base here */
377			if (base <= 10)
378				break;	/* not legal here */
379			flags &= ~(SIGNOK | PFXOK | NDIGITS);
380			goto ok;
381
382		/* sign ok only as first character */
383		case '+': case '-':
384			if (flags & SIGNOK) {
385				flags &= ~SIGNOK;
386				flags |= HAVESIGN;
387				goto ok;
388			}
389			break;
390
391		/*
392		 * x ok iff flag still set & 2nd char (or 3rd char if
393		 * we have a sign).
394		 */
395		case 'x': case 'X':
396			if (flags & PFXOK && p ==
397			    buf + 1 + !!(flags & HAVESIGN)) {
398				base = 16;	/* if %i */
399				flags &= ~PFXOK;
400				goto ok;
401			}
402			break;
403		}
404
405		/*
406		 * If we got here, c is not a legal character for a
407		 * number.  Stop accumulating digits.
408		 */
409		break;
410	ok:
411		/*
412		 * c is legal: store it and look at the next.
413		 */
414		*p++ = c;
415		if (--fp->_r > 0)
416			fp->_p++;
417		else if (__srefill(fp))
418			break;		/* EOF */
419	}
420	/*
421	 * If we had only a sign, it is no good; push back the sign.
422	 * If the number ends in `x', it was [sign] '0' 'x', so push
423	 * back the x and treat it as [sign] '0'.
424	 */
425	if (flags & NDIGITS) {
426		if (p > buf)
427			(void) __ungetc(*(u_char *)--p, fp);
428		return (0);
429	}
430	c = ((u_char *)p)[-1];
431	if (c == 'x' || c == 'X') {
432		--p;
433		(void) __ungetc(c, fp);
434	}
435	return (p - buf);
436}
437
438/*
439 * __vfscanf - MT-safe version
440 */
441int
442__vfscanf(FILE *fp, char const *fmt0, va_list ap)
443{
444	int ret;
445
446	FLOCKFILE_CANCELSAFE(fp);
447	ret = __svfscanf(fp, __get_locale(), fmt0, ap);
448	FUNLOCKFILE_CANCELSAFE();
449	return (ret);
450}
451int
452vfscanf_l(FILE *fp, locale_t locale, char const *fmt0, va_list ap)
453{
454	int ret;
455	FIX_LOCALE(locale);
456
457	FLOCKFILE_CANCELSAFE(fp);
458	ret = __svfscanf(fp, locale, fmt0, ap);
459	FUNLOCKFILE_CANCELSAFE();
460	return (ret);
461}
462
463/*
464 * __svfscanf - non-MT-safe version of __vfscanf
465 */
466int
467__svfscanf(FILE *fp, locale_t locale, const char *fmt0, va_list ap)
468{
469#define	GETARG(type)	((flags & SUPPRESS) ? SUPPRESS_PTR : va_arg(ap, type))
470	const u_char *fmt = (const u_char *)fmt0;
471	int c;			/* character from format, or conversion */
472	size_t width;		/* field width, or 0 */
473	int flags;		/* flags as defined above */
474	int nassigned;		/* number of fields assigned */
475	int nconversions;	/* number of conversions */
476	int nr;			/* characters read by the current conversion */
477	int nread;		/* number of characters consumed from fp */
478	int base;		/* base argument to conversion function */
479	char ccltab[256];	/* character class table for %[...] */
480	char buf[BUF];		/* buffer for numeric conversions */
481
482	ORIENT(fp, -1);
483
484	nassigned = 0;
485	nconversions = 0;
486	nread = 0;
487	for (;;) {
488		c = *fmt++;
489		if (c == 0)
490			return (nassigned);
491		if (isspace(c)) {
492			while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p))
493				nread++, fp->_r--, fp->_p++;
494			continue;
495		}
496		if (c != '%')
497			goto literal;
498		width = 0;
499		flags = 0;
500		/*
501		 * switch on the format.  continue if done;
502		 * break once format type is derived.
503		 */
504again:		c = *fmt++;
505		switch (c) {
506		case '%':
507literal:
508			if (fp->_r <= 0 && __srefill(fp))
509				goto input_failure;
510			if (*fp->_p != c)
511				goto match_failure;
512			fp->_r--, fp->_p++;
513			nread++;
514			continue;
515
516		case '*':
517			flags |= SUPPRESS;
518			goto again;
519		case 'j':
520			flags |= INTMAXT;
521			goto again;
522		case 'l':
523			if (flags & LONG) {
524				flags &= ~LONG;
525				flags |= LONGLONG;
526			} else
527				flags |= LONG;
528			goto again;
529		case 'q':
530			flags |= LONGLONG;	/* not quite */
531			goto again;
532		case 't':
533			flags |= PTRDIFFT;
534			goto again;
535		case 'z':
536			flags |= SIZET;
537			goto again;
538		case 'L':
539			flags |= LONGDBL;
540			goto again;
541		case 'h':
542			if (flags & SHORT) {
543				flags &= ~SHORT;
544				flags |= SHORTSHORT;
545			} else
546				flags |= SHORT;
547			goto again;
548
549		case '0': case '1': case '2': case '3': case '4':
550		case '5': case '6': case '7': case '8': case '9':
551			width = width * 10 + c - '0';
552			goto again;
553
554		/*
555		 * Conversions.
556		 */
557		case 'd':
558			c = CT_INT;
559			base = 10;
560			break;
561
562		case 'i':
563			c = CT_INT;
564			base = 0;
565			break;
566
567		case 'o':
568			c = CT_INT;
569			flags |= UNSIGNED;
570			base = 8;
571			break;
572
573		case 'u':
574			c = CT_INT;
575			flags |= UNSIGNED;
576			base = 10;
577			break;
578
579		case 'X':
580		case 'x':
581			flags |= PFXOK;	/* enable 0x prefixing */
582			c = CT_INT;
583			flags |= UNSIGNED;
584			base = 16;
585			break;
586
587#ifndef NO_FLOATING_POINT
588		case 'A': case 'E': case 'F': case 'G':
589		case 'a': case 'e': case 'f': case 'g':
590			c = CT_FLOAT;
591			break;
592#endif
593
594		case 'S':
595			flags |= LONG;
596			/* FALLTHROUGH */
597		case 's':
598			c = CT_STRING;
599			break;
600
601		case '[':
602			fmt = __sccl(ccltab, fmt);
603			flags |= NOSKIP;
604			c = CT_CCL;
605			break;
606
607		case 'C':
608			flags |= LONG;
609			/* FALLTHROUGH */
610		case 'c':
611			flags |= NOSKIP;
612			c = CT_CHAR;
613			break;
614
615		case 'p':	/* pointer format is like hex */
616			flags |= POINTER | PFXOK;
617			c = CT_INT;		/* assumes sizeof(uintmax_t) */
618			flags |= UNSIGNED;	/*      >= sizeof(uintptr_t) */
619			base = 16;
620			break;
621
622		case 'n':
623			if (flags & SUPPRESS)	/* ??? */
624				continue;
625			if (flags & SHORTSHORT)
626				*va_arg(ap, char *) = nread;
627			else if (flags & SHORT)
628				*va_arg(ap, short *) = nread;
629			else if (flags & LONG)
630				*va_arg(ap, long *) = nread;
631			else if (flags & LONGLONG)
632				*va_arg(ap, long long *) = nread;
633			else if (flags & INTMAXT)
634				*va_arg(ap, intmax_t *) = nread;
635			else if (flags & SIZET)
636				*va_arg(ap, size_t *) = nread;
637			else if (flags & PTRDIFFT)
638				*va_arg(ap, ptrdiff_t *) = nread;
639			else
640				*va_arg(ap, int *) = nread;
641			continue;
642
643		default:
644			goto match_failure;
645
646		/*
647		 * Disgusting backwards compatibility hack.	XXX
648		 */
649		case '\0':	/* compat */
650			return (EOF);
651		}
652
653		/*
654		 * We have a conversion that requires input.
655		 */
656		if (fp->_r <= 0 && __srefill(fp))
657			goto input_failure;
658
659		/*
660		 * Consume leading white space, except for formats
661		 * that suppress this.
662		 */
663		if ((flags & NOSKIP) == 0) {
664			while (isspace(*fp->_p)) {
665				nread++;
666				if (--fp->_r > 0)
667					fp->_p++;
668				else if (__srefill(fp))
669					goto input_failure;
670			}
671			/*
672			 * Note that there is at least one character in
673			 * the buffer, so conversions that do not set NOSKIP
674			 * ca no longer result in an input failure.
675			 */
676		}
677
678		/*
679		 * Do the conversion.
680		 */
681		switch (c) {
682
683		case CT_CHAR:
684			/* scan arbitrary characters (sets NOSKIP) */
685			if (width == 0)
686				width = 1;
687			if (flags & LONG) {
688				nr = convert_wchar(fp, GETARG(wchar_t *),
689				    width, locale);
690			} else {
691				nr = convert_char(fp, GETARG(char *), width);
692			}
693			if (nr < 0)
694				goto input_failure;
695			break;
696
697		case CT_CCL:
698			/* scan a (nonempty) character class (sets NOSKIP) */
699			if (width == 0)
700				width = (size_t)~0;	/* `infinity' */
701			if (flags & LONG) {
702				nr = convert_wccl(fp, GETARG(wchar_t *), width,
703				    ccltab, locale);
704			} else {
705				nr = convert_ccl(fp, GETARG(char *), width,
706				    ccltab);
707			}
708			if (nr <= 0) {
709				if (nr < 0)
710					goto input_failure;
711				else /* nr == 0 */
712					goto match_failure;
713			}
714			break;
715
716		case CT_STRING:
717			/* like CCL, but zero-length string OK, & no NOSKIP */
718			if (width == 0)
719				width = (size_t)~0;
720			if (flags & LONG) {
721				nr = convert_wstring(fp, GETARG(wchar_t *),
722				    width, locale);
723			} else {
724				nr = convert_string(fp, GETARG(char *), width);
725			}
726			if (nr < 0)
727				goto input_failure;
728			break;
729
730		case CT_INT:
731			/* scan an integer as if by the conversion function */
732#ifdef hardway
733			if (width == 0 || width > sizeof(buf) - 1)
734				width = sizeof(buf) - 1;
735#else
736			/* size_t is unsigned, hence this optimisation */
737			if (--width > sizeof(buf) - 2)
738				width = sizeof(buf) - 2;
739			width++;
740#endif
741			nr = parseint(fp, buf, width, base, flags);
742			if (nr == 0)
743				goto match_failure;
744			if ((flags & SUPPRESS) == 0) {
745				uintmax_t res;
746
747				buf[nr] = '\0';
748				if ((flags & UNSIGNED) == 0)
749				    res = strtoimax_l(buf, (char **)NULL, base, locale);
750				else
751				    res = strtoumax_l(buf, (char **)NULL, base, locale);
752				if (flags & POINTER)
753					*va_arg(ap, void **) =
754							(void *)(uintptr_t)res;
755				else if (flags & SHORTSHORT)
756					*va_arg(ap, char *) = res;
757				else if (flags & SHORT)
758					*va_arg(ap, short *) = res;
759				else if (flags & LONG)
760					*va_arg(ap, long *) = res;
761				else if (flags & LONGLONG)
762					*va_arg(ap, long long *) = res;
763				else if (flags & INTMAXT)
764					*va_arg(ap, intmax_t *) = res;
765				else if (flags & PTRDIFFT)
766					*va_arg(ap, ptrdiff_t *) = res;
767				else if (flags & SIZET)
768					*va_arg(ap, size_t *) = res;
769				else
770					*va_arg(ap, int *) = res;
771			}
772			break;
773
774#ifndef NO_FLOATING_POINT
775		case CT_FLOAT:
776			/* scan a floating point number as if by strtod */
777			if (width == 0 || width > sizeof(buf) - 1)
778				width = sizeof(buf) - 1;
779			nr = parsefloat(fp, buf, buf + width, locale);
780			if (nr == 0)
781				goto match_failure;
782			if ((flags & SUPPRESS) == 0) {
783				if (flags & LONGDBL) {
784					long double res = strtold_l(buf, NULL,
785					    locale);
786					*va_arg(ap, long double *) = res;
787				} else if (flags & LONG) {
788					double res = strtod_l(buf, NULL,
789					    locale);
790					*va_arg(ap, double *) = res;
791				} else {
792					float res = strtof_l(buf, NULL, locale);
793					*va_arg(ap, float *) = res;
794				}
795			}
796			break;
797#endif /* !NO_FLOATING_POINT */
798		}
799		if (!(flags & SUPPRESS))
800			nassigned++;
801		nread += nr;
802		nconversions++;
803	}
804input_failure:
805	return (nconversions != 0 ? nassigned : EOF);
806match_failure:
807	return (nassigned);
808}
809
810/*
811 * Fill in the given table from the scanset at the given format
812 * (just after `[').  Return a pointer to the character past the
813 * closing `]'.  The table has a 1 wherever characters should be
814 * considered part of the scanset.
815 */
816static const u_char *
817__sccl(char *tab, const u_char *fmt)
818{
819	int c, n, v, i;
820	struct xlocale_collate *table =
821		(struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
822
823	/* first `clear' the whole table */
824	c = *fmt++;		/* first char hat => negated scanset */
825	if (c == '^') {
826		v = 1;		/* default => accept */
827		c = *fmt++;	/* get new first char */
828	} else
829		v = 0;		/* default => reject */
830
831	/* XXX: Will not work if sizeof(tab*) > sizeof(char) */
832	(void) memset(tab, v, 256);
833
834	if (c == 0)
835		return (fmt - 1);/* format ended before closing ] */
836
837	/*
838	 * Now set the entries corresponding to the actual scanset
839	 * to the opposite of the above.
840	 *
841	 * The first character may be ']' (or '-') without being special;
842	 * the last character may be '-'.
843	 */
844	v = 1 - v;
845	for (;;) {
846		tab[c] = v;		/* take character c */
847doswitch:
848		n = *fmt++;		/* and examine the next */
849		switch (n) {
850
851		case 0:			/* format ended too soon */
852			return (fmt - 1);
853
854		case '-':
855			/*
856			 * A scanset of the form
857			 *	[01+-]
858			 * is defined as `the digit 0, the digit 1,
859			 * the character +, the character -', but
860			 * the effect of a scanset such as
861			 *	[a-zA-Z0-9]
862			 * is implementation defined.  The V7 Unix
863			 * scanf treats `a-z' as `the letters a through
864			 * z', but treats `a-a' as `the letter a, the
865			 * character -, and the letter a'.
866			 *
867			 * For compatibility, the `-' is not considered
868			 * to define a range if the character following
869			 * it is either a close bracket (required by ANSI)
870			 * or is not numerically greater than the character
871			 * we just stored in the table (c).
872			 */
873			n = *fmt;
874			if (n == ']'
875			    || (table->__collate_load_error ? n < c :
876				__collate_range_cmp(n, c) < 0
877			       )
878			   ) {
879				c = '-';
880				break;	/* resume the for(;;) */
881			}
882			fmt++;
883			/* fill in the range */
884			if (table->__collate_load_error) {
885				do {
886					tab[++c] = v;
887				} while (c < n);
888			} else {
889				for (i = 0; i < 256; i ++)
890					if (__collate_range_cmp(c, i) <= 0 &&
891					    __collate_range_cmp(i, n) <= 0
892					   )
893						tab[i] = v;
894			}
895#if 1	/* XXX another disgusting compatibility hack */
896			c = n;
897			/*
898			 * Alas, the V7 Unix scanf also treats formats
899			 * such as [a-c-e] as `the letters a through e'.
900			 * This too is permitted by the standard....
901			 */
902			goto doswitch;
903#else
904			c = *fmt++;
905			if (c == 0)
906				return (fmt - 1);
907			if (c == ']')
908				return (fmt);
909#endif
910			break;
911
912		case ']':		/* end of scanset */
913			return (fmt);
914
915		default:		/* just another character */
916			c = n;
917			break;
918		}
919	}
920	/* NOTREACHED */
921}
922
923#ifndef NO_FLOATING_POINT
924static int
925parsefloat(FILE *fp, char *buf, char *end, locale_t locale)
926{
927	char *commit, *p;
928	int infnanpos = 0, decptpos = 0;
929	enum {
930		S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX,
931		S_DIGITS, S_DECPT, S_FRAC, S_EXP, S_EXPDIGITS
932	} state = S_START;
933	unsigned char c;
934	const char *decpt = localeconv_l(locale)->decimal_point;
935	_Bool gotmantdig = 0, ishex = 0;
936
937	/*
938	 * We set commit = p whenever the string we have read so far
939	 * constitutes a valid representation of a floating point
940	 * number by itself.  At some point, the parse will complete
941	 * or fail, and we will ungetc() back to the last commit point.
942	 * To ensure that the file offset gets updated properly, it is
943	 * always necessary to read at least one character that doesn't
944	 * match; thus, we can't short-circuit "infinity" or "nan(...)".
945	 */
946	commit = buf - 1;
947	for (p = buf; p < end; ) {
948		c = *fp->_p;
949reswitch:
950		switch (state) {
951		case S_START:
952			state = S_GOTSIGN;
953			if (c == '-' || c == '+')
954				break;
955			else
956				goto reswitch;
957		case S_GOTSIGN:
958			switch (c) {
959			case '0':
960				state = S_MAYBEHEX;
961				commit = p;
962				break;
963			case 'I':
964			case 'i':
965				state = S_INF;
966				break;
967			case 'N':
968			case 'n':
969				state = S_NAN;
970				break;
971			default:
972				state = S_DIGITS;
973				goto reswitch;
974			}
975			break;
976		case S_INF:
977			if (infnanpos > 6 ||
978			    (c != "nfinity"[infnanpos] &&
979			     c != "NFINITY"[infnanpos]))
980				goto parsedone;
981			if (infnanpos == 1 || infnanpos == 6)
982				commit = p;	/* inf or infinity */
983			infnanpos++;
984			break;
985		case S_NAN:
986			switch (infnanpos) {
987			case 0:
988				if (c != 'A' && c != 'a')
989					goto parsedone;
990				break;
991			case 1:
992				if (c != 'N' && c != 'n')
993					goto parsedone;
994				else
995					commit = p;
996				break;
997			case 2:
998				if (c != '(')
999					goto parsedone;
1000				break;
1001			default:
1002				if (c == ')') {
1003					commit = p;
1004					state = S_DONE;
1005				} else if (!isalnum(c) && c != '_')
1006					goto parsedone;
1007				break;
1008			}
1009			infnanpos++;
1010			break;
1011		case S_DONE:
1012			goto parsedone;
1013		case S_MAYBEHEX:
1014			state = S_DIGITS;
1015			if (c == 'X' || c == 'x') {
1016				ishex = 1;
1017				break;
1018			} else {	/* we saw a '0', but no 'x' */
1019				gotmantdig = 1;
1020				goto reswitch;
1021			}
1022		case S_DIGITS:
1023			if ((ishex && isxdigit(c)) || isdigit(c)) {
1024				gotmantdig = 1;
1025				commit = p;
1026				break;
1027			} else {
1028				state = S_DECPT;
1029				goto reswitch;
1030			}
1031		case S_DECPT:
1032			if (c == decpt[decptpos]) {
1033				if (decpt[++decptpos] == '\0') {
1034					/* We read the complete decpt seq. */
1035					state = S_FRAC;
1036					if (gotmantdig)
1037						commit = p;
1038				}
1039				break;
1040			} else if (!decptpos) {
1041				/* We didn't read any decpt characters. */
1042				state = S_FRAC;
1043				goto reswitch;
1044			} else {
1045				/*
1046				 * We read part of a multibyte decimal point,
1047				 * but the rest is invalid, so bail.
1048				 */
1049				goto parsedone;
1050			}
1051		case S_FRAC:
1052			if (((c == 'E' || c == 'e') && !ishex) ||
1053			    ((c == 'P' || c == 'p') && ishex)) {
1054				if (!gotmantdig)
1055					goto parsedone;
1056				else
1057					state = S_EXP;
1058			} else if ((ishex && isxdigit(c)) || isdigit(c)) {
1059				commit = p;
1060				gotmantdig = 1;
1061			} else
1062				goto parsedone;
1063			break;
1064		case S_EXP:
1065			state = S_EXPDIGITS;
1066			if (c == '-' || c == '+')
1067				break;
1068			else
1069				goto reswitch;
1070		case S_EXPDIGITS:
1071			if (isdigit(c))
1072				commit = p;
1073			else
1074				goto parsedone;
1075			break;
1076		default:
1077			abort();
1078		}
1079		*p++ = c;
1080		if (--fp->_r > 0)
1081			fp->_p++;
1082		else if (__srefill(fp))
1083			break;	/* EOF */
1084	}
1085
1086parsedone:
1087	while (commit < --p)
1088		__ungetc(*(u_char *)p, fp);
1089	*++commit = '\0';
1090	return (commit - buf);
1091}
1092#endif
1093