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