var.c revision 255332
1251767Sgibbs/*	$FreeBSD: head/contrib/ipfilter/lib/var.c 255332 2013-09-06 23:11:19Z cy $	*/
2251767Sgibbs
3251767Sgibbs/*
4251767Sgibbs * Copyright (C) 2012 by Darren Reed.
5251767Sgibbs *
6251767Sgibbs * See the IPFILTER.LICENCE file for details on licencing.
7251767Sgibbs *
8251767Sgibbs * $Id$
9251767Sgibbs */
10251767Sgibbs
11251767Sgibbs#include <ctype.h>
12251767Sgibbs
13251767Sgibbs#include "ipf.h"
14251767Sgibbs
15251767Sgibbstypedef	struct	variable	{
16251767Sgibbs	struct	variable	*v_next;
17251767Sgibbs	char	*v_name;
18251767Sgibbs	char	*v_value;
19251767Sgibbs} variable_t;
20251767Sgibbs
21251767Sgibbsstatic	variable_t	*vtop = NULL;
22251767Sgibbs
23251767Sgibbsstatic variable_t *find_var __P((char *));
24251767Sgibbsstatic char *expand_string __P((char *, int));
25251767Sgibbs
26251767Sgibbs
27251767Sgibbsstatic variable_t *find_var(name)
28251767Sgibbs	char *name;
29251767Sgibbs{
30251767Sgibbs	variable_t *v;
31251767Sgibbs
32251767Sgibbs	for (v = vtop; v != NULL; v = v->v_next)
33251767Sgibbs		if (!strcmp(name, v->v_name))
34251767Sgibbs			return v;
35251767Sgibbs	return NULL;
36251767Sgibbs}
37251767Sgibbs
38251767Sgibbs
39251767Sgibbschar *get_variable(string, after, line)
40251767Sgibbs	char *string, **after;
41251767Sgibbs	int line;
42251767Sgibbs{
43251767Sgibbs	char c, *s, *t, *value;
44251767Sgibbs	variable_t *v;
45251767Sgibbs
46251767Sgibbs	s = string;
47251767Sgibbs
48251767Sgibbs	if (*s == '{') {
49251767Sgibbs		s++;
50251767Sgibbs		for (t = s; *t != '\0'; t++)
51251767Sgibbs			if (*t == '}')
52251767Sgibbs				break;
53251767Sgibbs		if (*t == '\0') {
54251767Sgibbs			fprintf(stderr, "%d: { without }\n", line);
55251767Sgibbs			return NULL;
56251767Sgibbs		}
57251767Sgibbs	} else if (ISALPHA(*s)) {
58251767Sgibbs		for (t = s + 1; *t != '\0'; t++)
59251767Sgibbs			if (!ISALPHA(*t) && !ISDIGIT(*t) && (*t != '_'))
60251767Sgibbs				break;
61251767Sgibbs	} else {
62251767Sgibbs		fprintf(stderr, "%d: variables cannot start with '%c'\n",
63251767Sgibbs			line, *s);
64251767Sgibbs		return NULL;
65251767Sgibbs	}
66251767Sgibbs
67251767Sgibbs	if (after != NULL)
68251767Sgibbs		*after = t;
69251767Sgibbs	c = *t;
70251767Sgibbs	*t = '\0';
71251767Sgibbs	v = find_var(s);
72251767Sgibbs	*t = c;
73251767Sgibbs	if (v == NULL) {
74251767Sgibbs		fprintf(stderr, "%d: unknown variable '%s'\n", line, s);
75251767Sgibbs		return NULL;
76251767Sgibbs	}
77251767Sgibbs
78251767Sgibbs	s = strdup(v->v_value);
79251767Sgibbs	value = expand_string(s, line);
80251767Sgibbs	if (value != s)
81251767Sgibbs		free(s);
82251767Sgibbs	return value;
83251767Sgibbs}
84251767Sgibbs
85251767Sgibbs
86251767Sgibbsstatic char *expand_string(oldstring, line)
87251767Sgibbs	char *oldstring;
88251767Sgibbs	int line;
89251767Sgibbs{
90251767Sgibbs	char c, *s, *p1, *p2, *p3, *newstring, *value;
91251767Sgibbs	int len;
92251767Sgibbs
93251767Sgibbs	p3 = NULL;
94251767Sgibbs	newstring = oldstring;
95251767Sgibbs
96251767Sgibbs	for (s = oldstring; *s != '\0'; s++)
97251767Sgibbs		if (*s == '$') {
98251767Sgibbs			*s = '\0';
99251767Sgibbs			s++;
100251767Sgibbs
101251767Sgibbs			switch (*s)
102251767Sgibbs			{
103251767Sgibbs			case '$' :
104251767Sgibbs				bcopy(s, s - 1, strlen(s));
105251767Sgibbs				break;
106251767Sgibbs			default :
107251767Sgibbs				c = *s;
108251767Sgibbs				if (c == '\0')
109251767Sgibbs					return newstring;
110251767Sgibbs
111251767Sgibbs				value = get_variable(s, &p3, line);
112251767Sgibbs				if (value == NULL)
113251767Sgibbs					return NULL;
114251767Sgibbs
115251767Sgibbs				p2 = expand_string(value, line);
116251767Sgibbs				if (p2 == NULL)
117251767Sgibbs					return NULL;
118251767Sgibbs
119251767Sgibbs				len = strlen(newstring) + strlen(p2);
120251767Sgibbs				if (p3 != NULL) {
121251767Sgibbs					if (c == '{' && *p3 == '}')
122251767Sgibbs						p3++;
123251767Sgibbs					len += strlen(p3);
124251767Sgibbs				}
125251767Sgibbs				p1 = malloc(len + 1);
126251767Sgibbs				if (p1 == NULL)
127251767Sgibbs					return NULL;
128251767Sgibbs
129251767Sgibbs				*(s - 1) = '\0';
130251767Sgibbs				strcpy(p1, newstring);
131251767Sgibbs				strcat(p1, p2);
132251767Sgibbs				if (p3 != NULL)
133251767Sgibbs					strcat(p1, p3);
134251767Sgibbs
135251767Sgibbs				s = p1 + len - strlen(p3) - 1;
136251767Sgibbs				if (newstring != oldstring)
137251767Sgibbs					free(newstring);
138251767Sgibbs				newstring = p1;
139251767Sgibbs				break;
140251767Sgibbs			}
141251767Sgibbs		}
142251767Sgibbs	return newstring;
143251767Sgibbs}
144251767Sgibbs
145251767Sgibbs
146251767Sgibbsvoid set_variable(name, value)
147251767Sgibbs	char *name;
148251767Sgibbs	char *value;
149251767Sgibbs{
150251767Sgibbs	variable_t *v;
151251767Sgibbs	int len;
152251767Sgibbs
153251767Sgibbs	if (name == NULL || value == NULL || *name == '\0')
154251767Sgibbs		return;
155251767Sgibbs
156251767Sgibbs	v = find_var(name);
157251767Sgibbs	if (v != NULL) {
158251767Sgibbs		free(v->v_value);
159251767Sgibbs		v->v_value = strdup(value);
160251767Sgibbs		return;
161251767Sgibbs	}
162251767Sgibbs
163251767Sgibbs	len = strlen(value);
164251767Sgibbs
165251767Sgibbs	if ((*value == '"' && value[len - 1] == '"') ||
166251767Sgibbs	    (*value == '\'' && value[len - 1] == '\'')) {
167251767Sgibbs		value[len - 1] = '\0';
168251767Sgibbs		value++;
169251767Sgibbs		len -=2;
170251767Sgibbs	}
171251767Sgibbs
172251767Sgibbs	v = (variable_t *)malloc(sizeof(*v));
173251767Sgibbs	if (v == NULL)
174251767Sgibbs		return;
175251767Sgibbs	v->v_name = strdup(name);
176251767Sgibbs	v->v_value = strdup(value);
177251767Sgibbs	v->v_next = vtop;
178251767Sgibbs	vtop = v;
179251767Sgibbs}
180251767Sgibbs