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