44bc301921
Reported by: jrtc27
Fixes: 2582ae5740
MFC after: 1 month
174 lines
2.9 KiB
C
174 lines
2.9 KiB
C
/* $FreeBSD$ */
|
|
|
|
/*
|
|
* Copyright (C) 2012 by Darren Reed.
|
|
*
|
|
* See the IPFILTER.LICENCE file for details on licencing.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
|
|
#include "ipf.h"
|
|
|
|
typedef struct variable {
|
|
struct variable *v_next;
|
|
char *v_name;
|
|
char *v_value;
|
|
} variable_t;
|
|
|
|
static variable_t *vtop = NULL;
|
|
|
|
static variable_t *find_var(char *);
|
|
static char *expand_string(char *, int);
|
|
|
|
|
|
static variable_t *find_var(name)
|
|
char *name;
|
|
{
|
|
variable_t *v;
|
|
|
|
for (v = vtop; v != NULL; v = v->v_next)
|
|
if (!strcmp(name, v->v_name))
|
|
return (v);
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
char *get_variable(char *string, char **after, int line)
|
|
{
|
|
char c, *s, *t, *value;
|
|
variable_t *v;
|
|
|
|
s = string;
|
|
|
|
if (*s == '{') {
|
|
s++;
|
|
for (t = s; *t != '\0'; t++)
|
|
if (*t == '}')
|
|
break;
|
|
if (*t == '\0') {
|
|
fprintf(stderr, "%d: { without }\n", line);
|
|
return (NULL);
|
|
}
|
|
} else if (ISALPHA(*s)) {
|
|
for (t = s + 1; *t != '\0'; t++)
|
|
if (!ISALPHA(*t) && !ISDIGIT(*t) && (*t != '_'))
|
|
break;
|
|
} else {
|
|
fprintf(stderr, "%d: variables cannot start with '%c'\n",
|
|
line, *s);
|
|
return (NULL);
|
|
}
|
|
|
|
if (after != NULL)
|
|
*after = t;
|
|
c = *t;
|
|
*t = '\0';
|
|
v = find_var(s);
|
|
*t = c;
|
|
if (v == NULL) {
|
|
fprintf(stderr, "%d: unknown variable '%s'\n", line, s);
|
|
return (NULL);
|
|
}
|
|
|
|
s = strdup(v->v_value);
|
|
value = expand_string(s, line);
|
|
if (value != s)
|
|
free(s);
|
|
return (value);
|
|
}
|
|
|
|
|
|
static char *expand_string(char *oldstring, int line)
|
|
{
|
|
char c, *s, *p1, *p2, *p3, *newstring, *value;
|
|
int len;
|
|
|
|
p3 = NULL;
|
|
newstring = oldstring;
|
|
|
|
for (s = oldstring; *s != '\0'; s++)
|
|
if (*s == '$') {
|
|
*s = '\0';
|
|
s++;
|
|
|
|
switch (*s)
|
|
{
|
|
case '$' :
|
|
bcopy(s, s - 1, strlen(s));
|
|
break;
|
|
default :
|
|
c = *s;
|
|
if (c == '\0')
|
|
return (newstring);
|
|
|
|
value = get_variable(s, &p3, line);
|
|
if (value == NULL)
|
|
return (NULL);
|
|
|
|
p2 = expand_string(value, line);
|
|
if (p2 == NULL)
|
|
return (NULL);
|
|
|
|
len = strlen(newstring) + strlen(p2);
|
|
if (p3 != NULL) {
|
|
if (c == '{' && *p3 == '}')
|
|
p3++;
|
|
len += strlen(p3);
|
|
}
|
|
p1 = malloc(len + 1);
|
|
if (p1 == NULL)
|
|
return (NULL);
|
|
|
|
*(s - 1) = '\0';
|
|
strcpy(p1, newstring);
|
|
strcat(p1, p2);
|
|
if (p3 != NULL)
|
|
strcat(p1, p3);
|
|
|
|
s = p1 + len - strlen(p3) - 1;
|
|
if (newstring != oldstring)
|
|
free(newstring);
|
|
newstring = p1;
|
|
break;
|
|
}
|
|
}
|
|
return (newstring);
|
|
}
|
|
|
|
|
|
void set_variable(char *name, char *value)
|
|
{
|
|
variable_t *v;
|
|
int len;
|
|
|
|
if (name == NULL || value == NULL || *name == '\0')
|
|
return;
|
|
|
|
v = find_var(name);
|
|
if (v != NULL) {
|
|
free(v->v_value);
|
|
v->v_value = strdup(value);
|
|
return;
|
|
}
|
|
|
|
len = strlen(value);
|
|
|
|
if ((*value == '"' && value[len - 1] == '"') ||
|
|
(*value == '\'' && value[len - 1] == '\'')) {
|
|
value[len - 1] = '\0';
|
|
value++;
|
|
len -=2;
|
|
}
|
|
|
|
v = (variable_t *)malloc(sizeof(*v));
|
|
if (v == NULL)
|
|
return;
|
|
v->v_name = strdup(name);
|
|
v->v_value = strdup(value);
|
|
v->v_next = vtop;
|
|
vtop = v;
|
|
}
|