mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 06:16:03 +00:00
parser: refactor variables and symbols table into their own class
While symtab for now has only static members, it will allow for a change in the future for each profile to have their own symbols like profile_name, etc.
This commit is contained in:
@@ -24,654 +24,27 @@
|
||||
|
||||
#include "immunix.h"
|
||||
#include "parser.h"
|
||||
|
||||
typedef int (*comparison_fn_t)(const void *, const void *);
|
||||
typedef void (*__free_fn_t)(void *);
|
||||
|
||||
|
||||
static void *my_symtab = NULL;
|
||||
|
||||
static int __expand_variable(struct symtab *symbol);
|
||||
|
||||
static struct symtab *new_symtab_entry(const char *name)
|
||||
{
|
||||
struct symtab *n = (struct symtab *) calloc(1, sizeof(*n));
|
||||
|
||||
if (!n) {
|
||||
PERROR("Failed to allocate memory: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n->var_name = strndup(name, PATH_MAX);
|
||||
if (!n->var_name) {
|
||||
PERROR("Failed to allocate memory: %s\n", strerror(errno));
|
||||
free(n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static struct set_value *new_set_value(const char *val)
|
||||
{
|
||||
struct set_value *n = (struct set_value *) calloc(1, sizeof(*n));
|
||||
|
||||
if (!n) {
|
||||
PERROR("Failed to allocate memory: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n->val = strndup(val, PATH_MAX);
|
||||
if (!n->val) {
|
||||
PERROR("Failed to allocate memory: %s\n", strerror(errno));
|
||||
free(n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static void free_values(struct set_value *val)
|
||||
{
|
||||
struct set_value *i = val, *tmp;
|
||||
|
||||
while (i) {
|
||||
if (i->val)
|
||||
free(i->val);
|
||||
tmp = i;
|
||||
i = i->next;
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static void free_symtab(struct symtab *symtab)
|
||||
{
|
||||
if (!symtab)
|
||||
return;
|
||||
|
||||
if (symtab->var_name)
|
||||
free(symtab->var_name);
|
||||
|
||||
free_values(symtab->values);
|
||||
free_values(symtab->expanded);
|
||||
free(symtab);
|
||||
}
|
||||
|
||||
/* abstract this out in case we switch data structures */
|
||||
static void add_to_set(struct set_value **list, const char *val)
|
||||
{
|
||||
struct set_value *new_item = new_set_value(val);
|
||||
|
||||
new_item->next = *list;
|
||||
*list = new_item;
|
||||
}
|
||||
|
||||
static int compare_symtabs(const void *a, const void *b)
|
||||
{
|
||||
char *a_name = ((struct symtab *) a)->var_name;
|
||||
char *b_name = ((struct symtab *) b)->var_name;
|
||||
return strcmp(a_name, b_name);
|
||||
}
|
||||
|
||||
static struct symtab *lookup_existing_symbol(const char *var)
|
||||
{
|
||||
struct symtab *tmp, **lookup;
|
||||
struct symtab *result = NULL;
|
||||
|
||||
tmp = new_symtab_entry(var);
|
||||
if (!tmp) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
lookup = (struct symtab **) tfind(tmp, &my_symtab, (comparison_fn_t) &compare_symtabs);
|
||||
if (!lookup) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = (*lookup);
|
||||
|
||||
out:
|
||||
free_symtab(tmp);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/* add_boolean_var
|
||||
* creates copies of arguments, so caller can free them after use
|
||||
*/
|
||||
|
||||
int add_boolean_var(const char *var, int value)
|
||||
{
|
||||
struct symtab *n, **result;
|
||||
int rc = 0;
|
||||
|
||||
n = new_symtab_entry(var);
|
||||
if (!n) {
|
||||
rc = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
n->type = sd_boolean;
|
||||
n->boolean = value;
|
||||
|
||||
result = (struct symtab **) tsearch(n, &my_symtab, (comparison_fn_t) &compare_symtabs);
|
||||
if (!result) {
|
||||
PERROR("Failed to allocate memory: %s\n", strerror(errno));
|
||||
rc = errno;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (*result != n) {
|
||||
/* already existing variable */
|
||||
PERROR("'%s' is already defined\n", var);
|
||||
rc = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
free_symtab(n);
|
||||
return rc;
|
||||
};
|
||||
|
||||
int get_boolean_var(const char *var)
|
||||
{
|
||||
struct symtab *result;
|
||||
int rc = 0;
|
||||
|
||||
result = lookup_existing_symbol(var);
|
||||
if (!result) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (result->type != sd_boolean) {
|
||||
PERROR("Variable %s is not a boolean variable\n", var);
|
||||
rc = -2; /* XXX - might change this to specific values */
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = result->boolean;
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int insert_set_var(struct symtab *var)
|
||||
{
|
||||
struct symtab **result;
|
||||
|
||||
result = (struct symtab **) tsearch(var, &my_symtab, (comparison_fn_t) &compare_symtabs);
|
||||
if (!result) {
|
||||
PERROR("Failed to allocate memory: %s\n", strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
if (*result != var) {
|
||||
/* already existing variable */
|
||||
PERROR("'%s' is already defined\n", var->var_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* new_set_var
|
||||
* creates copies of arguments, so caller can free them after use
|
||||
*/
|
||||
int new_set_var(const char *var, const char *value)
|
||||
{
|
||||
struct symtab *n;
|
||||
int rc = 0;
|
||||
|
||||
n = new_symtab_entry(var);
|
||||
if (!n) {
|
||||
rc = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
n->type = sd_set;
|
||||
add_to_set(&(n->values), value);
|
||||
|
||||
rc = insert_set_var(n);
|
||||
if (! rc)
|
||||
return 0;
|
||||
|
||||
err:
|
||||
free_symtab(n);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* add_set_value
|
||||
* creates copies of arguments, so caller can free them after use
|
||||
*/
|
||||
int add_set_value(const char *var, const char *value)
|
||||
{
|
||||
struct symtab *result;
|
||||
int rc = 0;
|
||||
|
||||
result = lookup_existing_symbol(var);
|
||||
if (!result) {
|
||||
PERROR("Failed to find declaration for: %s\n", var);
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (result->type != sd_set) {
|
||||
PERROR("Variable %s is not a set variable\n", var);
|
||||
rc = 2; /* XXX - might change this to specific values */
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strcmp(result->var_name, var) != 0) {
|
||||
PERROR("ASSERT: tfind found %s when looking up variable %s\n",
|
||||
result->var_name, var);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
add_to_set(&(result->values), value);
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* returns a pointer to the value list, which should be used as the
|
||||
* argument to the get_next_set_value() function. */
|
||||
struct set_value *get_set_var(const char *var)
|
||||
{
|
||||
struct symtab *result;
|
||||
struct set_value *valuelist = NULL;
|
||||
|
||||
result = lookup_existing_symbol(var);
|
||||
if (!result) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (result->type != sd_set) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strcmp(result->var_name, var) != 0) {
|
||||
PERROR("ASSERT: tfind found %s when looking up variable %s\n",
|
||||
result->var_name, var);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!result->expanded) {
|
||||
int err = __expand_variable(result);
|
||||
if (err) {
|
||||
PERROR("failure expanding variable %s\n", var);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
valuelist = result->expanded;
|
||||
out:
|
||||
return valuelist;
|
||||
}
|
||||
|
||||
/* iterator to walk the list of set values */
|
||||
char *get_next_set_value(struct set_value **list)
|
||||
{
|
||||
struct set_value *next;
|
||||
char *ret;
|
||||
|
||||
if (!list || !(*list))
|
||||
return NULL;
|
||||
|
||||
ret = (*list)->val;
|
||||
next = (*list)->next;
|
||||
(*list) = next;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct symtab *remove_set_var(const char *var_name)
|
||||
{
|
||||
struct symtab **result, *n, *var = NULL;
|
||||
|
||||
n = new_symtab_entry(var_name);
|
||||
if (!n) {
|
||||
//rc = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = (struct symtab **) tfind(n, &my_symtab, (comparison_fn_t) &compare_symtabs);
|
||||
if (!result) {
|
||||
/* XXX Warning? */
|
||||
//rc = ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
var = (*result);
|
||||
|
||||
result = (struct symtab **) tdelete(n, &my_symtab, (comparison_fn_t) &compare_symtabs);
|
||||
if (!result) {
|
||||
PERROR("ASSERT: delete_set_var: tfind found var %s but tdelete failed to delete it\n",
|
||||
var_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (var->type != sd_set) {
|
||||
PERROR("ASSERT: delete_set_var: deleting %s but is a boolean variable\n",
|
||||
var_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
out:
|
||||
free_symtab(n);
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
/* delete_symbol
|
||||
* removes an individual variable from the symbol table. We don't
|
||||
* support this in the language, but for special variables that change
|
||||
* between profiles, we need this.
|
||||
*/
|
||||
int delete_set_var(const char *var_name)
|
||||
{
|
||||
struct symtab *var;
|
||||
|
||||
var = remove_set_var(var_name);
|
||||
if (var) {
|
||||
free_symtab(var);
|
||||
return 0;
|
||||
}
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
static void *seenlist = NULL;
|
||||
|
||||
static int is_seen(const char *var)
|
||||
{
|
||||
char **lookup;
|
||||
lookup = (char **) tfind(var, &seenlist, (comparison_fn_t) &strcmp);
|
||||
return (lookup != NULL);
|
||||
}
|
||||
|
||||
static void push_seen_var(const char *var)
|
||||
{
|
||||
char **lookup;
|
||||
lookup = (char **) tsearch(var, &seenlist, (comparison_fn_t) &strcmp);
|
||||
if (*lookup != var) {
|
||||
PERROR("ASSERT: '%s' is already in the seenlist\n", var);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void pop_seen_var(const char *var)
|
||||
{
|
||||
char **lookup;
|
||||
lookup = (char **) tdelete(var, &seenlist, (comparison_fn_t) &strcmp);
|
||||
if (lookup == NULL) {
|
||||
PERROR("ASSERT: popped var '%s' not found on the seenlist\n", var);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static int __expand_variable(struct symtab *symbol)
|
||||
{
|
||||
struct set_value *list, *expanded = NULL;
|
||||
int retval = 0;
|
||||
struct var_string *split = NULL;
|
||||
|
||||
if (symbol->type == sd_boolean) {
|
||||
PERROR("Referenced variable %s is a boolean used in set context\n",
|
||||
symbol->var_name);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* already done */
|
||||
if (symbol->expanded)
|
||||
return 0;
|
||||
|
||||
push_seen_var(symbol->var_name);
|
||||
|
||||
for (list = symbol->values; list; list = list->next) {
|
||||
struct set_value *work_list = new_set_value(list->val);
|
||||
while (work_list) {
|
||||
struct symtab *ref;
|
||||
struct set_value *ref_item;
|
||||
struct set_value *t_value = work_list;
|
||||
int rc;
|
||||
|
||||
work_list = work_list->next;
|
||||
|
||||
split = split_out_var(t_value->val);
|
||||
if (!split) {
|
||||
/* fully expanded */
|
||||
add_to_set(&expanded, t_value->val);
|
||||
goto next;
|
||||
}
|
||||
|
||||
|
||||
if (is_seen(split->var)) {
|
||||
PERROR("Variable @{%s} is referenced recursively (by @{%s})\n",
|
||||
split->var, symbol->var_name);
|
||||
retval = 1;
|
||||
free_values(t_value);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ref = lookup_existing_symbol(split->var);
|
||||
if (!ref) {
|
||||
PERROR("Variable @{%s} references undefined variable @{%s}\n",
|
||||
symbol->var_name, split->var);
|
||||
retval = 3;
|
||||
free_values(t_value);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = __expand_variable(ref);
|
||||
if (rc != 0) {
|
||||
retval = rc;
|
||||
free_values(t_value);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ref->expanded) {
|
||||
PERROR("ASSERT: Variable @{%s} should have been expanded but isn't\n",
|
||||
split->var);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (ref_item = ref->expanded; ref_item; ref_item = ref_item->next) {
|
||||
char *expanded_string;
|
||||
if (!asprintf(&expanded_string, "%s%s%s",
|
||||
split->prefix ? split->prefix : "",
|
||||
ref_item->val,
|
||||
split->suffix ? split->suffix : "")) {
|
||||
PERROR("Out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
add_to_set(&work_list, expanded_string);
|
||||
free(expanded_string);
|
||||
}
|
||||
|
||||
next:
|
||||
t_value->next = NULL;
|
||||
free_values(t_value);
|
||||
free_var_string(split);
|
||||
}
|
||||
}
|
||||
|
||||
symbol->expanded = expanded;
|
||||
|
||||
out:
|
||||
pop_seen_var(symbol->var_name);
|
||||
free_var_string(split);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void expand_variable(const void *nodep, VISIT value, int level unused)
|
||||
{
|
||||
struct symtab **t = (struct symtab **) nodep;
|
||||
|
||||
if (value == preorder || value == endorder)
|
||||
return;
|
||||
|
||||
if ((*t)->type == sd_boolean)
|
||||
return;
|
||||
|
||||
__expand_variable(*t);
|
||||
}
|
||||
|
||||
void expand_variables(void)
|
||||
{
|
||||
twalk(my_symtab, &expand_variable);
|
||||
}
|
||||
|
||||
static inline void dump_set_values(struct set_value *value)
|
||||
{
|
||||
struct set_value *t = value;
|
||||
while (t) {
|
||||
printf(" \"%s\"", t->val);
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void __dump_symtab_entry(struct symtab *entry, int do_expanded)
|
||||
{
|
||||
switch (entry->type) {
|
||||
case sd_boolean:
|
||||
printf("$%s = %s\n", entry->var_name,
|
||||
entry->boolean ? "true" : "false");
|
||||
break;
|
||||
case sd_set:
|
||||
printf("@%s =", entry->var_name);
|
||||
if (do_expanded) {
|
||||
if (!entry->expanded) {
|
||||
__expand_variable(entry);
|
||||
}
|
||||
dump_set_values(entry->expanded);
|
||||
} else {
|
||||
dump_set_values(entry->values);
|
||||
}
|
||||
printf("\n");
|
||||
break;
|
||||
default:
|
||||
PERROR("ASSERT: unknown symbol table type for %s\n", entry->var_name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_symtab_entry(const void *nodep, VISIT value, int level unused)
|
||||
{
|
||||
struct symtab **t = (struct symtab **) nodep;
|
||||
|
||||
if (value == preorder || value == endorder)
|
||||
return;
|
||||
|
||||
__dump_symtab_entry(*t, 0);
|
||||
}
|
||||
|
||||
static void dump_expanded_symtab_entry(const void *nodep, VISIT value, int level unused)
|
||||
{
|
||||
struct symtab **t = (struct symtab **) nodep;
|
||||
|
||||
if (value == preorder || value == endorder)
|
||||
return;
|
||||
|
||||
__dump_symtab_entry(*t, 1);
|
||||
}
|
||||
|
||||
void dump_symtab(void)
|
||||
{
|
||||
twalk(my_symtab, &dump_symtab_entry);
|
||||
}
|
||||
|
||||
void dump_expanded_symtab(void)
|
||||
{
|
||||
twalk(my_symtab, &dump_expanded_symtab_entry);
|
||||
}
|
||||
|
||||
void free_symtabs(void)
|
||||
{
|
||||
if (my_symtab)
|
||||
tdestroy(my_symtab, (__free_fn_t)&free_symtab);
|
||||
my_symtab = NULL;
|
||||
}
|
||||
#include "symtab.h"
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
|
||||
#include "unit_test.h"
|
||||
|
||||
int test_compare_symtab(void)
|
||||
{
|
||||
int rc = 0;
|
||||
int retval;
|
||||
struct symtab *a, *b, *c;
|
||||
|
||||
a = new_symtab_entry("blah");
|
||||
b = new_symtab_entry("suck");
|
||||
MY_TEST(a && b, "allocation test");
|
||||
|
||||
retval = compare_symtabs(a, b);
|
||||
MY_TEST(retval < 0, "comparison 1");
|
||||
|
||||
retval = compare_symtabs(b, a);
|
||||
MY_TEST(retval > 0, "comparison 2");
|
||||
|
||||
retval = compare_symtabs(b, a);
|
||||
MY_TEST(retval != 0, "comparison 3");
|
||||
|
||||
retval = compare_symtabs(b, b);
|
||||
MY_TEST(retval == 0, "comparison 4");
|
||||
|
||||
c = new_symtab_entry("blah");
|
||||
retval = compare_symtabs(a, c);
|
||||
MY_TEST(retval == 0, "comparison 5");
|
||||
|
||||
free_symtab(a);
|
||||
free_symtab(b);
|
||||
free_symtab(c);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int test_seenlist(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
MY_TEST(!is_seen("oogabooga"), "lookup unseen variable");
|
||||
|
||||
push_seen_var("oogabooga");
|
||||
MY_TEST(is_seen("oogabooga"), "lookup seen variable 1");
|
||||
MY_TEST(!is_seen("not_seen"), "lookup unseen variable 2");
|
||||
|
||||
push_seen_var("heebiejeebie");
|
||||
MY_TEST(is_seen("oogabooga"), "lookup seen variable 2");
|
||||
MY_TEST(is_seen("heebiejeebie"), "lookup seen variable 3");
|
||||
MY_TEST(!is_seen("not_seen"), "lookup unseen variable 3");
|
||||
|
||||
pop_seen_var("oogabooga");
|
||||
MY_TEST(!is_seen("oogabooga"), "lookup unseen variable 4");
|
||||
MY_TEST(is_seen("heebiejeebie"), "lookup seen variable 4");
|
||||
MY_TEST(!is_seen("not_seen"), "lookup unseen variable 5");
|
||||
|
||||
pop_seen_var("heebiejeebie");
|
||||
MY_TEST(!is_seen("heebiejeebie"), "lookup unseen variable 6");
|
||||
|
||||
//pop_seen_var("not_seen"); /* triggers assert */
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int test_add_set_to_boolean(void)
|
||||
{
|
||||
int rc = 0;
|
||||
int retval;
|
||||
|
||||
struct value_list *val;
|
||||
/* test adding a set value to a boolean variable */
|
||||
retval = add_boolean_var("not_a_set_variable", 1);
|
||||
retval = symtab::add_var("@not_a_set_variable", 1);
|
||||
MY_TEST(retval == 0, "new boolean variable 3");
|
||||
retval = add_set_value("not_a_set_variable", "a set value");
|
||||
|
||||
val = new_value_list(strdup("a set value"));
|
||||
retval = symtab::add_set_value("@not_a_set_variable", val);
|
||||
MY_TEST(retval != 0, "add set value to boolean");
|
||||
|
||||
free_symtabs();
|
||||
symtab::free_symtab();
|
||||
free_value_list(val);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -680,19 +53,19 @@ int test_expand_bool_within_set(void)
|
||||
{
|
||||
int rc = 0;
|
||||
int retval;
|
||||
struct symtab *retsym;
|
||||
variable *retsym;
|
||||
|
||||
/* test expanding a boolean var within a set variable */
|
||||
retval = add_boolean_var("not_a_set_variable", 1);
|
||||
retval = symtab::add_var("@not_a_set_variable", 1);
|
||||
MY_TEST(retval == 0, "new boolean variable 4");
|
||||
retval = new_set_var("set_variable", "set_value@{not_a_set_variable}");
|
||||
retval = symtab::add_var("set_variable", "set_value@{not_a_set_variable}");
|
||||
MY_TEST(retval == 0, "add set value with embedded boolean");
|
||||
retsym = lookup_existing_symbol("set_variable");
|
||||
retsym = symtab::lookup_existing_symbol("set_variable");
|
||||
MY_TEST(retsym != NULL, "get set variable w/boolean");
|
||||
retval = __expand_variable(retsym);
|
||||
retval = retsym->expand_variable();
|
||||
MY_TEST(retval != 0, "expand set variable with embedded boolean");
|
||||
|
||||
free_symtabs();
|
||||
symtab::free_symtab();
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -701,21 +74,21 @@ int test_expand_recursive_set_vars(void)
|
||||
{
|
||||
int rc = 0;
|
||||
int retval;
|
||||
struct symtab *retsym;
|
||||
variable *retsym;
|
||||
|
||||
/* test expanding a recursive var within a set variable */
|
||||
retval = new_set_var("recursive_1", "set_value@{recursive_2}");
|
||||
retval = symtab::add_var("recursive_1", "set_value@{recursive_2}");
|
||||
MY_TEST(retval == 0, "new recursive set variable 1");
|
||||
retval = new_set_var("recursive_2", "set_value@{recursive_3}");
|
||||
retval = symtab::add_var("recursive_2", "set_value@{recursive_3}");
|
||||
MY_TEST(retval == 0, "new recursive set variable 2");
|
||||
retval = new_set_var("recursive_3", "set_value@{recursive_1}");
|
||||
retval = symtab::add_var("recursive_3", "set_value@{recursive_1}");
|
||||
MY_TEST(retval == 0, "new recursive set variable 3");
|
||||
retsym = lookup_existing_symbol("recursive_1");
|
||||
retsym = symtab::lookup_existing_symbol("recursive_1");
|
||||
MY_TEST(retsym != NULL, "get recursive set variable");
|
||||
retval = __expand_variable(retsym);
|
||||
retval = retsym->expand_variable();
|
||||
MY_TEST(retval != 0, "expand recursive set variable");
|
||||
|
||||
free_symtabs();
|
||||
symtab::free_symtab();
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -724,17 +97,17 @@ int test_expand_undefined_set_var(void)
|
||||
{
|
||||
int rc = 0;
|
||||
int retval;
|
||||
struct symtab *retsym;
|
||||
variable *retsym;
|
||||
|
||||
/* test expanding an undefined var within a set variable */
|
||||
retval = new_set_var("defined_var", "set_value@{undefined_var}");
|
||||
retval = symtab::add_var("defined_var", "set_value@{undefined_var}");
|
||||
MY_TEST(retval == 0, "new undefined test set variable");
|
||||
retsym = lookup_existing_symbol("defined_var");
|
||||
retsym = symtab::lookup_existing_symbol("defined_var");
|
||||
MY_TEST(retsym != NULL, "get undefined test set variable");
|
||||
retval = __expand_variable(retsym);
|
||||
retval = retsym->expand_variable();
|
||||
MY_TEST(retval != 0, "expand undefined set variable");
|
||||
|
||||
free_symtabs();
|
||||
symtab::free_symtab();
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -743,20 +116,20 @@ int test_expand_set_var_during_dump(void)
|
||||
{
|
||||
int rc = 0;
|
||||
int retval;
|
||||
struct symtab *retsym;
|
||||
variable *retsym;
|
||||
|
||||
/* test expanding an defined var within a set variable during var dump*/
|
||||
retval = new_set_var("set_var_1", "set_value@{set_var_2}");
|
||||
retval = symtab::add_var("set_var_1", "set_value@{set_var_2}");
|
||||
MY_TEST(retval == 0, "new dump expansion set variable 1");
|
||||
retval = new_set_var("set_var_2", "some other set_value");
|
||||
retval = symtab::add_var("set_var_2", "some other set_value");
|
||||
MY_TEST(retval == 0, "new dump expansion set variable 2");
|
||||
retsym = lookup_existing_symbol("set_var_1");
|
||||
retsym = symtab::lookup_existing_symbol("set_var_1");
|
||||
MY_TEST(retsym != NULL, "get dump expansion set variable 1");
|
||||
__dump_symtab_entry(retsym, 0);
|
||||
__dump_symtab_entry(retsym, 1);
|
||||
__dump_symtab_entry(retsym, 0);
|
||||
retsym->dump(false);
|
||||
retsym->dump(true);
|
||||
retsym->dump(false);
|
||||
|
||||
free_symtabs();
|
||||
symtab::free_symtab();
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -765,13 +138,17 @@ int test_delete_set_var(void)
|
||||
{
|
||||
int rc = 0;
|
||||
int retval;
|
||||
variable *deleted;
|
||||
variable *retsym;
|
||||
|
||||
retval = new_set_var("deleteme", "delete this variable");
|
||||
retval = symtab::add_var("deleteme", "delete this variable");
|
||||
MY_TEST(retval == 0, "new delete set variable");
|
||||
retval = delete_set_var("deleteme");
|
||||
MY_TEST(retval == 0, "delete set variable");
|
||||
deleted = symtab::delete_var("deleteme");
|
||||
MY_TEST(deleted != NULL, "delete set variable");
|
||||
retsym = symtab::lookup_existing_symbol(deleted->var_name.c_str());
|
||||
MY_TEST(retsym == NULL, "deleteme was deleted from symtable");
|
||||
|
||||
free_symtabs();
|
||||
symtab::free_symtab();
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -780,13 +157,12 @@ int main(void)
|
||||
{
|
||||
int rc = 0;
|
||||
int retval;
|
||||
struct set_value *retptr;
|
||||
struct value_list *list;
|
||||
struct value_list *val;
|
||||
variable *retsym;
|
||||
|
||||
rc = test_compare_symtab();
|
||||
|
||||
retval = test_seenlist();
|
||||
if (rc == 0)
|
||||
rc = retval;
|
||||
val = new_value_list(strdup("a set value"));
|
||||
retval = symtab::add_set_value("@not_a_set_variable", val);
|
||||
|
||||
retval = test_add_set_to_boolean();
|
||||
if (rc == 0)
|
||||
@@ -812,76 +188,94 @@ int main(void)
|
||||
if (rc == 0)
|
||||
rc = retval;
|
||||
|
||||
retval = new_set_var("test", "test value");
|
||||
retval = symtab::add_var("test", "test value");
|
||||
MY_TEST(retval == 0, "new set variable 1");
|
||||
|
||||
retval = new_set_var("test", "different value");
|
||||
retval = symtab::add_var("test", "different value");
|
||||
MY_TEST(retval != 0, "new set variable 2");
|
||||
|
||||
retval = new_set_var("testing", "testing");
|
||||
retval = symtab::add_var("testing", "testing");
|
||||
MY_TEST(retval == 0, "new set variable 3");
|
||||
|
||||
retval = new_set_var("monopuff", "Mockingbird");
|
||||
retval = symtab::add_var("monopuff", "Mockingbird");
|
||||
MY_TEST(retval == 0, "new set variable 4");
|
||||
|
||||
retval = new_set_var("stereopuff", "Unsupervised");
|
||||
retval = symtab::add_var("stereopuff", "Unsupervised");
|
||||
MY_TEST(retval == 0, "new set variable 5");
|
||||
|
||||
retval = add_set_value("stereopuff", "Fun to Steal");
|
||||
val = new_value_list(strdup("Fun to Steal"));
|
||||
list = val;
|
||||
retval = symtab::add_set_value("@stereopuff", val);
|
||||
MY_TEST(retval == 0, "add set value 1");
|
||||
|
||||
retval = add_set_value("stereopuff", "/in/direction");
|
||||
val = new_value_list(strdup("/in/direction"));
|
||||
list_append(list, val);
|
||||
retval = symtab::add_set_value("@stereopuff", val);
|
||||
MY_TEST(retval == 0, "add set value 2");
|
||||
|
||||
retval = add_set_value("no_such_variable", "stereopuff");
|
||||
val = new_value_list(strdup("stereopuff"));
|
||||
list_append(list, val);
|
||||
retval = symtab::add_set_value("@no_such_variable", val);
|
||||
MY_TEST(retval != 0, "add to non-existent set var");
|
||||
|
||||
retval = add_boolean_var("abuse", 0);
|
||||
retval = symtab::add_var("@abuse", 0);
|
||||
MY_TEST(retval == 0, "new boolean variable 1");
|
||||
|
||||
retval = add_boolean_var("abuse", 1);
|
||||
retval = symtab::add_var("@abuse", 1);
|
||||
MY_TEST(retval != 0, "duplicate boolean variable 1");
|
||||
|
||||
retval = add_boolean_var("stereopuff", 1);
|
||||
retval = symtab::add_var("@stereopuff", 1);
|
||||
MY_TEST(retval != 0, "duplicate boolean variable 2");
|
||||
|
||||
retval = add_boolean_var("shenanigan", 1);
|
||||
retval = symtab::add_var("@shenanigan", 1);
|
||||
MY_TEST(retval == 0, "new boolean variable 2");
|
||||
|
||||
retval = get_boolean_var("shenanigan");
|
||||
MY_TEST(retval == 1, "get boolean variable 1");
|
||||
retsym = symtab::get_boolean_var("@shenanigan");
|
||||
MY_TEST(retsym != NULL, "boolean variable 1 exists");
|
||||
MY_TEST(retsym->boolean == 1, "get boolean variable 1");
|
||||
|
||||
retval = get_boolean_var("abuse");
|
||||
MY_TEST(retval == 0, "get boolean variable 2");
|
||||
retsym = symtab::get_boolean_var("@abuse");
|
||||
MY_TEST(retsym != NULL, "boolean variable 2 exists");
|
||||
MY_TEST(retsym->boolean == 0, "get boolean variable 2");
|
||||
|
||||
retval = get_boolean_var("non_existant");
|
||||
MY_TEST(retval < 0, "get nonexistent boolean variable");
|
||||
retsym = symtab::get_boolean_var("@non_existant");
|
||||
MY_TEST(retsym == NULL, "get nonexistent boolean variable");
|
||||
|
||||
retval = get_boolean_var("stereopuff");
|
||||
MY_TEST(retval < 0, "get boolean variable that's declared a set var");
|
||||
retsym = symtab::get_boolean_var("@stereopuff");
|
||||
MY_TEST(retsym == NULL, "get boolean variable that's declared a set var");
|
||||
|
||||
retptr = get_set_var("daves_not_here_man");
|
||||
MY_TEST(retptr == NULL, "get nonexistent set variable");
|
||||
retsym = symtab::get_set_var("@daves_not_here_man");
|
||||
MY_TEST(retsym == NULL, "get nonexistent set variable");
|
||||
|
||||
retptr = get_set_var("abuse");
|
||||
MY_TEST(retptr == NULL, "get set variable that's declared a boolean");
|
||||
retsym = symtab::get_set_var("@abuse");
|
||||
MY_TEST(retsym == NULL, "get set variable that's declared a boolean");
|
||||
|
||||
/* test walking set values */
|
||||
retptr = get_set_var("monopuff");
|
||||
MY_TEST(retptr != NULL, "get set variable 1");
|
||||
retval = strcmp(get_next_set_value(&retptr), "Mockingbird");
|
||||
MY_TEST(retval == 0, "get set value 1");
|
||||
MY_TEST(get_next_set_value(&retptr) == NULL, "get no more set values 1");
|
||||
retsym = symtab::get_set_var("@monopuff");
|
||||
MY_TEST(retsym != NULL, "get set variable 1");
|
||||
MY_TEST(retsym->values.size() == 1, "only one value");
|
||||
MY_TEST(retsym->expanded.size() == 1, "only one expanded");
|
||||
|
||||
retval = new_set_var("eek", "Mocking@{monopuff}bir@{stereopuff}d@{stereopuff}");
|
||||
for (std::string value : retsym->values) {
|
||||
retval = strcmp(value.c_str(), "Mockingbird");
|
||||
MY_TEST(retval == 0, "get set value 1");
|
||||
}
|
||||
|
||||
for (std::string value : retsym->expanded) {
|
||||
retval = strcmp(value.c_str(), "Mockingbird");
|
||||
MY_TEST(retval == 0, "get set value 1 expanded");
|
||||
}
|
||||
|
||||
retval = symtab::add_var("eek", "Mocking@{monopuff}bir@{stereopuff}d@{stereopuff}");
|
||||
MY_TEST(retval == 0, "new set variable 4");
|
||||
|
||||
dump_symtab();
|
||||
expand_variables();
|
||||
dump_symtab();
|
||||
dump_expanded_symtab();
|
||||
symtab::dump(false);
|
||||
symtab::expand_variables();
|
||||
symtab::dump(false);
|
||||
symtab::dump(true);
|
||||
|
||||
free_symtabs();
|
||||
free_value_list(list);
|
||||
symtab::free_symtab();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
Reference in New Issue
Block a user