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