vfscanf.c revision 105098
174462Salfred/*-
274462Salfred * Copyright (c) 1990, 1993
3261046Smav *	The Regents of the University of California.  All rights reserved.
4261046Smav *
5261046Smav * This code is derived from software contributed to Berkeley by
68858Srgrimes * Chris Torek.
7261046Smav *
8261046Smav * Redistribution and use in source and binary forms, with or without
9261046Smav * modification, are permitted provided that the following conditions
10261046Smav * are met:
11261046Smav * 1. Redistributions of source code must retain the above copyright
12261046Smav *    notice, this list of conditions and the following disclaimer.
13261046Smav * 2. Redistributions in binary form must reproduce the above copyright
14261046Smav *    notice, this list of conditions and the following disclaimer in the
15261046Smav *    documentation and/or other materials provided with the distribution.
16261046Smav * 3. All advertising materials mentioning features or use of this software
178858Srgrimes *    must display the following acknowledgement:
18261046Smav *	This product includes software developed by the University of
19261046Smav *	California, Berkeley and its contributors.
20261046Smav * 4. Neither the name of the University nor the names of its contributors
21261046Smav *    may be used to endorse or promote products derived from this software
22261046Smav *    without specific prior written permission.
23261046Smav *
24261046Smav * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25261046Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27261046Smav * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28261046Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
298858Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3074462Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311903Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3250473Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331839Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341839Swollman * SUCH DAMAGE.
351839Swollman */
361839Swollman
371839Swollman#if defined(LIBC_SCCS) && !defined(lint)
381839Swollmanstatic char sccsid[] = "@(#)vfscanf.c	8.1 (Berkeley) 6/4/93";
391839Swollman#endif /* LIBC_SCCS and not lint */
401839Swollman#include <sys/cdefs.h>
411839Swollman__FBSDID("$FreeBSD: head/lib/libc/stdio/vfscanf.c 105098 2002-10-14 11:18:21Z tjr $");
421839Swollman
431839Swollman#include "namespace.h"
441839Swollman#include <ctype.h>
451839Swollman#include <inttypes.h>
461839Swollman#include <stdio.h>
471839Swollman#include <stdlib.h>
481839Swollman#include <stddef.h>
491839Swollman#include <stdarg.h>
501839Swollman#include <string.h>
511839Swollman#include <wchar.h>
521839Swollman#include <wctype.h>
531839Swollman#include "un-namespace.h"
541839Swollman
551839Swollman#include "collate.h"
561839Swollman#include "libc_private.h"
571839Swollman#include "local.h"
581839Swollman
591839Swollman#define FLOATING_POINT
601839Swollman
611839Swollman#ifdef FLOATING_POINT
621839Swollman#include <locale.h>
631839Swollman#include "floatio.h"
641839Swollman#endif
651839Swollman
661839Swollman#define	BUF		513	/* Maximum length of numeric string. */
671839Swollman
681839Swollman/*
691839Swollman * Flags used during conversion.
701839Swollman */
711839Swollman#define	LONG		0x01	/* l: long or double */
7274462Salfred#define	LONGDBL		0x02	/* L: long double */
7374462Salfred#define	SHORT		0x04	/* h: short */
741903Swollman#define	SUPPRESS	0x08	/* *: suppress assignment */
751903Swollman#define	POINTER		0x10	/* p: void * (as hex) */
761839Swollman#define	NOSKIP		0x20	/* [ or c: do not skip blanks */
771839Swollman#define	LONGLONG	0x400	/* ll: long long (+ deprecated q: quad) */
781839Swollman#define	INTMAXT		0x800	/* j: intmax_t */
791839Swollman#define	PTRDIFFT	0x1000	/* t: ptrdiff_t */
801839Swollman#define	SIZET		0x2000	/* z: size_t */
811839Swollman#define	SHORTSHORT	0x4000	/* hh: char */
821839Swollman#define	UNSIGNED	0x8000	/* %[oupxX] conversions */
831839Swollman
841839Swollman/*
851839Swollman * The following are used in numeric conversions only:
861839Swollman * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
871839Swollman * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
881839Swollman */
891839Swollman#define	SIGNOK		0x40	/* +/- is (still) legal */
901839Swollman#define	NDIGITS		0x80	/* no digits detected */
911839Swollman
921839Swollman#define	DPTOK		0x100	/* (float) decimal point is still legal */
931839Swollman#define	EXPOK		0x200	/* (float) exponent (e+3, etc) still legal */
941839Swollman
951839Swollman#define	PFXOK		0x100	/* 0x prefix is (still) legal */
961839Swollman#define	NZDIGITS	0x200	/* no zero digits detected */
971839Swollman
981839Swollman/*
991839Swollman * Conversion types.
1001903Swollman */
10193032Simp#define	CT_CHAR		0	/* %c conversion */
10293032Simp#define	CT_CCL		1	/* %[...] conversion */
10393032Simp#define	CT_STRING	2	/* %s conversion */
1041903Swollman#define	CT_INT		3	/* %[dioupxX] conversion */
1051903Swollman#define	CT_FLOAT	4	/* %[efgEFG] conversion */
10674462Salfred
107static const u_char *__sccl(char *, const u_char *);
108
109__weak_reference(__vfscanf, vfscanf);
110
111/*
112 * __vfscanf - MT-safe version
113 */
114int
115__vfscanf(FILE *fp, char const *fmt0, va_list ap)
116{
117	int ret;
118
119	FLOCKFILE(fp);
120	ret = __svfscanf(fp, fmt0, ap);
121	FUNLOCKFILE(fp);
122	return (ret);
123}
124
125/*
126 * __svfscanf - non-MT-safe version of __vfscanf
127 */
128int
129__svfscanf(FILE *fp, const char *fmt0, va_list ap)
130{
131	const u_char *fmt = (const u_char *)fmt0;
132	int c;			/* character from format, or conversion */
133	size_t width;		/* field width, or 0 */
134	char *p;		/* points into all kinds of strings */
135	int n;			/* handy integer */
136	int flags;		/* flags as defined above */
137	char *p0;		/* saves original value of p when necessary */
138	int nassigned;		/* number of fields assigned */
139	int nconversions;	/* number of conversions */
140	int nread;		/* number of characters consumed from fp */
141	int base;		/* base argument to conversion function */
142	char ccltab[256];	/* character class table for %[...] */
143	char buf[BUF];		/* buffer for numeric and mb conversions */
144	wchar_t *wcp;		/* handy wide character pointer */
145	wchar_t *wcp0;		/* saves original value of wcp */
146	mbstate_t mbs;		/* multibyte conversion state */
147	size_t nconv;		/* length of multibyte sequence converted */
148
149	/* `basefix' is used to avoid `if' tests in the integer scanner */
150	static short basefix[17] =
151		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
152#ifdef FLOATING_POINT
153	char decimal_point = localeconv()->decimal_point[0];
154#endif
155
156	ORIENT(fp, -1);
157
158	nassigned = 0;
159	nconversions = 0;
160	nread = 0;
161	for (;;) {
162		c = *fmt++;
163		if (c == 0)
164			return (nassigned);
165		if (isspace(c)) {
166			while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p))
167				nread++, fp->_r--, fp->_p++;
168			continue;
169		}
170		if (c != '%')
171			goto literal;
172		width = 0;
173		flags = 0;
174		/*
175		 * switch on the format.  continue if done;
176		 * break once format type is derived.
177		 */
178again:		c = *fmt++;
179		switch (c) {
180		case '%':
181literal:
182			if (fp->_r <= 0 && __srefill(fp))
183				goto input_failure;
184			if (*fp->_p != c)
185				goto match_failure;
186			fp->_r--, fp->_p++;
187			nread++;
188			continue;
189
190		case '*':
191			flags |= SUPPRESS;
192			goto again;
193		case 'j':
194			flags |= INTMAXT;
195			goto again;
196		case 'l':
197			if (flags & LONG) {
198				flags &= ~LONG;
199				flags |= LONGLONG;
200			} else
201				flags |= LONG;
202			goto again;
203		case 'q':
204			flags |= LONGLONG;	/* not quite */
205			goto again;
206		case 't':
207			flags |= PTRDIFFT;
208			goto again;
209		case 'z':
210			flags |= SIZET;
211			goto again;
212		case 'L':
213			flags |= LONGDBL;
214			goto again;
215		case 'h':
216			if (flags & SHORT) {
217				flags &= ~SHORT;
218				flags |= SHORTSHORT;
219			} else
220				flags |= SHORT;
221			goto again;
222
223		case '0': case '1': case '2': case '3': case '4':
224		case '5': case '6': case '7': case '8': case '9':
225			width = width * 10 + c - '0';
226			goto again;
227
228		/*
229		 * Conversions.
230		 */
231		case 'd':
232			c = CT_INT;
233			base = 10;
234			break;
235
236		case 'i':
237			c = CT_INT;
238			base = 0;
239			break;
240
241		case 'o':
242			c = CT_INT;
243			flags |= UNSIGNED;
244			base = 8;
245			break;
246
247		case 'u':
248			c = CT_INT;
249			flags |= UNSIGNED;
250			base = 10;
251			break;
252
253		case 'X':
254		case 'x':
255			flags |= PFXOK;	/* enable 0x prefixing */
256			c = CT_INT;
257			flags |= UNSIGNED;
258			base = 16;
259			break;
260
261#ifdef FLOATING_POINT
262		case 'E': case 'F': case 'G':
263		case 'e': case 'f': case 'g':
264			c = CT_FLOAT;
265			break;
266#endif
267
268		case 'S':
269			flags |= LONG;
270			/* FALLTHROUGH */
271		case 's':
272			c = CT_STRING;
273			break;
274
275		case '[':
276			fmt = __sccl(ccltab, fmt);
277			flags |= NOSKIP;
278			c = CT_CCL;
279			break;
280
281		case 'C':
282			flags |= LONG;
283			/* FALLTHROUGH */
284		case 'c':
285			flags |= NOSKIP;
286			c = CT_CHAR;
287			break;
288
289		case 'p':	/* pointer format is like hex */
290			flags |= POINTER | PFXOK;
291			c = CT_INT;		/* assumes sizeof(uintmax_t) */
292			flags |= UNSIGNED;	/*      >= sizeof(uintptr_t) */
293			base = 16;
294			break;
295
296		case 'n':
297			nconversions++;
298			if (flags & SUPPRESS)	/* ??? */
299				continue;
300			if (flags & SHORTSHORT)
301				*va_arg(ap, char *) = nread;
302			else if (flags & SHORT)
303				*va_arg(ap, short *) = nread;
304			else if (flags & LONG)
305				*va_arg(ap, long *) = nread;
306			else if (flags & LONGLONG)
307				*va_arg(ap, long long *) = nread;
308			else if (flags & INTMAXT)
309				*va_arg(ap, intmax_t *) = nread;
310			else if (flags & SIZET)
311				*va_arg(ap, size_t *) = nread;
312			else if (flags & PTRDIFFT)
313				*va_arg(ap, ptrdiff_t *) = nread;
314			else
315				*va_arg(ap, int *) = nread;
316			continue;
317
318		default:
319			goto match_failure;
320
321		/*
322		 * Disgusting backwards compatibility hack.	XXX
323		 */
324		case '\0':	/* compat */
325			return (EOF);
326		}
327
328		/*
329		 * We have a conversion that requires input.
330		 */
331		if (fp->_r <= 0 && __srefill(fp))
332			goto input_failure;
333
334		/*
335		 * Consume leading white space, except for formats
336		 * that suppress this.
337		 */
338		if ((flags & NOSKIP) == 0) {
339			while (isspace(*fp->_p)) {
340				nread++;
341				if (--fp->_r > 0)
342					fp->_p++;
343				else if (__srefill(fp))
344					goto input_failure;
345			}
346			/*
347			 * Note that there is at least one character in
348			 * the buffer, so conversions that do not set NOSKIP
349			 * ca no longer result in an input failure.
350			 */
351		}
352
353		/*
354		 * Do the conversion.
355		 */
356		switch (c) {
357
358		case CT_CHAR:
359			/* scan arbitrary characters (sets NOSKIP) */
360			if (width == 0)
361				width = 1;
362			if (flags & SUPPRESS) {
363				size_t sum = 0;
364				for (;;) {
365					if ((n = fp->_r) < width) {
366						sum += n;
367						width -= n;
368						fp->_p += n;
369						if (__srefill(fp)) {
370							if (sum == 0)
371							    goto input_failure;
372							break;
373						}
374					} else {
375						sum += width;
376						fp->_r -= width;
377						fp->_p += width;
378						break;
379					}
380				}
381				nread += sum;
382			} else if (flags & LONG) {
383				wcp = va_arg(ap, wchar_t *);
384				n = 0;
385				while (width != 0) {
386					if (n == MB_CUR_MAX)
387						goto input_failure;
388					buf[n++] = *fp->_p;
389					fp->_p++;
390					fp->_r--;
391					memset(&mbs, 0, sizeof(mbs));
392					nconv = mbrtowc(wcp, buf, n, &mbs);
393					if (nconv == 0 || nconv == (size_t)-1)
394						goto input_failure;
395					if (nconv != (size_t)-2) {
396						nread += n;
397						width--;
398						wcp++;
399						n = 0;
400					}
401					if (fp->_r <= 0 && __srefill(fp)) {
402						if (n != 0)
403							goto input_failure;
404						break;
405					}
406				}
407				nassigned++;
408			} else {
409				size_t r = fread((void *)va_arg(ap, char *), 1,
410				    width, fp);
411
412				if (r == 0)
413					goto input_failure;
414				nread += r;
415				nassigned++;
416			}
417			nconversions++;
418			break;
419
420		case CT_CCL:
421			/* scan a (nonempty) character class (sets NOSKIP) */
422			if (width == 0)
423				width = (size_t)~0;	/* `infinity' */
424			/* take only those things in the class */
425			if (flags & SUPPRESS) {
426				n = 0;
427				while (ccltab[*fp->_p]) {
428					n++, fp->_r--, fp->_p++;
429					if (--width == 0)
430						break;
431					if (fp->_r <= 0 && __srefill(fp)) {
432						if (n == 0)
433							goto input_failure;
434						break;
435					}
436				}
437				if (n == 0)
438					goto match_failure;
439			} else if (flags & LONG) {
440				wcp = wcp0 = va_arg(ap, wchar_t *);
441				n = 0;
442				while (width != 0) {
443					if (n == MB_CUR_MAX)
444						goto input_failure;
445					buf[n++] = *fp->_p;
446					fp->_p++;
447					fp->_r--;
448					memset(&mbs, 0, sizeof(mbs));
449					nconv = mbrtowc(wcp, buf, n, &mbs);
450					if (nconv == 0 || nconv == (size_t)-1)
451						goto input_failure;
452					if (nconv != (size_t)-2) {
453						if (wctob(*wcp) != EOF &&
454						    !ccltab[wctob(*wcp)]) {
455							while (--n > 0)
456								__ungetc(buf[n],
457								    fp);
458							break;
459						}
460						nread += n;
461						width--;
462						wcp++;
463						n = 0;
464					}
465					if (fp->_r <= 0 && __srefill(fp)) {
466						if (n != 0)
467							goto input_failure;
468						break;
469					}
470				}
471				if (n != 0)
472					goto input_failure;
473				n = wcp - wcp0;
474				if (n == 0)
475					goto match_failure;
476				*wcp = L'\0';
477				nassigned++;
478			} else {
479				p0 = p = va_arg(ap, char *);
480				while (ccltab[*fp->_p]) {
481					fp->_r--;
482					*p++ = *fp->_p++;
483					if (--width == 0)
484						break;
485					if (fp->_r <= 0 && __srefill(fp)) {
486						if (p == p0)
487							goto input_failure;
488						break;
489					}
490				}
491				n = p - p0;
492				if (n == 0)
493					goto match_failure;
494				*p = 0;
495				nassigned++;
496			}
497			nread += n;
498			nconversions++;
499			break;
500
501		case CT_STRING:
502			/* like CCL, but zero-length string OK, & no NOSKIP */
503			if (width == 0)
504				width = (size_t)~0;
505			if (flags & SUPPRESS) {
506				n = 0;
507				while (!isspace(*fp->_p)) {
508					n++, fp->_r--, fp->_p++;
509					if (--width == 0)
510						break;
511					if (fp->_r <= 0 && __srefill(fp))
512						break;
513				}
514				nread += n;
515			} else if (flags & LONG) {
516				wcp = va_arg(ap, wchar_t *);
517				n = 0;
518				while (!isspace(*fp->_p) && width != 0) {
519					if (n == MB_CUR_MAX)
520						goto input_failure;
521					buf[n++] = *fp->_p;
522					fp->_p++;
523					fp->_r--;
524					memset(&mbs, 0, sizeof(mbs));
525					nconv = mbrtowc(wcp, buf, n, &mbs);
526					if (nconv == 0 || nconv == (size_t)-1)
527						goto input_failure;
528					if (nconv != (size_t)-2) {
529						if (iswspace(*wcp)) {
530							while (--n > 0)
531								__ungetc(buf[n],
532								    fp);
533							break;
534						}
535						nread += n;
536						width--;
537						wcp++;
538						n = 0;
539					}
540					if (fp->_r <= 0 && __srefill(fp)) {
541						if (n != 0)
542							goto input_failure;
543						break;
544					}
545				}
546				*wcp = L'\0';
547				nassigned++;
548			} else {
549				p0 = p = va_arg(ap, char *);
550				while (!isspace(*fp->_p)) {
551					fp->_r--;
552					*p++ = *fp->_p++;
553					if (--width == 0)
554						break;
555					if (fp->_r <= 0 && __srefill(fp))
556						break;
557				}
558				*p = 0;
559				nread += p - p0;
560				nassigned++;
561			}
562			nconversions++;
563			continue;
564
565		case CT_INT:
566			/* scan an integer as if by the conversion function */
567#ifdef hardway
568			if (width == 0 || width > sizeof(buf) - 1)
569				width = sizeof(buf) - 1;
570#else
571			/* size_t is unsigned, hence this optimisation */
572			if (--width > sizeof(buf) - 2)
573				width = sizeof(buf) - 2;
574			width++;
575#endif
576			flags |= SIGNOK | NDIGITS | NZDIGITS;
577			for (p = buf; width; width--) {
578				c = *fp->_p;
579				/*
580				 * Switch on the character; `goto ok'
581				 * if we accept it as a part of number.
582				 */
583				switch (c) {
584
585				/*
586				 * The digit 0 is always legal, but is
587				 * special.  For %i conversions, if no
588				 * digits (zero or nonzero) have been
589				 * scanned (only signs), we will have
590				 * base==0.  In that case, we should set
591				 * it to 8 and enable 0x prefixing.
592				 * Also, if we have not scanned zero digits
593				 * before this, do not turn off prefixing
594				 * (someone else will turn it off if we
595				 * have scanned any nonzero digits).
596				 */
597				case '0':
598					if (base == 0) {
599						base = 8;
600						flags |= PFXOK;
601					}
602					if (flags & NZDIGITS)
603					    flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
604					else
605					    flags &= ~(SIGNOK|PFXOK|NDIGITS);
606					goto ok;
607
608				/* 1 through 7 always legal */
609				case '1': case '2': case '3':
610				case '4': case '5': case '6': case '7':
611					base = basefix[base];
612					flags &= ~(SIGNOK | PFXOK | NDIGITS);
613					goto ok;
614
615				/* digits 8 and 9 ok iff decimal or hex */
616				case '8': case '9':
617					base = basefix[base];
618					if (base <= 8)
619						break;	/* not legal here */
620					flags &= ~(SIGNOK | PFXOK | NDIGITS);
621					goto ok;
622
623				/* letters ok iff hex */
624				case 'A': case 'B': case 'C':
625				case 'D': case 'E': case 'F':
626				case 'a': case 'b': case 'c':
627				case 'd': case 'e': case 'f':
628					/* no need to fix base here */
629					if (base <= 10)
630						break;	/* not legal here */
631					flags &= ~(SIGNOK | PFXOK | NDIGITS);
632					goto ok;
633
634				/* sign ok only as first character */
635				case '+': case '-':
636					if (flags & SIGNOK) {
637						flags &= ~SIGNOK;
638						goto ok;
639					}
640					break;
641
642				/* x ok iff flag still set & 2nd char */
643				case 'x': case 'X':
644					if (flags & PFXOK && p == buf + 1) {
645						base = 16;	/* if %i */
646						flags &= ~PFXOK;
647						goto ok;
648					}
649					break;
650				}
651
652				/*
653				 * If we got here, c is not a legal character
654				 * for a number.  Stop accumulating digits.
655				 */
656				break;
657		ok:
658				/*
659				 * c is legal: store it and look at the next.
660				 */
661				*p++ = c;
662				if (--fp->_r > 0)
663					fp->_p++;
664				else if (__srefill(fp))
665					break;		/* EOF */
666			}
667			/*
668			 * If we had only a sign, it is no good; push
669			 * back the sign.  If the number ends in `x',
670			 * it was [sign] '0' 'x', so push back the x
671			 * and treat it as [sign] '0'.
672			 */
673			if (flags & NDIGITS) {
674				if (p > buf)
675					(void) __ungetc(*(u_char *)--p, fp);
676				goto match_failure;
677			}
678			c = ((u_char *)p)[-1];
679			if (c == 'x' || c == 'X') {
680				--p;
681				(void) __ungetc(c, fp);
682			}
683			if ((flags & SUPPRESS) == 0) {
684				uintmax_t res;
685
686				*p = 0;
687				if ((flags & UNSIGNED) == 0)
688				    res = strtoimax(buf, (char **)NULL, base);
689				else
690				    res = strtoumax(buf, (char **)NULL, base);
691				if (flags & POINTER)
692					*va_arg(ap, void **) =
693							(void *)(uintptr_t)res;
694				else if (flags & SHORTSHORT)
695					*va_arg(ap, char *) = res;
696				else if (flags & SHORT)
697					*va_arg(ap, short *) = res;
698				else if (flags & LONG)
699					*va_arg(ap, long *) = res;
700				else if (flags & LONGLONG)
701					*va_arg(ap, long long *) = res;
702				else if (flags & INTMAXT)
703					*va_arg(ap, intmax_t *) = res;
704				else if (flags & PTRDIFFT)
705					*va_arg(ap, ptrdiff_t *) = res;
706				else if (flags & SIZET)
707					*va_arg(ap, size_t *) = res;
708				else
709					*va_arg(ap, int *) = res;
710				nassigned++;
711			}
712			nread += p - buf;
713			nconversions++;
714			break;
715
716#ifdef FLOATING_POINT
717		case CT_FLOAT:
718			/* scan a floating point number as if by strtod */
719#ifdef hardway
720			if (width == 0 || width > sizeof(buf) - 1)
721				width = sizeof(buf) - 1;
722#else
723			/* size_t is unsigned, hence this optimisation */
724			if (--width > sizeof(buf) - 2)
725				width = sizeof(buf) - 2;
726			width++;
727#endif
728			flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
729			for (p = buf; width; width--) {
730				c = *fp->_p;
731				/*
732				 * This code mimicks the integer conversion
733				 * code, but is much simpler.
734				 */
735				switch (c) {
736
737				case '0': case '1': case '2': case '3':
738				case '4': case '5': case '6': case '7':
739				case '8': case '9':
740					flags &= ~(SIGNOK | NDIGITS);
741					goto fok;
742
743				case '+': case '-':
744					if (flags & SIGNOK) {
745						flags &= ~SIGNOK;
746						goto fok;
747					}
748					break;
749				case 'e': case 'E':
750					/* no exponent without some digits */
751					if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
752						flags =
753						    (flags & ~(EXPOK|DPTOK)) |
754						    SIGNOK | NDIGITS;
755						goto fok;
756					}
757					break;
758				default:
759					if ((char)c == decimal_point &&
760					    (flags & DPTOK)) {
761						flags &= ~(SIGNOK | DPTOK);
762						goto fok;
763					}
764					break;
765				}
766				break;
767		fok:
768				*p++ = c;
769				if (--fp->_r > 0)
770					fp->_p++;
771				else if (__srefill(fp))
772					break;	/* EOF */
773			}
774			/*
775			 * If no digits, might be missing exponent digits
776			 * (just give back the exponent) or might be missing
777			 * regular digits, but had sign and/or decimal point.
778			 */
779			if (flags & NDIGITS) {
780				if (flags & EXPOK) {
781					/* no digits at all */
782					while (p > buf)
783						__ungetc(*(u_char *)--p, fp);
784					goto match_failure;
785				}
786				/* just a bad exponent (e and maybe sign) */
787				c = *(u_char *)--p;
788				if (c != 'e' && c != 'E') {
789					(void) __ungetc(c, fp);/* sign */
790					c = *(u_char *)--p;
791				}
792				(void) __ungetc(c, fp);
793			}
794			if ((flags & SUPPRESS) == 0) {
795				double res;
796
797				*p = 0;
798				/* XXX this loses precision for long doubles. */
799				res = strtod(buf, (char **) NULL);
800				if (flags & LONGDBL)
801					*va_arg(ap, long double *) = res;
802				else if (flags & LONG)
803					*va_arg(ap, double *) = res;
804				else
805					*va_arg(ap, float *) = res;
806				nassigned++;
807			}
808			nread += p - buf;
809			nconversions++;
810			break;
811#endif /* FLOATING_POINT */
812		}
813	}
814input_failure:
815	return (nconversions != 0 ? nassigned : EOF);
816match_failure:
817	return (nassigned);
818}
819
820/*
821 * Fill in the given table from the scanset at the given format
822 * (just after `[').  Return a pointer to the character past the
823 * closing `]'.  The table has a 1 wherever characters should be
824 * considered part of the scanset.
825 */
826static const u_char *
827__sccl(tab, fmt)
828	char *tab;
829	const u_char *fmt;
830{
831	int c, n, v, i;
832
833	/* first `clear' the whole table */
834	c = *fmt++;		/* first char hat => negated scanset */
835	if (c == '^') {
836		v = 1;		/* default => accept */
837		c = *fmt++;	/* get new first char */
838	} else
839		v = 0;		/* default => reject */
840
841	/* XXX: Will not work if sizeof(tab*) > sizeof(char) */
842	(void) memset(tab, v, 256);
843
844	if (c == 0)
845		return (fmt - 1);/* format ended before closing ] */
846
847	/*
848	 * Now set the entries corresponding to the actual scanset
849	 * to the opposite of the above.
850	 *
851	 * The first character may be ']' (or '-') without being special;
852	 * the last character may be '-'.
853	 */
854	v = 1 - v;
855	for (;;) {
856		tab[c] = v;		/* take character c */
857doswitch:
858		n = *fmt++;		/* and examine the next */
859		switch (n) {
860
861		case 0:			/* format ended too soon */
862			return (fmt - 1);
863
864		case '-':
865			/*
866			 * A scanset of the form
867			 *	[01+-]
868			 * is defined as `the digit 0, the digit 1,
869			 * the character +, the character -', but
870			 * the effect of a scanset such as
871			 *	[a-zA-Z0-9]
872			 * is implementation defined.  The V7 Unix
873			 * scanf treats `a-z' as `the letters a through
874			 * z', but treats `a-a' as `the letter a, the
875			 * character -, and the letter a'.
876			 *
877			 * For compatibility, the `-' is not considerd
878			 * to define a range if the character following
879			 * it is either a close bracket (required by ANSI)
880			 * or is not numerically greater than the character
881			 * we just stored in the table (c).
882			 */
883			n = *fmt;
884			if (n == ']'
885			    || (__collate_load_error ? n < c :
886				__collate_range_cmp (n, c) < 0
887			       )
888			   ) {
889				c = '-';
890				break;	/* resume the for(;;) */
891			}
892			fmt++;
893			/* fill in the range */
894			if (__collate_load_error) {
895				do {
896					tab[++c] = v;
897				} while (c < n);
898			} else {
899				for (i = 0; i < 256; i ++)
900					if (   __collate_range_cmp (c, i) < 0
901					    && __collate_range_cmp (i, n) <= 0
902					   )
903						tab[i] = v;
904			}
905#if 1	/* XXX another disgusting compatibility hack */
906			c = n;
907			/*
908			 * Alas, the V7 Unix scanf also treats formats
909			 * such as [a-c-e] as `the letters a through e'.
910			 * This too is permitted by the standard....
911			 */
912			goto doswitch;
913#else
914			c = *fmt++;
915			if (c == 0)
916				return (fmt - 1);
917			if (c == ']')
918				return (fmt);
919#endif
920			break;
921
922		case ']':		/* end of scanset */
923			return (fmt);
924
925		default:		/* just another character */
926			c = n;
927			break;
928		}
929	}
930	/* NOTREACHED */
931}
932