xref: /freebsd/contrib/sendmail/libsm/vfscanf.c (revision d39bd2c1388b520fcba9abed1932acacead60fba)
140266059SGregory Neil Shapiro /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 2000-2001, 2004 Proofpoint, 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>
164313cc83SGregory Neil Shapiro SM_IDSTR(id, "@(#)$Id: vfscanf.c,v 1.55 2013-11-22 20:51:44 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
scanalrm(sig)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
sm_vfscanf(fp,timeout,fmt0,ap)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;
1135b0945b5SGregory Neil Shapiro 	va_list 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 */
125d0cef73dSGregory Neil Shapiro 
126d0cef73dSGregory Neil Shapiro 	/* conversion function (strtoll/strtoull) */
127d0cef73dSGregory Neil Shapiro 	ULONGLONG_T (*ccfn) __P((const char *, char **, int));
12840266059SGregory Neil Shapiro 	char ccltab[256];	/* character class table for %[...] */
12940266059SGregory Neil Shapiro 	char buf[BUF];		/* buffer for numeric conversions */
13040266059SGregory Neil Shapiro 	SM_EVENT *evt = NULL;
13140266059SGregory Neil Shapiro 
13240266059SGregory Neil Shapiro 	/* `basefix' is used to avoid `if' tests in the integer scanner */
13340266059SGregory Neil Shapiro 	static short basefix[17] =
13440266059SGregory Neil Shapiro 		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
13540266059SGregory Neil Shapiro 
13640266059SGregory Neil Shapiro 	if (timeout == SM_TIME_DEFAULT)
13740266059SGregory Neil Shapiro 		timeout = fp->f_timeout;
13840266059SGregory Neil Shapiro 	if (timeout == SM_TIME_IMMEDIATE)
13940266059SGregory Neil Shapiro 	{
14040266059SGregory Neil Shapiro 		/*
14140266059SGregory Neil Shapiro 		**  Filling the buffer will take time and we are wanted to
14240266059SGregory Neil Shapiro 		**  return immediately. So...
14340266059SGregory Neil Shapiro 		*/
14440266059SGregory Neil Shapiro 
14540266059SGregory Neil Shapiro 		errno = EAGAIN;
14640266059SGregory Neil Shapiro 		return SM_IO_EOF;
14740266059SGregory Neil Shapiro 	}
14840266059SGregory Neil Shapiro 
14940266059SGregory Neil Shapiro 	if (timeout != SM_TIME_FOREVER)
15040266059SGregory Neil Shapiro 	{
15140266059SGregory Neil Shapiro 		if (setjmp(ScanTimeOut) != 0)
15240266059SGregory Neil Shapiro 		{
15340266059SGregory Neil Shapiro 			errno = EAGAIN;
15440266059SGregory Neil Shapiro 			return SM_IO_EOF;
15540266059SGregory Neil Shapiro 		}
15640266059SGregory Neil Shapiro 
15740266059SGregory Neil Shapiro 		evt = sm_seteventm(timeout, scanalrm, 0);
15840266059SGregory Neil Shapiro 	}
15940266059SGregory Neil Shapiro 
16040266059SGregory Neil Shapiro 	nassigned = 0;
16140266059SGregory Neil Shapiro 	nread = 0;
16240266059SGregory Neil Shapiro 	base = 0;		/* XXX just to keep gcc happy */
16340266059SGregory Neil Shapiro 	ccfn = NULL;		/* XXX just to keep gcc happy */
16440266059SGregory Neil Shapiro 	for (;;)
16540266059SGregory Neil Shapiro 	{
16640266059SGregory Neil Shapiro 		c = *fmt++;
16740266059SGregory Neil Shapiro 		if (c == 0)
16840266059SGregory Neil Shapiro 		{
16940266059SGregory Neil Shapiro 			if (evt != NULL)
17040266059SGregory Neil Shapiro 				sm_clrevent(evt); /*  undo our timeout */
17140266059SGregory Neil Shapiro 			return nassigned;
17240266059SGregory Neil Shapiro 		}
17340266059SGregory Neil Shapiro 		if (isspace(c))
17440266059SGregory Neil Shapiro 		{
17540266059SGregory Neil Shapiro 			while ((fp->f_r > 0 || sm_refill(fp, SM_TIME_FOREVER)
17640266059SGregory Neil Shapiro 						== 0) &&
17740266059SGregory Neil Shapiro 			    isspace(*fp->f_p))
17840266059SGregory Neil Shapiro 				nread++, fp->f_r--, fp->f_p++;
17940266059SGregory Neil Shapiro 			continue;
18040266059SGregory Neil Shapiro 		}
18140266059SGregory Neil Shapiro 		if (c != '%')
18240266059SGregory Neil Shapiro 			goto literal;
18340266059SGregory Neil Shapiro 		width = 0;
18440266059SGregory Neil Shapiro 		flags = 0;
18540266059SGregory Neil Shapiro 
18640266059SGregory Neil Shapiro 		/*
18740266059SGregory Neil Shapiro 		**  switch on the format.  continue if done;
18840266059SGregory Neil Shapiro 		**  break once format type is derived.
18940266059SGregory Neil Shapiro 		*/
19040266059SGregory Neil Shapiro 
19140266059SGregory Neil Shapiro again:		c = *fmt++;
19240266059SGregory Neil Shapiro 		switch (c)
19340266059SGregory Neil Shapiro 		{
19440266059SGregory Neil Shapiro 		  case '%':
19540266059SGregory Neil Shapiro literal:
19640266059SGregory Neil Shapiro 			if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
19740266059SGregory Neil Shapiro 				goto input_failure;
19840266059SGregory Neil Shapiro 			if (*fp->f_p != c)
19940266059SGregory Neil Shapiro 				goto match_failure;
20040266059SGregory Neil Shapiro 			fp->f_r--, fp->f_p++;
20140266059SGregory Neil Shapiro 			nread++;
20240266059SGregory Neil Shapiro 			continue;
20340266059SGregory Neil Shapiro 
20440266059SGregory Neil Shapiro 		  case '*':
20540266059SGregory Neil Shapiro 			flags |= SUPPRESS;
20640266059SGregory Neil Shapiro 			goto again;
20740266059SGregory Neil Shapiro 		  case 'h':
20840266059SGregory Neil Shapiro 			flags |= SHORT;
20940266059SGregory Neil Shapiro 			goto again;
21040266059SGregory Neil Shapiro 		  case 'l':
21140266059SGregory Neil Shapiro 			if (*fmt == 'l')
21240266059SGregory Neil Shapiro 			{
21340266059SGregory Neil Shapiro 				fmt++;
21440266059SGregory Neil Shapiro 				flags |= QUAD;
21540266059SGregory Neil Shapiro 			}
21640266059SGregory Neil Shapiro 			else
21740266059SGregory Neil Shapiro 			{
21840266059SGregory Neil Shapiro 				flags |= LONG;
21940266059SGregory Neil Shapiro 			}
22040266059SGregory Neil Shapiro 			goto again;
22140266059SGregory Neil Shapiro 		  case 'q':
22240266059SGregory Neil Shapiro 			flags |= QUAD;
22340266059SGregory Neil Shapiro 			goto again;
22440266059SGregory Neil Shapiro 
22540266059SGregory Neil Shapiro 		  case '0': case '1': case '2': case '3': case '4':
22640266059SGregory Neil Shapiro 		  case '5': case '6': case '7': case '8': case '9':
22740266059SGregory Neil Shapiro 			width = width * 10 + c - '0';
22840266059SGregory Neil Shapiro 			goto again;
22940266059SGregory Neil Shapiro 
23040266059SGregory Neil Shapiro 		/*
23140266059SGregory Neil Shapiro 		**  Conversions.
23240266059SGregory Neil Shapiro 		**  Those marked `compat' are for 4.[123]BSD compatibility.
23340266059SGregory Neil Shapiro 		**
23440266059SGregory Neil Shapiro 		**  (According to ANSI, E and X formats are supposed
23540266059SGregory Neil Shapiro 		**  to the same as e and x.  Sorry about that.)
23640266059SGregory Neil Shapiro 		*/
23740266059SGregory Neil Shapiro 
23840266059SGregory Neil Shapiro 		  case 'D':	/* compat */
23940266059SGregory Neil Shapiro 			flags |= LONG;
24040266059SGregory Neil Shapiro 			/* FALLTHROUGH */
24140266059SGregory Neil Shapiro 		  case 'd':
24240266059SGregory Neil Shapiro 			c = CT_INT;
24340266059SGregory Neil Shapiro 			ccfn = (ULONGLONG_T (*)())sm_strtoll;
24440266059SGregory Neil Shapiro 			base = 10;
24540266059SGregory Neil Shapiro 			break;
24640266059SGregory Neil Shapiro 
24740266059SGregory Neil Shapiro 		  case 'i':
24840266059SGregory Neil Shapiro 			c = CT_INT;
24940266059SGregory Neil Shapiro 			ccfn = (ULONGLONG_T (*)())sm_strtoll;
25040266059SGregory Neil Shapiro 			base = 0;
25140266059SGregory Neil Shapiro 			break;
25240266059SGregory Neil Shapiro 
25340266059SGregory Neil Shapiro 		  case 'O':	/* compat */
25440266059SGregory Neil Shapiro 			flags |= LONG;
25540266059SGregory Neil Shapiro 			/* FALLTHROUGH */
25640266059SGregory Neil Shapiro 		  case 'o':
25740266059SGregory Neil Shapiro 			c = CT_INT;
25840266059SGregory Neil Shapiro 			ccfn = sm_strtoull;
25940266059SGregory Neil Shapiro 			base = 8;
26040266059SGregory Neil Shapiro 			break;
26140266059SGregory Neil Shapiro 
26240266059SGregory Neil Shapiro 		  case 'u':
26340266059SGregory Neil Shapiro 			c = CT_INT;
26440266059SGregory Neil Shapiro 			ccfn = sm_strtoull;
26540266059SGregory Neil Shapiro 			base = 10;
26640266059SGregory Neil Shapiro 			break;
26740266059SGregory Neil Shapiro 
26840266059SGregory Neil Shapiro 		  case 'X':
26940266059SGregory Neil Shapiro 		  case 'x':
27040266059SGregory Neil Shapiro 			flags |= PFXOK;	/* enable 0x prefixing */
27140266059SGregory Neil Shapiro 			c = CT_INT;
27240266059SGregory Neil Shapiro 			ccfn = sm_strtoull;
27340266059SGregory Neil Shapiro 			base = 16;
27440266059SGregory Neil Shapiro 			break;
27540266059SGregory Neil Shapiro 
27640266059SGregory Neil Shapiro 		  case 'E':
27740266059SGregory Neil Shapiro 		  case 'G':
27840266059SGregory Neil Shapiro 		  case 'e':
27940266059SGregory Neil Shapiro 		  case 'f':
28040266059SGregory Neil Shapiro 		  case 'g':
28140266059SGregory Neil Shapiro 			c = CT_FLOAT;
28240266059SGregory Neil Shapiro 			break;
28340266059SGregory Neil Shapiro 
28440266059SGregory Neil Shapiro 		  case 's':
28540266059SGregory Neil Shapiro 			c = CT_STRING;
28640266059SGregory Neil Shapiro 			break;
28740266059SGregory Neil Shapiro 
28840266059SGregory Neil Shapiro 		  case '[':
28940266059SGregory Neil Shapiro 			fmt = sm_sccl(ccltab, fmt);
29040266059SGregory Neil Shapiro 			flags |= NOSKIP;
29140266059SGregory Neil Shapiro 			c = CT_CCL;
29240266059SGregory Neil Shapiro 			break;
29340266059SGregory Neil Shapiro 
29440266059SGregory Neil Shapiro 		  case 'c':
29540266059SGregory Neil Shapiro 			flags |= NOSKIP;
29640266059SGregory Neil Shapiro 			c = CT_CHAR;
29740266059SGregory Neil Shapiro 			break;
29840266059SGregory Neil Shapiro 
29940266059SGregory Neil Shapiro 		  case 'p':	/* pointer format is like hex */
30040266059SGregory Neil Shapiro 			flags |= POINTER | PFXOK;
30140266059SGregory Neil Shapiro 			c = CT_INT;
30240266059SGregory Neil Shapiro 			ccfn = sm_strtoull;
30340266059SGregory Neil Shapiro 			base = 16;
30440266059SGregory Neil Shapiro 			break;
30540266059SGregory Neil Shapiro 
30640266059SGregory Neil Shapiro 		  case 'n':
30740266059SGregory Neil Shapiro 			if (flags & SUPPRESS)	/* ??? */
30840266059SGregory Neil Shapiro 				continue;
30940266059SGregory Neil Shapiro 			if (flags & SHORT)
31040266059SGregory Neil Shapiro 				*SM_VA_ARG(ap, short *) = nread;
31140266059SGregory Neil Shapiro 			else if (flags & LONG)
31240266059SGregory Neil Shapiro 				*SM_VA_ARG(ap, long *) = nread;
31340266059SGregory Neil Shapiro 			else
31440266059SGregory Neil Shapiro 				*SM_VA_ARG(ap, int *) = nread;
31540266059SGregory Neil Shapiro 			continue;
31640266059SGregory Neil Shapiro 
31740266059SGregory Neil Shapiro 		/* Disgusting backwards compatibility hacks.	XXX */
31840266059SGregory Neil Shapiro 		  case '\0':	/* compat */
31940266059SGregory Neil Shapiro 			if (evt != NULL)
32040266059SGregory Neil Shapiro 				sm_clrevent(evt); /*  undo our timeout */
32140266059SGregory Neil Shapiro 			return SM_IO_EOF;
32240266059SGregory Neil Shapiro 
32340266059SGregory Neil Shapiro 		  default:	/* compat */
32440266059SGregory Neil Shapiro 			if (isupper(c))
32540266059SGregory Neil Shapiro 				flags |= LONG;
32640266059SGregory Neil Shapiro 			c = CT_INT;
32740266059SGregory Neil Shapiro 			ccfn = (ULONGLONG_T (*)()) sm_strtoll;
32840266059SGregory Neil Shapiro 			base = 10;
32940266059SGregory Neil Shapiro 			break;
33040266059SGregory Neil Shapiro 		}
33140266059SGregory Neil Shapiro 
33240266059SGregory Neil Shapiro 		/* We have a conversion that requires input. */
33340266059SGregory Neil Shapiro 		if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
33440266059SGregory Neil Shapiro 			goto input_failure;
33540266059SGregory Neil Shapiro 
33640266059SGregory Neil Shapiro 		/*
33740266059SGregory Neil Shapiro 		**  Consume leading white space, except for formats
33840266059SGregory Neil Shapiro 		**  that suppress this.
33940266059SGregory Neil Shapiro 		*/
34040266059SGregory Neil Shapiro 
34140266059SGregory Neil Shapiro 		if ((flags & NOSKIP) == 0)
34240266059SGregory Neil Shapiro 		{
34340266059SGregory Neil Shapiro 			while (isspace(*fp->f_p))
34440266059SGregory Neil Shapiro 			{
34540266059SGregory Neil Shapiro 				nread++;
34640266059SGregory Neil Shapiro 				if (--fp->f_r > 0)
34740266059SGregory Neil Shapiro 					fp->f_p++;
34840266059SGregory Neil Shapiro 				else if (sm_refill(fp, SM_TIME_FOREVER))
34940266059SGregory Neil Shapiro 					goto input_failure;
35040266059SGregory Neil Shapiro 			}
35140266059SGregory Neil Shapiro 			/*
35240266059SGregory Neil Shapiro 			**  Note that there is at least one character in
35340266059SGregory Neil Shapiro 			**  the buffer, so conversions that do not set NOSKIP
35440266059SGregory Neil Shapiro 			**  can no longer result in an input failure.
35540266059SGregory Neil Shapiro 			*/
35640266059SGregory Neil Shapiro 		}
35740266059SGregory Neil Shapiro 
35840266059SGregory Neil Shapiro 		/* Do the conversion. */
35940266059SGregory Neil Shapiro 		switch (c)
36040266059SGregory Neil Shapiro 		{
36140266059SGregory Neil Shapiro 		  case CT_CHAR:
36240266059SGregory Neil Shapiro 			/* scan arbitrary characters (sets NOSKIP) */
36340266059SGregory Neil Shapiro 			if (width == 0)
36440266059SGregory Neil Shapiro 				width = 1;
36540266059SGregory Neil Shapiro 			if (flags & SUPPRESS)
36640266059SGregory Neil Shapiro 			{
36740266059SGregory Neil Shapiro 				size_t sum = 0;
36840266059SGregory Neil Shapiro 				for (;;)
36940266059SGregory Neil Shapiro 				{
37040266059SGregory Neil Shapiro 					if ((size_t) (n = fp->f_r) < width)
37140266059SGregory Neil Shapiro 					{
37240266059SGregory Neil Shapiro 						sum += n;
37340266059SGregory Neil Shapiro 						width -= n;
37440266059SGregory Neil Shapiro 						fp->f_p += n;
37540266059SGregory Neil Shapiro 						if (sm_refill(fp,
37640266059SGregory Neil Shapiro 							      SM_TIME_FOREVER))
37740266059SGregory Neil Shapiro 						{
37840266059SGregory Neil Shapiro 							if (sum == 0)
37940266059SGregory Neil Shapiro 								goto input_failure;
38040266059SGregory Neil Shapiro 							break;
38140266059SGregory Neil Shapiro 						}
38240266059SGregory Neil Shapiro 					}
38340266059SGregory Neil Shapiro 					else
38440266059SGregory Neil Shapiro 					{
38540266059SGregory Neil Shapiro 						sum += width;
38640266059SGregory Neil Shapiro 						fp->f_r -= width;
38740266059SGregory Neil Shapiro 						fp->f_p += width;
38840266059SGregory Neil Shapiro 						break;
38940266059SGregory Neil Shapiro 					}
39040266059SGregory Neil Shapiro 				}
39140266059SGregory Neil Shapiro 				nread += sum;
39240266059SGregory Neil Shapiro 			}
39340266059SGregory Neil Shapiro 			else
39440266059SGregory Neil Shapiro 			{
39540266059SGregory Neil Shapiro 				size_t r;
39640266059SGregory Neil Shapiro 
39740266059SGregory Neil Shapiro 				r = sm_io_read(fp, SM_TIME_FOREVER,
39840266059SGregory Neil Shapiro 						(void *) SM_VA_ARG(ap, char *),
39940266059SGregory Neil Shapiro 						width);
40040266059SGregory Neil Shapiro 				if (r == 0)
40140266059SGregory Neil Shapiro 					goto input_failure;
40240266059SGregory Neil Shapiro 				nread += r;
40340266059SGregory Neil Shapiro 				nassigned++;
40440266059SGregory Neil Shapiro 			}
40540266059SGregory Neil Shapiro 			break;
40640266059SGregory Neil Shapiro 
40740266059SGregory Neil Shapiro 		  case CT_CCL:
40840266059SGregory Neil Shapiro 			/* scan a (nonempty) character class (sets NOSKIP) */
40940266059SGregory Neil Shapiro 			if (width == 0)
41040266059SGregory Neil Shapiro 				width = (size_t)~0;	/* `infinity' */
41140266059SGregory Neil Shapiro 
41240266059SGregory Neil Shapiro 			/* take only those things in the class */
41340266059SGregory Neil Shapiro 			if (flags & SUPPRESS)
41440266059SGregory Neil Shapiro 			{
41540266059SGregory Neil Shapiro 				n = 0;
41640266059SGregory Neil Shapiro 				while (ccltab[*fp->f_p] != '\0')
41740266059SGregory Neil Shapiro 				{
41840266059SGregory Neil Shapiro 					n++, fp->f_r--, fp->f_p++;
41940266059SGregory Neil Shapiro 					if (--width == 0)
42040266059SGregory Neil Shapiro 						break;
42140266059SGregory Neil Shapiro 					if (fp->f_r <= 0 &&
42240266059SGregory Neil Shapiro 					    sm_refill(fp, SM_TIME_FOREVER))
42340266059SGregory Neil Shapiro 					{
42440266059SGregory Neil Shapiro 						if (n == 0) /* XXX how? */
42540266059SGregory Neil Shapiro 							goto input_failure;
42640266059SGregory Neil Shapiro 						break;
42740266059SGregory Neil Shapiro 					}
42840266059SGregory Neil Shapiro 				}
42940266059SGregory Neil Shapiro 				if (n == 0)
43040266059SGregory Neil Shapiro 					goto match_failure;
43140266059SGregory Neil Shapiro 			}
43240266059SGregory Neil Shapiro 			else
43340266059SGregory Neil Shapiro 			{
43440266059SGregory Neil Shapiro 				p0 = p = SM_VA_ARG(ap, char *);
43540266059SGregory Neil Shapiro 				while (ccltab[*fp->f_p] != '\0')
43640266059SGregory Neil Shapiro 				{
43740266059SGregory Neil Shapiro 					fp->f_r--;
43840266059SGregory Neil Shapiro 					*p++ = *fp->f_p++;
43940266059SGregory Neil Shapiro 					if (--width == 0)
44040266059SGregory Neil Shapiro 						break;
44140266059SGregory Neil Shapiro 					if (fp->f_r <= 0 &&
44240266059SGregory Neil Shapiro 					    sm_refill(fp, SM_TIME_FOREVER))
44340266059SGregory Neil Shapiro 					{
44440266059SGregory Neil Shapiro 						if (p == p0)
44540266059SGregory Neil Shapiro 							goto input_failure;
44640266059SGregory Neil Shapiro 						break;
44740266059SGregory Neil Shapiro 					}
44840266059SGregory Neil Shapiro 				}
44940266059SGregory Neil Shapiro 				n = p - p0;
45040266059SGregory Neil Shapiro 				if (n == 0)
45140266059SGregory Neil Shapiro 					goto match_failure;
45240266059SGregory Neil Shapiro 				*p = 0;
45340266059SGregory Neil Shapiro 				nassigned++;
45440266059SGregory Neil Shapiro 			}
45540266059SGregory Neil Shapiro 			nread += n;
45640266059SGregory Neil Shapiro 			break;
45740266059SGregory Neil Shapiro 
45840266059SGregory Neil Shapiro 		  case CT_STRING:
45940266059SGregory Neil Shapiro 			/* like CCL, but zero-length string OK, & no NOSKIP */
46040266059SGregory Neil Shapiro 			if (width == 0)
46140266059SGregory Neil Shapiro 				width = (size_t)~0;
46240266059SGregory Neil Shapiro 			if (flags & SUPPRESS)
46340266059SGregory Neil Shapiro 			{
46440266059SGregory Neil Shapiro 				n = 0;
46540266059SGregory Neil Shapiro 				while (!isspace(*fp->f_p))
46640266059SGregory Neil Shapiro 				{
46740266059SGregory Neil Shapiro 					n++, fp->f_r--, fp->f_p++;
46840266059SGregory Neil Shapiro 					if (--width == 0)
46940266059SGregory Neil Shapiro 						break;
47040266059SGregory Neil Shapiro 					if (fp->f_r <= 0 &&
47140266059SGregory Neil Shapiro 					    sm_refill(fp, SM_TIME_FOREVER))
47240266059SGregory Neil Shapiro 						break;
47340266059SGregory Neil Shapiro 				}
47440266059SGregory Neil Shapiro 				nread += n;
47540266059SGregory Neil Shapiro 			}
47640266059SGregory Neil Shapiro 			else
47740266059SGregory Neil Shapiro 			{
47840266059SGregory Neil Shapiro 				p0 = p = SM_VA_ARG(ap, char *);
47940266059SGregory Neil Shapiro 				while (!isspace(*fp->f_p))
48040266059SGregory Neil Shapiro 				{
48140266059SGregory Neil Shapiro 					fp->f_r--;
48240266059SGregory Neil Shapiro 					*p++ = *fp->f_p++;
48340266059SGregory Neil Shapiro 					if (--width == 0)
48440266059SGregory Neil Shapiro 						break;
48540266059SGregory Neil Shapiro 					if (fp->f_r <= 0 &&
48640266059SGregory Neil Shapiro 					    sm_refill(fp, SM_TIME_FOREVER))
48740266059SGregory Neil Shapiro 						break;
48840266059SGregory Neil Shapiro 				}
48940266059SGregory Neil Shapiro 				*p = 0;
49040266059SGregory Neil Shapiro 				nread += p - p0;
49140266059SGregory Neil Shapiro 				nassigned++;
49240266059SGregory Neil Shapiro 			}
49340266059SGregory Neil Shapiro 			continue;
49440266059SGregory Neil Shapiro 
49540266059SGregory Neil Shapiro 		  case CT_INT:
49640266059SGregory Neil Shapiro 			/* scan an integer as if by strtoll/strtoull */
49740266059SGregory Neil Shapiro #if SM_CONF_BROKEN_SIZE_T
49840266059SGregory Neil Shapiro 			if (width == 0 || width > sizeof(buf) - 1)
49940266059SGregory Neil Shapiro 				width = sizeof(buf) - 1;
50040266059SGregory Neil Shapiro #else /* SM_CONF_BROKEN_SIZE_T */
50140266059SGregory Neil Shapiro 			/* size_t is unsigned, hence this optimisation */
50240266059SGregory Neil Shapiro 			if (--width > sizeof(buf) - 2)
50340266059SGregory Neil Shapiro 				width = sizeof(buf) - 2;
50440266059SGregory Neil Shapiro 			width++;
50540266059SGregory Neil Shapiro #endif /* SM_CONF_BROKEN_SIZE_T */
50640266059SGregory Neil Shapiro 			flags |= SIGNOK | NDIGITS | NZDIGITS;
50740266059SGregory Neil Shapiro 			for (p = buf; width > 0; width--)
50840266059SGregory Neil Shapiro 			{
50940266059SGregory Neil Shapiro 				c = *fp->f_p;
51040266059SGregory Neil Shapiro 
51140266059SGregory Neil Shapiro 				/*
51240266059SGregory Neil Shapiro 				**  Switch on the character; `goto ok'
51340266059SGregory Neil Shapiro 				**  if we accept it as a part of number.
51440266059SGregory Neil Shapiro 				*/
51540266059SGregory Neil Shapiro 
51640266059SGregory Neil Shapiro 				switch (c)
51740266059SGregory Neil Shapiro 				{
51840266059SGregory Neil Shapiro 
51940266059SGregory Neil Shapiro 				/*
52040266059SGregory Neil Shapiro 				**  The digit 0 is always legal, but is
52140266059SGregory Neil Shapiro 				**  special.  For %i conversions, if no
52240266059SGregory Neil Shapiro 				**  digits (zero or nonzero) have been
52340266059SGregory Neil Shapiro 				**  scanned (only signs), we will have
52440266059SGregory Neil Shapiro 				**  base==0.  In that case, we should set
52540266059SGregory Neil Shapiro 				**  it to 8 and enable 0x prefixing.
52640266059SGregory Neil Shapiro 				**  Also, if we have not scanned zero digits
52740266059SGregory Neil Shapiro 				**  before this, do not turn off prefixing
52840266059SGregory Neil Shapiro 				**  (someone else will turn it off if we
52940266059SGregory Neil Shapiro 				**  have scanned any nonzero digits).
53040266059SGregory Neil Shapiro 				*/
53140266059SGregory Neil Shapiro 
53240266059SGregory Neil Shapiro 				  case '0':
53340266059SGregory Neil Shapiro 					if (base == 0)
53440266059SGregory Neil Shapiro 					{
53540266059SGregory Neil Shapiro 						base = 8;
53640266059SGregory Neil Shapiro 						flags |= PFXOK;
53740266059SGregory Neil Shapiro 					}
53840266059SGregory Neil Shapiro 					if (flags & NZDIGITS)
53940266059SGregory Neil Shapiro 					    flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
54040266059SGregory Neil Shapiro 					else
54140266059SGregory Neil Shapiro 					    flags &= ~(SIGNOK|PFXOK|NDIGITS);
54240266059SGregory Neil Shapiro 					goto ok;
54340266059SGregory Neil Shapiro 
54440266059SGregory Neil Shapiro 				/* 1 through 7 always legal */
54540266059SGregory Neil Shapiro 				  case '1': case '2': case '3':
54640266059SGregory Neil Shapiro 				  case '4': case '5': case '6': case '7':
54740266059SGregory Neil Shapiro 					base = basefix[base];
54840266059SGregory Neil Shapiro 					flags &= ~(SIGNOK | PFXOK | NDIGITS);
54940266059SGregory Neil Shapiro 					goto ok;
55040266059SGregory Neil Shapiro 
55140266059SGregory Neil Shapiro 				/* digits 8 and 9 ok iff decimal or hex */
55240266059SGregory Neil Shapiro 				  case '8': case '9':
55340266059SGregory Neil Shapiro 					base = basefix[base];
55440266059SGregory Neil Shapiro 					if (base <= 8)
55540266059SGregory Neil Shapiro 						break;	/* not legal here */
55640266059SGregory Neil Shapiro 					flags &= ~(SIGNOK | PFXOK | NDIGITS);
55740266059SGregory Neil Shapiro 					goto ok;
55840266059SGregory Neil Shapiro 
55940266059SGregory Neil Shapiro 				/* letters ok iff hex */
56040266059SGregory Neil Shapiro 				  case 'A': case 'B': case 'C':
56140266059SGregory Neil Shapiro 				  case 'D': case 'E': case 'F':
56240266059SGregory Neil Shapiro 				  case 'a': case 'b': case 'c':
56340266059SGregory Neil Shapiro 				  case 'd': case 'e': case 'f':
56440266059SGregory Neil Shapiro 
56540266059SGregory Neil Shapiro 					/* no need to fix base here */
56640266059SGregory Neil Shapiro 					if (base <= 10)
56740266059SGregory Neil Shapiro 						break;	/* not legal here */
56840266059SGregory Neil Shapiro 					flags &= ~(SIGNOK | PFXOK | NDIGITS);
56940266059SGregory Neil Shapiro 					goto ok;
57040266059SGregory Neil Shapiro 
57140266059SGregory Neil Shapiro 				/* sign ok only as first character */
57240266059SGregory Neil Shapiro 				  case '+': case '-':
57340266059SGregory Neil Shapiro 					if (flags & SIGNOK)
57440266059SGregory Neil Shapiro 					{
57540266059SGregory Neil Shapiro 						flags &= ~SIGNOK;
57640266059SGregory Neil Shapiro 						goto ok;
57740266059SGregory Neil Shapiro 					}
57840266059SGregory Neil Shapiro 					break;
57940266059SGregory Neil Shapiro 
58040266059SGregory Neil Shapiro 				/* x ok iff flag still set & 2nd char */
58140266059SGregory Neil Shapiro 				  case 'x': case 'X':
58240266059SGregory Neil Shapiro 					if (flags & PFXOK && p == buf + 1)
58340266059SGregory Neil Shapiro 					{
58440266059SGregory Neil Shapiro 						base = 16;	/* if %i */
58540266059SGregory Neil Shapiro 						flags &= ~PFXOK;
58640266059SGregory Neil Shapiro 						goto ok;
58740266059SGregory Neil Shapiro 					}
58840266059SGregory Neil Shapiro 					break;
58940266059SGregory Neil Shapiro 				}
59040266059SGregory Neil Shapiro 
59140266059SGregory Neil Shapiro 				/*
59240266059SGregory Neil Shapiro 				**  If we got here, c is not a legal character
59340266059SGregory Neil Shapiro 				**  for a number.  Stop accumulating digits.
59440266059SGregory Neil Shapiro 				*/
59540266059SGregory Neil Shapiro 
59640266059SGregory Neil Shapiro 				break;
59740266059SGregory Neil Shapiro 		ok:
59840266059SGregory Neil Shapiro 				/* c is legal: store it and look at the next. */
59940266059SGregory Neil Shapiro 				*p++ = c;
60040266059SGregory Neil Shapiro 				if (--fp->f_r > 0)
60140266059SGregory Neil Shapiro 					fp->f_p++;
60240266059SGregory Neil Shapiro 				else if (sm_refill(fp, SM_TIME_FOREVER))
60340266059SGregory Neil Shapiro 					break;		/* SM_IO_EOF */
60440266059SGregory Neil Shapiro 			}
60540266059SGregory Neil Shapiro 
60640266059SGregory Neil Shapiro 			/*
60740266059SGregory Neil Shapiro 			**  If we had only a sign, it is no good; push
60840266059SGregory Neil Shapiro 			**  back the sign.  If the number ends in `x',
60940266059SGregory Neil Shapiro 			**  it was [sign] '0' 'x', so push back the x
61040266059SGregory Neil Shapiro 			**  and treat it as [sign] '0'.
61140266059SGregory Neil Shapiro 			*/
61240266059SGregory Neil Shapiro 
61340266059SGregory Neil Shapiro 			if (flags & NDIGITS)
61440266059SGregory Neil Shapiro 			{
61540266059SGregory Neil Shapiro 				if (p > buf)
61640266059SGregory Neil Shapiro 					(void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
61740266059SGregory Neil Shapiro 							    *(unsigned char *)--p);
61840266059SGregory Neil Shapiro 				goto match_failure;
61940266059SGregory Neil Shapiro 			}
62040266059SGregory Neil Shapiro 			c = ((unsigned char *)p)[-1];
62140266059SGregory Neil Shapiro 			if (c == 'x' || c == 'X')
62240266059SGregory Neil Shapiro 			{
62340266059SGregory Neil Shapiro 				--p;
62440266059SGregory Neil Shapiro 				(void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
62540266059SGregory Neil Shapiro 			}
62640266059SGregory Neil Shapiro 			if ((flags & SUPPRESS) == 0)
62740266059SGregory Neil Shapiro 			{
62840266059SGregory Neil Shapiro 				ULONGLONG_T res;
62940266059SGregory Neil Shapiro 
63040266059SGregory Neil Shapiro 				*p = 0;
63140266059SGregory Neil Shapiro 				res = (*ccfn)(buf, (char **)NULL, base);
63240266059SGregory Neil Shapiro 				if (flags & POINTER)
63340266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, void **) =
63440266059SGregory Neil Shapiro 					    (void *)(long) res;
63540266059SGregory Neil Shapiro 				else if (flags & QUAD)
63640266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, LONGLONG_T *) = res;
63740266059SGregory Neil Shapiro 				else if (flags & LONG)
63840266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, long *) = res;
63940266059SGregory Neil Shapiro 				else if (flags & SHORT)
64040266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, short *) = res;
64140266059SGregory Neil Shapiro 				else
64240266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, int *) = res;
64340266059SGregory Neil Shapiro 				nassigned++;
64440266059SGregory Neil Shapiro 			}
64540266059SGregory Neil Shapiro 			nread += p - buf;
64640266059SGregory Neil Shapiro 			break;
64740266059SGregory Neil Shapiro 
64840266059SGregory Neil Shapiro 		  case CT_FLOAT:
64940266059SGregory Neil Shapiro 			/* scan a floating point number as if by strtod */
65040266059SGregory Neil Shapiro 			if (width == 0 || width > sizeof(buf) - 1)
65140266059SGregory Neil Shapiro 				width = sizeof(buf) - 1;
65240266059SGregory Neil Shapiro 			flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
65340266059SGregory Neil Shapiro 			for (p = buf; width; width--)
65440266059SGregory Neil Shapiro 			{
65540266059SGregory Neil Shapiro 				c = *fp->f_p;
65640266059SGregory Neil Shapiro 
65740266059SGregory Neil Shapiro 				/*
658*d39bd2c1SGregory Neil Shapiro 				**  This code mimics the integer conversion
65940266059SGregory Neil Shapiro 				**  code, but is much simpler.
66040266059SGregory Neil Shapiro 				*/
66140266059SGregory Neil Shapiro 
66240266059SGregory Neil Shapiro 				switch (c)
66340266059SGregory Neil Shapiro 				{
66440266059SGregory Neil Shapiro 
66540266059SGregory Neil Shapiro 				  case '0': case '1': case '2': case '3':
66640266059SGregory Neil Shapiro 				  case '4': case '5': case '6': case '7':
66740266059SGregory Neil Shapiro 				  case '8': case '9':
66840266059SGregory Neil Shapiro 					flags &= ~(SIGNOK | NDIGITS);
66940266059SGregory Neil Shapiro 					goto fok;
67040266059SGregory Neil Shapiro 
67140266059SGregory Neil Shapiro 				  case '+': case '-':
67240266059SGregory Neil Shapiro 					if (flags & SIGNOK)
67340266059SGregory Neil Shapiro 					{
67440266059SGregory Neil Shapiro 						flags &= ~SIGNOK;
67540266059SGregory Neil Shapiro 						goto fok;
67640266059SGregory Neil Shapiro 					}
67740266059SGregory Neil Shapiro 					break;
67840266059SGregory Neil Shapiro 				  case '.':
67940266059SGregory Neil Shapiro 					if (flags & DPTOK)
68040266059SGregory Neil Shapiro 					{
68140266059SGregory Neil Shapiro 						flags &= ~(SIGNOK | DPTOK);
68240266059SGregory Neil Shapiro 						goto fok;
68340266059SGregory Neil Shapiro 					}
68440266059SGregory Neil Shapiro 					break;
68540266059SGregory Neil Shapiro 				  case 'e': case 'E':
68640266059SGregory Neil Shapiro 
68740266059SGregory Neil Shapiro 					/* no exponent without some digits */
68840266059SGregory Neil Shapiro 					if ((flags&(NDIGITS|EXPOK)) == EXPOK)
68940266059SGregory Neil Shapiro 					{
69040266059SGregory Neil Shapiro 						flags =
69140266059SGregory Neil Shapiro 						    (flags & ~(EXPOK|DPTOK)) |
69240266059SGregory Neil Shapiro 						    SIGNOK | NDIGITS;
69340266059SGregory Neil Shapiro 						goto fok;
69440266059SGregory Neil Shapiro 					}
69540266059SGregory Neil Shapiro 					break;
69640266059SGregory Neil Shapiro 				}
69740266059SGregory Neil Shapiro 				break;
69840266059SGregory Neil Shapiro 		fok:
69940266059SGregory Neil Shapiro 				*p++ = c;
70040266059SGregory Neil Shapiro 				if (--fp->f_r > 0)
70140266059SGregory Neil Shapiro 					fp->f_p++;
70240266059SGregory Neil Shapiro 				else if (sm_refill(fp, SM_TIME_FOREVER))
70340266059SGregory Neil Shapiro 					break;	/* SM_IO_EOF */
70440266059SGregory Neil Shapiro 			}
70540266059SGregory Neil Shapiro 
70640266059SGregory Neil Shapiro 			/*
70740266059SGregory Neil Shapiro 			**  If no digits, might be missing exponent digits
70840266059SGregory Neil Shapiro 			**  (just give back the exponent) or might be missing
70940266059SGregory Neil Shapiro 			**  regular digits, but had sign and/or decimal point.
71040266059SGregory Neil Shapiro 			*/
71140266059SGregory Neil Shapiro 
71240266059SGregory Neil Shapiro 			if (flags & NDIGITS)
71340266059SGregory Neil Shapiro 			{
71440266059SGregory Neil Shapiro 				if (flags & EXPOK)
71540266059SGregory Neil Shapiro 				{
71640266059SGregory Neil Shapiro 					/* no digits at all */
71740266059SGregory Neil Shapiro 					while (p > buf)
71840266059SGregory Neil Shapiro 						(void) sm_io_ungetc(fp,
71940266059SGregory Neil Shapiro 							     SM_TIME_DEFAULT,
72040266059SGregory Neil Shapiro 							     *(unsigned char *)--p);
72140266059SGregory Neil Shapiro 					goto match_failure;
72240266059SGregory Neil Shapiro 				}
72340266059SGregory Neil Shapiro 
72440266059SGregory Neil Shapiro 				/* just a bad exponent (e and maybe sign) */
72540266059SGregory Neil Shapiro 				c = *(unsigned char *) --p;
72640266059SGregory Neil Shapiro 				if (c != 'e' && c != 'E')
72740266059SGregory Neil Shapiro 				{
72840266059SGregory Neil Shapiro 					(void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
72940266059SGregory Neil Shapiro 							    c); /* sign */
73040266059SGregory Neil Shapiro 					c = *(unsigned char *)--p;
73140266059SGregory Neil Shapiro 				}
73240266059SGregory Neil Shapiro 				(void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
73340266059SGregory Neil Shapiro 			}
73440266059SGregory Neil Shapiro 			if ((flags & SUPPRESS) == 0)
73540266059SGregory Neil Shapiro 			{
73640266059SGregory Neil Shapiro 				double res;
73740266059SGregory Neil Shapiro 
73840266059SGregory Neil Shapiro 				*p = 0;
73940266059SGregory Neil Shapiro 				res = strtod(buf, (char **) NULL);
74040266059SGregory Neil Shapiro 				if (flags & LONG)
74140266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, double *) = res;
74240266059SGregory Neil Shapiro 				else
74340266059SGregory Neil Shapiro 					*SM_VA_ARG(ap, float *) = res;
74440266059SGregory Neil Shapiro 				nassigned++;
74540266059SGregory Neil Shapiro 			}
74640266059SGregory Neil Shapiro 			nread += p - buf;
74740266059SGregory Neil Shapiro 			break;
74840266059SGregory Neil Shapiro 		}
74940266059SGregory Neil Shapiro 	}
75040266059SGregory Neil Shapiro input_failure:
75140266059SGregory Neil Shapiro 	if (evt != NULL)
75240266059SGregory Neil Shapiro 		sm_clrevent(evt); /*  undo our timeout */
75340266059SGregory Neil Shapiro 	return nassigned ? nassigned : -1;
75440266059SGregory Neil Shapiro match_failure:
75540266059SGregory Neil Shapiro 	if (evt != NULL)
75640266059SGregory Neil Shapiro 		sm_clrevent(evt); /*  undo our timeout */
75740266059SGregory Neil Shapiro 	return nassigned;
75840266059SGregory Neil Shapiro }
75940266059SGregory Neil Shapiro 
76040266059SGregory Neil Shapiro /*
76140266059SGregory Neil Shapiro **  SM_SCCL -- sequenced character comparison list
76240266059SGregory Neil Shapiro **
76340266059SGregory Neil Shapiro **  Fill in the given table from the scanset at the given format
76440266059SGregory Neil Shapiro **  (just after `[').  Return a pointer to the character past the
76540266059SGregory Neil Shapiro **  closing `]'.  The table has a 1 wherever characters should be
76640266059SGregory Neil Shapiro **  considered part of the scanset.
76740266059SGregory Neil Shapiro **
76840266059SGregory Neil Shapiro **	Parameters:
76940266059SGregory Neil Shapiro **		tab -- array flagging "active" char's to match (returned)
77040266059SGregory Neil Shapiro **		fmt -- character list (within "[]")
77140266059SGregory Neil Shapiro **
77240266059SGregory Neil Shapiro **	Results:
77340266059SGregory Neil Shapiro */
77440266059SGregory Neil Shapiro 
77540266059SGregory Neil Shapiro static unsigned char *
sm_sccl(tab,fmt)77640266059SGregory Neil Shapiro sm_sccl(tab, fmt)
77740266059SGregory Neil Shapiro 	register char *tab;
77840266059SGregory Neil Shapiro 	register unsigned char *fmt;
77940266059SGregory Neil Shapiro {
78040266059SGregory Neil Shapiro 	register int c, n, v;
78140266059SGregory Neil Shapiro 
78240266059SGregory Neil Shapiro 	/* first `clear' the whole table */
78340266059SGregory Neil Shapiro 	c = *fmt++;		/* first char hat => negated scanset */
78440266059SGregory Neil Shapiro 	if (c == '^')
78540266059SGregory Neil Shapiro 	{
78640266059SGregory Neil Shapiro 		v = 1;		/* default => accept */
78740266059SGregory Neil Shapiro 		c = *fmt++;	/* get new first char */
78840266059SGregory Neil Shapiro 	}
78940266059SGregory Neil Shapiro 	else
79040266059SGregory Neil Shapiro 		v = 0;		/* default => reject */
79140266059SGregory Neil Shapiro 
79240266059SGregory Neil Shapiro 	/* should probably use memset here */
79340266059SGregory Neil Shapiro 	for (n = 0; n < 256; n++)
79440266059SGregory Neil Shapiro 		tab[n] = v;
79540266059SGregory Neil Shapiro 	if (c == 0)
79640266059SGregory Neil Shapiro 		return fmt - 1;	/* format ended before closing ] */
79740266059SGregory Neil Shapiro 
79840266059SGregory Neil Shapiro 	/*
79940266059SGregory Neil Shapiro 	**  Now set the entries corresponding to the actual scanset
80040266059SGregory Neil Shapiro 	**  to the opposite of the above.
80140266059SGregory Neil Shapiro 	**
80240266059SGregory Neil Shapiro 	**  The first character may be ']' (or '-') without being special;
80340266059SGregory Neil Shapiro 	**  the last character may be '-'.
80440266059SGregory Neil Shapiro 	*/
80540266059SGregory Neil Shapiro 
80640266059SGregory Neil Shapiro 	v = 1 - v;
80740266059SGregory Neil Shapiro 	for (;;)
80840266059SGregory Neil Shapiro 	{
80940266059SGregory Neil Shapiro 		tab[c] = v;		/* take character c */
81040266059SGregory Neil Shapiro doswitch:
81140266059SGregory Neil Shapiro 		n = *fmt++;		/* and examine the next */
81240266059SGregory Neil Shapiro 		switch (n)
81340266059SGregory Neil Shapiro 		{
81440266059SGregory Neil Shapiro 
81540266059SGregory Neil Shapiro 		  case 0:			/* format ended too soon */
81640266059SGregory Neil Shapiro 			return fmt - 1;
81740266059SGregory Neil Shapiro 
81840266059SGregory Neil Shapiro 		  case '-':
81940266059SGregory Neil Shapiro 			/*
82040266059SGregory Neil Shapiro 			**  A scanset of the form
82140266059SGregory Neil Shapiro 			**	[01+-]
82240266059SGregory Neil Shapiro 			**  is defined as `the digit 0, the digit 1,
82340266059SGregory Neil Shapiro 			**  the character +, the character -', but
82440266059SGregory Neil Shapiro 			**  the effect of a scanset such as
82540266059SGregory Neil Shapiro 			**	[a-zA-Z0-9]
82640266059SGregory Neil Shapiro 			**  is implementation defined.  The V7 Unix
82740266059SGregory Neil Shapiro 			**  scanf treats `a-z' as `the letters a through
82840266059SGregory Neil Shapiro 			**  z', but treats `a-a' as `the letter a, the
82940266059SGregory Neil Shapiro 			**  character -, and the letter a'.
83040266059SGregory Neil Shapiro 			**
8315b0945b5SGregory Neil Shapiro 			**  For compatibility, the `-' is not considered
83240266059SGregory Neil Shapiro 			**  to define a range if the character following
83340266059SGregory Neil Shapiro 			**  it is either a close bracket (required by ANSI)
83440266059SGregory Neil Shapiro 			**  or is not numerically greater than the character
83540266059SGregory Neil Shapiro 			**  we just stored in the table (c).
83640266059SGregory Neil Shapiro 			*/
83740266059SGregory Neil Shapiro 
83840266059SGregory Neil Shapiro 			n = *fmt;
83940266059SGregory Neil Shapiro 			if (n == ']' || n < c)
84040266059SGregory Neil Shapiro 			{
84140266059SGregory Neil Shapiro 				c = '-';
84240266059SGregory Neil Shapiro 				break;	/* resume the for(;;) */
84340266059SGregory Neil Shapiro 			}
84440266059SGregory Neil Shapiro 			fmt++;
84540266059SGregory Neil Shapiro 			do
84640266059SGregory Neil Shapiro 			{
84740266059SGregory Neil Shapiro 				/* fill in the range */
84840266059SGregory Neil Shapiro 				tab[++c] = v;
84940266059SGregory Neil Shapiro 			} while (c < n);
85040266059SGregory Neil Shapiro #if 1	/* XXX another disgusting compatibility hack */
85140266059SGregory Neil Shapiro 
85240266059SGregory Neil Shapiro 			/*
85340266059SGregory Neil Shapiro 			**  Alas, the V7 Unix scanf also treats formats
85440266059SGregory Neil Shapiro 			**  such as [a-c-e] as `the letters a through e'.
85540266059SGregory Neil Shapiro 			**  This too is permitted by the standard....
85640266059SGregory Neil Shapiro 			*/
85740266059SGregory Neil Shapiro 
85840266059SGregory Neil Shapiro 			goto doswitch;
85940266059SGregory Neil Shapiro #else
86040266059SGregory Neil Shapiro 			c = *fmt++;
86140266059SGregory Neil Shapiro 			if (c == 0)
86240266059SGregory Neil Shapiro 				return fmt - 1;
86340266059SGregory Neil Shapiro 			if (c == ']')
86440266059SGregory Neil Shapiro 				return fmt;
86540266059SGregory Neil Shapiro 			break;
86640266059SGregory Neil Shapiro #endif
86740266059SGregory Neil Shapiro 
86840266059SGregory Neil Shapiro 		  case ']':		/* end of scanset */
86940266059SGregory Neil Shapiro 			return fmt;
87040266059SGregory Neil Shapiro 
87140266059SGregory Neil Shapiro 		  default:		/* just another character */
87240266059SGregory Neil Shapiro 			c = n;
87340266059SGregory Neil Shapiro 			break;
87440266059SGregory Neil Shapiro 		}
87540266059SGregory Neil Shapiro 	}
87640266059SGregory Neil Shapiro 	/* NOTREACHED */
87740266059SGregory Neil Shapiro }
878