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