1145519Sdarrenr/*	$FreeBSD$	*/
2145510Sdarrenr
3170268Sdarrenr/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5255332Scy *
6255332Scy * See the IPFILTER.LICENCE file for details on licencing.
7255332Scy *
8255332Scy * $Id$
9255332Scy */
10170268Sdarrenr
11145510Sdarrenr#include <ctype.h>
12145510Sdarrenr
13145510Sdarrenr#include "ipf.h"
14145510Sdarrenr
15145510Sdarrenrtypedef	struct	variable	{
16145510Sdarrenr	struct	variable	*v_next;
17145510Sdarrenr	char	*v_name;
18145510Sdarrenr	char	*v_value;
19145510Sdarrenr} variable_t;
20145510Sdarrenr
21145510Sdarrenrstatic	variable_t	*vtop = NULL;
22145510Sdarrenr
23145510Sdarrenrstatic variable_t *find_var __P((char *));
24145510Sdarrenrstatic char *expand_string __P((char *, int));
25145510Sdarrenr
26145510Sdarrenr
27145510Sdarrenrstatic variable_t *find_var(name)
28255332Scy	char *name;
29145510Sdarrenr{
30145510Sdarrenr	variable_t *v;
31145510Sdarrenr
32145510Sdarrenr	for (v = vtop; v != NULL; v = v->v_next)
33145510Sdarrenr		if (!strcmp(name, v->v_name))
34145510Sdarrenr			return v;
35145510Sdarrenr	return NULL;
36145510Sdarrenr}
37145510Sdarrenr
38145510Sdarrenr
39145510Sdarrenrchar *get_variable(string, after, line)
40255332Scy	char *string, **after;
41255332Scy	int line;
42145510Sdarrenr{
43145510Sdarrenr	char c, *s, *t, *value;
44145510Sdarrenr	variable_t *v;
45145510Sdarrenr
46145510Sdarrenr	s = string;
47145510Sdarrenr
48145510Sdarrenr	if (*s == '{') {
49145510Sdarrenr		s++;
50145510Sdarrenr		for (t = s; *t != '\0'; t++)
51145510Sdarrenr			if (*t == '}')
52145510Sdarrenr				break;
53145510Sdarrenr		if (*t == '\0') {
54145510Sdarrenr			fprintf(stderr, "%d: { without }\n", line);
55145510Sdarrenr			return NULL;
56145510Sdarrenr		}
57145510Sdarrenr	} else if (ISALPHA(*s)) {
58145510Sdarrenr		for (t = s + 1; *t != '\0'; t++)
59145510Sdarrenr			if (!ISALPHA(*t) && !ISDIGIT(*t) && (*t != '_'))
60145510Sdarrenr				break;
61145510Sdarrenr	} else {
62145510Sdarrenr		fprintf(stderr, "%d: variables cannot start with '%c'\n",
63145510Sdarrenr			line, *s);
64145510Sdarrenr		return NULL;
65145510Sdarrenr	}
66145510Sdarrenr
67145510Sdarrenr	if (after != NULL)
68145510Sdarrenr		*after = t;
69145510Sdarrenr	c = *t;
70145510Sdarrenr	*t = '\0';
71145510Sdarrenr	v = find_var(s);
72145510Sdarrenr	*t = c;
73145510Sdarrenr	if (v == NULL) {
74145510Sdarrenr		fprintf(stderr, "%d: unknown variable '%s'\n", line, s);
75145510Sdarrenr		return NULL;
76145510Sdarrenr	}
77145510Sdarrenr
78145510Sdarrenr	s = strdup(v->v_value);
79145510Sdarrenr	value = expand_string(s, line);
80145510Sdarrenr	if (value != s)
81145510Sdarrenr		free(s);
82145510Sdarrenr	return value;
83145510Sdarrenr}
84145510Sdarrenr
85145510Sdarrenr
86145510Sdarrenrstatic char *expand_string(oldstring, line)
87255332Scy	char *oldstring;
88255332Scy	int line;
89145510Sdarrenr{
90145510Sdarrenr	char c, *s, *p1, *p2, *p3, *newstring, *value;
91145510Sdarrenr	int len;
92145510Sdarrenr
93145510Sdarrenr	p3 = NULL;
94145510Sdarrenr	newstring = oldstring;
95145510Sdarrenr
96145510Sdarrenr	for (s = oldstring; *s != '\0'; s++)
97145510Sdarrenr		if (*s == '$') {
98145510Sdarrenr			*s = '\0';
99145510Sdarrenr			s++;
100145510Sdarrenr
101145510Sdarrenr			switch (*s)
102145510Sdarrenr			{
103145510Sdarrenr			case '$' :
104145510Sdarrenr				bcopy(s, s - 1, strlen(s));
105145510Sdarrenr				break;
106145510Sdarrenr			default :
107145510Sdarrenr				c = *s;
108145510Sdarrenr				if (c == '\0')
109145510Sdarrenr					return newstring;
110145510Sdarrenr
111145510Sdarrenr				value = get_variable(s, &p3, line);
112145510Sdarrenr				if (value == NULL)
113145510Sdarrenr					return NULL;
114145510Sdarrenr
115145510Sdarrenr				p2 = expand_string(value, line);
116145510Sdarrenr				if (p2 == NULL)
117145510Sdarrenr					return NULL;
118145510Sdarrenr
119145510Sdarrenr				len = strlen(newstring) + strlen(p2);
120145510Sdarrenr				if (p3 != NULL) {
121145510Sdarrenr					if (c == '{' && *p3 == '}')
122145510Sdarrenr						p3++;
123145510Sdarrenr					len += strlen(p3);
124145510Sdarrenr				}
125145510Sdarrenr				p1 = malloc(len + 1);
126145510Sdarrenr				if (p1 == NULL)
127145510Sdarrenr					return NULL;
128145510Sdarrenr
129145510Sdarrenr				*(s - 1) = '\0';
130145510Sdarrenr				strcpy(p1, newstring);
131145510Sdarrenr				strcat(p1, p2);
132145510Sdarrenr				if (p3 != NULL)
133145510Sdarrenr					strcat(p1, p3);
134145510Sdarrenr
135145510Sdarrenr				s = p1 + len - strlen(p3) - 1;
136145510Sdarrenr				if (newstring != oldstring)
137145510Sdarrenr					free(newstring);
138145510Sdarrenr				newstring = p1;
139145510Sdarrenr				break;
140145510Sdarrenr			}
141145510Sdarrenr		}
142145510Sdarrenr	return newstring;
143145510Sdarrenr}
144145510Sdarrenr
145145510Sdarrenr
146145510Sdarrenrvoid set_variable(name, value)
147255332Scy	char *name;
148255332Scy	char *value;
149145510Sdarrenr{
150145510Sdarrenr	variable_t *v;
151145510Sdarrenr	int len;
152145510Sdarrenr
153145510Sdarrenr	if (name == NULL || value == NULL || *name == '\0')
154145510Sdarrenr		return;
155145510Sdarrenr
156145510Sdarrenr	v = find_var(name);
157145510Sdarrenr	if (v != NULL) {
158145510Sdarrenr		free(v->v_value);
159145510Sdarrenr		v->v_value = strdup(value);
160145510Sdarrenr		return;
161145510Sdarrenr	}
162145510Sdarrenr
163145510Sdarrenr	len = strlen(value);
164145510Sdarrenr
165145510Sdarrenr	if ((*value == '"' && value[len - 1] == '"') ||
166145510Sdarrenr	    (*value == '\'' && value[len - 1] == '\'')) {
167145510Sdarrenr		value[len - 1] = '\0';
168145510Sdarrenr		value++;
169145510Sdarrenr		len -=2;
170145510Sdarrenr	}
171145510Sdarrenr
172145510Sdarrenr	v = (variable_t *)malloc(sizeof(*v));
173145510Sdarrenr	if (v == NULL)
174145510Sdarrenr		return;
175145510Sdarrenr	v->v_name = strdup(name);
176145510Sdarrenr	v->v_value = strdup(value);
177145510Sdarrenr	v->v_next = vtop;
178145510Sdarrenr	vtop = v;
179145510Sdarrenr}
180