142680Smsmith/*-
242680Smsmith * Copyright (c) 1990, 1993
342680Smsmith *	The Regents of the University of California.  All rights reserved.
442680Smsmith *
542680Smsmith * This code is derived from software contributed to Berkeley by
642680Smsmith * Chris Torek.
742680Smsmith *
842680Smsmith * Redistribution and use in source and binary forms, with or without
942680Smsmith * modification, are permitted provided that the following conditions
1042680Smsmith * are met:
1142680Smsmith * 1. Redistributions of source code must retain the above copyright
1242680Smsmith *    notice, this list of conditions and the following disclaimer.
1342680Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1442680Smsmith *    notice, this list of conditions and the following disclaimer in the
1542680Smsmith *    documentation and/or other materials provided with the distribution.
1642680Smsmith * 4. Neither the name of the University nor the names of its contributors
1742680Smsmith *    may be used to endorse or promote products derived from this software
1842680Smsmith *    without specific prior written permission.
1942680Smsmith *
2042680Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2142680Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2242680Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2342680Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2442680Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2542680Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2642680Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2742680Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2842680Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2942680Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3042680Smsmith * SUCH DAMAGE.
3142680Smsmith *
3242680Smsmith * From: Id: vfscanf.c,v 1.13 1998/09/25 12:20:27 obrien Exp
3352757Sphk * From: static char sccsid[] = "@(#)strtol.c	8.1 (Berkeley) 6/4/93";
3452757Sphk * From: static char sccsid[] = "@(#)strtoul.c	8.1 (Berkeley) 6/4/93";
3542680Smsmith */
3642680Smsmith
37116182Sobrien#include <sys/cdefs.h>
38116182Sobrien__FBSDID("$FreeBSD$");
39116182Sobrien
4042680Smsmith#include <sys/param.h>
4142680Smsmith#include <sys/systm.h>
4252843Sphk#include <sys/ctype.h>
43114216Skan#include <sys/limits.h>
4442680Smsmith
4542680Smsmith/*
4642680Smsmith * Note that stdarg.h and the ANSI style va_start macro is used for both
4742680Smsmith * ANSI and traditional C compilers.
4842680Smsmith */
4942680Smsmith#include <machine/stdarg.h>
5042680Smsmith
5142680Smsmith#define	BUF		32 	/* Maximum length of numeric string. */
5242680Smsmith
5342680Smsmith/*
5442680Smsmith * Flags used during conversion.
5542680Smsmith */
5642680Smsmith#define	LONG		0x01	/* l: long or double */
5742680Smsmith#define	SHORT		0x04	/* h: short */
5842680Smsmith#define	SUPPRESS	0x08	/* suppress assignment */
5942680Smsmith#define	POINTER		0x10	/* weird %p pointer (`fake hex') */
6042680Smsmith#define	NOSKIP		0x20	/* do not skip blanks */
6142680Smsmith#define	QUAD		0x400
62231697Sken#define	SHORTSHORT	0x4000	/** hh: char */
6342680Smsmith
6442680Smsmith/*
6542680Smsmith * The following are used in numeric conversions only:
6642680Smsmith * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
6742680Smsmith * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
6842680Smsmith */
6942680Smsmith#define	SIGNOK		0x40	/* +/- is (still) legal */
7042680Smsmith#define	NDIGITS		0x80	/* no digits detected */
7142680Smsmith
7242680Smsmith#define	DPTOK		0x100	/* (float) decimal point is still legal */
7342680Smsmith#define	EXPOK		0x200	/* (float) exponent (e+3, etc) still legal */
7442680Smsmith
7542680Smsmith#define	PFXOK		0x100	/* 0x prefix is (still) legal */
7642680Smsmith#define	NZDIGITS	0x200	/* no zero digits detected */
7742680Smsmith
7842680Smsmith/*
7942680Smsmith * Conversion types.
8042680Smsmith */
8142680Smsmith#define	CT_CHAR		0	/* %c conversion */
8242680Smsmith#define	CT_CCL		1	/* %[...] conversion */
8342680Smsmith#define	CT_STRING	2	/* %s conversion */
8442680Smsmith#define	CT_INT		3	/* integer, i.e., strtoq or strtouq */
8553648Sarchietypedef u_quad_t (*ccfntype)(const char *, char **, int);
8642680Smsmith
8743300Sdillonstatic const u_char *__sccl(char *, const u_char *);
8842680Smsmith
8942680Smsmithint
9042680Smsmithsscanf(const char *ibuf, const char *fmt, ...)
9142680Smsmith{
9242680Smsmith	va_list ap;
9342680Smsmith	int ret;
9442680Smsmith
9542680Smsmith	va_start(ap, fmt);
9642680Smsmith	ret = vsscanf(ibuf, fmt, ap);
9742680Smsmith	va_end(ap);
9842680Smsmith	return(ret);
9942680Smsmith}
10042680Smsmith
10142680Smsmithint
10242680Smsmithvsscanf(const char *inp, char const *fmt0, va_list ap)
10342680Smsmith{
10442680Smsmith	int inr;
10543300Sdillon	const u_char *fmt = (const u_char *)fmt0;
10642680Smsmith	int c;			/* character from format, or conversion */
10742680Smsmith	size_t width;		/* field width, or 0 */
10842680Smsmith	char *p;		/* points into all kinds of strings */
10942680Smsmith	int n;			/* handy integer */
11042680Smsmith	int flags;		/* flags as defined above */
11142680Smsmith	char *p0;		/* saves original value of p when necessary */
11242680Smsmith	int nassigned;		/* number of fields assigned */
11342680Smsmith	int nconversions;	/* number of conversions */
11442680Smsmith	int nread;		/* number of characters consumed from fp */
11542680Smsmith	int base;		/* base argument to strtoq/strtouq */
11642680Smsmith	ccfntype ccfn;		/* conversion function (strtoq/strtouq) */
11742680Smsmith	char ccltab[256];	/* character class table for %[...] */
11842680Smsmith	char buf[BUF];		/* buffer for numeric conversions */
11942680Smsmith
12042680Smsmith	/* `basefix' is used to avoid `if' tests in the integer scanner */
12142680Smsmith	static short basefix[17] =
12242680Smsmith		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
12342680Smsmith
12442680Smsmith	inr = strlen(inp);
12542680Smsmith
12642680Smsmith	nassigned = 0;
12742680Smsmith	nconversions = 0;
12842680Smsmith	nread = 0;
12942680Smsmith	base = 0;		/* XXX just to keep gcc happy */
13042680Smsmith	ccfn = NULL;		/* XXX just to keep gcc happy */
13142680Smsmith	for (;;) {
13242680Smsmith		c = *fmt++;
13342680Smsmith		if (c == 0)
13442680Smsmith			return (nassigned);
13542680Smsmith		if (isspace(c)) {
13642680Smsmith			while (inr > 0 && isspace(*inp))
13742680Smsmith				nread++, inr--, inp++;
13842680Smsmith			continue;
13942680Smsmith		}
14042680Smsmith		if (c != '%')
14142680Smsmith			goto literal;
14242680Smsmith		width = 0;
14342680Smsmith		flags = 0;
14442680Smsmith		/*
14542680Smsmith		 * switch on the format.  continue if done;
14642680Smsmith		 * break once format type is derived.
14742680Smsmith		 */
14842680Smsmithagain:		c = *fmt++;
14942680Smsmith		switch (c) {
15042680Smsmith		case '%':
15142680Smsmithliteral:
15242680Smsmith			if (inr <= 0)
15342680Smsmith				goto input_failure;
15442680Smsmith			if (*inp != c)
15542680Smsmith				goto match_failure;
15642680Smsmith			inr--, inp++;
15742680Smsmith			nread++;
15842680Smsmith			continue;
15942680Smsmith
16042680Smsmith		case '*':
16142680Smsmith			flags |= SUPPRESS;
16242680Smsmith			goto again;
16342680Smsmith		case 'l':
164231697Sken			if (flags & LONG){
165231697Sken				flags &= ~LONG;
166231697Sken				flags |= QUAD;
167231697Sken			} else {
168231697Sken				flags |= LONG;
169231697Sken			}
17042680Smsmith			goto again;
17142680Smsmith		case 'q':
17242680Smsmith			flags |= QUAD;
17342680Smsmith			goto again;
17442680Smsmith		case 'h':
175231697Sken			if (flags & SHORT){
176231697Sken				flags &= ~SHORT;
177231697Sken				flags |= SHORTSHORT;
178231697Sken			} else {
179231697Sken				flags |= SHORT;
180231697Sken			}
18142680Smsmith			goto again;
18242680Smsmith
18342680Smsmith		case '0': case '1': case '2': case '3': case '4':
18442680Smsmith		case '5': case '6': case '7': case '8': case '9':
18542680Smsmith			width = width * 10 + c - '0';
18642680Smsmith			goto again;
18742680Smsmith
18842680Smsmith		/*
18942680Smsmith		 * Conversions.
19042680Smsmith		 *
19142680Smsmith		 */
19242680Smsmith		case 'd':
19342680Smsmith			c = CT_INT;
19442680Smsmith			ccfn = (ccfntype)strtoq;
19542680Smsmith			base = 10;
19642680Smsmith			break;
19742680Smsmith
19842680Smsmith		case 'i':
19942680Smsmith			c = CT_INT;
20042680Smsmith			ccfn = (ccfntype)strtoq;
20142680Smsmith			base = 0;
20242680Smsmith			break;
20342680Smsmith
20442680Smsmith		case 'o':
20542680Smsmith			c = CT_INT;
20642680Smsmith			ccfn = strtouq;
20742680Smsmith			base = 8;
20842680Smsmith			break;
20942680Smsmith
21042680Smsmith		case 'u':
21142680Smsmith			c = CT_INT;
21242680Smsmith			ccfn = strtouq;
21342680Smsmith			base = 10;
21442680Smsmith			break;
21542680Smsmith
21642680Smsmith		case 'x':
21742680Smsmith			flags |= PFXOK;	/* enable 0x prefixing */
21842680Smsmith			c = CT_INT;
21942680Smsmith			ccfn = strtouq;
22042680Smsmith			base = 16;
22142680Smsmith			break;
22242680Smsmith
22342680Smsmith		case 's':
22442680Smsmith			c = CT_STRING;
22542680Smsmith			break;
22642680Smsmith
22742680Smsmith		case '[':
22842680Smsmith			fmt = __sccl(ccltab, fmt);
22942680Smsmith			flags |= NOSKIP;
23042680Smsmith			c = CT_CCL;
23142680Smsmith			break;
23242680Smsmith
23342680Smsmith		case 'c':
23442680Smsmith			flags |= NOSKIP;
23542680Smsmith			c = CT_CHAR;
23642680Smsmith			break;
23742680Smsmith
23842680Smsmith		case 'p':	/* pointer format is like hex */
23942680Smsmith			flags |= POINTER | PFXOK;
24042680Smsmith			c = CT_INT;
24142680Smsmith			ccfn = strtouq;
24242680Smsmith			base = 16;
24342680Smsmith			break;
24442680Smsmith
24542680Smsmith		case 'n':
24642680Smsmith			nconversions++;
24742680Smsmith			if (flags & SUPPRESS)	/* ??? */
24842680Smsmith				continue;
249231697Sken			if (flags & SHORTSHORT)
250231697Sken				*va_arg(ap, char *) = nread;
251231697Sken			else if (flags & SHORT)
25242680Smsmith				*va_arg(ap, short *) = nread;
25342680Smsmith			else if (flags & LONG)
25442680Smsmith				*va_arg(ap, long *) = nread;
25542680Smsmith			else if (flags & QUAD)
25642680Smsmith				*va_arg(ap, quad_t *) = nread;
25742680Smsmith			else
25842680Smsmith				*va_arg(ap, int *) = nread;
25942680Smsmith			continue;
26042680Smsmith		}
26142680Smsmith
26242680Smsmith		/*
26342680Smsmith		 * We have a conversion that requires input.
26442680Smsmith		 */
26542680Smsmith		if (inr <= 0)
26642680Smsmith			goto input_failure;
26742680Smsmith
26842680Smsmith		/*
26942680Smsmith		 * Consume leading white space, except for formats
27042680Smsmith		 * that suppress this.
27142680Smsmith		 */
27242680Smsmith		if ((flags & NOSKIP) == 0) {
27342680Smsmith			while (isspace(*inp)) {
27442680Smsmith				nread++;
27542680Smsmith				if (--inr > 0)
27642680Smsmith					inp++;
27742680Smsmith				else
27842680Smsmith					goto input_failure;
27942680Smsmith			}
28042680Smsmith			/*
28142680Smsmith			 * Note that there is at least one character in
28242680Smsmith			 * the buffer, so conversions that do not set NOSKIP
28342680Smsmith			 * can no longer result in an input failure.
28442680Smsmith			 */
28542680Smsmith		}
28642680Smsmith
28742680Smsmith		/*
28842680Smsmith		 * Do the conversion.
28942680Smsmith		 */
29042680Smsmith		switch (c) {
29142680Smsmith
29242680Smsmith		case CT_CHAR:
29342680Smsmith			/* scan arbitrary characters (sets NOSKIP) */
29442680Smsmith			if (width == 0)
29542680Smsmith				width = 1;
29642680Smsmith			if (flags & SUPPRESS) {
29742680Smsmith				size_t sum = 0;
29842680Smsmith				for (;;) {
29942680Smsmith					if ((n = inr) < width) {
30042680Smsmith						sum += n;
30142680Smsmith						width -= n;
30242680Smsmith						inp += n;
30342680Smsmith						if (sum == 0)
30442680Smsmith							goto input_failure;
305104363Sphk						break;
30642680Smsmith					} else {
30742680Smsmith						sum += width;
30842680Smsmith						inr -= width;
30942680Smsmith						inp += width;
31042680Smsmith						break;
31142680Smsmith					}
31242680Smsmith				}
31342680Smsmith				nread += sum;
31442680Smsmith			} else {
31542680Smsmith				bcopy(inp, va_arg(ap, char *), width);
31642680Smsmith				inr -= width;
31742680Smsmith				inp += width;
31842680Smsmith				nread += width;
31942680Smsmith				nassigned++;
32042680Smsmith			}
32142680Smsmith			nconversions++;
32242680Smsmith			break;
32342680Smsmith
32442680Smsmith		case CT_CCL:
32542680Smsmith			/* scan a (nonempty) character class (sets NOSKIP) */
32642680Smsmith			if (width == 0)
32742680Smsmith				width = (size_t)~0;	/* `infinity' */
32842680Smsmith			/* take only those things in the class */
32942680Smsmith			if (flags & SUPPRESS) {
33042680Smsmith				n = 0;
33144016Sdillon				while (ccltab[(unsigned char)*inp]) {
33242680Smsmith					n++, inr--, inp++;
33342680Smsmith					if (--width == 0)
33442680Smsmith						break;
33542680Smsmith					if (inr <= 0) {
33642680Smsmith						if (n == 0)
33742680Smsmith							goto input_failure;
33842680Smsmith						break;
33942680Smsmith					}
34042680Smsmith				}
34142680Smsmith				if (n == 0)
34242680Smsmith					goto match_failure;
34342680Smsmith			} else {
34442680Smsmith				p0 = p = va_arg(ap, char *);
34544016Sdillon				while (ccltab[(unsigned char)*inp]) {
34642680Smsmith					inr--;
34742680Smsmith					*p++ = *inp++;
34842680Smsmith					if (--width == 0)
34942680Smsmith						break;
35042680Smsmith					if (inr <= 0) {
35142680Smsmith						if (p == p0)
35242680Smsmith							goto input_failure;
35342680Smsmith						break;
35442680Smsmith					}
35542680Smsmith				}
35642680Smsmith				n = p - p0;
35742680Smsmith				if (n == 0)
35842680Smsmith					goto match_failure;
35942680Smsmith				*p = 0;
36042680Smsmith				nassigned++;
36142680Smsmith			}
36242680Smsmith			nread += n;
36342680Smsmith			nconversions++;
36442680Smsmith			break;
36542680Smsmith
36642680Smsmith		case CT_STRING:
36742680Smsmith			/* like CCL, but zero-length string OK, & no NOSKIP */
36842680Smsmith			if (width == 0)
36942680Smsmith				width = (size_t)~0;
37042680Smsmith			if (flags & SUPPRESS) {
37142680Smsmith				n = 0;
37242680Smsmith				while (!isspace(*inp)) {
37342680Smsmith					n++, inr--, inp++;
37442680Smsmith					if (--width == 0)
37542680Smsmith						break;
37642680Smsmith					if (inr <= 0)
37742680Smsmith						break;
37842680Smsmith				}
37942680Smsmith				nread += n;
38042680Smsmith			} else {
38142680Smsmith				p0 = p = va_arg(ap, char *);
38242680Smsmith				while (!isspace(*inp)) {
38342680Smsmith					inr--;
38442680Smsmith					*p++ = *inp++;
38542680Smsmith					if (--width == 0)
38642680Smsmith						break;
38742680Smsmith					if (inr <= 0)
38842680Smsmith						break;
38942680Smsmith				}
39042680Smsmith				*p = 0;
39142680Smsmith				nread += p - p0;
39242680Smsmith				nassigned++;
39342680Smsmith			}
39442680Smsmith			nconversions++;
39542680Smsmith			continue;
39642680Smsmith
39742680Smsmith		case CT_INT:
39842680Smsmith			/* scan an integer as if by strtoq/strtouq */
39942680Smsmith#ifdef hardway
40042680Smsmith			if (width == 0 || width > sizeof(buf) - 1)
40142680Smsmith				width = sizeof(buf) - 1;
40242680Smsmith#else
40342680Smsmith			/* size_t is unsigned, hence this optimisation */
40442680Smsmith			if (--width > sizeof(buf) - 2)
40542680Smsmith				width = sizeof(buf) - 2;
40642680Smsmith			width++;
40742680Smsmith#endif
40842680Smsmith			flags |= SIGNOK | NDIGITS | NZDIGITS;
40942680Smsmith			for (p = buf; width; width--) {
41042680Smsmith				c = *inp;
41142680Smsmith				/*
41242680Smsmith				 * Switch on the character; `goto ok'
41342680Smsmith				 * if we accept it as a part of number.
41442680Smsmith				 */
41542680Smsmith				switch (c) {
41642680Smsmith
41742680Smsmith				/*
41842680Smsmith				 * The digit 0 is always legal, but is
41942680Smsmith				 * special.  For %i conversions, if no
42042680Smsmith				 * digits (zero or nonzero) have been
42142680Smsmith				 * scanned (only signs), we will have
42242680Smsmith				 * base==0.  In that case, we should set
42342680Smsmith				 * it to 8 and enable 0x prefixing.
42442680Smsmith				 * Also, if we have not scanned zero digits
42542680Smsmith				 * before this, do not turn off prefixing
42642680Smsmith				 * (someone else will turn it off if we
42742680Smsmith				 * have scanned any nonzero digits).
42842680Smsmith				 */
42942680Smsmith				case '0':
43042680Smsmith					if (base == 0) {
43142680Smsmith						base = 8;
43242680Smsmith						flags |= PFXOK;
43342680Smsmith					}
43442680Smsmith					if (flags & NZDIGITS)
43542680Smsmith					    flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
43642680Smsmith					else
43742680Smsmith					    flags &= ~(SIGNOK|PFXOK|NDIGITS);
43842680Smsmith					goto ok;
43942680Smsmith
44042680Smsmith				/* 1 through 7 always legal */
44142680Smsmith				case '1': case '2': case '3':
44242680Smsmith				case '4': case '5': case '6': case '7':
44342680Smsmith					base = basefix[base];
44442680Smsmith					flags &= ~(SIGNOK | PFXOK | NDIGITS);
44542680Smsmith					goto ok;
44642680Smsmith
44742680Smsmith				/* digits 8 and 9 ok iff decimal or hex */
44842680Smsmith				case '8': case '9':
44942680Smsmith					base = basefix[base];
45042680Smsmith					if (base <= 8)
45142680Smsmith						break;	/* not legal here */
45242680Smsmith					flags &= ~(SIGNOK | PFXOK | NDIGITS);
45342680Smsmith					goto ok;
45442680Smsmith
45542680Smsmith				/* letters ok iff hex */
45642680Smsmith				case 'A': case 'B': case 'C':
45742680Smsmith				case 'D': case 'E': case 'F':
45842680Smsmith				case 'a': case 'b': case 'c':
45942680Smsmith				case 'd': case 'e': case 'f':
46042680Smsmith					/* no need to fix base here */
46142680Smsmith					if (base <= 10)
46242680Smsmith						break;	/* not legal here */
46342680Smsmith					flags &= ~(SIGNOK | PFXOK | NDIGITS);
46442680Smsmith					goto ok;
46542680Smsmith
46642680Smsmith				/* sign ok only as first character */
46742680Smsmith				case '+': case '-':
46842680Smsmith					if (flags & SIGNOK) {
46942680Smsmith						flags &= ~SIGNOK;
47042680Smsmith						goto ok;
47142680Smsmith					}
47242680Smsmith					break;
47342680Smsmith
47442680Smsmith				/* x ok iff flag still set & 2nd char */
47542680Smsmith				case 'x': case 'X':
47642680Smsmith					if (flags & PFXOK && p == buf + 1) {
47742680Smsmith						base = 16;	/* if %i */
47842680Smsmith						flags &= ~PFXOK;
47942680Smsmith						goto ok;
48042680Smsmith					}
48142680Smsmith					break;
48242680Smsmith				}
48342680Smsmith
48442680Smsmith				/*
48542680Smsmith				 * If we got here, c is not a legal character
48642680Smsmith				 * for a number.  Stop accumulating digits.
48742680Smsmith				 */
48842680Smsmith				break;
48942680Smsmith		ok:
49042680Smsmith				/*
49142680Smsmith				 * c is legal: store it and look at the next.
49242680Smsmith				 */
49342680Smsmith				*p++ = c;
49442680Smsmith				if (--inr > 0)
49542680Smsmith					inp++;
49642680Smsmith				else
49742680Smsmith					break;		/* end of input */
49842680Smsmith			}
49942680Smsmith			/*
50042680Smsmith			 * If we had only a sign, it is no good; push
50142680Smsmith			 * back the sign.  If the number ends in `x',
50242680Smsmith			 * it was [sign] '0' 'x', so push back the x
50342680Smsmith			 * and treat it as [sign] '0'.
50442680Smsmith			 */
50542680Smsmith			if (flags & NDIGITS) {
50642680Smsmith				if (p > buf) {
50742680Smsmith					inp--;
50842680Smsmith					inr++;
50942680Smsmith				}
51042680Smsmith				goto match_failure;
51142680Smsmith			}
51242680Smsmith			c = ((u_char *)p)[-1];
51342680Smsmith			if (c == 'x' || c == 'X') {
51442680Smsmith				--p;
51542680Smsmith				inp--;
51642680Smsmith				inr++;
51742680Smsmith			}
51842680Smsmith			if ((flags & SUPPRESS) == 0) {
51942680Smsmith				u_quad_t res;
52042680Smsmith
52142680Smsmith				*p = 0;
52253648Sarchie				res = (*ccfn)(buf, (char **)NULL, base);
52342680Smsmith				if (flags & POINTER)
52442680Smsmith					*va_arg(ap, void **) =
52550275Sbde						(void *)(uintptr_t)res;
526231697Sken				else if (flags & SHORTSHORT)
527231697Sken					*va_arg(ap, char *) = res;
52842680Smsmith				else if (flags & SHORT)
52942680Smsmith					*va_arg(ap, short *) = res;
53042680Smsmith				else if (flags & LONG)
53142680Smsmith					*va_arg(ap, long *) = res;
53242680Smsmith				else if (flags & QUAD)
53342680Smsmith					*va_arg(ap, quad_t *) = res;
53442680Smsmith				else
53542680Smsmith					*va_arg(ap, int *) = res;
53642680Smsmith				nassigned++;
53742680Smsmith			}
53842680Smsmith			nread += p - buf;
53942680Smsmith			nconversions++;
54042680Smsmith			break;
54142680Smsmith
54242680Smsmith		}
54342680Smsmith	}
54442680Smsmithinput_failure:
54542680Smsmith	return (nconversions != 0 ? nassigned : -1);
54642680Smsmithmatch_failure:
54742680Smsmith	return (nassigned);
54842680Smsmith}
54942680Smsmith
55042680Smsmith/*
55142680Smsmith * Fill in the given table from the scanset at the given format
55242680Smsmith * (just after `[').  Return a pointer to the character past the
55342680Smsmith * closing `]'.  The table has a 1 wherever characters should be
55442680Smsmith * considered part of the scanset.
55542680Smsmith */
55643300Sdillonstatic const u_char *
55743300Sdillon__sccl(char *tab, const u_char *fmt)
55842680Smsmith{
55942680Smsmith	int c, n, v;
56042680Smsmith
56142680Smsmith	/* first `clear' the whole table */
56242680Smsmith	c = *fmt++;		/* first char hat => negated scanset */
56342680Smsmith	if (c == '^') {
56442680Smsmith		v = 1;		/* default => accept */
56542680Smsmith		c = *fmt++;	/* get new first char */
56642680Smsmith	} else
56742680Smsmith		v = 0;		/* default => reject */
56842680Smsmith
56942680Smsmith	/* XXX: Will not work if sizeof(tab*) > sizeof(char) */
57042680Smsmith	for (n = 0; n < 256; n++)
57142680Smsmith		     tab[n] = v;	/* memset(tab, v, 256) */
57242680Smsmith
57342680Smsmith	if (c == 0)
57442680Smsmith		return (fmt - 1);/* format ended before closing ] */
57542680Smsmith
57642680Smsmith	/*
57742680Smsmith	 * Now set the entries corresponding to the actual scanset
57842680Smsmith	 * to the opposite of the above.
57942680Smsmith	 *
58042680Smsmith	 * The first character may be ']' (or '-') without being special;
58142680Smsmith	 * the last character may be '-'.
58242680Smsmith	 */
58342680Smsmith	v = 1 - v;
58442680Smsmith	for (;;) {
58542680Smsmith		tab[c] = v;		/* take character c */
58642680Smsmithdoswitch:
58742680Smsmith		n = *fmt++;		/* and examine the next */
58842680Smsmith		switch (n) {
58942680Smsmith
59042680Smsmith		case 0:			/* format ended too soon */
59142680Smsmith			return (fmt - 1);
59242680Smsmith
59342680Smsmith		case '-':
59442680Smsmith			/*
59542680Smsmith			 * A scanset of the form
59642680Smsmith			 *	[01+-]
59742680Smsmith			 * is defined as `the digit 0, the digit 1,
59842680Smsmith			 * the character +, the character -', but
59942680Smsmith			 * the effect of a scanset such as
60042680Smsmith			 *	[a-zA-Z0-9]
60142680Smsmith			 * is implementation defined.  The V7 Unix
60242680Smsmith			 * scanf treats `a-z' as `the letters a through
60342680Smsmith			 * z', but treats `a-a' as `the letter a, the
60442680Smsmith			 * character -, and the letter a'.
60542680Smsmith			 *
60642680Smsmith			 * For compatibility, the `-' is not considerd
60742680Smsmith			 * to define a range if the character following
60842680Smsmith			 * it is either a close bracket (required by ANSI)
60942680Smsmith			 * or is not numerically greater than the character
61042680Smsmith			 * we just stored in the table (c).
61142680Smsmith			 */
61242680Smsmith			n = *fmt;
61342680Smsmith			if (n == ']' || n < c) {
61442680Smsmith				c = '-';
61542680Smsmith				break;	/* resume the for(;;) */
61642680Smsmith			}
61742680Smsmith			fmt++;
61842680Smsmith			/* fill in the range */
61942680Smsmith			do {
62042680Smsmith			    tab[++c] = v;
62142680Smsmith			} while (c < n);
62242680Smsmith			c = n;
62342680Smsmith			/*
62442680Smsmith			 * Alas, the V7 Unix scanf also treats formats
62542680Smsmith			 * such as [a-c-e] as `the letters a through e'.
62642680Smsmith			 * This too is permitted by the standard....
62742680Smsmith			 */
62842680Smsmith			goto doswitch;
62942680Smsmith			break;
63042680Smsmith
63142680Smsmith		case ']':		/* end of scanset */
63242680Smsmith			return (fmt);
63342680Smsmith
63442680Smsmith		default:		/* just another character */
63542680Smsmith			c = n;
63642680Smsmith			break;
63742680Smsmith		}
63842680Smsmith	}
63942680Smsmith	/* NOTREACHED */
64042680Smsmith}
64142680Smsmith
642