From d9c9d10d9da76f067d3955bea71f7bb39e859fa5 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Fri, 12 Jun 2009 12:24:39 -0700 Subject: fixes to edify and updater script A few more changes to edify: - fix write_raw_image(); my last change neglected to close the write context, so the written image was corrupt. - each expression tracks the span of the source code from which it was compiled, so that assert()'s error message can include the source of the expression that failed. - the 'cookie' argument to each Function is replaced with a State object, which contains the cookie, the source script (for use with the above spans), and the current error message (replacing the global variables that were used for this purpose). - in the recovery image, a new command "ui_print" can be sent back through the command pipe to cause text to appear on the screen. Add a new ui_print() function to print things from scripts. Rename existing "print" function to "stdout". --- edify/expr.c | 506 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 249 insertions(+), 257 deletions(-) (limited to 'edify/expr.c') diff --git a/edify/expr.c b/edify/expr.c index 5470a2bac..406c67ea6 100644 --- a/edify/expr.c +++ b/edify/expr.c @@ -29,249 +29,241 @@ // - if Evaluate() on any argument returns NULL, return NULL. int BooleanString(const char* s) { - return s[0] != '\0'; + return s[0] != '\0'; } -char* Evaluate(void* cookie, Expr* expr) { - return expr->fn(expr->name, cookie, expr->argc, expr->argv); +char* Evaluate(State* state, Expr* expr) { + return expr->fn(expr->name, state, expr->argc, expr->argv); } -char* ConcatFn(const char* name, void* cookie, int argc, Expr* argv[]) { - if (argc == 0) { - return strdup(""); - } - char** strings = malloc(argc * sizeof(char*)); - int i; - for (i = 0; i < argc; ++i) { - strings[i] = NULL; - } - char* result = NULL; - int length = 0; - for (i = 0; i < argc; ++i) { - strings[i] = Evaluate(cookie, argv[i]); - if (strings[i] == NULL) { - goto done; +char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) { + if (argc == 0) { + return strdup(""); + } + char** strings = malloc(argc * sizeof(char*)); + int i; + for (i = 0; i < argc; ++i) { + strings[i] = NULL; + } + char* result = NULL; + int length = 0; + for (i = 0; i < argc; ++i) { + strings[i] = Evaluate(state, argv[i]); + if (strings[i] == NULL) { + goto done; + } + length += strlen(strings[i]); + } + + result = malloc(length+1); + int p = 0; + for (i = 0; i < argc; ++i) { + strcpy(result+p, strings[i]); + p += strlen(strings[i]); + } + result[p] = '\0'; + + done: + for (i = 0; i < argc; ++i) { + free(strings[i]); } - length += strlen(strings[i]); - } - - result = malloc(length+1); - int p = 0; - for (i = 0; i < argc; ++i) { - strcpy(result+p, strings[i]); - p += strlen(strings[i]); - } - result[p] = '\0'; - -done: - for (i = 0; i < argc; ++i) { - free(strings[i]); - } - return result; + return result; } -char* IfElseFn(const char* name, void* cookie, int argc, Expr* argv[]) { - if (argc != 2 && argc != 3) { - return NULL; - } - char* cond = Evaluate(cookie, argv[0]); - if (cond == NULL) { - return NULL; - } - - if (BooleanString(cond) == true) { - free(cond); - return Evaluate(cookie, argv[1]); - } else { - if (argc == 3) { - free(cond); - return Evaluate(cookie, argv[2]); +char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) { + if (argc != 2 && argc != 3) { + return NULL; + } + char* cond = Evaluate(state, argv[0]); + if (cond == NULL) { + return NULL; + } + + if (BooleanString(cond) == true) { + free(cond); + return Evaluate(state, argv[1]); } else { - return cond; + if (argc == 3) { + free(cond); + return Evaluate(state, argv[2]); + } else { + return cond; + } } - } } -char* AbortFn(const char* name, void* cookie, int argc, Expr* argv[]) { - char* msg = NULL; - if (argc > 0) { - msg = Evaluate(cookie, argv[0]); - } - SetError(msg == NULL ? "called abort()" : msg); - free(msg); - return NULL; +char* AbortFn(const char* name, State* state, int argc, Expr* argv[]) { + char* msg = NULL; + if (argc > 0) { + msg = Evaluate(state, argv[0]); + } + free(state->errmsg); + if (msg) { + state->errmsg = msg; + } else { + state->errmsg = strdup("called abort()"); + } + return NULL; } -char* AssertFn(const char* name, void* cookie, int argc, Expr* argv[]) { - int i; - for (i = 0; i < argc; ++i) { - char* v = Evaluate(cookie, argv[i]); - if (v == NULL) { - return NULL; - } - int b = BooleanString(v); - free(v); - if (!b) { - SetError("assert() failed"); - return NULL; +char* AssertFn(const char* name, State* state, int argc, Expr* argv[]) { + int i; + for (i = 0; i < argc; ++i) { + char* v = Evaluate(state, argv[i]); + if (v == NULL) { + return NULL; + } + int b = BooleanString(v); + free(v); + if (!b) { + int prefix_len; + int len = argv[i]->end - argv[i]->start; + char* err_src = malloc(len + 20); + strcpy(err_src, "assert failed: "); + prefix_len = strlen(err_src); + memcpy(err_src + prefix_len, state->script + argv[i]->start, len); + err_src[prefix_len + len] = '\0'; + free(state->errmsg); + state->errmsg = err_src; + return NULL; + } } - } - return strdup(""); + return strdup(""); } -char* SleepFn(const char* name, void* cookie, int argc, Expr* argv[]) { - char* val = Evaluate(cookie, argv[0]); - if (val == NULL) { - return NULL; - } - int v = strtol(val, NULL, 10); - sleep(v); - return val; +char* SleepFn(const char* name, State* state, int argc, Expr* argv[]) { + char* val = Evaluate(state, argv[0]); + if (val == NULL) { + return NULL; + } + int v = strtol(val, NULL, 10); + sleep(v); + return val; } -char* PrintFn(const char* name, void* cookie, int argc, Expr* argv[]) { - int i; - for (i = 0; i < argc; ++i) { - char* v = Evaluate(cookie, argv[i]); - if (v == NULL) { - return NULL; +char* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) { + int i; + for (i = 0; i < argc; ++i) { + char* v = Evaluate(state, argv[i]); + if (v == NULL) { + return NULL; + } + fputs(v, stdout); + free(v); } - fputs(v, stdout); - free(v); - } - return strdup(""); + return strdup(""); } -char* LogicalAndFn(const char* name, void* cookie, +char* LogicalAndFn(const char* name, State* state, int argc, Expr* argv[]) { - char* left = Evaluate(cookie, argv[0]); - if (left == NULL) return NULL; - if (BooleanString(left) == true) { - free(left); - return Evaluate(cookie, argv[1]); - } else { - return left; - } + char* left = Evaluate(state, argv[0]); + if (left == NULL) return NULL; + if (BooleanString(left) == true) { + free(left); + return Evaluate(state, argv[1]); + } else { + return left; + } } -char* LogicalOrFn(const char* name, void* cookie, +char* LogicalOrFn(const char* name, State* state, int argc, Expr* argv[]) { - char* left = Evaluate(cookie, argv[0]); - if (left == NULL) return NULL; - if (BooleanString(left) == false) { - free(left); - return Evaluate(cookie, argv[1]); - } else { - return left; - } + char* left = Evaluate(state, argv[0]); + if (left == NULL) return NULL; + if (BooleanString(left) == false) { + free(left); + return Evaluate(state, argv[1]); + } else { + return left; + } } -char* LogicalNotFn(const char* name, void* cookie, - int argc, Expr* argv[]) { - char* val = Evaluate(cookie, argv[0]); - if (val == NULL) return NULL; - bool bv = BooleanString(val); - free(val); - if (bv) { - return strdup(""); - } else { - return strdup("t"); - } +char* LogicalNotFn(const char* name, State* state, + int argc, Expr* argv[]) { + char* val = Evaluate(state, argv[0]); + if (val == NULL) return NULL; + bool bv = BooleanString(val); + free(val); + if (bv) { + return strdup(""); + } else { + return strdup("t"); + } } -char* SubstringFn(const char* name, void* cookie, +char* SubstringFn(const char* name, State* state, int argc, Expr* argv[]) { - char* needle = Evaluate(cookie, argv[0]); - if (needle == NULL) return NULL; - char* haystack = Evaluate(cookie, argv[1]); - if (haystack == NULL) { - free(needle); - return NULL; - } + char* needle = Evaluate(state, argv[0]); + if (needle == NULL) return NULL; + char* haystack = Evaluate(state, argv[1]); + if (haystack == NULL) { + free(needle); + return NULL; + } - char* result = strdup(strstr(haystack, needle) ? "t" : ""); - free(needle); - free(haystack); - return result; + char* result = strdup(strstr(haystack, needle) ? "t" : ""); + free(needle); + free(haystack); + return result; } -char* EqualityFn(const char* name, void* cookie, int argc, Expr* argv[]) { - char* left = Evaluate(cookie, argv[0]); - if (left == NULL) return NULL; - char* right = Evaluate(cookie, argv[1]); - if (right == NULL) { - free(left); - return NULL; - } - - char* result = strdup(strcmp(left, right) == 0 ? "t" : ""); - free(left); - free(right); - return result; -} +char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) { + char* left = Evaluate(state, argv[0]); + if (left == NULL) return NULL; + char* right = Evaluate(state, argv[1]); + if (right == NULL) { + free(left); + return NULL; + } -char* InequalityFn(const char* name, void* cookie, int argc, Expr* argv[]) { - char* left = Evaluate(cookie, argv[0]); - if (left == NULL) return NULL; - char* right = Evaluate(cookie, argv[1]); - if (right == NULL) { + char* result = strdup(strcmp(left, right) == 0 ? "t" : ""); free(left); - return NULL; - } - - char* result = strdup(strcmp(left, right) != 0 ? "t" : ""); - free(left); - free(right); - return result; + free(right); + return result; } -char* SequenceFn(const char* name, void* cookie, int argc, Expr* argv[]) { - char* left = Evaluate(cookie, argv[0]); - if (left == NULL) return NULL; - free(left); - return Evaluate(cookie, argv[1]); -} - -char* Literal(const char* name, void* cookie, int argc, Expr* argv[]) { - return strdup(name); -} +char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) { + char* left = Evaluate(state, argv[0]); + if (left == NULL) return NULL; + char* right = Evaluate(state, argv[1]); + if (right == NULL) { + free(left); + return NULL; + } -Expr* Build(Function fn, int count, ...) { - va_list v; - va_start(v, count); - Expr* e = malloc(sizeof(Expr)); - e->fn = fn; - e->name = "(operator)"; - e->argc = count; - e->argv = malloc(count * sizeof(Expr*)); - int i; - for (i = 0; i < count; ++i) { - e->argv[i] = va_arg(v, Expr*); - } - va_end(v); - return e; + char* result = strdup(strcmp(left, right) != 0 ? "t" : ""); + free(left); + free(right); + return result; } -// ----------------------------------------------------------------- -// error reporting -// ----------------------------------------------------------------- - -static char* error_message = NULL; - -void SetError(const char* message) { - if (error_message) { - free(error_message); - } - error_message = strdup(message); +char* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) { + char* left = Evaluate(state, argv[0]); + if (left == NULL) return NULL; + free(left); + return Evaluate(state, argv[1]); } -const char* GetError() { - return error_message; +char* Literal(const char* name, State* state, int argc, Expr* argv[]) { + return strdup(name); } -void ClearError() { - free(error_message); - error_message = NULL; +Expr* Build(Function fn, YYLTYPE loc, int count, ...) { + va_list v; + va_start(v, count); + Expr* e = malloc(sizeof(Expr)); + e->fn = fn; + e->name = "(operator)"; + e->argc = count; + e->argv = malloc(count * sizeof(Expr*)); + int i; + for (i = 0; i < count; ++i) { + e->argv[i] = va_arg(v, Expr*); + } + va_end(v); + e->start = loc.start; + e->end = loc.end; + return e; } // ----------------------------------------------------------------- @@ -283,44 +275,44 @@ static int fn_size = 0; NamedFunction* fn_table = NULL; void RegisterFunction(const char* name, Function fn) { - if (fn_entries >= fn_size) { - fn_size = fn_size*2 + 1; - fn_table = realloc(fn_table, fn_size * sizeof(NamedFunction)); - } - fn_table[fn_entries].name = name; - fn_table[fn_entries].fn = fn; - ++fn_entries; + if (fn_entries >= fn_size) { + fn_size = fn_size*2 + 1; + fn_table = realloc(fn_table, fn_size * sizeof(NamedFunction)); + } + fn_table[fn_entries].name = name; + fn_table[fn_entries].fn = fn; + ++fn_entries; } static int fn_entry_compare(const void* a, const void* b) { - const char* na = ((const NamedFunction*)a)->name; - const char* nb = ((const NamedFunction*)b)->name; - return strcmp(na, nb); + const char* na = ((const NamedFunction*)a)->name; + const char* nb = ((const NamedFunction*)b)->name; + return strcmp(na, nb); } void FinishRegistration() { - qsort(fn_table, fn_entries, sizeof(NamedFunction), fn_entry_compare); + qsort(fn_table, fn_entries, sizeof(NamedFunction), fn_entry_compare); } Function FindFunction(const char* name) { - NamedFunction key; - key.name = name; - NamedFunction* nf = bsearch(&key, fn_table, fn_entries, sizeof(NamedFunction), - fn_entry_compare); - if (nf == NULL) { - return NULL; - } - return nf->fn; + NamedFunction key; + key.name = name; + NamedFunction* nf = bsearch(&key, fn_table, fn_entries, + sizeof(NamedFunction), fn_entry_compare); + if (nf == NULL) { + return NULL; + } + return nf->fn; } void RegisterBuiltins() { - RegisterFunction("ifelse", IfElseFn); - RegisterFunction("abort", AbortFn); - RegisterFunction("assert", AssertFn); - RegisterFunction("concat", ConcatFn); - RegisterFunction("is_substring", SubstringFn); - RegisterFunction("print", PrintFn); - RegisterFunction("sleep", SleepFn); + RegisterFunction("ifelse", IfElseFn); + RegisterFunction("abort", AbortFn); + RegisterFunction("assert", AssertFn); + RegisterFunction("concat", ConcatFn); + RegisterFunction("is_substring", SubstringFn); + RegisterFunction("stdout", StdoutFn); + RegisterFunction("sleep", SleepFn); } @@ -331,44 +323,44 @@ void RegisterBuiltins() { // Evaluate the expressions in argv, giving 'count' char* (the ... is // zero or more char** to put them in). If any expression evaluates // to NULL, free the rest and return -1. Return 0 on success. -int ReadArgs(void* cookie, Expr* argv[], int count, ...) { - char** args = malloc(count * sizeof(char*)); - va_list v; - va_start(v, count); - int i; - for (i = 0; i < count; ++i) { - args[i] = Evaluate(cookie, argv[i]); - if (args[i] == NULL) { - va_end(v); - int j; - for (j = 0; j < i; ++j) { - free(args[j]); - } - return -1; +int ReadArgs(State* state, Expr* argv[], int count, ...) { + char** args = malloc(count * sizeof(char*)); + va_list v; + va_start(v, count); + int i; + for (i = 0; i < count; ++i) { + args[i] = Evaluate(state, argv[i]); + if (args[i] == NULL) { + va_end(v); + int j; + for (j = 0; j < i; ++j) { + free(args[j]); + } + return -1; + } + *(va_arg(v, char**)) = args[i]; } - *(va_arg(v, char**)) = args[i]; - } - va_end(v); - return 0; + va_end(v); + return 0; } // Evaluate the expressions in argv, returning an array of char* // results. If any evaluate to NULL, free the rest and return NULL. // The caller is responsible for freeing the returned array and the // strings it contains. -char** ReadVarArgs(void* cookie, int argc, Expr* argv[]) { - char** args = (char**)malloc(argc * sizeof(char*)); - int i = 0; - for (i = 0; i < argc; ++i) { - args[i] = Evaluate(cookie, argv[i]); - if (args[i] == NULL) { - int j; - for (j = 0; j < i; ++j) { - free(args[j]); - } - free(args); - return NULL; +char** ReadVarArgs(State* state, int argc, Expr* argv[]) { + char** args = (char**)malloc(argc * sizeof(char*)); + int i = 0; + for (i = 0; i < argc; ++i) { + args[i] = Evaluate(state, argv[i]); + if (args[i] == NULL) { + int j; + for (j = 0; j < i; ++j) { + free(args[j]); + } + free(args); + return NULL; + } } - } - return args; + return args; } -- cgit v1.2.3