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