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
284887Schin #include <ast.h>
294887Schin #include <ctype.h>
304887Schin
314887Schin /*
324887Schin * parse option expression in s using options in tab with element size siz
334887Schin * first element in tab must be a char*
344887Schin * options match
354887Schin *
364887Schin * [no]name[[:]=['"]value["']][, ]...
374887Schin *
384887Schin * f is called for each option
394887Schin *
404887Schin * (*f)(void* a, char* p, int n, char* v)
414887Schin *
424887Schin * a from stropt
434887Schin * p matching tab entry, or name if no table
444887Schin * n 0 if option had ``no'' prefix, -1 if :=, 1 otherwise
454887Schin * v option value pointer
464887Schin *
474887Schin * for unmatched options p is 0 and v is the offending option
484887Schin *
494887Schin * names in s may be shorter than tab names
504887Schin * longer names must have a prefix that matches a tab name
514887Schin * the first match is returned
524887Schin * \ escapes value using chresc()
534887Schin */
544887Schin
554887Schin int
stropt(const char * as,const void * tab,int siz,int (* f)(void *,const void *,int,const char *),void * a)564887Schin stropt(const char* as, const void* tab, int siz, int(*f)(void*, const void*, int, const char*), void* a)
574887Schin {
584887Schin register int c;
594887Schin register char* s;
604887Schin register char* v;
614887Schin register char* t;
624887Schin char** p;
634887Schin char* u;
644887Schin char* x;
654887Schin char* e;
664887Schin int n;
674887Schin int ql;
684887Schin int qr;
694887Schin int qc;
704887Schin
714887Schin if (!as) n = 0;
724887Schin else if (!(x = s = strdup(as))) n = -1;
734887Schin else
744887Schin {
754887Schin for (;;)
764887Schin {
774887Schin while (isspace(*s) || *s == ',') s++;
784887Schin if (*s == 'n' && *(s + 1) == 'o')
794887Schin {
804887Schin s += 2;
814887Schin n = 0;
824887Schin }
834887Schin else n = 1;
844887Schin if (!*s)
854887Schin {
864887Schin n = 0;
874887Schin break;
884887Schin }
894887Schin if (tab)
904887Schin {
914887Schin for (p = (char**)tab; t = *p; p = (char**)((char*)p + siz))
924887Schin {
934887Schin for (v = s; *t && *t++ == *v; v++);
944887Schin if (!*t || isspace(*v) || *v == ',' || *v == '=')
954887Schin break;
964887Schin if (*v == ':' && *(v + 1) == '=')
974887Schin {
984887Schin v++;
994887Schin n = -1;
1004887Schin break;
1014887Schin }
1024887Schin }
1034887Schin if (!t)
1044887Schin {
1054887Schin u = v = s;
1064887Schin p = 0;
1074887Schin }
1084887Schin }
1094887Schin else
1104887Schin {
1114887Schin p = (char**)(v = s);
1124887Schin t = 0;
1134887Schin }
1144887Schin while (*v && !isspace(*v) && *v != '=' && *v != ',')
1154887Schin if (*v++ == ':' && *v == '=')
1164887Schin {
1174887Schin if (!t)
1184887Schin *(v - 1) = 0;
1194887Schin n = -n;
1204887Schin break;
1214887Schin }
1224887Schin if (*v == '=')
1234887Schin {
1244887Schin if (!t)
1254887Schin *v = 0;
1264887Schin t = s = ++v;
1274887Schin ql = qr = 0;
1284887Schin while (c = *s++)
1294887Schin {
1304887Schin if (c == '\\')
1314887Schin {
1324887Schin *t++ = chresc(s - 1, &e);
1334887Schin s = e;
1344887Schin }
1354887Schin else if (c == qr)
1364887Schin {
1374887Schin if (qr != ql)
1384887Schin *t++ = c;
1394887Schin if (--qc <= 0)
1404887Schin qr = ql = 0;
1414887Schin }
1424887Schin else if (c == ql)
1434887Schin {
1444887Schin *t++ = c;
1454887Schin qc++;
1464887Schin }
1474887Schin else if (qr)
1484887Schin *t++ = c;
1494887Schin else if (c == ',' || isspace(c))
1504887Schin break;
1514887Schin else if (c == '"' || c == '\'')
1524887Schin {
1534887Schin ql = qr = c;
1544887Schin qc = 1;
1554887Schin }
1564887Schin else
1574887Schin {
1584887Schin *t++ = c;
1594887Schin if (c == '{')
1604887Schin {
1614887Schin ql = c;
1624887Schin qr = '}';
1634887Schin qc = 1;
1644887Schin }
1654887Schin else if (c == '(')
1664887Schin {
1674887Schin ql = c;
1684887Schin qr = ')';
1694887Schin qc = 1;
1704887Schin }
1714887Schin }
1724887Schin }
1734887Schin *t = 0;
1744887Schin }
1754887Schin else
1764887Schin {
1774887Schin s = v;
1784887Schin c = *s;
1794887Schin *s++ = 0;
1804887Schin }
1814887Schin n = p ? (*f)(a, p, n, v) : (*f)(a, p, v - u, u);
1824887Schin if (n || !c)
1834887Schin break;
1844887Schin }
1854887Schin free(x);
1864887Schin }
1874887Schin return n;
1884887Schin }
189