| /* |
| * 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 __P((char *)); |
| static char *expand_string __P((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(string, after, line) |
| char *string, **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(oldstring, line) |
| 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(name, value) |
| 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; |
| } |