1*0Sstevel@tonic-gate #include <ctype.h>
2*0Sstevel@tonic-gate 
3*0Sstevel@tonic-gate #include "ipf.h"
4*0Sstevel@tonic-gate 
5*0Sstevel@tonic-gate typedef	struct	variable	{
6*0Sstevel@tonic-gate 	struct	variable	*v_next;
7*0Sstevel@tonic-gate 	char	*v_name;
8*0Sstevel@tonic-gate 	char	*v_value;
9*0Sstevel@tonic-gate } variable_t;
10*0Sstevel@tonic-gate 
11*0Sstevel@tonic-gate static	variable_t	*vtop = NULL;
12*0Sstevel@tonic-gate 
13*0Sstevel@tonic-gate static variable_t *find_var __P((char *));
14*0Sstevel@tonic-gate static char *expand_string __P((char *, int));
15*0Sstevel@tonic-gate 
16*0Sstevel@tonic-gate 
17*0Sstevel@tonic-gate static variable_t *find_var(name)
18*0Sstevel@tonic-gate char *name;
19*0Sstevel@tonic-gate {
20*0Sstevel@tonic-gate 	variable_t *v;
21*0Sstevel@tonic-gate 
22*0Sstevel@tonic-gate 	for (v = vtop; v != NULL; v = v->v_next)
23*0Sstevel@tonic-gate 		if (!strcmp(name, v->v_name))
24*0Sstevel@tonic-gate 			return v;
25*0Sstevel@tonic-gate 	return NULL;
26*0Sstevel@tonic-gate }
27*0Sstevel@tonic-gate 
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate char *get_variable(string, after, line)
30*0Sstevel@tonic-gate char *string, **after;
31*0Sstevel@tonic-gate int line;
32*0Sstevel@tonic-gate {
33*0Sstevel@tonic-gate 	char c, *s, *t, *value;
34*0Sstevel@tonic-gate 	variable_t *v;
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate 	s = string;
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate 	if (*s == '{') {
39*0Sstevel@tonic-gate 		s++;
40*0Sstevel@tonic-gate 		for (t = s; *t != '\0'; t++)
41*0Sstevel@tonic-gate 			if (*t == '}')
42*0Sstevel@tonic-gate 				break;
43*0Sstevel@tonic-gate 		if (*t == '\0') {
44*0Sstevel@tonic-gate 			fprintf(stderr, "%d: { without }\n", line);
45*0Sstevel@tonic-gate 			return NULL;
46*0Sstevel@tonic-gate 		}
47*0Sstevel@tonic-gate 	} else if (isalpha(*s)) {
48*0Sstevel@tonic-gate 		for (t = s + 1; *t != '\0'; t++)
49*0Sstevel@tonic-gate 			if (!isalpha(*t) && !isdigit(*t))
50*0Sstevel@tonic-gate 				break;
51*0Sstevel@tonic-gate 	} else {
52*0Sstevel@tonic-gate 		fprintf(stderr, "%d: variables cannot start with '%c'\n",
53*0Sstevel@tonic-gate 			line, *s);
54*0Sstevel@tonic-gate 		return NULL;
55*0Sstevel@tonic-gate 	}
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate 	if (after != NULL)
58*0Sstevel@tonic-gate 		*after = t;
59*0Sstevel@tonic-gate 	c = *t;
60*0Sstevel@tonic-gate 	*t = '\0';
61*0Sstevel@tonic-gate 	v = find_var(s);
62*0Sstevel@tonic-gate 	*t = c;
63*0Sstevel@tonic-gate 	if (v == NULL) {
64*0Sstevel@tonic-gate 		fprintf(stderr, "%d: unknown variable '%s'\n", line, s);
65*0Sstevel@tonic-gate 		return NULL;
66*0Sstevel@tonic-gate 	}
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate 	s = strdup(v->v_value);
69*0Sstevel@tonic-gate 	value = expand_string(s, line);
70*0Sstevel@tonic-gate 	if (value != s)
71*0Sstevel@tonic-gate 		free(s);
72*0Sstevel@tonic-gate 	return value;
73*0Sstevel@tonic-gate }
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate static char *expand_string(oldstring, line)
77*0Sstevel@tonic-gate char *oldstring;
78*0Sstevel@tonic-gate int line;
79*0Sstevel@tonic-gate {
80*0Sstevel@tonic-gate 	char c, *s, *p1, *p2, *p3, *newstring, *value;
81*0Sstevel@tonic-gate 	int len;
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 	p3 = NULL;
84*0Sstevel@tonic-gate 	newstring = oldstring;
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	for (s = oldstring; *s != '\0'; s++)
87*0Sstevel@tonic-gate 		if (*s == '$') {
88*0Sstevel@tonic-gate 			*s = '\0';
89*0Sstevel@tonic-gate 			s++;
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 			switch (*s)
92*0Sstevel@tonic-gate 			{
93*0Sstevel@tonic-gate 			case '$' :
94*0Sstevel@tonic-gate 				bcopy(s, s - 1, strlen(s));
95*0Sstevel@tonic-gate 				break;
96*0Sstevel@tonic-gate 			default :
97*0Sstevel@tonic-gate 				c = *s;
98*0Sstevel@tonic-gate 				value = get_variable(s, &p3, line);
99*0Sstevel@tonic-gate 				if (value == NULL)
100*0Sstevel@tonic-gate 					return NULL;
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 				p2 = expand_string(value, line);
103*0Sstevel@tonic-gate 				if (p2 == NULL)
104*0Sstevel@tonic-gate 					return NULL;
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 				len = strlen(newstring) + strlen(p2);
107*0Sstevel@tonic-gate 				if (p3 != NULL) {
108*0Sstevel@tonic-gate 					if (c == '{' && *p3 == '}')
109*0Sstevel@tonic-gate 						p3++;
110*0Sstevel@tonic-gate 					len += strlen(p3);
111*0Sstevel@tonic-gate 				}
112*0Sstevel@tonic-gate 				p1 = malloc(len + 1);
113*0Sstevel@tonic-gate 				if (p1 == NULL)
114*0Sstevel@tonic-gate 					return NULL;
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate 				*(s - 1) = '\0';
117*0Sstevel@tonic-gate 				strcpy(p1, newstring);
118*0Sstevel@tonic-gate 				strcat(p1, p2);
119*0Sstevel@tonic-gate 				if (p3 != NULL)
120*0Sstevel@tonic-gate 					strcat(p1, p3);
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 				s = p1 + len - strlen(p3);
123*0Sstevel@tonic-gate 				if (newstring != oldstring)
124*0Sstevel@tonic-gate 					free(newstring);
125*0Sstevel@tonic-gate 				newstring = p1;
126*0Sstevel@tonic-gate 				break;
127*0Sstevel@tonic-gate 			}
128*0Sstevel@tonic-gate 		}
129*0Sstevel@tonic-gate 	return newstring;
130*0Sstevel@tonic-gate }
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate void set_variable(name, value)
134*0Sstevel@tonic-gate char *name;
135*0Sstevel@tonic-gate char *value;
136*0Sstevel@tonic-gate {
137*0Sstevel@tonic-gate 	variable_t *v;
138*0Sstevel@tonic-gate 	int len;
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	if (name == NULL || value == NULL || *name == '\0')
141*0Sstevel@tonic-gate 		return;
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 	v = find_var(name);
144*0Sstevel@tonic-gate 	if (v != NULL) {
145*0Sstevel@tonic-gate 		free(v->v_value);
146*0Sstevel@tonic-gate 		v->v_value = strdup(value);
147*0Sstevel@tonic-gate 		return;
148*0Sstevel@tonic-gate 	}
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 	len = strlen(value);
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	if ((*value == '"' && value[len - 1] == '"') ||
153*0Sstevel@tonic-gate 	    (*value == '\'' && value[len - 1] == '\'')) {
154*0Sstevel@tonic-gate 		value[len - 1] = '\0';
155*0Sstevel@tonic-gate 		value++;
156*0Sstevel@tonic-gate 		len -=2;
157*0Sstevel@tonic-gate 	}
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	v = (variable_t *)malloc(sizeof(*v));
160*0Sstevel@tonic-gate 	if (v == NULL)
161*0Sstevel@tonic-gate 		return;
162*0Sstevel@tonic-gate 	v->v_name = strdup(name);
163*0Sstevel@tonic-gate 	v->v_value = strdup(value);
164*0Sstevel@tonic-gate 	v->v_next = vtop;
165*0Sstevel@tonic-gate 	vtop = v;
166*0Sstevel@tonic-gate }
167