xref: /freebsd/contrib/sendmail/libsm/vfscanf.c (revision 4e4196cb7454f47341efebe4e0a17f1b8cd534c7)
140266059SGregory Neil Shapiro /*
2b6bacd31SGregory Neil Shapiro  * Copyright (c) 2000-2001, 2004 Sendmail, Inc. and its suppliers.
340266059SGregory Neil Shapiro  *      All rights reserved.
440266059SGregory Neil Shapiro  * Copyright (c) 1990, 1993
540266059SGregory Neil Shapiro  *	The Regents of the University of California.  All rights reserved.
640266059SGregory Neil Shapiro  *
740266059SGregory Neil Shapiro  * This code is derived from software contributed to Berkeley by
840266059SGregory Neil Shapiro  * Chris Torek.
940266059SGregory Neil Shapiro  *
1040266059SGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
1140266059SGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
1240266059SGregory Neil Shapiro  * the sendmail distribution.
1340266059SGregory Neil Shapiro  */
1440266059SGregory Neil Shapiro 
1540266059SGregory Neil Shapiro #include <sm/gen.h>
164e4196cbSGregory Neil Shapiro SM_IDSTR(id, "@(#)$Id: vfscanf.c,v 1.53 2005/06/14 23:07:20 ca Exp $")
1740266059SGregory Neil Shapiro 
1840266059SGregory Neil Shapiro #include <ctype.h>
1940266059SGregory Neil Shapiro #include <stdlib.h>
2040266059SGregory Neil Shapiro #include <errno.h>
2140266059SGregory Neil Shapiro #include <setjmp.h>
224e4196cbSGregory Neil Shapiro #include <sm/time.h>
2340266059SGregory Neil Shapiro #include <sm/varargs.h>
2440266059SGregory Neil Shapiro #include <sm/config.h>
2540266059SGregory Neil Shapiro #include <sm/io.h>
2640266059SGregory Neil Shapiro #include <sm/signal.h>
2740266059SGregory Neil Shapiro #include <sm/clock.h>
2840266059SGregory Neil Shapiro #include <sm/string.h>
2940266059SGregory Neil Shapiro #include "local.h"
3040266059SGregory Neil Shapiro 
3140266059SGregory Neil Shapiro #define BUF		513	/* Maximum length of numeric string. */
3240266059SGregory Neil Shapiro 
3340266059SGregory Neil Shapiro /* Flags used during conversion. */
3440266059SGregory Neil Shapiro #define LONG		0x01	/* l: long or double */
3540266059SGregory Neil Shapiro #define SHORT		0x04	/* h: short */
3640266059SGregory Neil Shapiro #define QUAD		0x08	/* q: quad (same as ll) */
3740266059SGregory Neil Shapiro #define SUPPRESS	0x10	/* suppress assignment */
3840266059SGregory Neil Shapiro #define POINTER		0x20	/* weird %p pointer (`fake hex') */
3940266059SGregory Neil Shapiro #define NOSKIP		0x40	/* do not skip blanks */
4040266059SGregory Neil Shapiro 
4140266059SGregory Neil Shapiro /*
4240266059SGregory Neil Shapiro **  The following are used in numeric conversions only:
4340266059SGregory Neil Shapiro **  SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
4440266059SGregory Neil Shapiro **  SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
4540266059SGregory Neil Shapiro */
4640266059SGregory Neil Shapiro 
4740266059SGregory Neil Shapiro #define SIGNOK		0x080	/* +/- is (still) legal */
4840266059SGregory Neil Shapiro #define NDIGITS		0x100	/* no digits detected */
4940266059SGregory Neil Shapiro 
5040266059SGregory Neil Shapiro #define DPTOK		0x200	/* (float) decimal point is still legal */
5140266059SGregory Neil Shapiro #define EXPOK		0x400	/* (float) exponent (e+3, etc) still legal */
5240266059SGregory Neil Shapiro 
5340266059SGregory Neil Shapiro #define PFXOK		0x200	/* 0x prefix is (still) legal */
5440266059SGregory Neil Shapiro #define NZDIGITS	0x400	/* no zero digits detected */
5540266059SGregory Neil Shapiro 
5640266059SGregory Neil Shapiro /* Conversion types. */
5740266059SGregory Neil Shapiro #define CT_CHAR		0	/* %c conversion */
5840266059SGregory Neil Shapiro #define CT_CCL		1	/* %[...] conversion */
5940266059SGregory Neil Shapiro #define CT_STRING	2	/* %s conversion */
6040266059SGregory Neil Shapiro #define CT_INT		3	/* integer, i.e., strtoll or strtoull */
6140266059SGregory Neil Shapiro #define CT_FLOAT	4	/* floating, i.e., strtod */
6240266059SGregory Neil Shapiro 
63b6bacd31SGregory Neil Shapiro static void		scanalrm __P((int));
6440266059SGregory Neil Shapiro static unsigned char	*sm_sccl __P((char *, unsigned char *));
6540266059SGregory Neil Shapiro static jmp_buf		ScanTimeOut;
6640266059SGregory Neil Shapiro 
6740266059SGregory Neil Shapiro /*
6840266059SGregory Neil Shapiro **  SCANALRM -- handler when timeout activated for sm_io_vfscanf()
6940266059SGregory Neil Shapiro **
7040266059SGregory Neil Shapiro **  Returns flow of control to where setjmp(ScanTimeOut) was set.
7140266059SGregory Neil Shapiro **
7240266059SGregory Neil Shapiro **	Parameters:
7340266059SGregory Neil Shapiro **		sig -- unused
7440266059SGregory Neil Shapiro **
7540266059SGregory Neil Shapiro **	Returns:
7640266059SGregory Neil Shapiro **		does not return
7740266059SGregory Neil Shapiro **
7840266059SGregory Neil Shapiro **	Side Effects:
7940266059SGregory Neil Shapiro **		returns flow of control to setjmp(ScanTimeOut).
8040266059SGregory Neil Shapiro **
8140266059SGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
8240266059SGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
8340266059SGregory Neil Shapiro **		DOING.
8440266059SGregory Neil Shapiro */
8540266059SGregory Neil Shapiro 
8640266059SGregory Neil Shapiro /* ARGSUSED0 */
8740266059SGregory Neil Shapiro static void
8840266059SGregory Neil Shapiro scanalrm(sig)
8940266059SGregory Neil Shapiro 	int sig;
9040266059SGregory Neil Shapiro {
9140266059SGregory Neil Shapiro 	longjmp(ScanTimeOut, 1);
9240266059SGregory Neil Shapiro }
9340266059SGregory Neil Shapiro 
9440266059SGregory Neil Shapiro /*
9540266059SGregory Neil Shapiro **  SM_VFSCANF -- convert input into data units
9640266059SGregory Neil Shapiro **
9740266059SGregory Neil Shapiro **	Parameters:
9840266059SGregory Neil Shapiro **		fp -- file pointer for input data
9940266059SGregory Neil Shapiro **		timeout -- time intvl allowed to complete (milliseconds)
10040266059SGregory Neil Shapiro **		fmt0 -- format for finding data units
10140266059SGregory Neil Shapiro **		ap -- vectors for memory location for storing data units
10240266059SGregory Neil Shapiro **
10340266059SGregory Neil Shapiro **	Results:
10440266059SGregory Neil Shapiro **		Success: number of data units assigned
10540266059SGregory Neil Shapiro **		Failure: SM_IO_EOF
10640266059SGregory Neil Shapiro */
10740266059SGregory Neil Shapiro 
10840266059SGregory Neil Shapiro int
10940266059SGregory Neil Shapiro sm_vfscanf(fp, timeout, fmt0, ap)
11040266059SGregory Neil Shapiro 	register SM_FILE_T *fp;
11140266059SGregory Neil Shapiro 	int SM_NONVOLATILE timeout;
11240266059SGregory Neil Shapiro 	char const *fmt0;
11340266059SGregory Neil Shapiro 	va_list SM_NONVOLATILE ap;
11440266059SGregory Neil Shapiro {
11540266059SGregory Neil Shapiro 	register unsigned char *SM_NONVOLATILE fmt = (unsigned char *) fmt0;
11640266059SGregory Neil Shapiro 	register int c;		/* character from format, or conversion */
11740266059SGregory Neil Shapiro 	register size_t width;	/* field width, or 0 */
11840266059SGregory Neil Shapiro 	register char *p;	/* points into all kinds of strings */
11940266059SGregory Neil Shapiro 	register int n;		/* handy integer */
12040266059SGregory Neil Shapiro 	register int flags;	/* flags as defined above */
12140266059SGregory Neil Shapiro 	register char *p0;	/* saves original value of p when necessary */
12240266059SGregory Neil Shapiro 	int nassigned;		/* number of fields assigned */
12340266059SGregory Neil Shapiro 	int nread;		/* number of characters consumed from fp */
12440266059SGregory Neil Shapiro 	int base;		/* base argument to strtoll/strtoull */
12540266059SGregory Neil Shapiro 	ULONGLONG_T (*ccfn)();	/* conversion function (strtoll/strtoull) */
12640266059SGregory Neil Shapiro 	char ccltab[256];	/* character class table for %[...] */
12740266059SGregory Neil Shapiro 	char buf[BUF];		/* buffer for numeric conversions */
12840266059SGregory Neil Shapiro 	SM_EVENT *evt = NULL;
12940266059SGregory Neil Shapiro 
13040266059SGregory Neil Shapiro 	/* `basefix' is used to avoid `if' tests in the integer scanner */
13140266059SGregory Neil Shapiro 	static short basefix[17] =
13240266059SGregory Neil Shapiro 		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
13340266059SGregory Neil Shapiro 
13440266059SGregory Neil Shapiro 	if (timeout == SM_TIME_DEFAULT)
13540266059SGregory Neil Shapiro 		timeout = fp->f_timeout;
13640266059SGregory Neil Shapiro 	if (timeout == SM_TIME_IMMEDIATE)
13740266059SGregory Neil Shapiro 	{
13840266059SGregory Neil Shapiro 		/*
13940266059SGregory Neil Shapiro 		**  Filling the buffer will take time and we are wanted to
14040266059SGregory Neil Shapiro 		**  return immediately. So...
14140266059SGregory Neil Shapiro 		*/
14240266059SGregory Neil Shapiro 
14340266059SGregory Neil Shapiro 		errno = EAGAIN;
14440266059SGregory Neil Shapiro 		return SM_IO_EOF;
14540266059SGregory Neil Shapiro 	}
14640266059SGregory Neil Shapiro 
14740266059SGregory Neil Shapiro 	if (timeout != SM_TIME_FOREVER)
14840266059SGregory Neil Shapiro 	{
14940266059SGregory Neil Shapiro 		if (setjmp(ScanTimeOut) != 0)
15040266059SGregory Neil Shapiro 		{
15140266059SGregory Neil Shapiro 			errno = EAGAIN;
15240266059SGregory Neil Shapiro 			return SM_IO_EOF;
15340266059SGregory Neil Shapiro 		}
15440266059SGregory Neil Shapiro 
15540266059SGregory Neil Shapiro 		evt = sm_seteventm(timeout, scanalrm, 0);
15640266059SGregory Neil Shapiro 	}
15740266059SGregory Neil Shapiro 
15840266059SGregory Neil Shapiro 	nassigned = 0;
15940266059SGregory Neil Shapiro 	nread = 0;
16040266059SGregory Neil Shapiro 	base = 0;		/* XXX just to keep gcc happy */
16140266059SGregory Neil Shapiro 	ccfn = NULL;		/* XXX just to keep gcc happy */
16240266059SGregory Neil Shapiro 	for (;;)
16340266059SGregory Neil Shapiro 	{
16440266059SGregory Neil Shapiro 		c = *fmt++;
16540266059SGregory Neil Shapiro 		if (c == 0)
16640266059SGregory Neil Shapiro 		{
16740266059SGregory Neil Shapiro 			if (evt != NULL)
16840266059SGregory Neil Shapiro 				sm_clrevent(evt); /*  undo our timeout */
16940266059SGregory Neil Shapiro 			return nassigned;
17040266059SGregory Neil Shapiro 		}
17140266059SGregory Neil Shapiro 		if (isspace(c))
17240266059SGregory Neil Shapiro 		{
17340266059SGregory Neil Shapiro 			while ((fp->f_r > 0 || sm_refill(fp, SM_TIME_FOREVER)
17440266059SGregory Neil Shapiro 						== 0) &&
17540266059SGregory Neil Shapiro 			    isspace(*fp->f_p))
17640266059SGregory Neil Shapiro 				nread++, fp->f_r--, fp->f_p++;
17740266059SGregory Neil Shapiro 			continue;
17840266059SGregory Neil Shapiro 		}
17940266059SGregory Neil Shapiro 		if (c != '%')
18040266059SGregory Neil Shapiro 			goto literal;
18140266059SGregory Neil Shapiro 		width = 0;
18240266059SGregory Neil Shapiro 		flags = 0;
18340266059SGregory Neil Shapiro 
18440266059SGregory Neil Shapiro 		/*
18540266059SGregory Neil Shapiro 		**  switch on the format.  continue if done;
18640266059SGregory Neil Shapiro 		**  break once format type is derived.
18740266059SGregory Neil Shapiro 		*/
18840266059SGregory Neil Shapiro 
18940266059SGregory Neil Shapiro again:		c = *fmt++;
19040266059SGregory Neil Shapiro 		switch (c)
19140266059SGregory Neil Shapiro 		{
19240266059SGregory Neil Shapiro 		  case '%':
19340266059SGregory Neil Shapiro literal:
19440266059SGregory Neil Shapiro 			if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
19540266059SGregory Neil Shapiro 				goto input_failure;
19640266059SGregory Neil Shapiro 			if (*fp->f_p != c)
19740266059SGregory Neil Shapiro 				goto match_failure;
19840266059SGregory Neil Shapiro 			fp->f_r--, fp->f_p++;
19940266059SGregory Neil Shapiro 			nread++;
20040266059SGregory Neil Shapiro 			continue;
20140266059SGregory Neil Shapiro 
20240266059SGregory Neil Shapiro 		  case '*':
20340266059SGregory Neil Shapiro 			flags |= SUPPRESS;
20440266059SGregory Neil Shapiro 			goto again;
20540266059SGregory Neil Shapiro 		  case 'h':
20640266059SGregory Neil Shapiro 			flags |= SHORT;
20740266059SGregory Neil Shapiro 			goto again;
20840266059SGregory Neil Shapiro 		  case 'l':
20940266059SGregory Neil Shapiro 			if (*fmt == 'l')
21040266059SGregory Neil Shapiro 			{
21140266059SGregory Neil Shapiro 				fmt++;
21240266059SGregory Neil Shapiro 				flags |= QUAD;
21340266059SGregory Neil Shapiro 			}
21440266059SGregory Neil Shapiro 			else
21540266059SGregory Neil Shapiro 			{
21640266059SGregory Neil Shapiro 				flags |= LONG;
21740266059SGregory Neil Shapiro 			}
21840266059SGregory Neil Shapiro 			goto again;
21940266059SGregory Neil Shapiro 		  case 'q':
22040266059SGregory Neil Shapiro 			flags |= QUAD;
22140266059SGregory Neil Shapiro 			goto again;
22240266059SGregory Neil Shapiro 
22340266059SGregory Neil Shapiro 		  case '0': case '1': case '2': case '3': case '4':
22440266059SGregory Neil Shapiro 		  case '5': case '6': case '7': case '8': case '9':
22540266059SGregory Neil Shapiro 			width = width * 10 + c - '0';
22640266059SGregory Neil Shapiro 			goto again;
22740266059SGregory Neil Shapiro 
22840266059SGregory Neil Shapiro 		/*
22940266059SGregory Neil Shapiro 		**  Conversions.
23040266059SGregory Neil Shapiro 		**  Those marked `compat' are for 4.[123]BSD compatibility.
23140266059SGregory Neil Shapiro 		**
23240266059SGregory Neil Shapiro 		**  (According to ANSI, E and X formats are supposed
23340266059SGregory Neil Shapiro 		**  to the same as e and x.  Sorry about that.)
23440266059SGregory Neil Shapiro 		*/
23540266059SGregory Neil Shapiro 
23640266059SGregory Neil Shapiro 		  case 'D':	/* compat */
23740266059SGregory Neil Shapiro 			flags |= LONG;
23840266059SGregory Neil Shapiro 			/* FALLTHROUGH */
23940266059SGregory Neil Shapiro 		  case 'd':
24040266059SGregory Neil Shapiro 			c = CT_INT;
24140266059SGregory Neil Shapiro 			ccfn = (ULONGLONG_T (*)())sm_strtoll;
24240266059SGregory Neil Shapiro 			base = 10;
24340266059SGregory Neil Shapiro 			break;
24440266059SGregory Neil Shapiro 
24540266059SGregory Neil Shapiro 		  case 'i':
24640266059SGregory Neil Shapiro 			c = CT_INT;
24740266059SGregory Neil Shapiro 			ccfn = (ULONGLONG_T (*)())sm_strtoll;
24840266059SGregory Neil Shapiro 			base = 0;
24940266059SGregory Neil Shapiro 			break;
25040266059SGregory Neil Shapiro 
25140266059SGregory Neil Shapiro 		  case 'O':	/* compat */
25240266059SGregory Neil Shapiro 			flags |= LONG;
25340266059SGregory Neil Shapiro 			/* FALLTHROUGH */
25440266059SGregory Neil Shapiro 		  case 'o':
25540266059SGregory Neil Shapiro 			c = CT_INT;
25640266059SGregory Neil Shapiro 			ccfn = sm_strtoull;
25740266059SGregory Neil Shapiro 			base = 8;
25840266059SGregory Neil Shapiro 			break;
25940266059SGregory Neil Shapiro 
26040266059SGregory Neil Shapiro 		  case 'u':
26140266059SGregory Neil Shapiro 			c = CT_INT;
26240266059SGregory Neil Shapiro 			ccfn = sm_strtoull;
26340266059SGregory Neil Shapiro 			base = 10;
26440266059SGregory Neil Shapiro 			break;
26540266059SGregory Neil Shapiro 
26640266059SGregory Neil Shapiro 		  case 'X':
26740266059SGregory Neil Shapiro 		  case 'x':
26840266059SGregory Neil Shapiro 			flags |= PFXOK;	/* enable 0x prefixing */
26940266059SGregory Neil Shapiro 			c = CT_INT;
27040266059SGregory Neil Shapiro 			ccfn = sm_strtoull;
27140266059SGregory Neil Shapiro 			base = 16;
27240266059SGregory Neil Shapiro 			break;
27340266059SGregory Neil Shapiro 
27440266059SGregory Neil Shapiro 		  case 'E':
27540266059SGregory Neil Shapiro 		  case 'G':
27640266059SGregory Neil Shapiro 		  case 'e':
27740266059SGregory Neil Shapiro 		  case 'f':
27840266059SGregory Neil Shapiro 		  case 'g':
27940266059SGregory Neil Shapiro 			c = CT_FLOAT;
28040266059SGregory Neil Shapiro 			break;
28140266059SGregory Neil Shapiro 
28240266059SGregory Neil Shapiro 		  case 's':
28340266059SGregory Neil Shapiro 			c = CT_STRING;
28440266059SGregory Neil Shapiro 			break;
28540266059SGregory Neil Shapiro 
28640266059SGregory Neil Shapiro 		  case '[':
28740266059SGregory Neil Shapiro 			fmt = sm_sccl(ccltab, fmt);
28840266059SGregory Neil Shapiro 			flags |= NOSKIP;
28940266059SGregory Neil Shapiro 			c = CT_CCL;
29040266059SGregory Neil Shapiro 			break;
29140266059SGregory Neil Shapiro 
29240266059SGregory Neil Shapiro 		  case 'c':
29340266059SGregory Neil Shapiro 			flags |= NOSKIP;
29440266059SGregory Neil Shapiro 			c = CT_CHAR;
29540266059SGregory Neil Shapiro 			break;
29640266059SGregory Neil Shapiro 
29740266059SGregory Neil Shapiro 		  case 'p':	/* pointer format is like hex */
29840266059SGregory Neil Shapiro 			flags |= POINTER | PFXOK;
29940266059SGregory Neil Shapiro 			c = CT_INT;
30040266059SGregory Neil Shapiro 			ccfn = sm_strtoull;
30140266059SGregory Neil Shapiro 			base = 16;
30240266059SGregory Neil Shapiro 			break;
30340266059SGregory Neil Shapiro 
30440266059SGregory Neil Shapiro 		  case 'n':
30540266059SGregory Neil Shapiro 			if (flags & SUPPRESS)	/* ??? */
30640266059SGregory Neil Shapiro 				continue;
30740266059SGregory Neil Shapiro 			if (flags & SHORT)
30840266059SGregory Neil Shapiro 				*SM_VA_ARG(ap, short *) = nread;
30940266059SGregory Neil Shapiro 			else if (flags & LONG)
31040266059SGregory Neil Shapiro 				*SM_VA_ARG(ap, long *) = nread;
31140266059SGregory Neil Shapiro 			else
31240266059SGregory Neil Shapiro 				*SM_VA_ARG(ap, int *) = nread;
31340266059SGregory Neil Shapiro 			continue;
31440266059SGregory Neil Shapiro 
31540266059SGregory Neil Shapiro 		/* Disgusting backwards compatibility hacks.	XXX */
31640266059SGregory Neil Shapiro 		  case '\0':	/* compat */
31740266059SGregory Neil Shapiro 			if (evt != NULL)
31840266059SGregory Neil Shapiro 				sm_clrevent(evt); /*  undo our timeout */
31940266059SGregory Neil Shapiro 			return SM_IO_EOF;
32040266059SGregory Neil Shapiro 
32140266059SGregory Neil Shapiro 		  default:	/* compat */
32240266059SGregory Neil Shapiro 			if (isupper(c))
32340266059SGregory Neil Shapiro 				flags |= LONG;
32440266059SGregory Neil Shapiro 			c = CT_INT;
32540266059SGregory Neil Shapiro 			ccfn = (ULONGLONG_T (*)()) sm_strtoll;
32640266059SGregory Neil Shapiro 			base = 10;
32740266059SGregory Neil Shapiro 			break;
32840266059SGregory Neil Shapiro 		}
32940266059SGregory Neil Shapiro 
33040266059SGregory Neil Shapiro 		/* We have a conversion that requires input. */
33140266059SGregory Neil Shapiro 		if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
33240266059SGregory Neil Shapiro 			goto input_failure;
33340266059SGregory Neil Shapiro 
33440266059SGregory Neil Shapiro 		/*
33540266059SGregory Neil Shapiro 		**  Consume leading white space, except for formats
33640266059SGregory Neil Shapiro 		**  that suppress this.
33740266059SGregory Neil Shapiro 		*/
33840266059SGregory Neil Shapiro 
33940266059SGregory Neil Shapiro 		if ((flags & NOSKIP) == 0)
34040266059SGregory Neil Shapiro 		{
34140266059SGregory Neil Shapiro 			while (isspace(*fp->f_p))
34240266059SGregory Neil Shapiro 			{
34340266059SGregory Neil Shapiro 				nread++;
34440266059SGregory Neil Shapiro 				if (--fp->f_r > 0)
34540266059SGregory Neil Shapiro 					fp->f_p++;
34640266059SGregory Neil Shapiro 				else if (sm_refill(fp, SM_TIME_FOREVER))
34740266059SGregory Neil Shapiro 					goto input_failure;
34840266059SGregory Neil Shapiro 			}
34940266059SGregory Neil Shapiro 			/*
35040266059SGregory Neil Shapiro 			**  Note that there is at least one character in
35140266059SGregory Neil Shapiro 			**  the buffer, so conversions that do not set NOSKIP
35240266059SGregory Neil Shapiro 			**  can no longer result in an input failure.
35340266059SGregory Neil Shapiro 			*/
35440266059SGregory Neil Shapiro 		}
35540266059SGregory Neil Shapiro 
35640266059SGregory Neil Shapiro 		/* Do the conversion. */
35740266059SGregory Neil Shapiro 		switch (c)
35840266059SGregory Neil Shapiro 		{
35940266059SGregory Neil Shapiro 		  case CT_CHAR:
36040266059SGregory Neil Shapiro 			/* scan arbitrary characters (sets NOSKIP) */
36140266059SGregory Neil Shapiro 			if (width == 0)
36240266059SGregory Neil Shapiro 				width = 1;
36340266059SGregory Neil Shapiro 			if (flags & SUPPRESS)
36440266059SGregory Neil Shapiro 			{
36540266059SGregory Neil Shapiro 				size_t sum = 0;
36640266059SGregory Neil Shapiro 				for (;;)
36740266059SGregory Neil Shapiro 				{
36840266059SGregory Neil Shapiro 					if ((size_t) (n = fp->f_r) < width)
36940266059SGregory Neil Shapiro 					{
37040266059SGregory Neil Shapiro 						sum += n;
37140266059SGregory Neil Shapiro 						width -= n;
37240266059SGregory Neil Shapiro 						fp->f_p += n;
37340266059SGregory Neil Shapiro 						if (sm_refill(fp,
37440266059SGregory Neil Shapiro 							      SM_TIME_FOREVER))
37540266059SGregory Neil Shapiro 						{
37640266059SGregory Neil Shapiro 							if (sum == 0)
37740266059SGregory Neil Shapiro 								goto input_failure;
37840266059SGregory Neil Shapiro 							break;
37940266059SGregory Neil Shapiro 						}
38040266059SGregory Neil Shapiro 					}
38140266059SGregory Neil Shapiro 					else
38240266059SGregory Neil Shapiro 					{
38340266059SGregory Neil Shapiro 						sum += width;
38440266059SGregory Neil Shapiro 						fp->f_r -= width;
38540266059SGregory Neil Shapiro 						fp->f_p += width;
38640266059SGregory Neil Shapiro 						break;
38740266059SGregory Neil Shapiro 					}
38840266059SGregory Neil Shapiro 				}
38940266059SGregory Neil Shapiro 				nread += sum;
39040266059SGregory Neil Shapiro 			}
39140266059SGregory Neil Shapiro 			else
39240266059SGregory Neil Shapiro 			{
39340266059SGregory Neil Shapiro 				size_t r;
39440266059SGregory Neil Shapiro 
39540266059SGregory Neil Shapiro 				r = sm_io_read(fp, SM_TIME_FOREVER,
39640266059SGregory Neil Shapiro 						(void *) SM_VA_ARG(ap, char *),
39740266059SGregory Neil Shapiro 						width);
39840266059SGregory Neil Shapiro 				if (r == 0)
39940266059SGregory Neil Shapiro 					goto input_failure;
40040266059SGregory Neil Shapiro 				nread += r;
40140266059SGregory Neil Shapiro 				nassigned++;
40240266059SGregory Neil Shapiro 			}
40340266059SGregory Neil Shapiro 			break;
40440266059SGregory Neil Shapiro 
40540266059SGregory Neil Shapiro 		  case CT_CCL:
40640266059SGregory Neil Shapiro 			/* scan a (nonempty) character class (sets NOSKIP) */
40740266059SGregory Neil Shapiro 			if (width == 0)
40840266059SGregory Neil Shapiro 				width = (size_t)~0;	/* `infinity' */
40940266059SGregory Neil Shapiro 
41040266059SGregory Neil Shapiro 			/* take only those things in the class */
41140266059SGregory Neil Shapiro 			if (flags & SUPPRESS)
41240266059SGregory Neil Shapiro 			{
41340266059SGregory Neil Shapiro 				n = 0;
41440266059SGregory Neil Shapiro 				while (ccltab[*fp->f_p] != '\0')
41540266059SGregory Neil Shapiro 				{
41640266059SGregory Neil Shapiro 					n++, fp->f_r--, fp->f_p++;
41740266059SGregory Neil Shapiro 					if (--width == 0)
41840266059SGregory Neil Shapiro 						break;
41940266059SGregory Neil Shapiro 					if (fp->f_r <= 0 &&
42040266059SGregory Neil Shapiro 					    sm_refill(fp, SM_TIME_FOREVER))
42140266059SGregory Neil Shapiro 					{
42240266059SGregory Neil Shapiro 						if (n == 0) /* XXX how? */
42340266059SGregory Neil Shapiro 							goto input_failure;
42440266059SGregory Neil Shapiro 						break;
42540266059SGregory Neil Shapiro 					}
42640266059SGregory Neil Shapiro 				}
42740266059SGregory Neil Shapiro 				if (n == 0)
42840266059SGregory Neil Shapiro 					goto match_failure;
42940266059SGregory Neil Shapiro 			}
43040266059SGregory Neil Shapiro 			else
43140266059SGregory Neil Shapiro 			{
43240266059SGregory Neil Shapiro 				p0 = p = SM_VA_ARG(ap, char *);
43340266059SGregory Neil Shapiro 				while (ccltab[*fp->f_p] != '\0')
43440266059SGregory Neil Shapiro 				{
43540266059SGregory Neil Shapiro 					fp->f_r--;
43640266059SGregory Neil Shapiro 					*p++ = *fp->f_p++;
43740266059SGregory Neil Shapiro 					if (--width == 0)
43840266059SGregory Neil Shapiro 						break;
43940266059SGregory Neil Shapiro 					if (fp->f_r <= 0 &&
44040266059SGregory Neil Shapiro 					    sm_refill(fp, SM_TIME_FOREVER))
44140266059SGregory Neil Shapiro 					{
44240266059SGregory Neil Shapiro 						if (p == p0)
44340266059SGregory Neil Shapiro 							goto input_failure;
44440266059SGregory Neil Shapiro 						break;
44540266059SGregory Neil Shapiro 					}
44640266059SGregory Neil Shapiro 				}
44740266059SGregory Neil Shapiro 				n = p - p0;
44840266059SGregory Neil Shapiro 				if (n == 0)
44940266059SGregory Neil Shapiro 					goto match_failure;
45040266059SGregory Neil Shapiro 				*p = 0;
45140266059SGregory Neil Shapiro 				nassigned++;
45240266059SGregory Neil Shapiro 			}
45340266059SGregory Neil Shapiro 			nread += n;
45440266059SGregory Neil Shapiro 			break;
45540266059SGregory Neil Shapiro 
45640266059SGregory Neil Shapiro 		  case CT_STRING:
45740266059SGregory Neil Shapiro 			/* like CCL, but zero-length string OK, & no NOSKIP */
45840266059SGregory Neil Shapiro 			if (width == 0)
45940266059SGregory Neil Shapiro 				width = (size_t)~0;
46040266059SGregory Neil Shapiro 			if (flags & SUPPRESS)
46140266059SGregory Neil Shapiro 			{
46240266059SGregory Neil Shapiro 				n = 0;
46340266059SGregory Neil Shapiro 				while (!isspace(*fp->f_p))
46440266059SGregory Neil Shapiro 				{
46540266059SGregory Neil Shapiro 					n++, fp->f_r--, fp->f_p++;
46640266059SGregory Neil Shapiro 					if (--width == 0)
46740266059SGregory Neil Shapiro 						break;
46840266059SGregory Neil Shapiro 					if (fp->f_r <= 0 &&
46940266059SGregory Neil Shapiro 					    sm_refill(fp, SM_TIME_FOREVER))
47040266059SGregory Neil Shapiro 						break;
47140266059SGregory Neil Shapiro 				}
47240266059SGregory Neil Shapiro 				nread += n;
47340266059SGregory Neil Shapiro 			}
47440266059SGregory Neil Shapiro 			else
47540266059SGregory Neil Shapiro 			{
47640266059SGregory Neil Shapiro 				p0 = p = SM_VA_ARG(ap, char *);
47740266059SGregory Neil Shapiro 				while (!isspace(*fp->f_p))
47840266059SGregory Neil Shapiro 				{
47940266059SGregory Neil Shapiro 					fp->f_r--;
48040266059SGregory Neil Shapiro 					*p++ = *fp->f_p++;
48140266059SGregory Neil Shapiro 					if (--width == 0)
48240266059SGregory Neil Shapiro 						break;
48340266059SGregory Neil Shapiro 					if (fp->f_r <= 0 &&
48440266059SGregory Neil Shapiro 					    sm_refill(fp, SM_TIME_FOREVER))
48540266059SGregory Neil Shapiro 						break;
48640266059SGregory Neil Shapiro 				}
48740266059SGregory Neil Shapiro 				*p = 0;
48840266059SGregory Neil Shapiro 				nread += p - p0;
48940266059SGregory Neil Shapiro 				nassigned++;
49040266059SGregory Neil Shapiro 			}
49140266059SGregory Neil Shapiro 			continue;
49240266059SGregory Neil Shapiro 
49340266059SGregory Neil Shapiro 		  case CT_INT:
49440266059SGregory Neil Shapiro 			/* scan an integer as if by strtoll/strtoull */
49540266059SGregory Neil Shapiro #if SM_CONF_BROKEN_SIZE_T
49640266059SGregory Neil Shapiro 			if (width == 0 || width > sizeof(buf) - 1)
49740266059SGregory Neil Shapiro 				width = sizeof(buf) - 1;
49840266059SGregory Neil Shapiro #else /* SM_CONF_BROKEN_SIZE_T */
49940266059SGregory Neil Shapiro 			/* size_t is unsigned, hence this optimisation */
50040266059SGregory Neil Shapiro 			if (--width > sizeof(buf) - 2)
50140266059SGregory Neil Shapiro 				width = sizeof(buf) - 2;
50240266059SGregory Neil Shapiro 			width++;
50340266059SGregory Neil Shapiro #endif /* SM_CONF_BROKEN_SIZE_T */
50440266059SGregory Neil Shapiro 			flags |= SIGNOK | NDIGITS | NZDIGITS;
50540266059SGregory Neil Shapiro 			for (p = buf; width > 0; width--)
50640266059SGregory Neil Shapiro 			{
50740266059SGregory Neil Shapiro 				c = *fp->f_p;
50840266059SGregory Neil Shapiro 
50940266059SGregory Neil Shapiro 				/*
51040266059SGregory Neil Shapiro 				**  Switch on the character; `goto ok'
51140266059SGregory Neil Shapiro 				**  if we accept it as a part of number.
51240266059SGregory Neil Shapiro 				*/
51340266059SGregory Neil Shapiro 
51440266059SGregory Neil Shapiro 				switch (c)
51540266059SGregory Neil Shapiro 				{
51640266059SGregory Neil Shapiro 
51740266059SGregory Neil Shapiro 				/*
51840266059SGregory Neil Shapiro 				**  The digit 0 is always legal, but is
51940266059SGregory Neil Shapiro 				**  special.  For %i conversions, if no
52040266059SGregory Neil Shapiro 				**  digits (zero or nonzero) have been
52140266059SGregory Neil Shapiro 				**  scanned (only signs), we will have
52240266059SGregory Neil Shapiro 				**  base==0.  In that case, we should set
52340266059SGregory Neil Shapiro 				**  it to 8 and enable 0x prefixing.
52440266059SGregory Neil Shapiro 				**  Also, if we have not scanned zero digits
52540266059SGregory Neil Shapiro 				**  before this, do not turn off prefixing
52640266059SGregory Neil Shapiro 				**  (someone else will turn it off if we
52740266059SGregory Neil Shapiro 				**  have scanned any nonzero digits).
52840266059SGregory Neil Shapiro 				*/
52940266059SGregory Neil Shapiro 
53040266059SGregory Neil Shapiro 				  case '0':
53140266059SGregory Neil Shapiro 					if (base == 0)
53240266059SGregory Neil Shapiro 					{
53340266059SGregory Neil Shapiro 						base = 8;
53440266059SGregory Neil Shapiro 						flags |= PFXOK;
53540266059SGregory Neil Shapiro 					}
53640266059SGregory Neil Shapiro 					if (flags & NZDIGITS)
53740266059SGregory Neil Shapiro 					    flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
53840266059SGregory Neil Shapiro 					else
53940266059SGregory Neil Shapiro 					    flags &= ~(SIGNOK|PFXOK|NDIGITS);
54040266059SGregory Neil Shapiro 					goto ok;
54140266059SGregory Neil Shapiro 
54240266059SGregory Neil Shapiro 				/* 1 through 7 always legal */
54340266059SGregory Neil Shapiro 				  case '1': case '2': case '3':
54440266059SGregory Neil Shapiro 				  case '4': case '5': case '6': case '7':
54540266059SGregory Neil Shapiro 					base = basefix[base];
54640266059SGregory Neil Shapiro 					flags &= ~(SIGNOK | PFXOK | NDIGITS);
54740266059SGregory Neil Shapiro 					goto ok;
54840266059SGregory Neil Shapiro 
54940266059SGregory Neil Shapiro 				/* digits 8 and 9 ok iff decimal or hex */
55040266059SGregory Neil Shapiro 				  case '8': case '9':
55140266059SGregory Neil Shapiro 					base = basefix[base];
55240266059SGregory Neil Shapiro 					if (base <= 8)
55340266059SGregory Neil Shapiro 						break;	/* not legal here */
55440266059SGregory Neil Shapiro 					flags &= ~(SIGNOK | PFXOK | NDIGITS);
55540266059SGregory Neil Shapiro 					goto ok;
55640266059SGregory Neil Shapiro 
55740266059SGregory Neil Shapiro 				/* letters ok iff hex */
55840266059SGregory Neil Shapiro 				  case 'A': case 'B': case 'C':
55940266059SGregory Neil Shapiro 				  case 'D': case 'E': case 'F':
56040266059SGregory Neil Shapiro 				  case 'a': case 'b': case 'c':
56140266059SGregory Neil Shapiro 				  case 'd': case 'e': case 'f':
56240266059SGregory Neil Shapiro 
56340266059SGregory Neil Shapiro 					/* no need to fix base here */
56440266059SGregory Neil Shapiro 					if (base <= 10)
56540266059SGregory Neil Shapiro 						break;	/* not legal here */
56640266059SGregory Neil Shapiro 					flags &= ~(SIGNOK | PFXOK | NDIGITS);
56740266059SGregory Neil Shapiro 					goto ok;
56840266059SGregory Neil Shapiro 
56940266059SGregory Neil Shapiro 				/* sign ok only as first character */
57040266059SGregory Neil Shapiro 				  case '+': case '-':
57140266059SGregory Neil Shapiro 					if (flags & SIGNOK)
57240266059SGregory Neil Shapiro 					{
57340266059SGregory Neil Shapiro 						flags &= ~SIGNOK;
57440266059SGregory Neil Shapiro 						goto ok;
57540266059SGregory Neil Shapiro 					}
57640266059SGregory Neil Shapiro 					break;
57740266059SGregory Neil Shapiro 
57840266059SGregory Neil Shapiro 				/* x ok iff flag still set & 2nd char */
57940266059SGregory Neil Shapiro 				  case 'x': case 'X':
58040266059SGregory Neil Shapiro 					if (flags & PFXOK && p == buf + 1)
58140266059SGregory Neil Shapiro 					{
58240266059SGregory Neil Shapiro 						base = 16;	/* if %i */
58340266059SGregory Neil Shapiro 						flags &= ~PFXOK;
58440266059SGregory Neil Shapiro 						goto ok;
58540266059SGregory Neil Shapiro 					}
58640266059SGregory Neil Shapiro 					break;
58740266059SGregory Neil Shapiro 				}
58840266059SGregory Neil Shapiro 
58940266059SGregory Neil Shapiro 				/*
59040266059SGregory Neil Shapiro 				**  If we got here, c is not a legal character
59140266059SGregory Neil Shapiro 				**  for a number.  Stop accumulating digits.
59240266059SGregory Neil Shapiro 				*/
59340266059SGregory Neil Shapiro 
59440266059SGregory Neil Shapiro 				break;
59540266059SGregory Neil Shapiro 		ok:
59640266059SGregory Neil Shapiro 				/* c is legal: store it and look at the next. */
59740266059SGregory Neil Shapiro 				*p++ = c;
59840266059SGregory Neil Shapiro 				if (--fp->f_r > 0)
59940266059SGregory Neil Shapiro 					fp->f_p++;
60040266059SGregory Neil Shapiro 				else if (sm_refill(fp, SM_TIME_FOREVER))
60140266059SGregory Neil Shapiro 					break;		/* SM_IO_EOF */
60240266059SGregory Neil Shapiro 			}
60340266059SGregory Neil Shapiro 
60440266059SGregory Neil Shapiro 			/*
60540266059SGregory Neil Shapiro 			**  If we had only a sign, it is no good; push
60640266059SGregory Neil Shapiro 			**  back the sign.  If the number ends in `x',
60740266059SGregory Neil Shapiro 			**  it was [sign] '0' 'x', so push back the x
60840266059SGregory Neil Shapiro 			**  and treat it as [sign] '0'.
60940266059SGregory Neil Shapiro 			*/
61040266059SGregory Neil Shapiro 
61140266059SGregory Neil Shapiro 			if (flags & NDIGITS)
61240266059SGregory Neil Shapiro 			{
61340266059SGregory Neil Shapiro 				if (p > buf)
61440266059SGregory Neil Shapiro 					(void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
61540266059SGregory Neil Shapiro 							    *(unsigned char *)--p);
61640266059SGregory Neil Shapiro 				goto match_failure;
61740266059SGregory Neil Shapiro 			}
61840266059SGregory Neil Shapiro 			c = ((unsigned char *)p)[-1];
61940266059SGregory Neil Shapiro 			if (c == 'x' || c == 'X')
62040266059SGregory Neil Shapiro 			{
62140266059SGregory Neil Shapiro 				--p;
62240266059SGregory Neil Shapiro 				(void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
62340266059SGregory Neil Shapiro 			}
62440266059SGregory Neil Shapiro 			if ((flags & SUPPRESS) == 0)
62540266059SGregory Neil Shapiro 			{
62640266059SGregory Neil Shapiro 				ULONGLONG_T res;
62740266059SGregory Neil Shapiro 
62840266059SGregory Neil Shapiro 				*p = 0;
62940266059SGregory Neil Shapiro 				res = (*ccfn)(buf, (char **)NULL, base);
63040266059SGregory Neil Shapiro 				if (flags & POINTER)
63140266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, void **) =
63240266059SGregory Neil Shapiro 					    (void *)(long) res;
63340266059SGregory Neil Shapiro 				else if (flags & QUAD)
63440266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, LONGLONG_T *) = res;
63540266059SGregory Neil Shapiro 				else if (flags & LONG)
63640266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, long *) = res;
63740266059SGregory Neil Shapiro 				else if (flags & SHORT)
63840266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, short *) = res;
63940266059SGregory Neil Shapiro 				else
64040266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, int *) = res;
64140266059SGregory Neil Shapiro 				nassigned++;
64240266059SGregory Neil Shapiro 			}
64340266059SGregory Neil Shapiro 			nread += p - buf;
64440266059SGregory Neil Shapiro 			break;
64540266059SGregory Neil Shapiro 
64640266059SGregory Neil Shapiro 		  case CT_FLOAT:
64740266059SGregory Neil Shapiro 			/* scan a floating point number as if by strtod */
64840266059SGregory Neil Shapiro 			if (width == 0 || width > sizeof(buf) - 1)
64940266059SGregory Neil Shapiro 				width = sizeof(buf) - 1;
65040266059SGregory Neil Shapiro 			flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
65140266059SGregory Neil Shapiro 			for (p = buf; width; width--)
65240266059SGregory Neil Shapiro 			{
65340266059SGregory Neil Shapiro 				c = *fp->f_p;
65440266059SGregory Neil Shapiro 
65540266059SGregory Neil Shapiro 				/*
65640266059SGregory Neil Shapiro 				**  This code mimicks the integer conversion
65740266059SGregory Neil Shapiro 				**  code, but is much simpler.
65840266059SGregory Neil Shapiro 				*/
65940266059SGregory Neil Shapiro 
66040266059SGregory Neil Shapiro 				switch (c)
66140266059SGregory Neil Shapiro 				{
66240266059SGregory Neil Shapiro 
66340266059SGregory Neil Shapiro 				  case '0': case '1': case '2': case '3':
66440266059SGregory Neil Shapiro 				  case '4': case '5': case '6': case '7':
66540266059SGregory Neil Shapiro 				  case '8': case '9':
66640266059SGregory Neil Shapiro 					flags &= ~(SIGNOK | NDIGITS);
66740266059SGregory Neil Shapiro 					goto fok;
66840266059SGregory Neil Shapiro 
66940266059SGregory Neil Shapiro 				  case '+': case '-':
67040266059SGregory Neil Shapiro 					if (flags & SIGNOK)
67140266059SGregory Neil Shapiro 					{
67240266059SGregory Neil Shapiro 						flags &= ~SIGNOK;
67340266059SGregory Neil Shapiro 						goto fok;
67440266059SGregory Neil Shapiro 					}
67540266059SGregory Neil Shapiro 					break;
67640266059SGregory Neil Shapiro 				  case '.':
67740266059SGregory Neil Shapiro 					if (flags & DPTOK)
67840266059SGregory Neil Shapiro 					{
67940266059SGregory Neil Shapiro 						flags &= ~(SIGNOK | DPTOK);
68040266059SGregory Neil Shapiro 						goto fok;
68140266059SGregory Neil Shapiro 					}
68240266059SGregory Neil Shapiro 					break;
68340266059SGregory Neil Shapiro 				  case 'e': case 'E':
68440266059SGregory Neil Shapiro 
68540266059SGregory Neil Shapiro 					/* no exponent without some digits */
68640266059SGregory Neil Shapiro 					if ((flags&(NDIGITS|EXPOK)) == EXPOK)
68740266059SGregory Neil Shapiro 					{
68840266059SGregory Neil Shapiro 						flags =
68940266059SGregory Neil Shapiro 						    (flags & ~(EXPOK|DPTOK)) |
69040266059SGregory Neil Shapiro 						    SIGNOK | NDIGITS;
69140266059SGregory Neil Shapiro 						goto fok;
69240266059SGregory Neil Shapiro 					}
69340266059SGregory Neil Shapiro 					break;
69440266059SGregory Neil Shapiro 				}
69540266059SGregory Neil Shapiro 				break;
69640266059SGregory Neil Shapiro 		fok:
69740266059SGregory Neil Shapiro 				*p++ = c;
69840266059SGregory Neil Shapiro 				if (--fp->f_r > 0)
69940266059SGregory Neil Shapiro 					fp->f_p++;
70040266059SGregory Neil Shapiro 				else if (sm_refill(fp, SM_TIME_FOREVER))
70140266059SGregory Neil Shapiro 					break;	/* SM_IO_EOF */
70240266059SGregory Neil Shapiro 			}
70340266059SGregory Neil Shapiro 
70440266059SGregory Neil Shapiro 			/*
70540266059SGregory Neil Shapiro 			**  If no digits, might be missing exponent digits
70640266059SGregory Neil Shapiro 			**  (just give back the exponent) or might be missing
70740266059SGregory Neil Shapiro 			**  regular digits, but had sign and/or decimal point.
70840266059SGregory Neil Shapiro 			*/
70940266059SGregory Neil Shapiro 
71040266059SGregory Neil Shapiro 			if (flags & NDIGITS)
71140266059SGregory Neil Shapiro 			{
71240266059SGregory Neil Shapiro 				if (flags & EXPOK)
71340266059SGregory Neil Shapiro 				{
71440266059SGregory Neil Shapiro 					/* no digits at all */
71540266059SGregory Neil Shapiro 					while (p > buf)
71640266059SGregory Neil Shapiro 						(void) sm_io_ungetc(fp,
71740266059SGregory Neil Shapiro 							     SM_TIME_DEFAULT,
71840266059SGregory Neil Shapiro 							     *(unsigned char *)--p);
71940266059SGregory Neil Shapiro 					goto match_failure;
72040266059SGregory Neil Shapiro 				}
72140266059SGregory Neil Shapiro 
72240266059SGregory Neil Shapiro 				/* just a bad exponent (e and maybe sign) */
72340266059SGregory Neil Shapiro 				c = *(unsigned char *) --p;
72440266059SGregory Neil Shapiro 				if (c != 'e' && c != 'E')
72540266059SGregory Neil Shapiro 				{
72640266059SGregory Neil Shapiro 					(void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
72740266059SGregory Neil Shapiro 							    c); /* sign */
72840266059SGregory Neil Shapiro 					c = *(unsigned char *)--p;
72940266059SGregory Neil Shapiro 				}
73040266059SGregory Neil Shapiro 				(void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
73140266059SGregory Neil Shapiro 			}
73240266059SGregory Neil Shapiro 			if ((flags & SUPPRESS) == 0)
73340266059SGregory Neil Shapiro 			{
73440266059SGregory Neil Shapiro 				double res;
73540266059SGregory Neil Shapiro 
73640266059SGregory Neil Shapiro 				*p = 0;
73740266059SGregory Neil Shapiro 				res = strtod(buf, (char **) NULL);
73840266059SGregory Neil Shapiro 				if (flags & LONG)
73940266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, double *) = res;
74040266059SGregory Neil Shapiro 				else
74140266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, float *) = res;
74240266059SGregory Neil Shapiro 				nassigned++;
74340266059SGregory Neil Shapiro 			}
74440266059SGregory Neil Shapiro 			nread += p - buf;
74540266059SGregory Neil Shapiro 			break;
74640266059SGregory Neil Shapiro 		}
74740266059SGregory Neil Shapiro 	}
74840266059SGregory Neil Shapiro input_failure:
74940266059SGregory Neil Shapiro 	if (evt != NULL)
75040266059SGregory Neil Shapiro 		sm_clrevent(evt); /*  undo our timeout */
75140266059SGregory Neil Shapiro 	return nassigned ? nassigned : -1;
75240266059SGregory Neil Shapiro match_failure:
75340266059SGregory Neil Shapiro 	if (evt != NULL)
75440266059SGregory Neil Shapiro 		sm_clrevent(evt); /*  undo our timeout */
75540266059SGregory Neil Shapiro 	return nassigned;
75640266059SGregory Neil Shapiro }
75740266059SGregory Neil Shapiro 
75840266059SGregory Neil Shapiro /*
75940266059SGregory Neil Shapiro **  SM_SCCL -- sequenced character comparison list
76040266059SGregory Neil Shapiro **
76140266059SGregory Neil Shapiro **  Fill in the given table from the scanset at the given format
76240266059SGregory Neil Shapiro **  (just after `[').  Return a pointer to the character past the
76340266059SGregory Neil Shapiro **  closing `]'.  The table has a 1 wherever characters should be
76440266059SGregory Neil Shapiro **  considered part of the scanset.
76540266059SGregory Neil Shapiro **
76640266059SGregory Neil Shapiro **	Parameters:
76740266059SGregory Neil Shapiro **		tab -- array flagging "active" char's to match (returned)
76840266059SGregory Neil Shapiro **		fmt -- character list (within "[]")
76940266059SGregory Neil Shapiro **
77040266059SGregory Neil Shapiro **	Results:
77140266059SGregory Neil Shapiro */
77240266059SGregory Neil Shapiro 
77340266059SGregory Neil Shapiro static unsigned char *
77440266059SGregory Neil Shapiro sm_sccl(tab, fmt)
77540266059SGregory Neil Shapiro 	register char *tab;
77640266059SGregory Neil Shapiro 	register unsigned char *fmt;
77740266059SGregory Neil Shapiro {
77840266059SGregory Neil Shapiro 	register int c, n, v;
77940266059SGregory Neil Shapiro 
78040266059SGregory Neil Shapiro 	/* first `clear' the whole table */
78140266059SGregory Neil Shapiro 	c = *fmt++;		/* first char hat => negated scanset */
78240266059SGregory Neil Shapiro 	if (c == '^')
78340266059SGregory Neil Shapiro 	{
78440266059SGregory Neil Shapiro 		v = 1;		/* default => accept */
78540266059SGregory Neil Shapiro 		c = *fmt++;	/* get new first char */
78640266059SGregory Neil Shapiro 	}
78740266059SGregory Neil Shapiro 	else
78840266059SGregory Neil Shapiro 		v = 0;		/* default => reject */
78940266059SGregory Neil Shapiro 
79040266059SGregory Neil Shapiro 	/* should probably use memset here */
79140266059SGregory Neil Shapiro 	for (n = 0; n < 256; n++)
79240266059SGregory Neil Shapiro 		tab[n] = v;
79340266059SGregory Neil Shapiro 	if (c == 0)
79440266059SGregory Neil Shapiro 		return fmt - 1;	/* format ended before closing ] */
79540266059SGregory Neil Shapiro 
79640266059SGregory Neil Shapiro 	/*
79740266059SGregory Neil Shapiro 	**  Now set the entries corresponding to the actual scanset
79840266059SGregory Neil Shapiro 	**  to the opposite of the above.
79940266059SGregory Neil Shapiro 	**
80040266059SGregory Neil Shapiro 	**  The first character may be ']' (or '-') without being special;
80140266059SGregory Neil Shapiro 	**  the last character may be '-'.
80240266059SGregory Neil Shapiro 	*/
80340266059SGregory Neil Shapiro 
80440266059SGregory Neil Shapiro 	v = 1 - v;
80540266059SGregory Neil Shapiro 	for (;;)
80640266059SGregory Neil Shapiro 	{
80740266059SGregory Neil Shapiro 		tab[c] = v;		/* take character c */
80840266059SGregory Neil Shapiro doswitch:
80940266059SGregory Neil Shapiro 		n = *fmt++;		/* and examine the next */
81040266059SGregory Neil Shapiro 		switch (n)
81140266059SGregory Neil Shapiro 		{
81240266059SGregory Neil Shapiro 
81340266059SGregory Neil Shapiro 		  case 0:			/* format ended too soon */
81440266059SGregory Neil Shapiro 			return fmt - 1;
81540266059SGregory Neil Shapiro 
81640266059SGregory Neil Shapiro 		  case '-':
81740266059SGregory Neil Shapiro 			/*
81840266059SGregory Neil Shapiro 			**  A scanset of the form
81940266059SGregory Neil Shapiro 			**	[01+-]
82040266059SGregory Neil Shapiro 			**  is defined as `the digit 0, the digit 1,
82140266059SGregory Neil Shapiro 			**  the character +, the character -', but
82240266059SGregory Neil Shapiro 			**  the effect of a scanset such as
82340266059SGregory Neil Shapiro 			**	[a-zA-Z0-9]
82440266059SGregory Neil Shapiro 			**  is implementation defined.  The V7 Unix
82540266059SGregory Neil Shapiro 			**  scanf treats `a-z' as `the letters a through
82640266059SGregory Neil Shapiro 			**  z', but treats `a-a' as `the letter a, the
82740266059SGregory Neil Shapiro 			**  character -, and the letter a'.
82840266059SGregory Neil Shapiro 			**
82940266059SGregory Neil Shapiro 			**  For compatibility, the `-' is not considerd
83040266059SGregory Neil Shapiro 			**  to define a range if the character following
83140266059SGregory Neil Shapiro 			**  it is either a close bracket (required by ANSI)
83240266059SGregory Neil Shapiro 			**  or is not numerically greater than the character
83340266059SGregory Neil Shapiro 			**  we just stored in the table (c).
83440266059SGregory Neil Shapiro 			*/
83540266059SGregory Neil Shapiro 
83640266059SGregory Neil Shapiro 			n = *fmt;
83740266059SGregory Neil Shapiro 			if (n == ']' || n < c)
83840266059SGregory Neil Shapiro 			{
83940266059SGregory Neil Shapiro 				c = '-';
84040266059SGregory Neil Shapiro 				break;	/* resume the for(;;) */
84140266059SGregory Neil Shapiro 			}
84240266059SGregory Neil Shapiro 			fmt++;
84340266059SGregory Neil Shapiro 			do
84440266059SGregory Neil Shapiro 			{
84540266059SGregory Neil Shapiro 				/* fill in the range */
84640266059SGregory Neil Shapiro 				tab[++c] = v;
84740266059SGregory Neil Shapiro 			} while (c < n);
84840266059SGregory Neil Shapiro #if 1	/* XXX another disgusting compatibility hack */
84940266059SGregory Neil Shapiro 
85040266059SGregory Neil Shapiro 			/*
85140266059SGregory Neil Shapiro 			**  Alas, the V7 Unix scanf also treats formats
85240266059SGregory Neil Shapiro 			**  such as [a-c-e] as `the letters a through e'.
85340266059SGregory Neil Shapiro 			**  This too is permitted by the standard....
85440266059SGregory Neil Shapiro 			*/
85540266059SGregory Neil Shapiro 
85640266059SGregory Neil Shapiro 			goto doswitch;
85740266059SGregory Neil Shapiro #else
85840266059SGregory Neil Shapiro 			c = *fmt++;
85940266059SGregory Neil Shapiro 			if (c == 0)
86040266059SGregory Neil Shapiro 				return fmt - 1;
86140266059SGregory Neil Shapiro 			if (c == ']')
86240266059SGregory Neil Shapiro 				return fmt;
86340266059SGregory Neil Shapiro 			break;
86440266059SGregory Neil Shapiro #endif
86540266059SGregory Neil Shapiro 
86640266059SGregory Neil Shapiro 		  case ']':		/* end of scanset */
86740266059SGregory Neil Shapiro 			return fmt;
86840266059SGregory Neil Shapiro 
86940266059SGregory Neil Shapiro 		  default:		/* just another character */
87040266059SGregory Neil Shapiro 			c = n;
87140266059SGregory Neil Shapiro 			break;
87240266059SGregory Neil Shapiro 		}
87340266059SGregory Neil Shapiro 	}
87440266059SGregory Neil Shapiro 	/* NOTREACHED */
87540266059SGregory Neil Shapiro }
876