1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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 
28 #include <ast.h>
29 #include <ctype.h>
30 
31 /*
32  * parse option expression in s using options in tab with element size siz
33  * first element in tab must be a char*
34  * options match
35  *
36  *	[no]name[[:]=['"]value["']][, ]...
37  *
38  * f is called for each option
39  *
40  *	(*f)(void* a, char* p, int n, char* v)
41  *
42  *	a	from stropt
43  *	p	matching tab entry, or name if no table
44  *	n	0 if option had ``no'' prefix, -1 if :=, 1 otherwise
45  *	v	option value pointer
46  *
47  * for unmatched options p is 0 and v is the offending option
48  *
49  * names in s may be shorter than tab names
50  * longer names must have a prefix that matches a tab name
51  * the first match is returned
52  * \ escapes value using chresc()
53  */
54 
55 int
stropt(const char * as,const void * tab,int siz,int (* f)(void *,const void *,int,const char *),void * a)56 stropt(const char* as, const void* tab, int siz, int(*f)(void*, const void*, int, const char*), void* a)
57 {
58 	register int	c;
59 	register char*	s;
60 	register char*	v;
61 	register char*	t;
62 	char**		p;
63 	char*		u;
64 	char*		x;
65 	char*		e;
66 	int		n;
67 	int		ql;
68 	int		qr;
69 	int		qc;
70 
71 	if (!as) n = 0;
72 	else if (!(x = s = strdup(as))) n = -1;
73 	else
74 	{
75 		for (;;)
76 		{
77 			while (isspace(*s) || *s == ',') s++;
78 			if (*s == 'n' && *(s + 1) == 'o')
79 			{
80 				s += 2;
81 				n = 0;
82 			}
83 			else n = 1;
84 			if (!*s)
85 			{
86 				n = 0;
87 				break;
88 			}
89 			if (tab)
90 			{
91 				for (p = (char**)tab; t = *p; p = (char**)((char*)p + siz))
92 				{
93 					for (v = s; *t && *t++ == *v; v++);
94 					if (!*t || isspace(*v) || *v == ',' || *v == '=')
95 						break;
96 					if (*v == ':' && *(v + 1) == '=')
97 					{
98 						v++;
99 						n = -1;
100 						break;
101 					}
102 				}
103 				if (!t)
104 				{
105 					u = v = s;
106 					p = 0;
107 				}
108 			}
109 			else
110 			{
111 				p = (char**)(v = s);
112 				t = 0;
113 			}
114 			while (*v && !isspace(*v) && *v != '=' && *v != ',')
115 				if (*v++ == ':' && *v == '=')
116 				{
117 					if (!t)
118 						*(v - 1) = 0;
119 					n = -n;
120 					break;
121 				}
122 			if (*v == '=')
123 			{
124 				if (!t)
125 					*v = 0;
126 				t = s = ++v;
127 				ql = qr = 0;
128 				while (c = *s++)
129 				{
130 					if (c == '\\')
131 					{
132 						*t++ = chresc(s - 1, &e);
133 						s = e;
134 					}
135 					else if (c == qr)
136 					{
137 						if (qr != ql)
138 							*t++ = c;
139 						if (--qc <= 0)
140 							qr = ql = 0;
141 					}
142 					else if (c == ql)
143 					{
144 						*t++ = c;
145 						qc++;
146 					}
147 					else if (qr)
148 						*t++ = c;
149 					else if (c == ',' || isspace(c))
150 						break;
151 					else if (c == '"' || c == '\'')
152 					{
153 						ql = qr = c;
154 						qc = 1;
155 					}
156 					else
157 					{
158 						*t++ = c;
159 						if (c == '{')
160 						{
161 							ql = c;
162 							qr = '}';
163 							qc = 1;
164 						}
165 						else if (c == '(')
166 						{
167 							ql = c;
168 							qr = ')';
169 							qc = 1;
170 						}
171 					}
172 				}
173 				*t = 0;
174 			}
175 			else
176 			{
177 				s = v;
178 				c = *s;
179 				*s++ = 0;
180 			}
181 			n = p ? (*f)(a, p, n, v) : (*f)(a, p, v - u, u);
182 			if (n || !c)
183 				break;
184 		}
185 		free(x);
186 	}
187 	return n;
188 }
189