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