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