X-Git-Url: https://jxself.org/git/?p=carl9170fw.git;a=blobdiff_plain;f=config%2Fpreprocess.c;h=0574039238c65cf1df6bb1dba86b9fff8c989375;hp=528be594e1d01f6d03b729e43fdc0fccf20b0001;hb=6598140e430d622be926aed43ec19fec8326cd11;hpb=2344a769a43b21f2a45a0397cc6d518b7cea7e33 diff --git a/config/preprocess.c b/config/preprocess.c index 528be59..0574039 100644 --- a/config/preprocess.c +++ b/config/preprocess.c @@ -106,6 +106,35 @@ struct function { char *(*func)(int argc, char *argv[]); }; +static char *do_error_if(int argc, char *argv[]) +{ + if (!strcmp(argv[0], "y")) + pperror("%s", argv[1]); + + return NULL; +} + +static char *do_filename(int argc, char *argv[]) +{ + return xstrdup(current_file->name); +} + +static char *do_info(int argc, char *argv[]) +{ + printf("%s\n", argv[0]); + + return xstrdup(""); +} + +static char *do_lineno(int argc, char *argv[]) +{ + char buf[16]; + + sprintf(buf, "%d", yylineno); + + return xstrdup(buf); +} + static char *do_shell(int argc, char *argv[]) { FILE *p; @@ -146,9 +175,23 @@ static char *do_shell(int argc, char *argv[]) return xstrdup(buf); } +static char *do_warning_if(int argc, char *argv[]) +{ + if (!strcmp(argv[0], "y")) + fprintf(stderr, "%s:%d: %s\n", + current_file->name, yylineno, argv[1]); + + return xstrdup(""); +} + static const struct function function_table[] = { /* Name MIN MAX Function */ + { "error-if", 2, 2, do_error_if }, + { "filename", 0, 0, do_filename }, + { "info", 1, 1, do_info }, + { "lineno", 0, 0, do_lineno }, { "shell", 1, 1, do_shell }, + { "warning-if", 2, 2, do_warning_if }, }; #define FUNCTION_MAX_ARGS 16 @@ -177,6 +220,107 @@ static char *function_expand(const char *name, int argc, char *argv[]) return NULL; } +/* + * Variables (and user-defined functions) + */ +static LIST_HEAD(variable_list); + +struct variable { + char *name; + char *value; + enum variable_flavor flavor; + struct list_head node; +}; + +static struct variable *variable_lookup(const char *name) +{ + struct variable *v; + + list_for_each_entry(v, &variable_list, node) { + if (!strcmp(name, v->name)) + return v; + } + + return NULL; +} + +static char *variable_expand(const char *name, int argc, char *argv[]) +{ + struct variable *v; + char *res; + + v = variable_lookup(name); + if (!v) + return NULL; + + if (v->flavor == VAR_RECURSIVE) + res = expand_string_with_args(v->value, argc, argv); + else + res = xstrdup(v->value); + + return res; +} + +void variable_add(const char *name, const char *value, + enum variable_flavor flavor) +{ + struct variable *v; + char *new_value; + bool append = false; + + v = variable_lookup(name); + if (v) { + /* For defined variables, += inherits the existing flavor */ + if (flavor == VAR_APPEND) { + flavor = v->flavor; + append = true; + } else { + free(v->value); + } + } else { + /* For undefined variables, += assumes the recursive flavor */ + if (flavor == VAR_APPEND) + flavor = VAR_RECURSIVE; + + v = xmalloc(sizeof(*v)); + v->name = xstrdup(name); + list_add_tail(&v->node, &variable_list); + } + + v->flavor = flavor; + + if (flavor == VAR_SIMPLE) + new_value = expand_string(value); + else + new_value = xstrdup(value); + + if (append) { + v->value = xrealloc(v->value, + strlen(v->value) + strlen(new_value) + 2); + strcat(v->value, " "); + strcat(v->value, new_value); + free(new_value); + } else { + v->value = new_value; + } +} + +static void variable_del(struct variable *v) +{ + list_del(&v->node); + free(v->name); + free(v->value); + free(v); +} + +void variable_all_del(void) +{ + struct variable *v, *tmp; + + list_for_each_entry_safe(v, tmp, &variable_list, node) + variable_del(v); +} + /* * Evaluate a clause with arguments. argc/argv are arguments from the upper * function call. @@ -185,14 +329,26 @@ static char *function_expand(const char *name, int argc, char *argv[]) */ static char *eval_clause(const char *str, size_t len, int argc, char *argv[]) { - char *tmp, *name, *res, *prev, *p; + char *tmp, *name, *res, *endptr, *prev, *p; int new_argc = 0; char *new_argv[FUNCTION_MAX_ARGS]; int nest = 0; int i; + unsigned long n; tmp = xstrndup(str, len); + /* + * If variable name is '1', '2', etc. It is generally an argument + * from a user-function call (i.e. local-scope variable). If not + * available, then look-up global-scope variables. + */ + n = strtoul(tmp, &endptr, 10); + if (!*endptr && n > 0 && n <= argc) { + res = xstrdup(argv[n - 1]); + goto free_tmp; + } + prev = p = tmp; /* @@ -238,6 +394,11 @@ static char *eval_clause(const char *str, size_t len, int argc, char *argv[]) new_argv[i] = expand_string_with_args(new_argv[i + 1], argc, argv); + /* Search for variables */ + res = variable_expand(name, new_argc, new_argv); + if (res) + goto free; + /* Look for built-in functions */ res = function_expand(name, new_argc, new_argv); if (res) @@ -255,6 +416,7 @@ free: for (i = 0; i < new_argc; i++) free(new_argv[i]); free(name); +free_tmp: free(tmp); return res;