xref: /freebsd/sbin/ipf/libipf/var.c (revision 2a63c3be158216222d89a073dcbd6a72ee4aab5a)
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 
14 typedef	struct	variable	{
15 	struct	variable	*v_next;
16 	char	*v_name;
17 	char	*v_value;
18 } variable_t;
19 
20 static	variable_t	*vtop = NULL;
21 
22 static variable_t *find_var(char *);
23 static char *expand_string(char *, int);
24 
25 
find_var(char * name)26 static 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 
get_variable(char * string,char ** after,int line)37 char *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 
expand_string(char * oldstring,int line)82 static 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 
set_variable(char * name,char * value)140 void 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