1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2009 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* 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 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