xref: /csrg-svn/lib/libc/stdio/vfscanf.c (revision 17951)
1 static char sccsid[] = "@(#)vfscanf.c	4.3	(Berkeley)	85/02/13";
2 
3 /* @(#)doscan.c	4.1 (Berkeley) 12/21/80 */
4 #include <stdio.h>
5 #include	<ctype.h>
6 
7 #define	SPC	01
8 #define	STP	02
9 
10 #define	SHORT	0
11 #define	REGULAR	1
12 #define	LONG	2
13 #define	INT	0
14 #define	FLOAT	1
15 
16 static char *_getccl();
17 
18 static char _sctab[256] = {
19 	0,0,0,0,0,0,0,0,
20 	0,SPC,SPC,0,0,0,0,0,
21 	0,0,0,0,0,0,0,0,
22 	0,0,0,0,0,0,0,0,
23 	SPC,0,0,0,0,0,0,0,
24 	0,0,0,0,0,0,0,0,
25 	0,0,0,0,0,0,0,0,
26 	0,0,0,0,0,0,0,0,
27 };
28 
29 _doscan(iop, fmt, argp)
30 FILE *iop;
31 register char *fmt;
32 register int **argp;
33 {
34 	register int ch;
35 	int nmatch, len, ch1;
36 	int **ptr, fileended, size;
37 
38 	nmatch = 0;
39 	fileended = 0;
40 	for (;;) switch (ch = *fmt++) {
41 	case '\0':
42 		return (nmatch);
43 	case '%':
44 		if ((ch = *fmt++) == '%')
45 			goto def;
46 		ptr = 0;
47 		if (ch != '*')
48 			ptr = argp++;
49 		else
50 			ch = *fmt++;
51 		len = 0;
52 		size = REGULAR;
53 		while (isdigit(ch)) {
54 			len = len*10 + ch - '0';
55 			ch = *fmt++;
56 		}
57 		if (len == 0)
58 			len = 30000;
59 		if (ch=='l') {
60 			size = LONG;
61 			ch = *fmt++;
62 		} else if (ch=='h') {
63 			size = SHORT;
64 			ch = *fmt++;
65 		} else if (ch=='[')
66 			fmt = _getccl(fmt);
67 		if (isupper(ch)) {
68 			ch = tolower(ch);
69 			size = LONG;
70 		}
71 		if (ch == '\0')
72 			return(-1);
73 		if (_innum(ptr, ch, len, size, iop, &fileended) && ptr)
74 			nmatch++;
75 		if (fileended)
76 			return(nmatch? nmatch: -1);
77 		break;
78 
79 	case ' ':
80 	case '\n':
81 	case '\t':
82 		while ((ch1 = getc(iop))==' ' || ch1=='\t' || ch1=='\n')
83 			;
84 		if (ch1 != EOF)
85 			ungetc(ch1, iop);
86 		break;
87 
88 	default:
89 	def:
90 		ch1 = getc(iop);
91 		if (ch1 != ch) {
92 			if (ch1==EOF)
93 				return(-1);
94 			ungetc(ch1, iop);
95 			return(nmatch);
96 		}
97 	}
98 }
99 
100 static
101 _innum(ptr, type, len, size, iop, eofptr)
102 int **ptr, *eofptr;
103 FILE *iop;
104 {
105 	extern double atof();
106 	register char *np;
107 	char numbuf[64];
108 	register c, base;
109 	int expseen, scale, negflg, c1, ndigit;
110 	long lcval;
111 
112 	if (type=='c' || type=='s' || type=='[')
113 		return(_instr(ptr? *(char **)ptr: (char *)NULL, type, len, iop, eofptr));
114 	lcval = 0;
115 	ndigit = 0;
116 	scale = INT;
117 	if (type=='e'||type=='f')
118 		scale = FLOAT;
119 	base = 10;
120 	if (type=='o')
121 		base = 8;
122 	else if (type=='x')
123 		base = 16;
124 	np = numbuf;
125 	expseen = 0;
126 	negflg = 0;
127 	while ((c = getc(iop))==' ' || c=='\t' || c=='\n');
128 	if (c=='-') {
129 		negflg++;
130 		*np++ = c;
131 		c = getc(iop);
132 		len--;
133 	} else if (c=='+') {
134 		len--;
135 		c = getc(iop);
136 	}
137 	for ( ; --len>=0; *np++ = c, c = getc(iop)) {
138 		if (isdigit(c)
139 		 || base==16 && ('a'<=c && c<='f' || 'A'<=c && c<='F')) {
140 			ndigit++;
141 			if (base==8)
142 				lcval <<=3;
143 			else if (base==10)
144 				lcval = ((lcval<<2) + lcval)<<1;
145 			else
146 				lcval <<= 4;
147 			c1 = c;
148 			if (isdigit(c))
149 				c -= '0';
150 			else if ('a'<=c && c<='f')
151 				c -= 'a'-10;
152 			else
153 				c -= 'A'-10;
154 			lcval += c;
155 			c = c1;
156 			continue;
157 		} else if (c=='.') {
158 			if (base!=10 || scale==INT)
159 				break;
160 			ndigit++;
161 			continue;
162 		} else if ((c=='e'||c=='E') && expseen==0) {
163 			if (base!=10 || scale==INT || ndigit==0)
164 				break;
165 			expseen++;
166 			*np++ = c;
167 			c = getc(iop);
168 			if (c!='+'&&c!='-'&&('0'>c||c>'9'))
169 				break;
170 		} else
171 			break;
172 	}
173 	if (negflg)
174 		lcval = -lcval;
175 	if (c != EOF) {
176 		ungetc(c, iop);
177 		*eofptr = 0;
178 	} else
179 		*eofptr = 1;
180  	if (ptr==NULL || np==numbuf || (negflg && np==numbuf+1) )/* gene dykes*/
181 		return(0);
182 	*np++ = 0;
183 	switch((scale<<4) | size) {
184 
185 	case (FLOAT<<4) | SHORT:
186 	case (FLOAT<<4) | REGULAR:
187 		**(float **)ptr = atof(numbuf);
188 		break;
189 
190 	case (FLOAT<<4) | LONG:
191 		**(double **)ptr = atof(numbuf);
192 		break;
193 
194 	case (INT<<4) | SHORT:
195 		**(short **)ptr = lcval;
196 		break;
197 
198 	case (INT<<4) | REGULAR:
199 		**(int **)ptr = lcval;
200 		break;
201 
202 	case (INT<<4) | LONG:
203 		**(long **)ptr = lcval;
204 		break;
205 	}
206 	return(1);
207 }
208 
209 static
210 _instr(ptr, type, len, iop, eofptr)
211 register char *ptr;
212 register FILE *iop;
213 int *eofptr;
214 {
215 	register ch;
216 	register char *optr;
217 	int ignstp;
218 
219 	*eofptr = 0;
220 	optr = ptr;
221 	if (type=='c' && len==30000)
222 		len = 1;
223 	ignstp = 0;
224 	if (type=='s')
225 		ignstp = SPC;
226 	while ((ch = getc(iop)) != EOF && _sctab[ch] & ignstp)
227 		;
228 	ignstp = SPC;
229 	if (type=='c')
230 		ignstp = 0;
231 	else if (type=='[')
232 		ignstp = STP;
233 	while (ch!=EOF && (_sctab[ch]&ignstp)==0) {
234 		if (ptr)
235 			*ptr++ = ch;
236 		if (--len <= 0)
237 			break;
238 		ch = getc(iop);
239 	}
240 	if (ch != EOF) {
241 		if (len > 0)
242 			ungetc(ch, iop);
243 		*eofptr = 0;
244 	} else
245 		*eofptr = 1;
246 	if (ptr && ptr!=optr) {
247 		if (type!='c')
248 			*ptr++ = '\0';
249 		return(1);
250 	}
251 	return(0);
252 }
253 
254 static char *
255 _getccl(s)
256 register unsigned char *s;
257 {
258 	register c, t;
259 
260 	t = 0;
261 	if (*s == '^') {
262 		t++;
263 		s++;
264 	}
265 	for (c = 0; c < (sizeof _sctab / sizeof _sctab[0]); c++)
266 		if (t)
267 			_sctab[c] &= ~STP;
268 		else
269 			_sctab[c] |= STP;
270 	if ((c = *s) == ']' || c == '-') {	/* first char is special */
271 		if (t)
272 			_sctab[c] |= STP;
273 		else
274 			_sctab[c] &= ~STP;
275 		s++;
276 	}
277 	while ((c = *s++) != ']') {
278 		if (c==0)
279 			return((char *)--s);
280 		else if (c == '-' && *s != ']' && s[-2] < *s) {
281 			for (c = s[-2] + 1; c < *s; c++)
282 				if (t)
283 					_sctab[c] |= STP;
284 				else
285 					_sctab[c] &= ~STP;
286 		} else if (t)
287 			_sctab[c] |= STP;
288 		else
289 			_sctab[c] &= ~STP;
290 	}
291 	return((char *)s);
292 }
293