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
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
55int
56stropt(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