diff --git a/commands/printenv.c b/commands/printenv.c index b18c7a1..10e882a 100644 --- a/commands/printenv.c +++ b/commands/printenv.c @@ -27,8 +27,8 @@ static int do_printenv(int argc, char *argv[]) { - struct variable_d *var; - struct env_context *c, *current_c; + struct variable_d *v; + struct env_context *c; if (argc == 2) { const char *val = getenv(argv[1]); @@ -40,22 +40,16 @@ return 1; } - current_c = get_current_context(); - var = current_c->local->next; + c = get_current_context(); printf("locals:\n"); - while (var) { - printf("%s=%s\n", var_name(var), var_val(var)); - var = var->next; - } + list_for_each_entry(v, &c->local, list) + printf("%s=%s\n", var_name(v), var_val(v)); printf("globals:\n"); c = get_current_context(); - while(c) { - var = c->global->next; - while (var) { - printf("%s=%s\n", var_name(var), var_val(var)); - var = var->next; - } + while (c) { + list_for_each_entry(v, &c->global, list) + printf("%s=%s\n", var_name(v), var_val(v)); c = c->parent; } diff --git a/common/complete.c b/common/complete.c index 32d0d19..9206ef0 100644 --- a/common/complete.c +++ b/common/complete.c @@ -208,7 +208,7 @@ { struct device_d *dev; struct variable_d *var; - struct env_context *c, *current_c; + struct env_context *c; char *instr_param; int len; char end = '='; @@ -225,21 +225,23 @@ instr_param = strchr(instr, '.'); len = strlen(instr); - current_c = get_current_context(); - for(var = current_c->local->next; var; var = var->next) { + c = get_current_context(); + list_for_each_entry(var, &c->local, list) { if (strncmp(instr, var_name(var), len)) continue; string_list_add_asprintf(sl, "%s%s%c", begin, var_name(var), end); } - for (c = get_current_context(); c; c = c->parent) { - for (var = c->global->next; var; var = var->next) { + c = get_current_context(); + while (c) { + list_for_each_entry(var, &c->global, list) { if (strncmp(instr, var_name(var), len)) continue; string_list_add_asprintf(sl, "%s%s%c", begin, var_name(var), end); } + c = c->parent; } if (instr_param) { diff --git a/common/env.c b/common/env.c index 1b2a7c2..33a871f 100644 --- a/common/env.c +++ b/common/env.c @@ -30,23 +30,36 @@ #include #include -#define VARIABLE_D_SIZE(name, value) (sizeof(struct variable_d) + strlen(name) + strlen(value) + 2) +static struct env_context root = { + .local = LIST_HEAD_INIT(root.local), + .global = LIST_HEAD_INIT(root.global), +}; -static struct env_context *context; +static struct env_context *context = &root; /** * Remove a list of environment variables * @param[in] v Variable anchor to remove */ -static void free_variables(struct variable_d *v) +static void free_context(struct env_context *c) { - struct variable_d *next; + struct variable_d *v, *tmp; - while (v) { - next = v->next; + list_for_each_entry_safe(v, tmp, &c->local, list) { + free(v->name); + free(v->data); + list_del(&v->list); free(v); - v = next; } + + list_for_each_entry_safe(v, tmp, &c->global, list) { + free(v->name); + free(v->data); + list_del(&v->list); + free(v); + } + + free(c); } /** Read back current context */ @@ -58,19 +71,14 @@ /** - * FIXME + * Create a new variable context and put it on the stack */ int env_push_context(void) { struct env_context *c = xzalloc(sizeof(struct env_context)); - c->local = xzalloc(VARIABLE_D_SIZE("", "")); - c->global = xzalloc(VARIABLE_D_SIZE("", "")); - - if (!context) { - context = c; - return 0; - } + INIT_LIST_HEAD(&c->local); + INIT_LIST_HEAD(&c->global); c->parent = context; context = c; @@ -78,10 +86,8 @@ return 0; } -postcore_initcall(env_push_context); - /** - * FIXME + * free current variable context and restore the previous one */ int env_pop_context(void) { @@ -89,9 +95,7 @@ if (context->parent) { c = context->parent; - free_variables(context->local); - free_variables(context->global); - free(context); + free_context(context); context = c; return 0; } @@ -105,7 +109,7 @@ */ char *var_val(struct variable_d *var) { - return &var->data[strlen(var->data) + 1]; + return var->data; } /** @@ -115,16 +119,18 @@ */ char *var_name(struct variable_d *var) { - return var->data; + return var->name; } -static const char *getenv_raw(struct variable_d *var, const char *name) +static const char *getenv_raw(struct list_head *l, const char *name) { - while (var) { - if (!strcmp(var_name(var), name)) - return var_val(var); - var = var->next; + struct variable_d *v; + + list_for_each_entry(v, l, list) { + if (!strcmp(var_name(v), name)) + return var_val(v); } + return NULL; } @@ -150,12 +156,12 @@ c = context; - val = getenv_raw(c->local, name); + val = getenv_raw(&c->local, name); if (val) return val; while (c) { - val = getenv_raw(c->global, name); + val = getenv_raw(&c->global, name); if (val) return val; c = c->parent; @@ -164,34 +170,35 @@ } EXPORT_SYMBOL(getenv); -static int setenv_raw(struct variable_d *var, const char *name, const char *value) +static int setenv_raw(struct list_head *l, const char *name, const char *value) { - struct variable_d *newvar = NULL; + struct variable_d *v; - if (value) { - newvar = xzalloc(VARIABLE_D_SIZE(name, value)); - strcpy(&newvar->data[0], name); - strcpy(&newvar->data[strlen(name) + 1], value); - } - - while (var->next) { - if (!strcmp(var->next->data, name)) { + list_for_each_entry(v, l, list) { + if (!strcmp(v->name, name)) { if (value) { - newvar->next = var->next->next; - free(var->next); - var->next = newvar; + free(v->data); + v->data = xstrdup(value); + return 0; } else { - struct variable_d *tmp; - tmp = var->next; - var->next = var->next->next; - free(tmp); + list_del(&v->list); + free(v->name); + free(v->data); + free(v); + return 0; } } - var = var->next; } - var->next = newvar; + + if (value) { + v = xzalloc(sizeof(*v)); + v->name = xstrdup(name); + v->data = xstrdup(value); + list_add_tail(&v->list, l); + } + return 0; } @@ -199,8 +206,8 @@ { char *name = strdup(_name); char *par; - struct variable_d *var; int ret = 0; + struct list_head *list; if (value && !*value) value = NULL; @@ -224,12 +231,12 @@ goto out; } - if (getenv_raw(context->global, name)) - var = context->global; + if (getenv_raw(&context->global, name)) + list = &context->global; else - var = context->local; + list = &context->local; - ret = setenv_raw(var, name, value); + ret = setenv_raw(list, name, value); out: free(name); @@ -239,11 +246,11 @@ int export(const char *varname) { - const char *val = getenv_raw(context->local, varname); + const char *val = getenv_raw(&context->local, varname); if (val) { - setenv_raw(context->global, varname, val); - setenv_raw(context->local, varname, NULL); + setenv_raw(&context->global, varname, val); + setenv_raw(&context->local, varname, NULL); } return 0; } diff --git a/include/environment.h b/include/environment.h index 5cd7ecf..fd7735a 100644 --- a/include/environment.h +++ b/include/environment.h @@ -26,14 +26,15 @@ * Managment of a environment variable */ struct variable_d { - struct variable_d *next; /**< List management */ - char data[0]; /**< variable length data */ + struct list_head list; + char *name; + char *data; }; struct env_context { - struct env_context *parent; /**< FIXME */ - struct variable_d *local; /**< FIXME */ - struct variable_d *global; /**< FIXME */ + struct env_context *parent; + struct list_head local; + struct list_head global; }; struct env_context *get_current_context(void);