xref: /titanic_51/usr/src/cmd/sendmail/libsm/vfscanf.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2000-2001, 2004 Sendmail, Inc. and its suppliers.
3*7c478bd9Sstevel@tonic-gate  *      All rights reserved.
4*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1990, 1993
5*7c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
6*7c478bd9Sstevel@tonic-gate  *
7*7c478bd9Sstevel@tonic-gate  * This code is derived from software contributed to Berkeley by
8*7c478bd9Sstevel@tonic-gate  * Chris Torek.
9*7c478bd9Sstevel@tonic-gate  *
10*7c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
11*7c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
12*7c478bd9Sstevel@tonic-gate  * the sendmail distribution.
13*7c478bd9Sstevel@tonic-gate  */
14*7c478bd9Sstevel@tonic-gate 
15*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
16*7c478bd9Sstevel@tonic-gate 
17*7c478bd9Sstevel@tonic-gate #include <sm/gen.h>
18*7c478bd9Sstevel@tonic-gate SM_IDSTR(id, "@(#)$Id: vfscanf.c,v 1.52 2004/08/03 20:56:32 ca Exp $")
19*7c478bd9Sstevel@tonic-gate 
20*7c478bd9Sstevel@tonic-gate #include <ctype.h>
21*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
22*7c478bd9Sstevel@tonic-gate #include <errno.h>
23*7c478bd9Sstevel@tonic-gate #include <setjmp.h>
24*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
25*7c478bd9Sstevel@tonic-gate #include <sm/varargs.h>
26*7c478bd9Sstevel@tonic-gate #include <sm/config.h>
27*7c478bd9Sstevel@tonic-gate #include <sm/io.h>
28*7c478bd9Sstevel@tonic-gate #include <sm/signal.h>
29*7c478bd9Sstevel@tonic-gate #include <sm/clock.h>
30*7c478bd9Sstevel@tonic-gate #include <sm/string.h>
31*7c478bd9Sstevel@tonic-gate #include "local.h"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #define BUF		513	/* Maximum length of numeric string. */
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate /* Flags used during conversion. */
36*7c478bd9Sstevel@tonic-gate #define LONG		0x01	/* l: long or double */
37*7c478bd9Sstevel@tonic-gate #define SHORT		0x04	/* h: short */
38*7c478bd9Sstevel@tonic-gate #define QUAD		0x08	/* q: quad (same as ll) */
39*7c478bd9Sstevel@tonic-gate #define SUPPRESS	0x10	/* suppress assignment */
40*7c478bd9Sstevel@tonic-gate #define POINTER		0x20	/* weird %p pointer (`fake hex') */
41*7c478bd9Sstevel@tonic-gate #define NOSKIP		0x40	/* do not skip blanks */
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate /*
44*7c478bd9Sstevel@tonic-gate **  The following are used in numeric conversions only:
45*7c478bd9Sstevel@tonic-gate **  SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
46*7c478bd9Sstevel@tonic-gate **  SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
47*7c478bd9Sstevel@tonic-gate */
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate #define SIGNOK		0x080	/* +/- is (still) legal */
50*7c478bd9Sstevel@tonic-gate #define NDIGITS		0x100	/* no digits detected */
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate #define DPTOK		0x200	/* (float) decimal point is still legal */
53*7c478bd9Sstevel@tonic-gate #define EXPOK		0x400	/* (float) exponent (e+3, etc) still legal */
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate #define PFXOK		0x200	/* 0x prefix is (still) legal */
56*7c478bd9Sstevel@tonic-gate #define NZDIGITS	0x400	/* no zero digits detected */
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate /* Conversion types. */
59*7c478bd9Sstevel@tonic-gate #define CT_CHAR		0	/* %c conversion */
60*7c478bd9Sstevel@tonic-gate #define CT_CCL		1	/* %[...] conversion */
61*7c478bd9Sstevel@tonic-gate #define CT_STRING	2	/* %s conversion */
62*7c478bd9Sstevel@tonic-gate #define CT_INT		3	/* integer, i.e., strtoll or strtoull */
63*7c478bd9Sstevel@tonic-gate #define CT_FLOAT	4	/* floating, i.e., strtod */
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate static void		scanalrm __P((int));
66*7c478bd9Sstevel@tonic-gate static unsigned char	*sm_sccl __P((char *, unsigned char *));
67*7c478bd9Sstevel@tonic-gate static jmp_buf		ScanTimeOut;
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate /*
70*7c478bd9Sstevel@tonic-gate **  SCANALRM -- handler when timeout activated for sm_io_vfscanf()
71*7c478bd9Sstevel@tonic-gate **
72*7c478bd9Sstevel@tonic-gate **  Returns flow of control to where setjmp(ScanTimeOut) was set.
73*7c478bd9Sstevel@tonic-gate **
74*7c478bd9Sstevel@tonic-gate **	Parameters:
75*7c478bd9Sstevel@tonic-gate **		sig -- unused
76*7c478bd9Sstevel@tonic-gate **
77*7c478bd9Sstevel@tonic-gate **	Returns:
78*7c478bd9Sstevel@tonic-gate **		does not return
79*7c478bd9Sstevel@tonic-gate **
80*7c478bd9Sstevel@tonic-gate **	Side Effects:
81*7c478bd9Sstevel@tonic-gate **		returns flow of control to setjmp(ScanTimeOut).
82*7c478bd9Sstevel@tonic-gate **
83*7c478bd9Sstevel@tonic-gate **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
84*7c478bd9Sstevel@tonic-gate **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
85*7c478bd9Sstevel@tonic-gate **		DOING.
86*7c478bd9Sstevel@tonic-gate */
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate /* ARGSUSED0 */
89*7c478bd9Sstevel@tonic-gate static void
90*7c478bd9Sstevel@tonic-gate scanalrm(sig)
91*7c478bd9Sstevel@tonic-gate 	int sig;
92*7c478bd9Sstevel@tonic-gate {
93*7c478bd9Sstevel@tonic-gate 	longjmp(ScanTimeOut, 1);
94*7c478bd9Sstevel@tonic-gate }
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate /*
97*7c478bd9Sstevel@tonic-gate **  SM_VFSCANF -- convert input into data units
98*7c478bd9Sstevel@tonic-gate **
99*7c478bd9Sstevel@tonic-gate **	Parameters:
100*7c478bd9Sstevel@tonic-gate **		fp -- file pointer for input data
101*7c478bd9Sstevel@tonic-gate **		timeout -- time intvl allowed to complete (milliseconds)
102*7c478bd9Sstevel@tonic-gate **		fmt0 -- format for finding data units
103*7c478bd9Sstevel@tonic-gate **		ap -- vectors for memory location for storing data units
104*7c478bd9Sstevel@tonic-gate **
105*7c478bd9Sstevel@tonic-gate **	Results:
106*7c478bd9Sstevel@tonic-gate **		Success: number of data units assigned
107*7c478bd9Sstevel@tonic-gate **		Failure: SM_IO_EOF
108*7c478bd9Sstevel@tonic-gate */
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate int
111*7c478bd9Sstevel@tonic-gate sm_vfscanf(fp, timeout, fmt0, ap)
112*7c478bd9Sstevel@tonic-gate 	register SM_FILE_T *fp;
113*7c478bd9Sstevel@tonic-gate 	int SM_NONVOLATILE timeout;
114*7c478bd9Sstevel@tonic-gate 	char const *fmt0;
115*7c478bd9Sstevel@tonic-gate 	va_list SM_NONVOLATILE ap;
116*7c478bd9Sstevel@tonic-gate {
117*7c478bd9Sstevel@tonic-gate 	register unsigned char *SM_NONVOLATILE fmt = (unsigned char *) fmt0;
118*7c478bd9Sstevel@tonic-gate 	register int c;		/* character from format, or conversion */
119*7c478bd9Sstevel@tonic-gate 	register size_t width;	/* field width, or 0 */
120*7c478bd9Sstevel@tonic-gate 	register char *p;	/* points into all kinds of strings */
121*7c478bd9Sstevel@tonic-gate 	register int n;		/* handy integer */
122*7c478bd9Sstevel@tonic-gate 	register int flags;	/* flags as defined above */
123*7c478bd9Sstevel@tonic-gate 	register char *p0;	/* saves original value of p when necessary */
124*7c478bd9Sstevel@tonic-gate 	int nassigned;		/* number of fields assigned */
125*7c478bd9Sstevel@tonic-gate 	int nread;		/* number of characters consumed from fp */
126*7c478bd9Sstevel@tonic-gate 	int base;		/* base argument to strtoll/strtoull */
127*7c478bd9Sstevel@tonic-gate 	ULONGLONG_T (*ccfn)();	/* conversion function (strtoll/strtoull) */
128*7c478bd9Sstevel@tonic-gate 	char ccltab[256];	/* character class table for %[...] */
129*7c478bd9Sstevel@tonic-gate 	char buf[BUF];		/* buffer for numeric conversions */
130*7c478bd9Sstevel@tonic-gate 	SM_EVENT *evt = NULL;
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	/* `basefix' is used to avoid `if' tests in the integer scanner */
133*7c478bd9Sstevel@tonic-gate 	static short basefix[17] =
134*7c478bd9Sstevel@tonic-gate 		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	if (timeout == SM_TIME_DEFAULT)
137*7c478bd9Sstevel@tonic-gate 		timeout = fp->f_timeout;
138*7c478bd9Sstevel@tonic-gate 	if (timeout == SM_TIME_IMMEDIATE)
139*7c478bd9Sstevel@tonic-gate 	{
140*7c478bd9Sstevel@tonic-gate 		/*
141*7c478bd9Sstevel@tonic-gate 		**  Filling the buffer will take time and we are wanted to
142*7c478bd9Sstevel@tonic-gate 		**  return immediately. So...
143*7c478bd9Sstevel@tonic-gate 		*/
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 		errno = EAGAIN;
146*7c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;
147*7c478bd9Sstevel@tonic-gate 	}
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 	if (timeout != SM_TIME_FOREVER)
150*7c478bd9Sstevel@tonic-gate 	{
151*7c478bd9Sstevel@tonic-gate 		if (setjmp(ScanTimeOut) != 0)
152*7c478bd9Sstevel@tonic-gate 		{
153*7c478bd9Sstevel@tonic-gate 			errno = EAGAIN;
154*7c478bd9Sstevel@tonic-gate 			return SM_IO_EOF;
155*7c478bd9Sstevel@tonic-gate 		}
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 		evt = sm_seteventm(timeout, scanalrm, 0);
158*7c478bd9Sstevel@tonic-gate 	}
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	nassigned = 0;
161*7c478bd9Sstevel@tonic-gate 	nread = 0;
162*7c478bd9Sstevel@tonic-gate 	base = 0;		/* XXX just to keep gcc happy */
163*7c478bd9Sstevel@tonic-gate 	ccfn = NULL;		/* XXX just to keep gcc happy */
164*7c478bd9Sstevel@tonic-gate 	for (;;)
165*7c478bd9Sstevel@tonic-gate 	{
166*7c478bd9Sstevel@tonic-gate 		c = *fmt++;
167*7c478bd9Sstevel@tonic-gate 		if (c == 0)
168*7c478bd9Sstevel@tonic-gate 		{
169*7c478bd9Sstevel@tonic-gate 			if (evt != NULL)
170*7c478bd9Sstevel@tonic-gate 				sm_clrevent(evt); /*  undo our timeout */
171*7c478bd9Sstevel@tonic-gate 			return nassigned;
172*7c478bd9Sstevel@tonic-gate 		}
173*7c478bd9Sstevel@tonic-gate 		if (isspace(c))
174*7c478bd9Sstevel@tonic-gate 		{
175*7c478bd9Sstevel@tonic-gate 			while ((fp->f_r > 0 || sm_refill(fp, SM_TIME_FOREVER)
176*7c478bd9Sstevel@tonic-gate 						== 0) &&
177*7c478bd9Sstevel@tonic-gate 			    isspace(*fp->f_p))
178*7c478bd9Sstevel@tonic-gate 				nread++, fp->f_r--, fp->f_p++;
179*7c478bd9Sstevel@tonic-gate 			continue;
180*7c478bd9Sstevel@tonic-gate 		}
181*7c478bd9Sstevel@tonic-gate 		if (c != '%')
182*7c478bd9Sstevel@tonic-gate 			goto literal;
183*7c478bd9Sstevel@tonic-gate 		width = 0;
184*7c478bd9Sstevel@tonic-gate 		flags = 0;
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 		/*
187*7c478bd9Sstevel@tonic-gate 		**  switch on the format.  continue if done;
188*7c478bd9Sstevel@tonic-gate 		**  break once format type is derived.
189*7c478bd9Sstevel@tonic-gate 		*/
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate again:		c = *fmt++;
192*7c478bd9Sstevel@tonic-gate 		switch (c)
193*7c478bd9Sstevel@tonic-gate 		{
194*7c478bd9Sstevel@tonic-gate 		  case '%':
195*7c478bd9Sstevel@tonic-gate literal:
196*7c478bd9Sstevel@tonic-gate 			if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
197*7c478bd9Sstevel@tonic-gate 				goto input_failure;
198*7c478bd9Sstevel@tonic-gate 			if (*fp->f_p != c)
199*7c478bd9Sstevel@tonic-gate 				goto match_failure;
200*7c478bd9Sstevel@tonic-gate 			fp->f_r--, fp->f_p++;
201*7c478bd9Sstevel@tonic-gate 			nread++;
202*7c478bd9Sstevel@tonic-gate 			continue;
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 		  case '*':
205*7c478bd9Sstevel@tonic-gate 			flags |= SUPPRESS;
206*7c478bd9Sstevel@tonic-gate 			goto again;
207*7c478bd9Sstevel@tonic-gate 		  case 'h':
208*7c478bd9Sstevel@tonic-gate 			flags |= SHORT;
209*7c478bd9Sstevel@tonic-gate 			goto again;
210*7c478bd9Sstevel@tonic-gate 		  case 'l':
211*7c478bd9Sstevel@tonic-gate 			if (*fmt == 'l')
212*7c478bd9Sstevel@tonic-gate 			{
213*7c478bd9Sstevel@tonic-gate 				fmt++;
214*7c478bd9Sstevel@tonic-gate 				flags |= QUAD;
215*7c478bd9Sstevel@tonic-gate 			}
216*7c478bd9Sstevel@tonic-gate 			else
217*7c478bd9Sstevel@tonic-gate 			{
218*7c478bd9Sstevel@tonic-gate 				flags |= LONG;
219*7c478bd9Sstevel@tonic-gate 			}
220*7c478bd9Sstevel@tonic-gate 			goto again;
221*7c478bd9Sstevel@tonic-gate 		  case 'q':
222*7c478bd9Sstevel@tonic-gate 			flags |= QUAD;
223*7c478bd9Sstevel@tonic-gate 			goto again;
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 		  case '0': case '1': case '2': case '3': case '4':
226*7c478bd9Sstevel@tonic-gate 		  case '5': case '6': case '7': case '8': case '9':
227*7c478bd9Sstevel@tonic-gate 			width = width * 10 + c - '0';
228*7c478bd9Sstevel@tonic-gate 			goto again;
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 		/*
231*7c478bd9Sstevel@tonic-gate 		**  Conversions.
232*7c478bd9Sstevel@tonic-gate 		**  Those marked `compat' are for 4.[123]BSD compatibility.
233*7c478bd9Sstevel@tonic-gate 		**
234*7c478bd9Sstevel@tonic-gate 		**  (According to ANSI, E and X formats are supposed
235*7c478bd9Sstevel@tonic-gate 		**  to the same as e and x.  Sorry about that.)
236*7c478bd9Sstevel@tonic-gate 		*/
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 		  case 'D':	/* compat */
239*7c478bd9Sstevel@tonic-gate 			flags |= LONG;
240*7c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
241*7c478bd9Sstevel@tonic-gate 		  case 'd':
242*7c478bd9Sstevel@tonic-gate 			c = CT_INT;
243*7c478bd9Sstevel@tonic-gate 			ccfn = (ULONGLONG_T (*)())sm_strtoll;
244*7c478bd9Sstevel@tonic-gate 			base = 10;
245*7c478bd9Sstevel@tonic-gate 			break;
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 		  case 'i':
248*7c478bd9Sstevel@tonic-gate 			c = CT_INT;
249*7c478bd9Sstevel@tonic-gate 			ccfn = (ULONGLONG_T (*)())sm_strtoll;
250*7c478bd9Sstevel@tonic-gate 			base = 0;
251*7c478bd9Sstevel@tonic-gate 			break;
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 		  case 'O':	/* compat */
254*7c478bd9Sstevel@tonic-gate 			flags |= LONG;
255*7c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
256*7c478bd9Sstevel@tonic-gate 		  case 'o':
257*7c478bd9Sstevel@tonic-gate 			c = CT_INT;
258*7c478bd9Sstevel@tonic-gate 			ccfn = sm_strtoull;
259*7c478bd9Sstevel@tonic-gate 			base = 8;
260*7c478bd9Sstevel@tonic-gate 			break;
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 		  case 'u':
263*7c478bd9Sstevel@tonic-gate 			c = CT_INT;
264*7c478bd9Sstevel@tonic-gate 			ccfn = sm_strtoull;
265*7c478bd9Sstevel@tonic-gate 			base = 10;
266*7c478bd9Sstevel@tonic-gate 			break;
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 		  case 'X':
269*7c478bd9Sstevel@tonic-gate 		  case 'x':
270*7c478bd9Sstevel@tonic-gate 			flags |= PFXOK;	/* enable 0x prefixing */
271*7c478bd9Sstevel@tonic-gate 			c = CT_INT;
272*7c478bd9Sstevel@tonic-gate 			ccfn = sm_strtoull;
273*7c478bd9Sstevel@tonic-gate 			base = 16;
274*7c478bd9Sstevel@tonic-gate 			break;
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 		  case 'E':
277*7c478bd9Sstevel@tonic-gate 		  case 'G':
278*7c478bd9Sstevel@tonic-gate 		  case 'e':
279*7c478bd9Sstevel@tonic-gate 		  case 'f':
280*7c478bd9Sstevel@tonic-gate 		  case 'g':
281*7c478bd9Sstevel@tonic-gate 			c = CT_FLOAT;
282*7c478bd9Sstevel@tonic-gate 			break;
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 		  case 's':
285*7c478bd9Sstevel@tonic-gate 			c = CT_STRING;
286*7c478bd9Sstevel@tonic-gate 			break;
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 		  case '[':
289*7c478bd9Sstevel@tonic-gate 			fmt = sm_sccl(ccltab, fmt);
290*7c478bd9Sstevel@tonic-gate 			flags |= NOSKIP;
291*7c478bd9Sstevel@tonic-gate 			c = CT_CCL;
292*7c478bd9Sstevel@tonic-gate 			break;
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 		  case 'c':
295*7c478bd9Sstevel@tonic-gate 			flags |= NOSKIP;
296*7c478bd9Sstevel@tonic-gate 			c = CT_CHAR;
297*7c478bd9Sstevel@tonic-gate 			break;
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 		  case 'p':	/* pointer format is like hex */
300*7c478bd9Sstevel@tonic-gate 			flags |= POINTER | PFXOK;
301*7c478bd9Sstevel@tonic-gate 			c = CT_INT;
302*7c478bd9Sstevel@tonic-gate 			ccfn = sm_strtoull;
303*7c478bd9Sstevel@tonic-gate 			base = 16;
304*7c478bd9Sstevel@tonic-gate 			break;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 		  case 'n':
307*7c478bd9Sstevel@tonic-gate 			if (flags & SUPPRESS)	/* ??? */
308*7c478bd9Sstevel@tonic-gate 				continue;
309*7c478bd9Sstevel@tonic-gate 			if (flags & SHORT)
310*7c478bd9Sstevel@tonic-gate 				*SM_VA_ARG(ap, short *) = nread;
311*7c478bd9Sstevel@tonic-gate 			else if (flags & LONG)
312*7c478bd9Sstevel@tonic-gate 				*SM_VA_ARG(ap, long *) = nread;
313*7c478bd9Sstevel@tonic-gate 			else
314*7c478bd9Sstevel@tonic-gate 				*SM_VA_ARG(ap, int *) = nread;
315*7c478bd9Sstevel@tonic-gate 			continue;
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 		/* Disgusting backwards compatibility hacks.	XXX */
318*7c478bd9Sstevel@tonic-gate 		  case '\0':	/* compat */
319*7c478bd9Sstevel@tonic-gate 			if (evt != NULL)
320*7c478bd9Sstevel@tonic-gate 				sm_clrevent(evt); /*  undo our timeout */
321*7c478bd9Sstevel@tonic-gate 			return SM_IO_EOF;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 		  default:	/* compat */
324*7c478bd9Sstevel@tonic-gate 			if (isupper(c))
325*7c478bd9Sstevel@tonic-gate 				flags |= LONG;
326*7c478bd9Sstevel@tonic-gate 			c = CT_INT;
327*7c478bd9Sstevel@tonic-gate 			ccfn = (ULONGLONG_T (*)()) sm_strtoll;
328*7c478bd9Sstevel@tonic-gate 			base = 10;
329*7c478bd9Sstevel@tonic-gate 			break;
330*7c478bd9Sstevel@tonic-gate 		}
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 		/* We have a conversion that requires input. */
333*7c478bd9Sstevel@tonic-gate 		if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
334*7c478bd9Sstevel@tonic-gate 			goto input_failure;
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 		/*
337*7c478bd9Sstevel@tonic-gate 		**  Consume leading white space, except for formats
338*7c478bd9Sstevel@tonic-gate 		**  that suppress this.
339*7c478bd9Sstevel@tonic-gate 		*/
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 		if ((flags & NOSKIP) == 0)
342*7c478bd9Sstevel@tonic-gate 		{
343*7c478bd9Sstevel@tonic-gate 			while (isspace(*fp->f_p))
344*7c478bd9Sstevel@tonic-gate 			{
345*7c478bd9Sstevel@tonic-gate 				nread++;
346*7c478bd9Sstevel@tonic-gate 				if (--fp->f_r > 0)
347*7c478bd9Sstevel@tonic-gate 					fp->f_p++;
348*7c478bd9Sstevel@tonic-gate 				else if (sm_refill(fp, SM_TIME_FOREVER))
349*7c478bd9Sstevel@tonic-gate 					goto input_failure;
350*7c478bd9Sstevel@tonic-gate 			}
351*7c478bd9Sstevel@tonic-gate 			/*
352*7c478bd9Sstevel@tonic-gate 			**  Note that there is at least one character in
353*7c478bd9Sstevel@tonic-gate 			**  the buffer, so conversions that do not set NOSKIP
354*7c478bd9Sstevel@tonic-gate 			**  can no longer result in an input failure.
355*7c478bd9Sstevel@tonic-gate 			*/
356*7c478bd9Sstevel@tonic-gate 		}
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 		/* Do the conversion. */
359*7c478bd9Sstevel@tonic-gate 		switch (c)
360*7c478bd9Sstevel@tonic-gate 		{
361*7c478bd9Sstevel@tonic-gate 		  case CT_CHAR:
362*7c478bd9Sstevel@tonic-gate 			/* scan arbitrary characters (sets NOSKIP) */
363*7c478bd9Sstevel@tonic-gate 			if (width == 0)
364*7c478bd9Sstevel@tonic-gate 				width = 1;
365*7c478bd9Sstevel@tonic-gate 			if (flags & SUPPRESS)
366*7c478bd9Sstevel@tonic-gate 			{
367*7c478bd9Sstevel@tonic-gate 				size_t sum = 0;
368*7c478bd9Sstevel@tonic-gate 				for (;;)
369*7c478bd9Sstevel@tonic-gate 				{
370*7c478bd9Sstevel@tonic-gate 					if ((size_t) (n = fp->f_r) < width)
371*7c478bd9Sstevel@tonic-gate 					{
372*7c478bd9Sstevel@tonic-gate 						sum += n;
373*7c478bd9Sstevel@tonic-gate 						width -= n;
374*7c478bd9Sstevel@tonic-gate 						fp->f_p += n;
375*7c478bd9Sstevel@tonic-gate 						if (sm_refill(fp,
376*7c478bd9Sstevel@tonic-gate 							      SM_TIME_FOREVER))
377*7c478bd9Sstevel@tonic-gate 						{
378*7c478bd9Sstevel@tonic-gate 							if (sum == 0)
379*7c478bd9Sstevel@tonic-gate 								goto input_failure;
380*7c478bd9Sstevel@tonic-gate 							break;
381*7c478bd9Sstevel@tonic-gate 						}
382*7c478bd9Sstevel@tonic-gate 					}
383*7c478bd9Sstevel@tonic-gate 					else
384*7c478bd9Sstevel@tonic-gate 					{
385*7c478bd9Sstevel@tonic-gate 						sum += width;
386*7c478bd9Sstevel@tonic-gate 						fp->f_r -= width;
387*7c478bd9Sstevel@tonic-gate 						fp->f_p += width;
388*7c478bd9Sstevel@tonic-gate 						break;
389*7c478bd9Sstevel@tonic-gate 					}
390*7c478bd9Sstevel@tonic-gate 				}
391*7c478bd9Sstevel@tonic-gate 				nread += sum;
392*7c478bd9Sstevel@tonic-gate 			}
393*7c478bd9Sstevel@tonic-gate 			else
394*7c478bd9Sstevel@tonic-gate 			{
395*7c478bd9Sstevel@tonic-gate 				size_t r;
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 				r = sm_io_read(fp, SM_TIME_FOREVER,
398*7c478bd9Sstevel@tonic-gate 						(void *) SM_VA_ARG(ap, char *),
399*7c478bd9Sstevel@tonic-gate 						width);
400*7c478bd9Sstevel@tonic-gate 				if (r == 0)
401*7c478bd9Sstevel@tonic-gate 					goto input_failure;
402*7c478bd9Sstevel@tonic-gate 				nread += r;
403*7c478bd9Sstevel@tonic-gate 				nassigned++;
404*7c478bd9Sstevel@tonic-gate 			}
405*7c478bd9Sstevel@tonic-gate 			break;
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 		  case CT_CCL:
408*7c478bd9Sstevel@tonic-gate 			/* scan a (nonempty) character class (sets NOSKIP) */
409*7c478bd9Sstevel@tonic-gate 			if (width == 0)
410*7c478bd9Sstevel@tonic-gate 				width = (size_t)~0;	/* `infinity' */
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate 			/* take only those things in the class */
413*7c478bd9Sstevel@tonic-gate 			if (flags & SUPPRESS)
414*7c478bd9Sstevel@tonic-gate 			{
415*7c478bd9Sstevel@tonic-gate 				n = 0;
416*7c478bd9Sstevel@tonic-gate 				while (ccltab[*fp->f_p] != '\0')
417*7c478bd9Sstevel@tonic-gate 				{
418*7c478bd9Sstevel@tonic-gate 					n++, fp->f_r--, fp->f_p++;
419*7c478bd9Sstevel@tonic-gate 					if (--width == 0)
420*7c478bd9Sstevel@tonic-gate 						break;
421*7c478bd9Sstevel@tonic-gate 					if (fp->f_r <= 0 &&
422*7c478bd9Sstevel@tonic-gate 					    sm_refill(fp, SM_TIME_FOREVER))
423*7c478bd9Sstevel@tonic-gate 					{
424*7c478bd9Sstevel@tonic-gate 						if (n == 0) /* XXX how? */
425*7c478bd9Sstevel@tonic-gate 							goto input_failure;
426*7c478bd9Sstevel@tonic-gate 						break;
427*7c478bd9Sstevel@tonic-gate 					}
428*7c478bd9Sstevel@tonic-gate 				}
429*7c478bd9Sstevel@tonic-gate 				if (n == 0)
430*7c478bd9Sstevel@tonic-gate 					goto match_failure;
431*7c478bd9Sstevel@tonic-gate 			}
432*7c478bd9Sstevel@tonic-gate 			else
433*7c478bd9Sstevel@tonic-gate 			{
434*7c478bd9Sstevel@tonic-gate 				p0 = p = SM_VA_ARG(ap, char *);
435*7c478bd9Sstevel@tonic-gate 				while (ccltab[*fp->f_p] != '\0')
436*7c478bd9Sstevel@tonic-gate 				{
437*7c478bd9Sstevel@tonic-gate 					fp->f_r--;
438*7c478bd9Sstevel@tonic-gate 					*p++ = *fp->f_p++;
439*7c478bd9Sstevel@tonic-gate 					if (--width == 0)
440*7c478bd9Sstevel@tonic-gate 						break;
441*7c478bd9Sstevel@tonic-gate 					if (fp->f_r <= 0 &&
442*7c478bd9Sstevel@tonic-gate 					    sm_refill(fp, SM_TIME_FOREVER))
443*7c478bd9Sstevel@tonic-gate 					{
444*7c478bd9Sstevel@tonic-gate 						if (p == p0)
445*7c478bd9Sstevel@tonic-gate 							goto input_failure;
446*7c478bd9Sstevel@tonic-gate 						break;
447*7c478bd9Sstevel@tonic-gate 					}
448*7c478bd9Sstevel@tonic-gate 				}
449*7c478bd9Sstevel@tonic-gate 				n = p - p0;
450*7c478bd9Sstevel@tonic-gate 				if (n == 0)
451*7c478bd9Sstevel@tonic-gate 					goto match_failure;
452*7c478bd9Sstevel@tonic-gate 				*p = 0;
453*7c478bd9Sstevel@tonic-gate 				nassigned++;
454*7c478bd9Sstevel@tonic-gate 			}
455*7c478bd9Sstevel@tonic-gate 			nread += n;
456*7c478bd9Sstevel@tonic-gate 			break;
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 		  case CT_STRING:
459*7c478bd9Sstevel@tonic-gate 			/* like CCL, but zero-length string OK, & no NOSKIP */
460*7c478bd9Sstevel@tonic-gate 			if (width == 0)
461*7c478bd9Sstevel@tonic-gate 				width = (size_t)~0;
462*7c478bd9Sstevel@tonic-gate 			if (flags & SUPPRESS)
463*7c478bd9Sstevel@tonic-gate 			{
464*7c478bd9Sstevel@tonic-gate 				n = 0;
465*7c478bd9Sstevel@tonic-gate 				while (!isspace(*fp->f_p))
466*7c478bd9Sstevel@tonic-gate 				{
467*7c478bd9Sstevel@tonic-gate 					n++, fp->f_r--, fp->f_p++;
468*7c478bd9Sstevel@tonic-gate 					if (--width == 0)
469*7c478bd9Sstevel@tonic-gate 						break;
470*7c478bd9Sstevel@tonic-gate 					if (fp->f_r <= 0 &&
471*7c478bd9Sstevel@tonic-gate 					    sm_refill(fp, SM_TIME_FOREVER))
472*7c478bd9Sstevel@tonic-gate 						break;
473*7c478bd9Sstevel@tonic-gate 				}
474*7c478bd9Sstevel@tonic-gate 				nread += n;
475*7c478bd9Sstevel@tonic-gate 			}
476*7c478bd9Sstevel@tonic-gate 			else
477*7c478bd9Sstevel@tonic-gate 			{
478*7c478bd9Sstevel@tonic-gate 				p0 = p = SM_VA_ARG(ap, char *);
479*7c478bd9Sstevel@tonic-gate 				while (!isspace(*fp->f_p))
480*7c478bd9Sstevel@tonic-gate 				{
481*7c478bd9Sstevel@tonic-gate 					fp->f_r--;
482*7c478bd9Sstevel@tonic-gate 					*p++ = *fp->f_p++;
483*7c478bd9Sstevel@tonic-gate 					if (--width == 0)
484*7c478bd9Sstevel@tonic-gate 						break;
485*7c478bd9Sstevel@tonic-gate 					if (fp->f_r <= 0 &&
486*7c478bd9Sstevel@tonic-gate 					    sm_refill(fp, SM_TIME_FOREVER))
487*7c478bd9Sstevel@tonic-gate 						break;
488*7c478bd9Sstevel@tonic-gate 				}
489*7c478bd9Sstevel@tonic-gate 				*p = 0;
490*7c478bd9Sstevel@tonic-gate 				nread += p - p0;
491*7c478bd9Sstevel@tonic-gate 				nassigned++;
492*7c478bd9Sstevel@tonic-gate 			}
493*7c478bd9Sstevel@tonic-gate 			continue;
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 		  case CT_INT:
496*7c478bd9Sstevel@tonic-gate 			/* scan an integer as if by strtoll/strtoull */
497*7c478bd9Sstevel@tonic-gate #if SM_CONF_BROKEN_SIZE_T
498*7c478bd9Sstevel@tonic-gate 			if (width == 0 || width > sizeof(buf) - 1)
499*7c478bd9Sstevel@tonic-gate 				width = sizeof(buf) - 1;
500*7c478bd9Sstevel@tonic-gate #else /* SM_CONF_BROKEN_SIZE_T */
501*7c478bd9Sstevel@tonic-gate 			/* size_t is unsigned, hence this optimisation */
502*7c478bd9Sstevel@tonic-gate 			if (--width > sizeof(buf) - 2)
503*7c478bd9Sstevel@tonic-gate 				width = sizeof(buf) - 2;
504*7c478bd9Sstevel@tonic-gate 			width++;
505*7c478bd9Sstevel@tonic-gate #endif /* SM_CONF_BROKEN_SIZE_T */
506*7c478bd9Sstevel@tonic-gate 			flags |= SIGNOK | NDIGITS | NZDIGITS;
507*7c478bd9Sstevel@tonic-gate 			for (p = buf; width > 0; width--)
508*7c478bd9Sstevel@tonic-gate 			{
509*7c478bd9Sstevel@tonic-gate 				c = *fp->f_p;
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 				/*
512*7c478bd9Sstevel@tonic-gate 				**  Switch on the character; `goto ok'
513*7c478bd9Sstevel@tonic-gate 				**  if we accept it as a part of number.
514*7c478bd9Sstevel@tonic-gate 				*/
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 				switch (c)
517*7c478bd9Sstevel@tonic-gate 				{
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 				/*
520*7c478bd9Sstevel@tonic-gate 				**  The digit 0 is always legal, but is
521*7c478bd9Sstevel@tonic-gate 				**  special.  For %i conversions, if no
522*7c478bd9Sstevel@tonic-gate 				**  digits (zero or nonzero) have been
523*7c478bd9Sstevel@tonic-gate 				**  scanned (only signs), we will have
524*7c478bd9Sstevel@tonic-gate 				**  base==0.  In that case, we should set
525*7c478bd9Sstevel@tonic-gate 				**  it to 8 and enable 0x prefixing.
526*7c478bd9Sstevel@tonic-gate 				**  Also, if we have not scanned zero digits
527*7c478bd9Sstevel@tonic-gate 				**  before this, do not turn off prefixing
528*7c478bd9Sstevel@tonic-gate 				**  (someone else will turn it off if we
529*7c478bd9Sstevel@tonic-gate 				**  have scanned any nonzero digits).
530*7c478bd9Sstevel@tonic-gate 				*/
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 				  case '0':
533*7c478bd9Sstevel@tonic-gate 					if (base == 0)
534*7c478bd9Sstevel@tonic-gate 					{
535*7c478bd9Sstevel@tonic-gate 						base = 8;
536*7c478bd9Sstevel@tonic-gate 						flags |= PFXOK;
537*7c478bd9Sstevel@tonic-gate 					}
538*7c478bd9Sstevel@tonic-gate 					if (flags & NZDIGITS)
539*7c478bd9Sstevel@tonic-gate 					    flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
540*7c478bd9Sstevel@tonic-gate 					else
541*7c478bd9Sstevel@tonic-gate 					    flags &= ~(SIGNOK|PFXOK|NDIGITS);
542*7c478bd9Sstevel@tonic-gate 					goto ok;
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 				/* 1 through 7 always legal */
545*7c478bd9Sstevel@tonic-gate 				  case '1': case '2': case '3':
546*7c478bd9Sstevel@tonic-gate 				  case '4': case '5': case '6': case '7':
547*7c478bd9Sstevel@tonic-gate 					base = basefix[base];
548*7c478bd9Sstevel@tonic-gate 					flags &= ~(SIGNOK | PFXOK | NDIGITS);
549*7c478bd9Sstevel@tonic-gate 					goto ok;
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 				/* digits 8 and 9 ok iff decimal or hex */
552*7c478bd9Sstevel@tonic-gate 				  case '8': case '9':
553*7c478bd9Sstevel@tonic-gate 					base = basefix[base];
554*7c478bd9Sstevel@tonic-gate 					if (base <= 8)
555*7c478bd9Sstevel@tonic-gate 						break;	/* not legal here */
556*7c478bd9Sstevel@tonic-gate 					flags &= ~(SIGNOK | PFXOK | NDIGITS);
557*7c478bd9Sstevel@tonic-gate 					goto ok;
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 				/* letters ok iff hex */
560*7c478bd9Sstevel@tonic-gate 				  case 'A': case 'B': case 'C':
561*7c478bd9Sstevel@tonic-gate 				  case 'D': case 'E': case 'F':
562*7c478bd9Sstevel@tonic-gate 				  case 'a': case 'b': case 'c':
563*7c478bd9Sstevel@tonic-gate 				  case 'd': case 'e': case 'f':
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 					/* no need to fix base here */
566*7c478bd9Sstevel@tonic-gate 					if (base <= 10)
567*7c478bd9Sstevel@tonic-gate 						break;	/* not legal here */
568*7c478bd9Sstevel@tonic-gate 					flags &= ~(SIGNOK | PFXOK | NDIGITS);
569*7c478bd9Sstevel@tonic-gate 					goto ok;
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 				/* sign ok only as first character */
572*7c478bd9Sstevel@tonic-gate 				  case '+': case '-':
573*7c478bd9Sstevel@tonic-gate 					if (flags & SIGNOK)
574*7c478bd9Sstevel@tonic-gate 					{
575*7c478bd9Sstevel@tonic-gate 						flags &= ~SIGNOK;
576*7c478bd9Sstevel@tonic-gate 						goto ok;
577*7c478bd9Sstevel@tonic-gate 					}
578*7c478bd9Sstevel@tonic-gate 					break;
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 				/* x ok iff flag still set & 2nd char */
581*7c478bd9Sstevel@tonic-gate 				  case 'x': case 'X':
582*7c478bd9Sstevel@tonic-gate 					if (flags & PFXOK && p == buf + 1)
583*7c478bd9Sstevel@tonic-gate 					{
584*7c478bd9Sstevel@tonic-gate 						base = 16;	/* if %i */
585*7c478bd9Sstevel@tonic-gate 						flags &= ~PFXOK;
586*7c478bd9Sstevel@tonic-gate 						goto ok;
587*7c478bd9Sstevel@tonic-gate 					}
588*7c478bd9Sstevel@tonic-gate 					break;
589*7c478bd9Sstevel@tonic-gate 				}
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 				/*
592*7c478bd9Sstevel@tonic-gate 				**  If we got here, c is not a legal character
593*7c478bd9Sstevel@tonic-gate 				**  for a number.  Stop accumulating digits.
594*7c478bd9Sstevel@tonic-gate 				*/
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 				break;
597*7c478bd9Sstevel@tonic-gate 		ok:
598*7c478bd9Sstevel@tonic-gate 				/* c is legal: store it and look at the next. */
599*7c478bd9Sstevel@tonic-gate 				*p++ = c;
600*7c478bd9Sstevel@tonic-gate 				if (--fp->f_r > 0)
601*7c478bd9Sstevel@tonic-gate 					fp->f_p++;
602*7c478bd9Sstevel@tonic-gate 				else if (sm_refill(fp, SM_TIME_FOREVER))
603*7c478bd9Sstevel@tonic-gate 					break;		/* SM_IO_EOF */
604*7c478bd9Sstevel@tonic-gate 			}
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 			/*
607*7c478bd9Sstevel@tonic-gate 			**  If we had only a sign, it is no good; push
608*7c478bd9Sstevel@tonic-gate 			**  back the sign.  If the number ends in `x',
609*7c478bd9Sstevel@tonic-gate 			**  it was [sign] '0' 'x', so push back the x
610*7c478bd9Sstevel@tonic-gate 			**  and treat it as [sign] '0'.
611*7c478bd9Sstevel@tonic-gate 			*/
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 			if (flags & NDIGITS)
614*7c478bd9Sstevel@tonic-gate 			{
615*7c478bd9Sstevel@tonic-gate 				if (p > buf)
616*7c478bd9Sstevel@tonic-gate 					(void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
617*7c478bd9Sstevel@tonic-gate 							    *(unsigned char *)--p);
618*7c478bd9Sstevel@tonic-gate 				goto match_failure;
619*7c478bd9Sstevel@tonic-gate 			}
620*7c478bd9Sstevel@tonic-gate 			c = ((unsigned char *)p)[-1];
621*7c478bd9Sstevel@tonic-gate 			if (c == 'x' || c == 'X')
622*7c478bd9Sstevel@tonic-gate 			{
623*7c478bd9Sstevel@tonic-gate 				--p;
624*7c478bd9Sstevel@tonic-gate 				(void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
625*7c478bd9Sstevel@tonic-gate 			}
626*7c478bd9Sstevel@tonic-gate 			if ((flags & SUPPRESS) == 0)
627*7c478bd9Sstevel@tonic-gate 			{
628*7c478bd9Sstevel@tonic-gate 				ULONGLONG_T res;
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 				*p = 0;
631*7c478bd9Sstevel@tonic-gate 				res = (*ccfn)(buf, (char **)NULL, base);
632*7c478bd9Sstevel@tonic-gate 				if (flags & POINTER)
633*7c478bd9Sstevel@tonic-gate 					*SM_VA_ARG(ap, void **) =
634*7c478bd9Sstevel@tonic-gate 					    (void *)(long) res;
635*7c478bd9Sstevel@tonic-gate 				else if (flags & QUAD)
636*7c478bd9Sstevel@tonic-gate 					*SM_VA_ARG(ap, LONGLONG_T *) = res;
637*7c478bd9Sstevel@tonic-gate 				else if (flags & LONG)
638*7c478bd9Sstevel@tonic-gate 					*SM_VA_ARG(ap, long *) = res;
639*7c478bd9Sstevel@tonic-gate 				else if (flags & SHORT)
640*7c478bd9Sstevel@tonic-gate 					*SM_VA_ARG(ap, short *) = res;
641*7c478bd9Sstevel@tonic-gate 				else
642*7c478bd9Sstevel@tonic-gate 					*SM_VA_ARG(ap, int *) = res;
643*7c478bd9Sstevel@tonic-gate 				nassigned++;
644*7c478bd9Sstevel@tonic-gate 			}
645*7c478bd9Sstevel@tonic-gate 			nread += p - buf;
646*7c478bd9Sstevel@tonic-gate 			break;
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate 		  case CT_FLOAT:
649*7c478bd9Sstevel@tonic-gate 			/* scan a floating point number as if by strtod */
650*7c478bd9Sstevel@tonic-gate 			if (width == 0 || width > sizeof(buf) - 1)
651*7c478bd9Sstevel@tonic-gate 				width = sizeof(buf) - 1;
652*7c478bd9Sstevel@tonic-gate 			flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
653*7c478bd9Sstevel@tonic-gate 			for (p = buf; width; width--)
654*7c478bd9Sstevel@tonic-gate 			{
655*7c478bd9Sstevel@tonic-gate 				c = *fp->f_p;
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate 				/*
658*7c478bd9Sstevel@tonic-gate 				**  This code mimicks the integer conversion
659*7c478bd9Sstevel@tonic-gate 				**  code, but is much simpler.
660*7c478bd9Sstevel@tonic-gate 				*/
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 				switch (c)
663*7c478bd9Sstevel@tonic-gate 				{
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 				  case '0': case '1': case '2': case '3':
666*7c478bd9Sstevel@tonic-gate 				  case '4': case '5': case '6': case '7':
667*7c478bd9Sstevel@tonic-gate 				  case '8': case '9':
668*7c478bd9Sstevel@tonic-gate 					flags &= ~(SIGNOK | NDIGITS);
669*7c478bd9Sstevel@tonic-gate 					goto fok;
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 				  case '+': case '-':
672*7c478bd9Sstevel@tonic-gate 					if (flags & SIGNOK)
673*7c478bd9Sstevel@tonic-gate 					{
674*7c478bd9Sstevel@tonic-gate 						flags &= ~SIGNOK;
675*7c478bd9Sstevel@tonic-gate 						goto fok;
676*7c478bd9Sstevel@tonic-gate 					}
677*7c478bd9Sstevel@tonic-gate 					break;
678*7c478bd9Sstevel@tonic-gate 				  case '.':
679*7c478bd9Sstevel@tonic-gate 					if (flags & DPTOK)
680*7c478bd9Sstevel@tonic-gate 					{
681*7c478bd9Sstevel@tonic-gate 						flags &= ~(SIGNOK | DPTOK);
682*7c478bd9Sstevel@tonic-gate 						goto fok;
683*7c478bd9Sstevel@tonic-gate 					}
684*7c478bd9Sstevel@tonic-gate 					break;
685*7c478bd9Sstevel@tonic-gate 				  case 'e': case 'E':
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 					/* no exponent without some digits */
688*7c478bd9Sstevel@tonic-gate 					if ((flags&(NDIGITS|EXPOK)) == EXPOK)
689*7c478bd9Sstevel@tonic-gate 					{
690*7c478bd9Sstevel@tonic-gate 						flags =
691*7c478bd9Sstevel@tonic-gate 						    (flags & ~(EXPOK|DPTOK)) |
692*7c478bd9Sstevel@tonic-gate 						    SIGNOK | NDIGITS;
693*7c478bd9Sstevel@tonic-gate 						goto fok;
694*7c478bd9Sstevel@tonic-gate 					}
695*7c478bd9Sstevel@tonic-gate 					break;
696*7c478bd9Sstevel@tonic-gate 				}
697*7c478bd9Sstevel@tonic-gate 				break;
698*7c478bd9Sstevel@tonic-gate 		fok:
699*7c478bd9Sstevel@tonic-gate 				*p++ = c;
700*7c478bd9Sstevel@tonic-gate 				if (--fp->f_r > 0)
701*7c478bd9Sstevel@tonic-gate 					fp->f_p++;
702*7c478bd9Sstevel@tonic-gate 				else if (sm_refill(fp, SM_TIME_FOREVER))
703*7c478bd9Sstevel@tonic-gate 					break;	/* SM_IO_EOF */
704*7c478bd9Sstevel@tonic-gate 			}
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate 			/*
707*7c478bd9Sstevel@tonic-gate 			**  If no digits, might be missing exponent digits
708*7c478bd9Sstevel@tonic-gate 			**  (just give back the exponent) or might be missing
709*7c478bd9Sstevel@tonic-gate 			**  regular digits, but had sign and/or decimal point.
710*7c478bd9Sstevel@tonic-gate 			*/
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 			if (flags & NDIGITS)
713*7c478bd9Sstevel@tonic-gate 			{
714*7c478bd9Sstevel@tonic-gate 				if (flags & EXPOK)
715*7c478bd9Sstevel@tonic-gate 				{
716*7c478bd9Sstevel@tonic-gate 					/* no digits at all */
717*7c478bd9Sstevel@tonic-gate 					while (p > buf)
718*7c478bd9Sstevel@tonic-gate 						(void) sm_io_ungetc(fp,
719*7c478bd9Sstevel@tonic-gate 							     SM_TIME_DEFAULT,
720*7c478bd9Sstevel@tonic-gate 							     *(unsigned char *)--p);
721*7c478bd9Sstevel@tonic-gate 					goto match_failure;
722*7c478bd9Sstevel@tonic-gate 				}
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate 				/* just a bad exponent (e and maybe sign) */
725*7c478bd9Sstevel@tonic-gate 				c = *(unsigned char *) --p;
726*7c478bd9Sstevel@tonic-gate 				if (c != 'e' && c != 'E')
727*7c478bd9Sstevel@tonic-gate 				{
728*7c478bd9Sstevel@tonic-gate 					(void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
729*7c478bd9Sstevel@tonic-gate 							    c); /* sign */
730*7c478bd9Sstevel@tonic-gate 					c = *(unsigned char *)--p;
731*7c478bd9Sstevel@tonic-gate 				}
732*7c478bd9Sstevel@tonic-gate 				(void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
733*7c478bd9Sstevel@tonic-gate 			}
734*7c478bd9Sstevel@tonic-gate 			if ((flags & SUPPRESS) == 0)
735*7c478bd9Sstevel@tonic-gate 			{
736*7c478bd9Sstevel@tonic-gate 				double res;
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 				*p = 0;
739*7c478bd9Sstevel@tonic-gate 				res = strtod(buf, (char **) NULL);
740*7c478bd9Sstevel@tonic-gate 				if (flags & LONG)
741*7c478bd9Sstevel@tonic-gate 					*SM_VA_ARG(ap, double *) = res;
742*7c478bd9Sstevel@tonic-gate 				else
743*7c478bd9Sstevel@tonic-gate 					*SM_VA_ARG(ap, float *) = res;
744*7c478bd9Sstevel@tonic-gate 				nassigned++;
745*7c478bd9Sstevel@tonic-gate 			}
746*7c478bd9Sstevel@tonic-gate 			nread += p - buf;
747*7c478bd9Sstevel@tonic-gate 			break;
748*7c478bd9Sstevel@tonic-gate 		}
749*7c478bd9Sstevel@tonic-gate 	}
750*7c478bd9Sstevel@tonic-gate input_failure:
751*7c478bd9Sstevel@tonic-gate 	if (evt != NULL)
752*7c478bd9Sstevel@tonic-gate 		sm_clrevent(evt); /*  undo our timeout */
753*7c478bd9Sstevel@tonic-gate 	return nassigned ? nassigned : -1;
754*7c478bd9Sstevel@tonic-gate match_failure:
755*7c478bd9Sstevel@tonic-gate 	if (evt != NULL)
756*7c478bd9Sstevel@tonic-gate 		sm_clrevent(evt); /*  undo our timeout */
757*7c478bd9Sstevel@tonic-gate 	return nassigned;
758*7c478bd9Sstevel@tonic-gate }
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate /*
761*7c478bd9Sstevel@tonic-gate **  SM_SCCL -- sequenced character comparison list
762*7c478bd9Sstevel@tonic-gate **
763*7c478bd9Sstevel@tonic-gate **  Fill in the given table from the scanset at the given format
764*7c478bd9Sstevel@tonic-gate **  (just after `[').  Return a pointer to the character past the
765*7c478bd9Sstevel@tonic-gate **  closing `]'.  The table has a 1 wherever characters should be
766*7c478bd9Sstevel@tonic-gate **  considered part of the scanset.
767*7c478bd9Sstevel@tonic-gate **
768*7c478bd9Sstevel@tonic-gate **	Parameters:
769*7c478bd9Sstevel@tonic-gate **		tab -- array flagging "active" char's to match (returned)
770*7c478bd9Sstevel@tonic-gate **		fmt -- character list (within "[]")
771*7c478bd9Sstevel@tonic-gate **
772*7c478bd9Sstevel@tonic-gate **	Results:
773*7c478bd9Sstevel@tonic-gate */
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate static unsigned char *
776*7c478bd9Sstevel@tonic-gate sm_sccl(tab, fmt)
777*7c478bd9Sstevel@tonic-gate 	register char *tab;
778*7c478bd9Sstevel@tonic-gate 	register unsigned char *fmt;
779*7c478bd9Sstevel@tonic-gate {
780*7c478bd9Sstevel@tonic-gate 	register int c, n, v;
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 	/* first `clear' the whole table */
783*7c478bd9Sstevel@tonic-gate 	c = *fmt++;		/* first char hat => negated scanset */
784*7c478bd9Sstevel@tonic-gate 	if (c == '^')
785*7c478bd9Sstevel@tonic-gate 	{
786*7c478bd9Sstevel@tonic-gate 		v = 1;		/* default => accept */
787*7c478bd9Sstevel@tonic-gate 		c = *fmt++;	/* get new first char */
788*7c478bd9Sstevel@tonic-gate 	}
789*7c478bd9Sstevel@tonic-gate 	else
790*7c478bd9Sstevel@tonic-gate 		v = 0;		/* default => reject */
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	/* should probably use memset here */
793*7c478bd9Sstevel@tonic-gate 	for (n = 0; n < 256; n++)
794*7c478bd9Sstevel@tonic-gate 		tab[n] = v;
795*7c478bd9Sstevel@tonic-gate 	if (c == 0)
796*7c478bd9Sstevel@tonic-gate 		return fmt - 1;	/* format ended before closing ] */
797*7c478bd9Sstevel@tonic-gate 
798*7c478bd9Sstevel@tonic-gate 	/*
799*7c478bd9Sstevel@tonic-gate 	**  Now set the entries corresponding to the actual scanset
800*7c478bd9Sstevel@tonic-gate 	**  to the opposite of the above.
801*7c478bd9Sstevel@tonic-gate 	**
802*7c478bd9Sstevel@tonic-gate 	**  The first character may be ']' (or '-') without being special;
803*7c478bd9Sstevel@tonic-gate 	**  the last character may be '-'.
804*7c478bd9Sstevel@tonic-gate 	*/
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 	v = 1 - v;
807*7c478bd9Sstevel@tonic-gate 	for (;;)
808*7c478bd9Sstevel@tonic-gate 	{
809*7c478bd9Sstevel@tonic-gate 		tab[c] = v;		/* take character c */
810*7c478bd9Sstevel@tonic-gate doswitch:
811*7c478bd9Sstevel@tonic-gate 		n = *fmt++;		/* and examine the next */
812*7c478bd9Sstevel@tonic-gate 		switch (n)
813*7c478bd9Sstevel@tonic-gate 		{
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate 		  case 0:			/* format ended too soon */
816*7c478bd9Sstevel@tonic-gate 			return fmt - 1;
817*7c478bd9Sstevel@tonic-gate 
818*7c478bd9Sstevel@tonic-gate 		  case '-':
819*7c478bd9Sstevel@tonic-gate 			/*
820*7c478bd9Sstevel@tonic-gate 			**  A scanset of the form
821*7c478bd9Sstevel@tonic-gate 			**	[01+-]
822*7c478bd9Sstevel@tonic-gate 			**  is defined as `the digit 0, the digit 1,
823*7c478bd9Sstevel@tonic-gate 			**  the character +, the character -', but
824*7c478bd9Sstevel@tonic-gate 			**  the effect of a scanset such as
825*7c478bd9Sstevel@tonic-gate 			**	[a-zA-Z0-9]
826*7c478bd9Sstevel@tonic-gate 			**  is implementation defined.  The V7 Unix
827*7c478bd9Sstevel@tonic-gate 			**  scanf treats `a-z' as `the letters a through
828*7c478bd9Sstevel@tonic-gate 			**  z', but treats `a-a' as `the letter a, the
829*7c478bd9Sstevel@tonic-gate 			**  character -, and the letter a'.
830*7c478bd9Sstevel@tonic-gate 			**
831*7c478bd9Sstevel@tonic-gate 			**  For compatibility, the `-' is not considerd
832*7c478bd9Sstevel@tonic-gate 			**  to define a range if the character following
833*7c478bd9Sstevel@tonic-gate 			**  it is either a close bracket (required by ANSI)
834*7c478bd9Sstevel@tonic-gate 			**  or is not numerically greater than the character
835*7c478bd9Sstevel@tonic-gate 			**  we just stored in the table (c).
836*7c478bd9Sstevel@tonic-gate 			*/
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 			n = *fmt;
839*7c478bd9Sstevel@tonic-gate 			if (n == ']' || n < c)
840*7c478bd9Sstevel@tonic-gate 			{
841*7c478bd9Sstevel@tonic-gate 				c = '-';
842*7c478bd9Sstevel@tonic-gate 				break;	/* resume the for(;;) */
843*7c478bd9Sstevel@tonic-gate 			}
844*7c478bd9Sstevel@tonic-gate 			fmt++;
845*7c478bd9Sstevel@tonic-gate 			do
846*7c478bd9Sstevel@tonic-gate 			{
847*7c478bd9Sstevel@tonic-gate 				/* fill in the range */
848*7c478bd9Sstevel@tonic-gate 				tab[++c] = v;
849*7c478bd9Sstevel@tonic-gate 			} while (c < n);
850*7c478bd9Sstevel@tonic-gate #if 1	/* XXX another disgusting compatibility hack */
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate 			/*
853*7c478bd9Sstevel@tonic-gate 			**  Alas, the V7 Unix scanf also treats formats
854*7c478bd9Sstevel@tonic-gate 			**  such as [a-c-e] as `the letters a through e'.
855*7c478bd9Sstevel@tonic-gate 			**  This too is permitted by the standard....
856*7c478bd9Sstevel@tonic-gate 			*/
857*7c478bd9Sstevel@tonic-gate 
858*7c478bd9Sstevel@tonic-gate 			goto doswitch;
859*7c478bd9Sstevel@tonic-gate #else
860*7c478bd9Sstevel@tonic-gate 			c = *fmt++;
861*7c478bd9Sstevel@tonic-gate 			if (c == 0)
862*7c478bd9Sstevel@tonic-gate 				return fmt - 1;
863*7c478bd9Sstevel@tonic-gate 			if (c == ']')
864*7c478bd9Sstevel@tonic-gate 				return fmt;
865*7c478bd9Sstevel@tonic-gate 			break;
866*7c478bd9Sstevel@tonic-gate #endif
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 		  case ']':		/* end of scanset */
869*7c478bd9Sstevel@tonic-gate 			return fmt;
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 		  default:		/* just another character */
872*7c478bd9Sstevel@tonic-gate 			c = n;
873*7c478bd9Sstevel@tonic-gate 			break;
874*7c478bd9Sstevel@tonic-gate 		}
875*7c478bd9Sstevel@tonic-gate 	}
876*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
877*7c478bd9Sstevel@tonic-gate }
878