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