1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin /*
24da2e3ebdSchin  * Glenn Fowler
25da2e3ebdSchin  * AT&T Research
26da2e3ebdSchin  *
27da2e3ebdSchin  * scan s for tokens in fmt
28da2e3ebdSchin  * s modified in place and not restored
29da2e3ebdSchin  * if nxt!=0 then it will point to the first unread char in s
30da2e3ebdSchin  * the number of scanned tokens is returned
31da2e3ebdSchin  * -1 returned if s was not empty and fmt failed to match
32da2e3ebdSchin  *
33da2e3ebdSchin  * ' ' in fmt matches 0 or more {space,tab}
34da2e3ebdSchin  * '\n' in fmt eats remainder of current line
35da2e3ebdSchin  * "..." and '...' quotes interpreted
36da2e3ebdSchin  * newline is equivalent to end of buf except when quoted
37da2e3ebdSchin  * \\ quotes following char
38da2e3ebdSchin  *
39da2e3ebdSchin  * message support for %s and %v data
40da2e3ebdSchin  *
41da2e3ebdSchin  *	(5:12345)		fixed length strings, ) may be \t
42da2e3ebdSchin  *	(null)			NiL
43da2e3ebdSchin  *
44da2e3ebdSchin  * "..." and '...' may span \n, and \\n is the line splice
45da2e3ebdSchin  * quoted '\r' translated to '\n'
46da2e3ebdSchin  * otherwise tokenizing is unconditionally terminated by '\n'
47da2e3ebdSchin  *
48da2e3ebdSchin  * a null arg pointer skips that arg
49da2e3ebdSchin  *
50da2e3ebdSchin  *	%c		char
51da2e3ebdSchin  *	%[hl]d		[short|int|long] base 10
52da2e3ebdSchin  *	%f		double
53da2e3ebdSchin  *	%g		double
54da2e3ebdSchin  *	%[hl]n		[short|int|long] C-style base
55da2e3ebdSchin  *	%[hl]o		[short|int|long] base 8
56da2e3ebdSchin  *	%s		string
57da2e3ebdSchin  *	%[hl]u		same as %[hl]n
58da2e3ebdSchin  *	%v		argv, elements
59da2e3ebdSchin  *	%[hl]x		[short|int|long] base 16
60da2e3ebdSchin  *
61da2e3ebdSchin  * unmatched char args are set to "", int args to 0
62da2e3ebdSchin  */
63da2e3ebdSchin 
64da2e3ebdSchin #include <ast.h>
65da2e3ebdSchin #include <tok.h>
66da2e3ebdSchin 
67da2e3ebdSchin static char	empty[1];
68da2e3ebdSchin 
69da2e3ebdSchin /*
70da2e3ebdSchin  * get one string token into p
71da2e3ebdSchin  */
72da2e3ebdSchin 
73da2e3ebdSchin static char*
lextok(register char * s,register int c,char ** p,int * n)74da2e3ebdSchin lextok(register char* s, register int c, char** p, int* n)
75da2e3ebdSchin {
76da2e3ebdSchin 	register char*	t;
77da2e3ebdSchin 	register int	q;
78da2e3ebdSchin 	char*		b;
79da2e3ebdSchin 	char*		u;
80da2e3ebdSchin 
81da2e3ebdSchin 	if (*s == '(' && (!c || c == ' ' || c == '\n'))
82da2e3ebdSchin 	{
83da2e3ebdSchin 		q = strtol(s + 1, &b, 10);
84da2e3ebdSchin 		if (*b == ':')
85da2e3ebdSchin 		{
86da2e3ebdSchin 			if (*(t = ++b + q) == ')' || *t == '\t')
87da2e3ebdSchin 			{
88da2e3ebdSchin 				s = t;
89da2e3ebdSchin 				*s++ = 0;
90da2e3ebdSchin 				goto end;
91da2e3ebdSchin 			}
92da2e3ebdSchin 		}
93da2e3ebdSchin 		else if (strneq(b, "null)", 5))
94da2e3ebdSchin 		{
95da2e3ebdSchin 			s = b + 5;
96da2e3ebdSchin 			b = 0;
97da2e3ebdSchin 			goto end;
98da2e3ebdSchin 		}
99da2e3ebdSchin 	}
100da2e3ebdSchin 	b = s;
101da2e3ebdSchin 	q = 0;
102da2e3ebdSchin 	t = 0;
103da2e3ebdSchin 	for (;;)
104da2e3ebdSchin 	{
105da2e3ebdSchin 		if (!*s || !q && *s == '\n')
106da2e3ebdSchin 		{
107da2e3ebdSchin 			if (!q)
108da2e3ebdSchin 			{
109da2e3ebdSchin 				if (!c || c == ' ' || c == '\n') (*n)++;
110da2e3ebdSchin 				else
111da2e3ebdSchin 				{
112da2e3ebdSchin 					s = b;
113da2e3ebdSchin 					b = empty;
114da2e3ebdSchin 					break;
115da2e3ebdSchin 				}
116da2e3ebdSchin 			}
117da2e3ebdSchin 			if (t) *t = 0;
118da2e3ebdSchin 			break;
119da2e3ebdSchin 		}
120da2e3ebdSchin 		else if (*s == '\\')
121da2e3ebdSchin 		{
122da2e3ebdSchin 			u = s;
123da2e3ebdSchin 			if (!*++s || *s == '\n' && (!*++s || *s == '\n')) continue;
124da2e3ebdSchin 			if (p)
125da2e3ebdSchin 			{
126da2e3ebdSchin 				if (b == u) b = s;
127da2e3ebdSchin 				else if (!t) t = u;
128da2e3ebdSchin 			}
129da2e3ebdSchin 		}
130da2e3ebdSchin 		else if (q)
131da2e3ebdSchin 		{
132da2e3ebdSchin 			if (*s == q)
133da2e3ebdSchin 			{
134da2e3ebdSchin 				q = 0;
135da2e3ebdSchin 				if (!t) t = s;
136da2e3ebdSchin 				s++;
137da2e3ebdSchin 				continue;
138da2e3ebdSchin 			}
139da2e3ebdSchin 			else if (*s == '\r') *s = '\n';
140da2e3ebdSchin 		}
141da2e3ebdSchin 		else if (*s == '"' || *s == '\'')
142da2e3ebdSchin 		{
143da2e3ebdSchin 			q = *s++;
144da2e3ebdSchin 			if (p)
145da2e3ebdSchin 			{
146da2e3ebdSchin 				if (b == (s - 1)) b = s;
147da2e3ebdSchin 				else if (!t) t = s - 1;
148da2e3ebdSchin 			}
149da2e3ebdSchin 			continue;
150da2e3ebdSchin 		}
151da2e3ebdSchin 		else if (*s == c || c == ' ' && *s == '\t')
152da2e3ebdSchin 		{
153da2e3ebdSchin 			*s++ = 0;
154da2e3ebdSchin 			if (t) *t = 0;
155da2e3ebdSchin 		end:
156da2e3ebdSchin 			if (c == ' ') while (*s == ' ' || *s == '\t') s++;
157da2e3ebdSchin 			(*n)++;
158da2e3ebdSchin 			break;
159da2e3ebdSchin 		}
160da2e3ebdSchin 		if (t) *t++ = *s;
161da2e3ebdSchin 		s++;
162da2e3ebdSchin 	}
163da2e3ebdSchin 	if (p) *p = b;
164da2e3ebdSchin 	return(s);
165da2e3ebdSchin }
166da2e3ebdSchin 
167da2e3ebdSchin /*
168da2e3ebdSchin  * scan entry
169da2e3ebdSchin  */
170da2e3ebdSchin 
171da2e3ebdSchin int
tokscan(register char * s,char ** nxt,const char * fmt,...)172da2e3ebdSchin tokscan(register char* s, char** nxt, const char* fmt, ...)
173da2e3ebdSchin {
174da2e3ebdSchin 	register int	c;
175da2e3ebdSchin 	register char*	f;
176da2e3ebdSchin 	int		num = 0;
177da2e3ebdSchin 	char*		skip = 0;
178da2e3ebdSchin 	int		q;
179da2e3ebdSchin 	int		onum;
180da2e3ebdSchin 	long		val;
181da2e3ebdSchin 	double		dval;
182da2e3ebdSchin 	va_list		ap;
183da2e3ebdSchin 	char*		p_char;
184da2e3ebdSchin 	double*		p_double;
185da2e3ebdSchin 	int*		p_int;
186da2e3ebdSchin 	long*		p_long;
187da2e3ebdSchin 	short*		p_short;
188da2e3ebdSchin 	char**		p_string;
189da2e3ebdSchin 	char*		prv_f = 0;
190da2e3ebdSchin 	va_list		prv_ap;
191da2e3ebdSchin 
192da2e3ebdSchin 	va_start(ap, fmt);
193da2e3ebdSchin 	if (!*s || *s == '\n')
194da2e3ebdSchin 	{
195da2e3ebdSchin 		skip = s;
196da2e3ebdSchin 		s = empty;
197da2e3ebdSchin 	}
198da2e3ebdSchin 	f = (char*)fmt;
199da2e3ebdSchin 	for (;;) switch (c = *f++)
200da2e3ebdSchin 	{
201da2e3ebdSchin 	case 0:
202da2e3ebdSchin 		if (f = prv_f)
203da2e3ebdSchin 		{
204da2e3ebdSchin 			prv_f = 0;
205da2e3ebdSchin 			/* prv_ap value is guarded by prv_f */
206da2e3ebdSchin 			va_copy(ap, prv_ap);
207da2e3ebdSchin 			continue;
208da2e3ebdSchin 		}
209da2e3ebdSchin 		goto done;
210da2e3ebdSchin 	case ' ':
211da2e3ebdSchin 		while (*s == ' ' || *s == '\t') s++;
212da2e3ebdSchin 		break;
213da2e3ebdSchin 	case '%':
214da2e3ebdSchin 		onum = num;
215da2e3ebdSchin 		switch (c = *f++)
216da2e3ebdSchin 		{
217da2e3ebdSchin 		case 'h':
218da2e3ebdSchin 		case 'l':
219da2e3ebdSchin 			q = c;
220da2e3ebdSchin 			c = *f++;
221da2e3ebdSchin 			break;
222da2e3ebdSchin 		default:
223da2e3ebdSchin 			q = 0;
224da2e3ebdSchin 			break;
225da2e3ebdSchin 		}
226da2e3ebdSchin 		switch (c)
227da2e3ebdSchin 		{
228da2e3ebdSchin 		case 0:
229da2e3ebdSchin 		case '%':
230da2e3ebdSchin 			f--;
231da2e3ebdSchin 			continue;
232da2e3ebdSchin 		case ':':
233da2e3ebdSchin 			prv_f = f;
234da2e3ebdSchin 			f = va_arg(ap, char*);
235da2e3ebdSchin 			va_copy(prv_ap, ap);
236da2e3ebdSchin 			va_copy(ap, va_listval(va_arg(ap, va_listarg)));
237da2e3ebdSchin 			continue;
238da2e3ebdSchin 		case 'c':
239da2e3ebdSchin 			p_char = va_arg(ap, char*);
240da2e3ebdSchin 			if (!(c = *s) || c == '\n')
241da2e3ebdSchin 			{
242da2e3ebdSchin 				if (p_char) *p_char = 0;
243da2e3ebdSchin 			}
244da2e3ebdSchin 			else
245da2e3ebdSchin 			{
246da2e3ebdSchin 				if (p_char) *p_char = c;
247da2e3ebdSchin 				s++;
248da2e3ebdSchin 				num++;
249da2e3ebdSchin 			}
250da2e3ebdSchin 			break;
251da2e3ebdSchin 		case 'd':
252da2e3ebdSchin 		case 'n':
253da2e3ebdSchin 		case 'o':
254da2e3ebdSchin 		case 'u':
255da2e3ebdSchin 		case 'x':
256da2e3ebdSchin 			switch (c)
257da2e3ebdSchin 			{
258da2e3ebdSchin 			case 'd':
259da2e3ebdSchin 				c = 10;
260da2e3ebdSchin 				break;
261da2e3ebdSchin 			case 'n':
262da2e3ebdSchin 			case 'u':
263da2e3ebdSchin 				c = 0;
264da2e3ebdSchin 				break;
265da2e3ebdSchin 			case 'o':
266da2e3ebdSchin 				c = 8;
267da2e3ebdSchin 				break;
268da2e3ebdSchin 			case 'x':
269da2e3ebdSchin 				c = 16;
270da2e3ebdSchin 				break;
271da2e3ebdSchin 			}
272da2e3ebdSchin 			if (!*s || *s == '\n')
273da2e3ebdSchin 			{
274da2e3ebdSchin 				val = 0;
275da2e3ebdSchin 				p_char = s;
276da2e3ebdSchin 			}
277da2e3ebdSchin 			else val = strtol(s, &p_char, c);
278da2e3ebdSchin 			switch (q)
279da2e3ebdSchin 			{
280da2e3ebdSchin 			case 'h':
281da2e3ebdSchin 				if (p_short = va_arg(ap, short*)) *p_short = (short)val;
282da2e3ebdSchin 				break;
283da2e3ebdSchin 			case 'l':
284da2e3ebdSchin 				if (p_long = va_arg(ap, long*)) *p_long = val;
285da2e3ebdSchin 				break;
286da2e3ebdSchin 			default:
287da2e3ebdSchin 				if (p_int = va_arg(ap, int*)) *p_int = (int)val;
288da2e3ebdSchin 				break;
289da2e3ebdSchin 			}
290da2e3ebdSchin 			if (s != p_char)
291da2e3ebdSchin 			{
292da2e3ebdSchin 				s = p_char;
293da2e3ebdSchin 				num++;
294da2e3ebdSchin 			}
295da2e3ebdSchin 			break;
296da2e3ebdSchin 		case 'f':
297da2e3ebdSchin 		case 'g':
298da2e3ebdSchin 			if (!*s || *s == '\n')
299da2e3ebdSchin 			{
300da2e3ebdSchin 				dval = 0;
301da2e3ebdSchin 				p_char = s;
302da2e3ebdSchin 			}
303da2e3ebdSchin 			else dval = strtod(s, &p_char);
304da2e3ebdSchin 			if (p_double = va_arg(ap, double*)) *p_double = dval;
305da2e3ebdSchin 			if (s != p_char)
306da2e3ebdSchin 			{
307da2e3ebdSchin 				s = p_char;
308da2e3ebdSchin 				num++;
309da2e3ebdSchin 			}
310da2e3ebdSchin 			break;
311da2e3ebdSchin 		case 's':
312da2e3ebdSchin 			p_string = va_arg(ap, char**);
313da2e3ebdSchin 			if (q = *f) f++;
314da2e3ebdSchin 			if (!*s || *s == '\n')
315da2e3ebdSchin 			{
316da2e3ebdSchin 				if (p_string) *p_string = s;
317da2e3ebdSchin 			}
318da2e3ebdSchin 			else s = lextok(s, q, p_string, &num);
319da2e3ebdSchin 			break;
320da2e3ebdSchin 		case 'v':
321da2e3ebdSchin 			p_string = va_arg(ap, char**);
322da2e3ebdSchin 			c = va_arg(ap, int);
323da2e3ebdSchin 			if (q = *f) f++;
324da2e3ebdSchin 			if ((!*s || *s == '\n') && p_string)
325da2e3ebdSchin 			{
326da2e3ebdSchin 				*p_string = 0;
327da2e3ebdSchin 				p_string = 0;
328da2e3ebdSchin 			}
329da2e3ebdSchin 			while (*s && *s != '\n' && --c > 0)
330da2e3ebdSchin 			{
331da2e3ebdSchin 				s = lextok(s, q, p_string, &num);
332da2e3ebdSchin 				if (p_string) p_string++;
333da2e3ebdSchin 			}
334da2e3ebdSchin 			if (p_string) *p_string = 0;
335da2e3ebdSchin 			break;
336da2e3ebdSchin 		}
337da2e3ebdSchin 		if (skip) num = onum;
338da2e3ebdSchin 		else if (num == onum)
339da2e3ebdSchin 		{
340da2e3ebdSchin 			if (!num) num = -1;
341da2e3ebdSchin 			skip = s;
342da2e3ebdSchin 			s = empty;
343da2e3ebdSchin 		}
344da2e3ebdSchin 		break;
345da2e3ebdSchin 	case '\n':
346da2e3ebdSchin 		goto done;
347da2e3ebdSchin 	default:
348da2e3ebdSchin 		if ((*s++ != c) && !skip)
349da2e3ebdSchin 		{
350da2e3ebdSchin 			skip = s - 1;
351da2e3ebdSchin 			s = empty;
352da2e3ebdSchin 		}
353da2e3ebdSchin 		break;
354da2e3ebdSchin 	}
355da2e3ebdSchin  done:
356da2e3ebdSchin 	va_end(ap);
357da2e3ebdSchin 	if (*s == '\n') *s++ = 0;
358da2e3ebdSchin 	if (nxt) *nxt = skip ? skip : s;
359da2e3ebdSchin 	return(num);
360da2e3ebdSchin }
361