xref: /freebsd/sbin/ipf/libipf/var.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
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(char *name)
28 {
29 	variable_t *v;
30 
31 	for (v = vtop; v != NULL; v = v->v_next)
32 		if (!strcmp(name, v->v_name))
33 			return (v);
34 	return (NULL);
35 }
36 
37 
38 char *get_variable(char *string, char **after, int line)
39 {
40 	char c, *s, *t, *value;
41 	variable_t *v;
42 
43 	s = string;
44 
45 	if (*s == '{') {
46 		s++;
47 		for (t = s; *t != '\0'; t++)
48 			if (*t == '}')
49 				break;
50 		if (*t == '\0') {
51 			fprintf(stderr, "%d: { without }\n", line);
52 			return (NULL);
53 		}
54 	} else if (ISALPHA(*s)) {
55 		for (t = s + 1; *t != '\0'; t++)
56 			if (!ISALPHA(*t) && !ISDIGIT(*t) && (*t != '_'))
57 				break;
58 	} else {
59 		fprintf(stderr, "%d: variables cannot start with '%c'\n",
60 			line, *s);
61 		return (NULL);
62 	}
63 
64 	if (after != NULL)
65 		*after = t;
66 	c = *t;
67 	*t = '\0';
68 	v = find_var(s);
69 	*t = c;
70 	if (v == NULL) {
71 		fprintf(stderr, "%d: unknown variable '%s'\n", line, s);
72 		return (NULL);
73 	}
74 
75 	s = strdup(v->v_value);
76 	value = expand_string(s, line);
77 	if (value != s)
78 		free(s);
79 	return (value);
80 }
81 
82 
83 static char *expand_string(char *oldstring, int 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 
141 void set_variable(char *name, char *value)
142 {
143 	variable_t *v;
144 	int len;
145 
146 	if (name == NULL || value == NULL || *name == '\0')
147 		return;
148 
149 	v = find_var(name);
150 	if (v != NULL) {
151 		free(v->v_value);
152 		v->v_value = strdup(value);
153 		return;
154 	}
155 
156 	len = strlen(value);
157 
158 	if ((*value == '"' && value[len - 1] == '"') ||
159 	    (*value == '\'' && value[len - 1] == '\'')) {
160 		value[len - 1] = '\0';
161 		value++;
162 		len -=2;
163 	}
164 
165 	v = (variable_t *)malloc(sizeof(*v));
166 	if (v == NULL)
167 		return;
168 	v->v_name = strdup(name);
169 	v->v_value = strdup(value);
170 	v->v_next = vtop;
171 	vtop = v;
172 }
173