1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1985-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
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