xref: /csrg-svn/lib/libc/stdio/vfscanf.c (revision 26640)
1*26640Sdonn #if defined(LIBC_SCCS) && !defined(lint)
2*26640Sdonn static char sccsid[] = "@(#)vfscanf.c	5.2 (Berkeley) 03/09/86";
3*26640Sdonn #endif LIBC_SCCS and not lint
49415Smckusick 
59415Smckusick #include <stdio.h>
69415Smckusick #include	<ctype.h>
79415Smckusick 
89415Smckusick #define	SPC	01
99415Smckusick #define	STP	02
109415Smckusick 
119415Smckusick #define	SHORT	0
129415Smckusick #define	REGULAR	1
139415Smckusick #define	LONG	2
149415Smckusick #define	INT	0
159415Smckusick #define	FLOAT	1
169415Smckusick 
1717951Sserge static char *_getccl();
189415Smckusick 
1917951Sserge static char _sctab[256] = {
209415Smckusick 	0,0,0,0,0,0,0,0,
219415Smckusick 	0,SPC,SPC,0,0,0,0,0,
229415Smckusick 	0,0,0,0,0,0,0,0,
239415Smckusick 	0,0,0,0,0,0,0,0,
249415Smckusick 	SPC,0,0,0,0,0,0,0,
259415Smckusick 	0,0,0,0,0,0,0,0,
269415Smckusick 	0,0,0,0,0,0,0,0,
279415Smckusick 	0,0,0,0,0,0,0,0,
289415Smckusick };
299415Smckusick 
309415Smckusick _doscan(iop, fmt, argp)
319415Smckusick FILE *iop;
329415Smckusick register char *fmt;
339415Smckusick register int **argp;
349415Smckusick {
359415Smckusick 	register int ch;
369415Smckusick 	int nmatch, len, ch1;
379415Smckusick 	int **ptr, fileended, size;
389415Smckusick 
399415Smckusick 	nmatch = 0;
409415Smckusick 	fileended = 0;
419415Smckusick 	for (;;) switch (ch = *fmt++) {
429415Smckusick 	case '\0':
439415Smckusick 		return (nmatch);
449415Smckusick 	case '%':
459415Smckusick 		if ((ch = *fmt++) == '%')
469415Smckusick 			goto def;
479415Smckusick 		ptr = 0;
489415Smckusick 		if (ch != '*')
499415Smckusick 			ptr = argp++;
509415Smckusick 		else
519415Smckusick 			ch = *fmt++;
529415Smckusick 		len = 0;
539415Smckusick 		size = REGULAR;
549415Smckusick 		while (isdigit(ch)) {
559415Smckusick 			len = len*10 + ch - '0';
569415Smckusick 			ch = *fmt++;
579415Smckusick 		}
589415Smckusick 		if (len == 0)
599415Smckusick 			len = 30000;
609415Smckusick 		if (ch=='l') {
619415Smckusick 			size = LONG;
629415Smckusick 			ch = *fmt++;
639415Smckusick 		} else if (ch=='h') {
649415Smckusick 			size = SHORT;
659415Smckusick 			ch = *fmt++;
669415Smckusick 		} else if (ch=='[')
679415Smckusick 			fmt = _getccl(fmt);
689415Smckusick 		if (isupper(ch)) {
699415Smckusick 			ch = tolower(ch);
709415Smckusick 			size = LONG;
719415Smckusick 		}
729415Smckusick 		if (ch == '\0')
739415Smckusick 			return(-1);
749415Smckusick 		if (_innum(ptr, ch, len, size, iop, &fileended) && ptr)
759415Smckusick 			nmatch++;
769415Smckusick 		if (fileended)
779415Smckusick 			return(nmatch? nmatch: -1);
789415Smckusick 		break;
799415Smckusick 
809415Smckusick 	case ' ':
819415Smckusick 	case '\n':
829415Smckusick 	case '\t':
839415Smckusick 		while ((ch1 = getc(iop))==' ' || ch1=='\t' || ch1=='\n')
849415Smckusick 			;
859415Smckusick 		if (ch1 != EOF)
869415Smckusick 			ungetc(ch1, iop);
879415Smckusick 		break;
889415Smckusick 
899415Smckusick 	default:
909415Smckusick 	def:
919415Smckusick 		ch1 = getc(iop);
929415Smckusick 		if (ch1 != ch) {
939415Smckusick 			if (ch1==EOF)
949415Smckusick 				return(-1);
959415Smckusick 			ungetc(ch1, iop);
969415Smckusick 			return(nmatch);
979415Smckusick 		}
989415Smckusick 	}
999415Smckusick }
1009415Smckusick 
10117951Sserge static
1029415Smckusick _innum(ptr, type, len, size, iop, eofptr)
1039415Smckusick int **ptr, *eofptr;
10417951Sserge FILE *iop;
1059415Smckusick {
1069415Smckusick 	extern double atof();
1079415Smckusick 	register char *np;
1089415Smckusick 	char numbuf[64];
1099415Smckusick 	register c, base;
1109415Smckusick 	int expseen, scale, negflg, c1, ndigit;
1119415Smckusick 	long lcval;
1129415Smckusick 
1139415Smckusick 	if (type=='c' || type=='s' || type=='[')
1149415Smckusick 		return(_instr(ptr? *(char **)ptr: (char *)NULL, type, len, iop, eofptr));
1159415Smckusick 	lcval = 0;
1169415Smckusick 	ndigit = 0;
1179415Smckusick 	scale = INT;
1189415Smckusick 	if (type=='e'||type=='f')
1199415Smckusick 		scale = FLOAT;
1209415Smckusick 	base = 10;
1219415Smckusick 	if (type=='o')
1229415Smckusick 		base = 8;
1239415Smckusick 	else if (type=='x')
1249415Smckusick 		base = 16;
1259415Smckusick 	np = numbuf;
1269415Smckusick 	expseen = 0;
1279415Smckusick 	negflg = 0;
1289415Smckusick 	while ((c = getc(iop))==' ' || c=='\t' || c=='\n');
1299415Smckusick 	if (c=='-') {
1309415Smckusick 		negflg++;
1319415Smckusick 		*np++ = c;
1329415Smckusick 		c = getc(iop);
1339415Smckusick 		len--;
1349415Smckusick 	} else if (c=='+') {
1359415Smckusick 		len--;
1369415Smckusick 		c = getc(iop);
1379415Smckusick 	}
1389415Smckusick 	for ( ; --len>=0; *np++ = c, c = getc(iop)) {
1399415Smckusick 		if (isdigit(c)
1409415Smckusick 		 || base==16 && ('a'<=c && c<='f' || 'A'<=c && c<='F')) {
1419415Smckusick 			ndigit++;
1429415Smckusick 			if (base==8)
1439415Smckusick 				lcval <<=3;
1449415Smckusick 			else if (base==10)
1459415Smckusick 				lcval = ((lcval<<2) + lcval)<<1;
1469415Smckusick 			else
1479415Smckusick 				lcval <<= 4;
1489415Smckusick 			c1 = c;
1499415Smckusick 			if (isdigit(c))
1509415Smckusick 				c -= '0';
1519415Smckusick 			else if ('a'<=c && c<='f')
1529415Smckusick 				c -= 'a'-10;
1539415Smckusick 			else
1549415Smckusick 				c -= 'A'-10;
1559415Smckusick 			lcval += c;
1569415Smckusick 			c = c1;
1579415Smckusick 			continue;
1589415Smckusick 		} else if (c=='.') {
1599415Smckusick 			if (base!=10 || scale==INT)
1609415Smckusick 				break;
1619415Smckusick 			ndigit++;
1629415Smckusick 			continue;
1639415Smckusick 		} else if ((c=='e'||c=='E') && expseen==0) {
1649415Smckusick 			if (base!=10 || scale==INT || ndigit==0)
1659415Smckusick 				break;
1669415Smckusick 			expseen++;
1679415Smckusick 			*np++ = c;
1689415Smckusick 			c = getc(iop);
1699415Smckusick 			if (c!='+'&&c!='-'&&('0'>c||c>'9'))
1709415Smckusick 				break;
1719415Smckusick 		} else
1729415Smckusick 			break;
1739415Smckusick 	}
1749415Smckusick 	if (negflg)
1759415Smckusick 		lcval = -lcval;
1769415Smckusick 	if (c != EOF) {
1779415Smckusick 		ungetc(c, iop);
1789415Smckusick 		*eofptr = 0;
1799415Smckusick 	} else
1809415Smckusick 		*eofptr = 1;
1819416Smckusick  	if (ptr==NULL || np==numbuf || (negflg && np==numbuf+1) )/* gene dykes*/
1829415Smckusick 		return(0);
1839415Smckusick 	*np++ = 0;
1849415Smckusick 	switch((scale<<4) | size) {
1859415Smckusick 
1869415Smckusick 	case (FLOAT<<4) | SHORT:
1879415Smckusick 	case (FLOAT<<4) | REGULAR:
1889415Smckusick 		**(float **)ptr = atof(numbuf);
1899415Smckusick 		break;
1909415Smckusick 
1919415Smckusick 	case (FLOAT<<4) | LONG:
1929415Smckusick 		**(double **)ptr = atof(numbuf);
1939415Smckusick 		break;
1949415Smckusick 
1959415Smckusick 	case (INT<<4) | SHORT:
1969415Smckusick 		**(short **)ptr = lcval;
1979415Smckusick 		break;
1989415Smckusick 
1999415Smckusick 	case (INT<<4) | REGULAR:
2009415Smckusick 		**(int **)ptr = lcval;
2019415Smckusick 		break;
2029415Smckusick 
2039415Smckusick 	case (INT<<4) | LONG:
2049415Smckusick 		**(long **)ptr = lcval;
2059415Smckusick 		break;
2069415Smckusick 	}
2079415Smckusick 	return(1);
2089415Smckusick }
2099415Smckusick 
21017951Sserge static
2119415Smckusick _instr(ptr, type, len, iop, eofptr)
2129415Smckusick register char *ptr;
21317951Sserge register FILE *iop;
2149415Smckusick int *eofptr;
2159415Smckusick {
2169415Smckusick 	register ch;
2179415Smckusick 	register char *optr;
2189415Smckusick 	int ignstp;
2199415Smckusick 
2209415Smckusick 	*eofptr = 0;
2219415Smckusick 	optr = ptr;
2229415Smckusick 	if (type=='c' && len==30000)
2239415Smckusick 		len = 1;
2249415Smckusick 	ignstp = 0;
2259415Smckusick 	if (type=='s')
2269415Smckusick 		ignstp = SPC;
22717951Sserge 	while ((ch = getc(iop)) != EOF && _sctab[ch] & ignstp)
22817951Sserge 		;
2299415Smckusick 	ignstp = SPC;
2309415Smckusick 	if (type=='c')
2319415Smckusick 		ignstp = 0;
2329415Smckusick 	else if (type=='[')
2339415Smckusick 		ignstp = STP;
2349415Smckusick 	while (ch!=EOF && (_sctab[ch]&ignstp)==0) {
2359415Smckusick 		if (ptr)
2369415Smckusick 			*ptr++ = ch;
2379415Smckusick 		if (--len <= 0)
2389415Smckusick 			break;
2399415Smckusick 		ch = getc(iop);
2409415Smckusick 	}
2419415Smckusick 	if (ch != EOF) {
2429415Smckusick 		if (len > 0)
2439415Smckusick 			ungetc(ch, iop);
2449415Smckusick 		*eofptr = 0;
2459415Smckusick 	} else
2469415Smckusick 		*eofptr = 1;
2479415Smckusick 	if (ptr && ptr!=optr) {
2489415Smckusick 		if (type!='c')
2499415Smckusick 			*ptr++ = '\0';
2509415Smckusick 		return(1);
2519415Smckusick 	}
2529415Smckusick 	return(0);
2539415Smckusick }
2549415Smckusick 
25517951Sserge static char *
2569415Smckusick _getccl(s)
25717951Sserge register unsigned char *s;
2589415Smckusick {
2599415Smckusick 	register c, t;
2609415Smckusick 
2619415Smckusick 	t = 0;
2629415Smckusick 	if (*s == '^') {
2639415Smckusick 		t++;
2649415Smckusick 		s++;
2659415Smckusick 	}
26617951Sserge 	for (c = 0; c < (sizeof _sctab / sizeof _sctab[0]); c++)
2679415Smckusick 		if (t)
2689415Smckusick 			_sctab[c] &= ~STP;
2699415Smckusick 		else
2709415Smckusick 			_sctab[c] |= STP;
27117951Sserge 	if ((c = *s) == ']' || c == '-') {	/* first char is special */
2729415Smckusick 		if (t)
27317951Sserge 			_sctab[c] |= STP;
2749415Smckusick 		else
27517951Sserge 			_sctab[c] &= ~STP;
27617951Sserge 		s++;
27717951Sserge 	}
27817951Sserge 	while ((c = *s++) != ']') {
2799415Smckusick 		if (c==0)
28017951Sserge 			return((char *)--s);
28117951Sserge 		else if (c == '-' && *s != ']' && s[-2] < *s) {
28217951Sserge 			for (c = s[-2] + 1; c < *s; c++)
28317951Sserge 				if (t)
28417951Sserge 					_sctab[c] |= STP;
28517951Sserge 				else
28617951Sserge 					_sctab[c] &= ~STP;
28717951Sserge 		} else if (t)
28817951Sserge 			_sctab[c] |= STP;
28917951Sserge 		else
29017951Sserge 			_sctab[c] &= ~STP;
2919415Smckusick 	}
29217951Sserge 	return((char *)s);
2939415Smckusick }
294