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: stable/11/sys/kern/subr_scanf.c 351760 2019-09-03 16:38:52Z mav $");
39116182Sobrien
4042680Smsmith#include <sys/param.h>
4142680Smsmith#include <sys/systm.h>
4252843Sphk#include <sys/ctype.h>
43114216Skan#include <sys/limits.h>
44351760Smav#include <sys/stddef.h>
4542680Smsmith
4642680Smsmith/*
4742680Smsmith * Note that stdarg.h and the ANSI style va_start macro is used for both
4842680Smsmith * ANSI and traditional C compilers.
4942680Smsmith */
5042680Smsmith#include <machine/stdarg.h>
5142680Smsmith
5242680Smsmith#define	BUF		32 	/* Maximum length of numeric string. */
5342680Smsmith
5442680Smsmith/*
5542680Smsmith * Flags used during conversion.
5642680Smsmith */
5742680Smsmith#define	LONG		0x01	/* l: long or double */
5842680Smsmith#define	SHORT		0x04	/* h: short */
5942680Smsmith#define	SUPPRESS	0x08	/* suppress assignment */
6042680Smsmith#define	POINTER		0x10	/* weird %p pointer (`fake hex') */
6142680Smsmith#define	NOSKIP		0x20	/* do not skip blanks */
6242680Smsmith#define	QUAD		0x400
63351760Smav#define	INTMAXT		0x800	/* j: intmax_t */
64351760Smav#define	PTRDIFFT	0x1000	/* t: ptrdiff_t */
65351760Smav#define	SIZET		0x2000	/* z: size_t */
66230587Sken#define	SHORTSHORT	0x4000	/** hh: char */
6742680Smsmith
6842680Smsmith/*
6942680Smsmith * The following are used in numeric conversions only:
7042680Smsmith * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
7142680Smsmith * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
7242680Smsmith */
7342680Smsmith#define	SIGNOK		0x40	/* +/- is (still) legal */
7442680Smsmith#define	NDIGITS		0x80	/* no digits detected */
7542680Smsmith
7642680Smsmith#define	DPTOK		0x100	/* (float) decimal point is still legal */
7742680Smsmith#define	EXPOK		0x200	/* (float) exponent (e+3, etc) still legal */
7842680Smsmith
7942680Smsmith#define	PFXOK		0x100	/* 0x prefix is (still) legal */
8042680Smsmith#define	NZDIGITS	0x200	/* no zero digits detected */
8142680Smsmith
8242680Smsmith/*
8342680Smsmith * Conversion types.
8442680Smsmith */
8542680Smsmith#define	CT_CHAR		0	/* %c conversion */
8642680Smsmith#define	CT_CCL		1	/* %[...] conversion */
8742680Smsmith#define	CT_STRING	2	/* %s conversion */
8842680Smsmith#define	CT_INT		3	/* integer, i.e., strtoq or strtouq */
8953648Sarchietypedef u_quad_t (*ccfntype)(const char *, char **, int);
9042680Smsmith
9143300Sdillonstatic const u_char *__sccl(char *, const u_char *);
9242680Smsmith
9342680Smsmithint
9442680Smsmithsscanf(const char *ibuf, const char *fmt, ...)
9542680Smsmith{
9642680Smsmith	va_list ap;
9742680Smsmith	int ret;
9842680Smsmith
9942680Smsmith	va_start(ap, fmt);
10042680Smsmith	ret = vsscanf(ibuf, fmt, ap);
10142680Smsmith	va_end(ap);
10242680Smsmith	return(ret);
10342680Smsmith}
10442680Smsmith
10542680Smsmithint
10642680Smsmithvsscanf(const char *inp, char const *fmt0, va_list ap)
10742680Smsmith{
10842680Smsmith	int inr;
10943300Sdillon	const u_char *fmt = (const u_char *)fmt0;
11042680Smsmith	int c;			/* character from format, or conversion */
11142680Smsmith	size_t width;		/* field width, or 0 */
11242680Smsmith	char *p;		/* points into all kinds of strings */
11342680Smsmith	int n;			/* handy integer */
11442680Smsmith	int flags;		/* flags as defined above */
11542680Smsmith	char *p0;		/* saves original value of p when necessary */
11642680Smsmith	int nassigned;		/* number of fields assigned */
11742680Smsmith	int nconversions;	/* number of conversions */
11842680Smsmith	int nread;		/* number of characters consumed from fp */
11942680Smsmith	int base;		/* base argument to strtoq/strtouq */
12042680Smsmith	ccfntype ccfn;		/* conversion function (strtoq/strtouq) */
12142680Smsmith	char ccltab[256];	/* character class table for %[...] */
12242680Smsmith	char buf[BUF];		/* buffer for numeric conversions */
12342680Smsmith
12442680Smsmith	/* `basefix' is used to avoid `if' tests in the integer scanner */
12542680Smsmith	static short basefix[17] =
12642680Smsmith		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
12742680Smsmith
12842680Smsmith	inr = strlen(inp);
12942680Smsmith
13042680Smsmith	nassigned = 0;
13142680Smsmith	nconversions = 0;
13242680Smsmith	nread = 0;
13342680Smsmith	base = 0;		/* XXX just to keep gcc happy */
13442680Smsmith	ccfn = NULL;		/* XXX just to keep gcc happy */
13542680Smsmith	for (;;) {
13642680Smsmith		c = *fmt++;
13742680Smsmith		if (c == 0)
13842680Smsmith			return (nassigned);
13942680Smsmith		if (isspace(c)) {
14042680Smsmith			while (inr > 0 && isspace(*inp))
14142680Smsmith				nread++, inr--, inp++;
14242680Smsmith			continue;
14342680Smsmith		}
14442680Smsmith		if (c != '%')
14542680Smsmith			goto literal;
14642680Smsmith		width = 0;
14742680Smsmith		flags = 0;
14842680Smsmith		/*
14942680Smsmith		 * switch on the format.  continue if done;
15042680Smsmith		 * break once format type is derived.
15142680Smsmith		 */
15242680Smsmithagain:		c = *fmt++;
15342680Smsmith		switch (c) {
15442680Smsmith		case '%':
15542680Smsmithliteral:
15642680Smsmith			if (inr <= 0)
15742680Smsmith				goto input_failure;
15842680Smsmith			if (*inp != c)
15942680Smsmith				goto match_failure;
16042680Smsmith			inr--, inp++;
16142680Smsmith			nread++;
16242680Smsmith			continue;
16342680Smsmith
16442680Smsmith		case '*':
16542680Smsmith			flags |= SUPPRESS;
16642680Smsmith			goto again;
167351760Smav		case 'j':
168351760Smav			flags |= INTMAXT;
169351760Smav			goto again;
17042680Smsmith		case 'l':
171230587Sken			if (flags & LONG){
172230587Sken				flags &= ~LONG;
173230587Sken				flags |= QUAD;
174230587Sken			} else {
175230587Sken				flags |= LONG;
176230587Sken			}
17742680Smsmith			goto again;
17842680Smsmith		case 'q':
17942680Smsmith			flags |= QUAD;
18042680Smsmith			goto again;
181351760Smav		case 't':
182351760Smav			flags |= PTRDIFFT;
183351760Smav			goto again;
184351760Smav		case 'z':
185351760Smav			flags |= SIZET;
186351760Smav			goto again;
18742680Smsmith		case 'h':
188230587Sken			if (flags & SHORT){
189230587Sken				flags &= ~SHORT;
190230587Sken				flags |= SHORTSHORT;
191230587Sken			} else {
192230587Sken				flags |= SHORT;
193230587Sken			}
19442680Smsmith			goto again;
19542680Smsmith
19642680Smsmith		case '0': case '1': case '2': case '3': case '4':
19742680Smsmith		case '5': case '6': case '7': case '8': case '9':
19842680Smsmith			width = width * 10 + c - '0';
19942680Smsmith			goto again;
20042680Smsmith
20142680Smsmith		/*
20242680Smsmith		 * Conversions.
20342680Smsmith		 *
20442680Smsmith		 */
20542680Smsmith		case 'd':
20642680Smsmith			c = CT_INT;
20742680Smsmith			ccfn = (ccfntype)strtoq;
20842680Smsmith			base = 10;
20942680Smsmith			break;
21042680Smsmith
21142680Smsmith		case 'i':
21242680Smsmith			c = CT_INT;
21342680Smsmith			ccfn = (ccfntype)strtoq;
21442680Smsmith			base = 0;
21542680Smsmith			break;
21642680Smsmith
21742680Smsmith		case 'o':
21842680Smsmith			c = CT_INT;
21942680Smsmith			ccfn = strtouq;
22042680Smsmith			base = 8;
22142680Smsmith			break;
22242680Smsmith
22342680Smsmith		case 'u':
22442680Smsmith			c = CT_INT;
22542680Smsmith			ccfn = strtouq;
22642680Smsmith			base = 10;
22742680Smsmith			break;
22842680Smsmith
22942680Smsmith		case 'x':
23042680Smsmith			flags |= PFXOK;	/* enable 0x prefixing */
23142680Smsmith			c = CT_INT;
23242680Smsmith			ccfn = strtouq;
23342680Smsmith			base = 16;
23442680Smsmith			break;
23542680Smsmith
23642680Smsmith		case 's':
23742680Smsmith			c = CT_STRING;
23842680Smsmith			break;
23942680Smsmith
24042680Smsmith		case '[':
24142680Smsmith			fmt = __sccl(ccltab, fmt);
24242680Smsmith			flags |= NOSKIP;
24342680Smsmith			c = CT_CCL;
24442680Smsmith			break;
24542680Smsmith
24642680Smsmith		case 'c':
24742680Smsmith			flags |= NOSKIP;
24842680Smsmith			c = CT_CHAR;
24942680Smsmith			break;
25042680Smsmith
25142680Smsmith		case 'p':	/* pointer format is like hex */
25242680Smsmith			flags |= POINTER | PFXOK;
25342680Smsmith			c = CT_INT;
25442680Smsmith			ccfn = strtouq;
25542680Smsmith			base = 16;
25642680Smsmith			break;
25742680Smsmith
25842680Smsmith		case 'n':
25942680Smsmith			nconversions++;
26042680Smsmith			if (flags & SUPPRESS)	/* ??? */
26142680Smsmith				continue;
262230587Sken			if (flags & SHORTSHORT)
263230587Sken				*va_arg(ap, char *) = nread;
264230587Sken			else if (flags & SHORT)
26542680Smsmith				*va_arg(ap, short *) = nread;
26642680Smsmith			else if (flags & LONG)
26742680Smsmith				*va_arg(ap, long *) = nread;
26842680Smsmith			else if (flags & QUAD)
26942680Smsmith				*va_arg(ap, quad_t *) = nread;
270351760Smav			else if (flags & INTMAXT)
271351760Smav				*va_arg(ap, intmax_t *) = nread;
272351760Smav			else if (flags & SIZET)
273351760Smav				*va_arg(ap, size_t *) = nread;
274351760Smav			else if (flags & PTRDIFFT)
275351760Smav				*va_arg(ap, ptrdiff_t *) = nread;
27642680Smsmith			else
27742680Smsmith				*va_arg(ap, int *) = nread;
27842680Smsmith			continue;
27942680Smsmith		}
28042680Smsmith
28142680Smsmith		/*
28242680Smsmith		 * We have a conversion that requires input.
28342680Smsmith		 */
28442680Smsmith		if (inr <= 0)
28542680Smsmith			goto input_failure;
28642680Smsmith
28742680Smsmith		/*
28842680Smsmith		 * Consume leading white space, except for formats
28942680Smsmith		 * that suppress this.
29042680Smsmith		 */
29142680Smsmith		if ((flags & NOSKIP) == 0) {
29242680Smsmith			while (isspace(*inp)) {
29342680Smsmith				nread++;
29442680Smsmith				if (--inr > 0)
29542680Smsmith					inp++;
29642680Smsmith				else
29742680Smsmith					goto input_failure;
29842680Smsmith			}
29942680Smsmith			/*
30042680Smsmith			 * Note that there is at least one character in
30142680Smsmith			 * the buffer, so conversions that do not set NOSKIP
30242680Smsmith			 * can no longer result in an input failure.
30342680Smsmith			 */
30442680Smsmith		}
30542680Smsmith
30642680Smsmith		/*
30742680Smsmith		 * Do the conversion.
30842680Smsmith		 */
30942680Smsmith		switch (c) {
31042680Smsmith
31142680Smsmith		case CT_CHAR:
31242680Smsmith			/* scan arbitrary characters (sets NOSKIP) */
31342680Smsmith			if (width == 0)
31442680Smsmith				width = 1;
31542680Smsmith			if (flags & SUPPRESS) {
31642680Smsmith				size_t sum = 0;
31742680Smsmith				for (;;) {
31842680Smsmith					if ((n = inr) < width) {
31942680Smsmith						sum += n;
32042680Smsmith						width -= n;
32142680Smsmith						inp += n;
32242680Smsmith						if (sum == 0)
32342680Smsmith							goto input_failure;
324104363Sphk						break;
32542680Smsmith					} else {
32642680Smsmith						sum += width;
32742680Smsmith						inr -= width;
32842680Smsmith						inp += width;
32942680Smsmith						break;
33042680Smsmith					}
33142680Smsmith				}
33242680Smsmith				nread += sum;
33342680Smsmith			} else {
33442680Smsmith				bcopy(inp, va_arg(ap, char *), width);
33542680Smsmith				inr -= width;
33642680Smsmith				inp += width;
33742680Smsmith				nread += width;
33842680Smsmith				nassigned++;
33942680Smsmith			}
34042680Smsmith			nconversions++;
34142680Smsmith			break;
34242680Smsmith
34342680Smsmith		case CT_CCL:
34442680Smsmith			/* scan a (nonempty) character class (sets NOSKIP) */
34542680Smsmith			if (width == 0)
34642680Smsmith				width = (size_t)~0;	/* `infinity' */
34742680Smsmith			/* take only those things in the class */
34842680Smsmith			if (flags & SUPPRESS) {
34942680Smsmith				n = 0;
35044016Sdillon				while (ccltab[(unsigned char)*inp]) {
35142680Smsmith					n++, inr--, inp++;
35242680Smsmith					if (--width == 0)
35342680Smsmith						break;
35442680Smsmith					if (inr <= 0) {
35542680Smsmith						if (n == 0)
35642680Smsmith							goto input_failure;
35742680Smsmith						break;
35842680Smsmith					}
35942680Smsmith				}
36042680Smsmith				if (n == 0)
36142680Smsmith					goto match_failure;
36242680Smsmith			} else {
36342680Smsmith				p0 = p = va_arg(ap, char *);
36444016Sdillon				while (ccltab[(unsigned char)*inp]) {
36542680Smsmith					inr--;
36642680Smsmith					*p++ = *inp++;
36742680Smsmith					if (--width == 0)
36842680Smsmith						break;
36942680Smsmith					if (inr <= 0) {
37042680Smsmith						if (p == p0)
37142680Smsmith							goto input_failure;
37242680Smsmith						break;
37342680Smsmith					}
37442680Smsmith				}
37542680Smsmith				n = p - p0;
37642680Smsmith				if (n == 0)
37742680Smsmith					goto match_failure;
37842680Smsmith				*p = 0;
37942680Smsmith				nassigned++;
38042680Smsmith			}
38142680Smsmith			nread += n;
38242680Smsmith			nconversions++;
38342680Smsmith			break;
38442680Smsmith
38542680Smsmith		case CT_STRING:
38642680Smsmith			/* like CCL, but zero-length string OK, & no NOSKIP */
38742680Smsmith			if (width == 0)
38842680Smsmith				width = (size_t)~0;
38942680Smsmith			if (flags & SUPPRESS) {
39042680Smsmith				n = 0;
39142680Smsmith				while (!isspace(*inp)) {
39242680Smsmith					n++, inr--, inp++;
39342680Smsmith					if (--width == 0)
39442680Smsmith						break;
39542680Smsmith					if (inr <= 0)
39642680Smsmith						break;
39742680Smsmith				}
39842680Smsmith				nread += n;
39942680Smsmith			} else {
40042680Smsmith				p0 = p = va_arg(ap, char *);
40142680Smsmith				while (!isspace(*inp)) {
40242680Smsmith					inr--;
40342680Smsmith					*p++ = *inp++;
40442680Smsmith					if (--width == 0)
40542680Smsmith						break;
40642680Smsmith					if (inr <= 0)
40742680Smsmith						break;
40842680Smsmith				}
40942680Smsmith				*p = 0;
41042680Smsmith				nread += p - p0;
41142680Smsmith				nassigned++;
41242680Smsmith			}
41342680Smsmith			nconversions++;
41442680Smsmith			continue;
41542680Smsmith
41642680Smsmith		case CT_INT:
41742680Smsmith			/* scan an integer as if by strtoq/strtouq */
41842680Smsmith#ifdef hardway
41942680Smsmith			if (width == 0 || width > sizeof(buf) - 1)
42042680Smsmith				width = sizeof(buf) - 1;
42142680Smsmith#else
42242680Smsmith			/* size_t is unsigned, hence this optimisation */
42342680Smsmith			if (--width > sizeof(buf) - 2)
42442680Smsmith				width = sizeof(buf) - 2;
42542680Smsmith			width++;
42642680Smsmith#endif
42742680Smsmith			flags |= SIGNOK | NDIGITS | NZDIGITS;
42842680Smsmith			for (p = buf; width; width--) {
42942680Smsmith				c = *inp;
43042680Smsmith				/*
43142680Smsmith				 * Switch on the character; `goto ok'
43242680Smsmith				 * if we accept it as a part of number.
43342680Smsmith				 */
43442680Smsmith				switch (c) {
43542680Smsmith
43642680Smsmith				/*
43742680Smsmith				 * The digit 0 is always legal, but is
43842680Smsmith				 * special.  For %i conversions, if no
43942680Smsmith				 * digits (zero or nonzero) have been
44042680Smsmith				 * scanned (only signs), we will have
44142680Smsmith				 * base==0.  In that case, we should set
44242680Smsmith				 * it to 8 and enable 0x prefixing.
44342680Smsmith				 * Also, if we have not scanned zero digits
44442680Smsmith				 * before this, do not turn off prefixing
44542680Smsmith				 * (someone else will turn it off if we
44642680Smsmith				 * have scanned any nonzero digits).
44742680Smsmith				 */
44842680Smsmith				case '0':
44942680Smsmith					if (base == 0) {
45042680Smsmith						base = 8;
45142680Smsmith						flags |= PFXOK;
45242680Smsmith					}
45342680Smsmith					if (flags & NZDIGITS)
45442680Smsmith					    flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
45542680Smsmith					else
45642680Smsmith					    flags &= ~(SIGNOK|PFXOK|NDIGITS);
45742680Smsmith					goto ok;
45842680Smsmith
45942680Smsmith				/* 1 through 7 always legal */
46042680Smsmith				case '1': case '2': case '3':
46142680Smsmith				case '4': case '5': case '6': case '7':
46242680Smsmith					base = basefix[base];
46342680Smsmith					flags &= ~(SIGNOK | PFXOK | NDIGITS);
46442680Smsmith					goto ok;
46542680Smsmith
46642680Smsmith				/* digits 8 and 9 ok iff decimal or hex */
46742680Smsmith				case '8': case '9':
46842680Smsmith					base = basefix[base];
46942680Smsmith					if (base <= 8)
47042680Smsmith						break;	/* not legal here */
47142680Smsmith					flags &= ~(SIGNOK | PFXOK | NDIGITS);
47242680Smsmith					goto ok;
47342680Smsmith
47442680Smsmith				/* letters ok iff hex */
47542680Smsmith				case 'A': case 'B': case 'C':
47642680Smsmith				case 'D': case 'E': case 'F':
47742680Smsmith				case 'a': case 'b': case 'c':
47842680Smsmith				case 'd': case 'e': case 'f':
47942680Smsmith					/* no need to fix base here */
48042680Smsmith					if (base <= 10)
48142680Smsmith						break;	/* not legal here */
48242680Smsmith					flags &= ~(SIGNOK | PFXOK | NDIGITS);
48342680Smsmith					goto ok;
48442680Smsmith
48542680Smsmith				/* sign ok only as first character */
48642680Smsmith				case '+': case '-':
48742680Smsmith					if (flags & SIGNOK) {
48842680Smsmith						flags &= ~SIGNOK;
48942680Smsmith						goto ok;
49042680Smsmith					}
49142680Smsmith					break;
49242680Smsmith
49342680Smsmith				/* x ok iff flag still set & 2nd char */
49442680Smsmith				case 'x': case 'X':
49542680Smsmith					if (flags & PFXOK && p == buf + 1) {
49642680Smsmith						base = 16;	/* if %i */
49742680Smsmith						flags &= ~PFXOK;
49842680Smsmith						goto ok;
49942680Smsmith					}
50042680Smsmith					break;
50142680Smsmith				}
50242680Smsmith
50342680Smsmith				/*
50442680Smsmith				 * If we got here, c is not a legal character
50542680Smsmith				 * for a number.  Stop accumulating digits.
50642680Smsmith				 */
50742680Smsmith				break;
50842680Smsmith		ok:
50942680Smsmith				/*
51042680Smsmith				 * c is legal: store it and look at the next.
51142680Smsmith				 */
51242680Smsmith				*p++ = c;
51342680Smsmith				if (--inr > 0)
51442680Smsmith					inp++;
51542680Smsmith				else
51642680Smsmith					break;		/* end of input */
51742680Smsmith			}
51842680Smsmith			/*
51942680Smsmith			 * If we had only a sign, it is no good; push
52042680Smsmith			 * back the sign.  If the number ends in `x',
52142680Smsmith			 * it was [sign] '0' 'x', so push back the x
52242680Smsmith			 * and treat it as [sign] '0'.
52342680Smsmith			 */
52442680Smsmith			if (flags & NDIGITS) {
52542680Smsmith				if (p > buf) {
52642680Smsmith					inp--;
52742680Smsmith					inr++;
52842680Smsmith				}
52942680Smsmith				goto match_failure;
53042680Smsmith			}
53142680Smsmith			c = ((u_char *)p)[-1];
53242680Smsmith			if (c == 'x' || c == 'X') {
53342680Smsmith				--p;
53442680Smsmith				inp--;
53542680Smsmith				inr++;
53642680Smsmith			}
53742680Smsmith			if ((flags & SUPPRESS) == 0) {
53842680Smsmith				u_quad_t res;
53942680Smsmith
54042680Smsmith				*p = 0;
54153648Sarchie				res = (*ccfn)(buf, (char **)NULL, base);
54242680Smsmith				if (flags & POINTER)
54342680Smsmith					*va_arg(ap, void **) =
54450275Sbde						(void *)(uintptr_t)res;
545230587Sken				else if (flags & SHORTSHORT)
546230587Sken					*va_arg(ap, char *) = res;
54742680Smsmith				else if (flags & SHORT)
54842680Smsmith					*va_arg(ap, short *) = res;
54942680Smsmith				else if (flags & LONG)
55042680Smsmith					*va_arg(ap, long *) = res;
55142680Smsmith				else if (flags & QUAD)
55242680Smsmith					*va_arg(ap, quad_t *) = res;
553351760Smav				else if (flags & INTMAXT)
554351760Smav					*va_arg(ap, intmax_t *) = res;
555351760Smav				else if (flags & PTRDIFFT)
556351760Smav					*va_arg(ap, ptrdiff_t *) = res;
557351760Smav				else if (flags & SIZET)
558351760Smav					*va_arg(ap, size_t *) = res;
55942680Smsmith				else
56042680Smsmith					*va_arg(ap, int *) = res;
56142680Smsmith				nassigned++;
56242680Smsmith			}
56342680Smsmith			nread += p - buf;
56442680Smsmith			nconversions++;
56542680Smsmith			break;
56642680Smsmith
56742680Smsmith		}
56842680Smsmith	}
56942680Smsmithinput_failure:
57042680Smsmith	return (nconversions != 0 ? nassigned : -1);
57142680Smsmithmatch_failure:
57242680Smsmith	return (nassigned);
57342680Smsmith}
57442680Smsmith
57542680Smsmith/*
57642680Smsmith * Fill in the given table from the scanset at the given format
57742680Smsmith * (just after `[').  Return a pointer to the character past the
57842680Smsmith * closing `]'.  The table has a 1 wherever characters should be
57942680Smsmith * considered part of the scanset.
58042680Smsmith */
58143300Sdillonstatic const u_char *
58243300Sdillon__sccl(char *tab, const u_char *fmt)
58342680Smsmith{
58442680Smsmith	int c, n, v;
58542680Smsmith
58642680Smsmith	/* first `clear' the whole table */
58742680Smsmith	c = *fmt++;		/* first char hat => negated scanset */
58842680Smsmith	if (c == '^') {
58942680Smsmith		v = 1;		/* default => accept */
59042680Smsmith		c = *fmt++;	/* get new first char */
59142680Smsmith	} else
59242680Smsmith		v = 0;		/* default => reject */
59342680Smsmith
59442680Smsmith	/* XXX: Will not work if sizeof(tab*) > sizeof(char) */
59542680Smsmith	for (n = 0; n < 256; n++)
59642680Smsmith		     tab[n] = v;	/* memset(tab, v, 256) */
59742680Smsmith
59842680Smsmith	if (c == 0)
59942680Smsmith		return (fmt - 1);/* format ended before closing ] */
60042680Smsmith
60142680Smsmith	/*
60242680Smsmith	 * Now set the entries corresponding to the actual scanset
60342680Smsmith	 * to the opposite of the above.
60442680Smsmith	 *
60542680Smsmith	 * The first character may be ']' (or '-') without being special;
60642680Smsmith	 * the last character may be '-'.
60742680Smsmith	 */
60842680Smsmith	v = 1 - v;
60942680Smsmith	for (;;) {
61042680Smsmith		tab[c] = v;		/* take character c */
61142680Smsmithdoswitch:
61242680Smsmith		n = *fmt++;		/* and examine the next */
61342680Smsmith		switch (n) {
61442680Smsmith
61542680Smsmith		case 0:			/* format ended too soon */
61642680Smsmith			return (fmt - 1);
61742680Smsmith
61842680Smsmith		case '-':
61942680Smsmith			/*
62042680Smsmith			 * A scanset of the form
62142680Smsmith			 *	[01+-]
62242680Smsmith			 * is defined as `the digit 0, the digit 1,
62342680Smsmith			 * the character +, the character -', but
62442680Smsmith			 * the effect of a scanset such as
62542680Smsmith			 *	[a-zA-Z0-9]
62642680Smsmith			 * is implementation defined.  The V7 Unix
62742680Smsmith			 * scanf treats `a-z' as `the letters a through
62842680Smsmith			 * z', but treats `a-a' as `the letter a, the
62942680Smsmith			 * character -, and the letter a'.
63042680Smsmith			 *
631298819Spfg			 * For compatibility, the `-' is not considered
63242680Smsmith			 * to define a range if the character following
63342680Smsmith			 * it is either a close bracket (required by ANSI)
63442680Smsmith			 * or is not numerically greater than the character
63542680Smsmith			 * we just stored in the table (c).
63642680Smsmith			 */
63742680Smsmith			n = *fmt;
63842680Smsmith			if (n == ']' || n < c) {
63942680Smsmith				c = '-';
64042680Smsmith				break;	/* resume the for(;;) */
64142680Smsmith			}
64242680Smsmith			fmt++;
64342680Smsmith			/* fill in the range */
64442680Smsmith			do {
64542680Smsmith			    tab[++c] = v;
64642680Smsmith			} while (c < n);
64742680Smsmith			c = n;
64842680Smsmith			/*
64942680Smsmith			 * Alas, the V7 Unix scanf also treats formats
65042680Smsmith			 * such as [a-c-e] as `the letters a through e'.
65142680Smsmith			 * This too is permitted by the standard....
65242680Smsmith			 */
65342680Smsmith			goto doswitch;
65442680Smsmith			break;
65542680Smsmith
65642680Smsmith		case ']':		/* end of scanset */
65742680Smsmith			return (fmt);
65842680Smsmith
65942680Smsmith		default:		/* just another character */
66042680Smsmith			c = n;
66142680Smsmith			break;
66242680Smsmith		}
66342680Smsmith	}
66442680Smsmith	/* NOTREACHED */
66542680Smsmith}
66642680Smsmith
667