xref: /onnv-gate/usr/src/lib/libast/common/string/tokscan.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin /*
244887Schin  * Glenn Fowler
254887Schin  * AT&T Research
264887Schin  *
274887Schin  * scan s for tokens in fmt
284887Schin  * s modified in place and not restored
294887Schin  * if nxt!=0 then it will point to the first unread char in s
304887Schin  * the number of scanned tokens is returned
314887Schin  * -1 returned if s was not empty and fmt failed to match
324887Schin  *
334887Schin  * ' ' in fmt matches 0 or more {space,tab}
344887Schin  * '\n' in fmt eats remainder of current line
354887Schin  * "..." and '...' quotes interpreted
364887Schin  * newline is equivalent to end of buf except when quoted
374887Schin  * \\ quotes following char
384887Schin  *
394887Schin  * message support for %s and %v data
404887Schin  *
414887Schin  *	(5:12345)		fixed length strings, ) may be \t
424887Schin  *	(null)			NiL
434887Schin  *
444887Schin  * "..." and '...' may span \n, and \\n is the line splice
454887Schin  * quoted '\r' translated to '\n'
464887Schin  * otherwise tokenizing is unconditionally terminated by '\n'
474887Schin  *
484887Schin  * a null arg pointer skips that arg
494887Schin  *
504887Schin  *	%c		char
514887Schin  *	%[hl]d		[short|int|long] base 10
524887Schin  *	%f		double
534887Schin  *	%g		double
544887Schin  *	%[hl]n		[short|int|long] C-style base
554887Schin  *	%[hl]o		[short|int|long] base 8
564887Schin  *	%s		string
574887Schin  *	%[hl]u		same as %[hl]n
584887Schin  *	%v		argv, elements
594887Schin  *	%[hl]x		[short|int|long] base 16
604887Schin  *
614887Schin  * unmatched char args are set to "", int args to 0
624887Schin  */
634887Schin 
644887Schin #include <ast.h>
654887Schin #include <tok.h>
664887Schin 
674887Schin static char	empty[1];
684887Schin 
694887Schin /*
704887Schin  * get one string token into p
714887Schin  */
724887Schin 
734887Schin static char*
lextok(register char * s,register int c,char ** p,int * n)744887Schin lextok(register char* s, register int c, char** p, int* n)
754887Schin {
764887Schin 	register char*	t;
774887Schin 	register int	q;
784887Schin 	char*		b;
794887Schin 	char*		u;
804887Schin 
814887Schin 	if (*s == '(' && (!c || c == ' ' || c == '\n'))
824887Schin 	{
834887Schin 		q = strtol(s + 1, &b, 10);
844887Schin 		if (*b == ':')
854887Schin 		{
864887Schin 			if (*(t = ++b + q) == ')' || *t == '\t')
874887Schin 			{
884887Schin 				s = t;
894887Schin 				*s++ = 0;
904887Schin 				goto end;
914887Schin 			}
924887Schin 		}
934887Schin 		else if (strneq(b, "null)", 5))
944887Schin 		{
954887Schin 			s = b + 5;
964887Schin 			b = 0;
974887Schin 			goto end;
984887Schin 		}
994887Schin 	}
1004887Schin 	b = s;
1014887Schin 	q = 0;
1024887Schin 	t = 0;
1034887Schin 	for (;;)
1044887Schin 	{
1054887Schin 		if (!*s || !q && *s == '\n')
1064887Schin 		{
1074887Schin 			if (!q)
1084887Schin 			{
1094887Schin 				if (!c || c == ' ' || c == '\n') (*n)++;
1104887Schin 				else
1114887Schin 				{
1124887Schin 					s = b;
1134887Schin 					b = empty;
1144887Schin 					break;
1154887Schin 				}
1164887Schin 			}
1174887Schin 			if (t) *t = 0;
1184887Schin 			break;
1194887Schin 		}
1204887Schin 		else if (*s == '\\')
1214887Schin 		{
1224887Schin 			u = s;
1234887Schin 			if (!*++s || *s == '\n' && (!*++s || *s == '\n')) continue;
1244887Schin 			if (p)
1254887Schin 			{
1264887Schin 				if (b == u) b = s;
1274887Schin 				else if (!t) t = u;
1284887Schin 			}
1294887Schin 		}
1304887Schin 		else if (q)
1314887Schin 		{
1324887Schin 			if (*s == q)
1334887Schin 			{
1344887Schin 				q = 0;
1354887Schin 				if (!t) t = s;
1364887Schin 				s++;
1374887Schin 				continue;
1384887Schin 			}
1394887Schin 			else if (*s == '\r') *s = '\n';
1404887Schin 		}
1414887Schin 		else if (*s == '"' || *s == '\'')
1424887Schin 		{
1434887Schin 			q = *s++;
1444887Schin 			if (p)
1454887Schin 			{
1464887Schin 				if (b == (s - 1)) b = s;
1474887Schin 				else if (!t) t = s - 1;
1484887Schin 			}
1494887Schin 			continue;
1504887Schin 		}
1514887Schin 		else if (*s == c || c == ' ' && *s == '\t')
1524887Schin 		{
1534887Schin 			*s++ = 0;
1544887Schin 			if (t) *t = 0;
1554887Schin 		end:
1564887Schin 			if (c == ' ') while (*s == ' ' || *s == '\t') s++;
1574887Schin 			(*n)++;
1584887Schin 			break;
1594887Schin 		}
1604887Schin 		if (t) *t++ = *s;
1614887Schin 		s++;
1624887Schin 	}
1634887Schin 	if (p) *p = b;
1644887Schin 	return(s);
1654887Schin }
1664887Schin 
1674887Schin /*
1684887Schin  * scan entry
1694887Schin  */
1704887Schin 
1714887Schin int
tokscan(register char * s,char ** nxt,const char * fmt,...)1724887Schin tokscan(register char* s, char** nxt, const char* fmt, ...)
1734887Schin {
1744887Schin 	register int	c;
1754887Schin 	register char*	f;
1764887Schin 	int		num = 0;
1774887Schin 	char*		skip = 0;
1784887Schin 	int		q;
1794887Schin 	int		onum;
1804887Schin 	long		val;
1814887Schin 	double		dval;
1824887Schin 	va_list		ap;
1834887Schin 	char*		p_char;
1844887Schin 	double*		p_double;
1854887Schin 	int*		p_int;
1864887Schin 	long*		p_long;
1874887Schin 	short*		p_short;
1884887Schin 	char**		p_string;
1894887Schin 	char*		prv_f = 0;
1904887Schin 	va_list		prv_ap;
1914887Schin 
1924887Schin 	va_start(ap, fmt);
1934887Schin 	if (!*s || *s == '\n')
1944887Schin 	{
1954887Schin 		skip = s;
1964887Schin 		s = empty;
1974887Schin 	}
1984887Schin 	f = (char*)fmt;
1994887Schin 	for (;;) switch (c = *f++)
2004887Schin 	{
2014887Schin 	case 0:
2024887Schin 		if (f = prv_f)
2034887Schin 		{
2044887Schin 			prv_f = 0;
2054887Schin 			/* prv_ap value is guarded by prv_f */
2064887Schin 			va_copy(ap, prv_ap);
2074887Schin 			continue;
2084887Schin 		}
2094887Schin 		goto done;
2104887Schin 	case ' ':
2114887Schin 		while (*s == ' ' || *s == '\t') s++;
2124887Schin 		break;
2134887Schin 	case '%':
2144887Schin 		onum = num;
2154887Schin 		switch (c = *f++)
2164887Schin 		{
2174887Schin 		case 'h':
2184887Schin 		case 'l':
2194887Schin 			q = c;
2204887Schin 			c = *f++;
2214887Schin 			break;
2224887Schin 		default:
2234887Schin 			q = 0;
2244887Schin 			break;
2254887Schin 		}
2264887Schin 		switch (c)
2274887Schin 		{
2284887Schin 		case 0:
2294887Schin 		case '%':
2304887Schin 			f--;
2314887Schin 			continue;
2324887Schin 		case ':':
2334887Schin 			prv_f = f;
2344887Schin 			f = va_arg(ap, char*);
2354887Schin 			va_copy(prv_ap, ap);
2364887Schin 			va_copy(ap, va_listval(va_arg(ap, va_listarg)));
2374887Schin 			continue;
2384887Schin 		case 'c':
2394887Schin 			p_char = va_arg(ap, char*);
2404887Schin 			if (!(c = *s) || c == '\n')
2414887Schin 			{
2424887Schin 				if (p_char) *p_char = 0;
2434887Schin 			}
2444887Schin 			else
2454887Schin 			{
2464887Schin 				if (p_char) *p_char = c;
2474887Schin 				s++;
2484887Schin 				num++;
2494887Schin 			}
2504887Schin 			break;
2514887Schin 		case 'd':
2524887Schin 		case 'n':
2534887Schin 		case 'o':
2544887Schin 		case 'u':
2554887Schin 		case 'x':
2564887Schin 			switch (c)
2574887Schin 			{
2584887Schin 			case 'd':
2594887Schin 				c = 10;
2604887Schin 				break;
2614887Schin 			case 'n':
2624887Schin 			case 'u':
2634887Schin 				c = 0;
2644887Schin 				break;
2654887Schin 			case 'o':
2664887Schin 				c = 8;
2674887Schin 				break;
2684887Schin 			case 'x':
2694887Schin 				c = 16;
2704887Schin 				break;
2714887Schin 			}
2724887Schin 			if (!*s || *s == '\n')
2734887Schin 			{
2744887Schin 				val = 0;
2754887Schin 				p_char = s;
2764887Schin 			}
2774887Schin 			else val = strtol(s, &p_char, c);
2784887Schin 			switch (q)
2794887Schin 			{
2804887Schin 			case 'h':
2814887Schin 				if (p_short = va_arg(ap, short*)) *p_short = (short)val;
2824887Schin 				break;
2834887Schin 			case 'l':
2844887Schin 				if (p_long = va_arg(ap, long*)) *p_long = val;
2854887Schin 				break;
2864887Schin 			default:
2874887Schin 				if (p_int = va_arg(ap, int*)) *p_int = (int)val;
2884887Schin 				break;
2894887Schin 			}
2904887Schin 			if (s != p_char)
2914887Schin 			{
2924887Schin 				s = p_char;
2934887Schin 				num++;
2944887Schin 			}
2954887Schin 			break;
2964887Schin 		case 'f':
2974887Schin 		case 'g':
2984887Schin 			if (!*s || *s == '\n')
2994887Schin 			{
3004887Schin 				dval = 0;
3014887Schin 				p_char = s;
3024887Schin 			}
3034887Schin 			else dval = strtod(s, &p_char);
3044887Schin 			if (p_double = va_arg(ap, double*)) *p_double = dval;
3054887Schin 			if (s != p_char)
3064887Schin 			{
3074887Schin 				s = p_char;
3084887Schin 				num++;
3094887Schin 			}
3104887Schin 			break;
3114887Schin 		case 's':
3124887Schin 			p_string = va_arg(ap, char**);
3134887Schin 			if (q = *f) f++;
3144887Schin 			if (!*s || *s == '\n')
3154887Schin 			{
3164887Schin 				if (p_string) *p_string = s;
3174887Schin 			}
3184887Schin 			else s = lextok(s, q, p_string, &num);
3194887Schin 			break;
3204887Schin 		case 'v':
3214887Schin 			p_string = va_arg(ap, char**);
3224887Schin 			c = va_arg(ap, int);
3234887Schin 			if (q = *f) f++;
3244887Schin 			if ((!*s || *s == '\n') && p_string)
3254887Schin 			{
3264887Schin 				*p_string = 0;
3274887Schin 				p_string = 0;
3284887Schin 			}
3294887Schin 			while (*s && *s != '\n' && --c > 0)
3304887Schin 			{
3314887Schin 				s = lextok(s, q, p_string, &num);
3324887Schin 				if (p_string) p_string++;
3334887Schin 			}
3344887Schin 			if (p_string) *p_string = 0;
3354887Schin 			break;
3364887Schin 		}
3374887Schin 		if (skip) num = onum;
3384887Schin 		else if (num == onum)
3394887Schin 		{
3404887Schin 			if (!num) num = -1;
3414887Schin 			skip = s;
3424887Schin 			s = empty;
3434887Schin 		}
3444887Schin 		break;
3454887Schin 	case '\n':
3464887Schin 		goto done;
3474887Schin 	default:
3484887Schin 		if ((*s++ != c) && !skip)
3494887Schin 		{
3504887Schin 			skip = s - 1;
3514887Schin 			s = empty;
3524887Schin 		}
3534887Schin 		break;
3544887Schin 	}
3554887Schin  done:
3564887Schin 	va_end(ap);
3574887Schin 	if (*s == '\n') *s++ = 0;
3584887Schin 	if (nxt) *nxt = skip ? skip : s;
3594887Schin 	return(num);
3604887Schin }
361