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".
This commit is contained in:
+256
-264
@@ -29,249 +29,241 @@
|
|||||||
// - if Evaluate() on any argument returns NULL, return NULL.
|
// - if Evaluate() on any argument returns NULL, return NULL.
|
||||||
|
|
||||||
int BooleanString(const char* s) {
|
int BooleanString(const char* s) {
|
||||||
return s[0] != '\0';
|
return s[0] != '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Evaluate(void* cookie, Expr* expr) {
|
char* Evaluate(State* state, Expr* expr) {
|
||||||
return expr->fn(expr->name, cookie, expr->argc, expr->argv);
|
return expr->fn(expr->name, state, expr->argc, expr->argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* ConcatFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
return strdup("");
|
return strdup("");
|
||||||
}
|
}
|
||||||
char** strings = malloc(argc * sizeof(char*));
|
char** strings = malloc(argc * sizeof(char*));
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < argc; ++i) {
|
for (i = 0; i < argc; ++i) {
|
||||||
strings[i] = NULL;
|
strings[i] = NULL;
|
||||||
}
|
}
|
||||||
char* result = NULL;
|
char* result = NULL;
|
||||||
int length = 0;
|
int length = 0;
|
||||||
for (i = 0; i < argc; ++i) {
|
for (i = 0; i < argc; ++i) {
|
||||||
strings[i] = Evaluate(cookie, argv[i]);
|
strings[i] = Evaluate(state, argv[i]);
|
||||||
if (strings[i] == NULL) {
|
if (strings[i] == NULL) {
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
|
length += strlen(strings[i]);
|
||||||
}
|
}
|
||||||
length += strlen(strings[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = malloc(length+1);
|
result = malloc(length+1);
|
||||||
int p = 0;
|
int p = 0;
|
||||||
for (i = 0; i < argc; ++i) {
|
for (i = 0; i < argc; ++i) {
|
||||||
strcpy(result+p, strings[i]);
|
strcpy(result+p, strings[i]);
|
||||||
p += strlen(strings[i]);
|
p += strlen(strings[i]);
|
||||||
}
|
}
|
||||||
result[p] = '\0';
|
result[p] = '\0';
|
||||||
|
|
||||||
done:
|
done:
|
||||||
for (i = 0; i < argc; ++i) {
|
for (i = 0; i < argc; ++i) {
|
||||||
free(strings[i]);
|
free(strings[i]);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* IfElseFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
if (argc != 2 && argc != 3) {
|
if (argc != 2 && argc != 3) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
char* cond = Evaluate(cookie, argv[0]);
|
char* cond = Evaluate(state, argv[0]);
|
||||||
if (cond == NULL) {
|
if (cond == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BooleanString(cond) == true) {
|
if (BooleanString(cond) == true) {
|
||||||
free(cond);
|
free(cond);
|
||||||
return Evaluate(cookie, argv[1]);
|
return Evaluate(state, argv[1]);
|
||||||
} else {
|
|
||||||
if (argc == 3) {
|
|
||||||
free(cond);
|
|
||||||
return Evaluate(cookie, argv[2]);
|
|
||||||
} else {
|
} 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* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
char* msg = NULL;
|
char* msg = NULL;
|
||||||
if (argc > 0) {
|
if (argc > 0) {
|
||||||
msg = Evaluate(cookie, argv[0]);
|
msg = Evaluate(state, argv[0]);
|
||||||
}
|
|
||||||
SetError(msg == NULL ? "called abort()" : msg);
|
|
||||||
free(msg);
|
|
||||||
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(state->errmsg);
|
||||||
free(v);
|
if (msg) {
|
||||||
if (!b) {
|
state->errmsg = msg;
|
||||||
SetError("assert() failed");
|
} else {
|
||||||
return NULL;
|
state->errmsg = strdup("called abort()");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return strdup("");
|
|
||||||
}
|
|
||||||
|
|
||||||
char* SleepFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
|
||||||
char* val = Evaluate(cookie, argv[0]);
|
|
||||||
if (val == NULL) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
int v = strtol(val, NULL, 10);
|
|
||||||
sleep(v);
|
|
||||||
return val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char* PrintFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < argc; ++i) {
|
for (i = 0; i < argc; ++i) {
|
||||||
char* v = Evaluate(cookie, argv[i]);
|
char* v = Evaluate(state, argv[i]);
|
||||||
if (v == NULL) {
|
if (v == NULL) {
|
||||||
return 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fputs(v, stdout);
|
|
||||||
free(v);
|
|
||||||
}
|
|
||||||
return strdup("");
|
|
||||||
}
|
|
||||||
|
|
||||||
char* LogicalAndFn(const char* name, void* cookie,
|
|
||||||
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* LogicalOrFn(const char* name, void* cookie,
|
|
||||||
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* 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("");
|
return strdup("");
|
||||||
} else {
|
|
||||||
return strdup("t");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char* SubstringFn(const char* name, void* cookie,
|
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* 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);
|
||||||
|
}
|
||||||
|
return strdup("");
|
||||||
|
}
|
||||||
|
|
||||||
|
char* LogicalAndFn(const char* name, State* state,
|
||||||
|
int argc, Expr* argv[]) {
|
||||||
|
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, State* state,
|
||||||
int argc, Expr* argv[]) {
|
int argc, Expr* argv[]) {
|
||||||
char* needle = Evaluate(cookie, argv[0]);
|
char* left = Evaluate(state, argv[0]);
|
||||||
if (needle == NULL) return NULL;
|
if (left == NULL) return NULL;
|
||||||
char* haystack = Evaluate(cookie, argv[1]);
|
if (BooleanString(left) == false) {
|
||||||
if (haystack == NULL) {
|
free(left);
|
||||||
|
return Evaluate(state, argv[1]);
|
||||||
|
} else {
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, State* state,
|
||||||
|
int argc, Expr* argv[]) {
|
||||||
|
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(needle);
|
||||||
return NULL;
|
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* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
char* left = Evaluate(cookie, argv[0]);
|
char* left = Evaluate(state, argv[0]);
|
||||||
if (left == NULL) return NULL;
|
if (left == NULL) return NULL;
|
||||||
char* right = Evaluate(cookie, argv[1]);
|
char* right = Evaluate(state, argv[1]);
|
||||||
if (right == NULL) {
|
if (right == NULL) {
|
||||||
|
free(left);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* result = strdup(strcmp(left, right) == 0 ? "t" : "");
|
||||||
free(left);
|
free(left);
|
||||||
return NULL;
|
free(right);
|
||||||
}
|
return result;
|
||||||
|
|
||||||
char* result = strdup(strcmp(left, right) == 0 ? "t" : "");
|
|
||||||
free(left);
|
|
||||||
free(right);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char* InequalityFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
char* left = Evaluate(cookie, argv[0]);
|
char* left = Evaluate(state, argv[0]);
|
||||||
if (left == NULL) return NULL;
|
if (left == NULL) return NULL;
|
||||||
char* right = Evaluate(cookie, argv[1]);
|
char* right = Evaluate(state, argv[1]);
|
||||||
if (right == NULL) {
|
if (right == NULL) {
|
||||||
|
free(left);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* result = strdup(strcmp(left, right) != 0 ? "t" : "");
|
||||||
free(left);
|
free(left);
|
||||||
return NULL;
|
free(right);
|
||||||
}
|
return result;
|
||||||
|
|
||||||
char* result = strdup(strcmp(left, right) != 0 ? "t" : "");
|
|
||||||
free(left);
|
|
||||||
free(right);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char* SequenceFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
char* left = Evaluate(cookie, argv[0]);
|
char* left = Evaluate(state, argv[0]);
|
||||||
if (left == NULL) return NULL;
|
if (left == NULL) return NULL;
|
||||||
free(left);
|
free(left);
|
||||||
return Evaluate(cookie, argv[1]);
|
return Evaluate(state, argv[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Literal(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* Literal(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
return strdup(name);
|
return strdup(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr* Build(Function fn, int count, ...) {
|
Expr* Build(Function fn, YYLTYPE loc, int count, ...) {
|
||||||
va_list v;
|
va_list v;
|
||||||
va_start(v, count);
|
va_start(v, count);
|
||||||
Expr* e = malloc(sizeof(Expr));
|
Expr* e = malloc(sizeof(Expr));
|
||||||
e->fn = fn;
|
e->fn = fn;
|
||||||
e->name = "(operator)";
|
e->name = "(operator)";
|
||||||
e->argc = count;
|
e->argc = count;
|
||||||
e->argv = malloc(count * sizeof(Expr*));
|
e->argv = malloc(count * sizeof(Expr*));
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
e->argv[i] = va_arg(v, Expr*);
|
e->argv[i] = va_arg(v, Expr*);
|
||||||
}
|
}
|
||||||
va_end(v);
|
va_end(v);
|
||||||
return e;
|
e->start = loc.start;
|
||||||
}
|
e->end = loc.end;
|
||||||
|
return e;
|
||||||
// -----------------------------------------------------------------
|
|
||||||
// error reporting
|
|
||||||
// -----------------------------------------------------------------
|
|
||||||
|
|
||||||
static char* error_message = NULL;
|
|
||||||
|
|
||||||
void SetError(const char* message) {
|
|
||||||
if (error_message) {
|
|
||||||
free(error_message);
|
|
||||||
}
|
|
||||||
error_message = strdup(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* GetError() {
|
|
||||||
return error_message;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearError() {
|
|
||||||
free(error_message);
|
|
||||||
error_message = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
@@ -283,44 +275,44 @@ static int fn_size = 0;
|
|||||||
NamedFunction* fn_table = NULL;
|
NamedFunction* fn_table = NULL;
|
||||||
|
|
||||||
void RegisterFunction(const char* name, Function fn) {
|
void RegisterFunction(const char* name, Function fn) {
|
||||||
if (fn_entries >= fn_size) {
|
if (fn_entries >= fn_size) {
|
||||||
fn_size = fn_size*2 + 1;
|
fn_size = fn_size*2 + 1;
|
||||||
fn_table = realloc(fn_table, fn_size * sizeof(NamedFunction));
|
fn_table = realloc(fn_table, fn_size * sizeof(NamedFunction));
|
||||||
}
|
}
|
||||||
fn_table[fn_entries].name = name;
|
fn_table[fn_entries].name = name;
|
||||||
fn_table[fn_entries].fn = fn;
|
fn_table[fn_entries].fn = fn;
|
||||||
++fn_entries;
|
++fn_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fn_entry_compare(const void* a, const void* b) {
|
static int fn_entry_compare(const void* a, const void* b) {
|
||||||
const char* na = ((const NamedFunction*)a)->name;
|
const char* na = ((const NamedFunction*)a)->name;
|
||||||
const char* nb = ((const NamedFunction*)b)->name;
|
const char* nb = ((const NamedFunction*)b)->name;
|
||||||
return strcmp(na, nb);
|
return strcmp(na, nb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FinishRegistration() {
|
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) {
|
Function FindFunction(const char* name) {
|
||||||
NamedFunction key;
|
NamedFunction key;
|
||||||
key.name = name;
|
key.name = name;
|
||||||
NamedFunction* nf = bsearch(&key, fn_table, fn_entries, sizeof(NamedFunction),
|
NamedFunction* nf = bsearch(&key, fn_table, fn_entries,
|
||||||
fn_entry_compare);
|
sizeof(NamedFunction), fn_entry_compare);
|
||||||
if (nf == NULL) {
|
if (nf == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return nf->fn;
|
return nf->fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterBuiltins() {
|
void RegisterBuiltins() {
|
||||||
RegisterFunction("ifelse", IfElseFn);
|
RegisterFunction("ifelse", IfElseFn);
|
||||||
RegisterFunction("abort", AbortFn);
|
RegisterFunction("abort", AbortFn);
|
||||||
RegisterFunction("assert", AssertFn);
|
RegisterFunction("assert", AssertFn);
|
||||||
RegisterFunction("concat", ConcatFn);
|
RegisterFunction("concat", ConcatFn);
|
||||||
RegisterFunction("is_substring", SubstringFn);
|
RegisterFunction("is_substring", SubstringFn);
|
||||||
RegisterFunction("print", PrintFn);
|
RegisterFunction("stdout", StdoutFn);
|
||||||
RegisterFunction("sleep", SleepFn);
|
RegisterFunction("sleep", SleepFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -331,44 +323,44 @@ void RegisterBuiltins() {
|
|||||||
// Evaluate the expressions in argv, giving 'count' char* (the ... is
|
// Evaluate the expressions in argv, giving 'count' char* (the ... is
|
||||||
// zero or more char** to put them in). If any expression evaluates
|
// zero or more char** to put them in). If any expression evaluates
|
||||||
// to NULL, free the rest and return -1. Return 0 on success.
|
// to NULL, free the rest and return -1. Return 0 on success.
|
||||||
int ReadArgs(void* cookie, Expr* argv[], int count, ...) {
|
int ReadArgs(State* state, Expr* argv[], int count, ...) {
|
||||||
char** args = malloc(count * sizeof(char*));
|
char** args = malloc(count * sizeof(char*));
|
||||||
va_list v;
|
va_list v;
|
||||||
va_start(v, count);
|
va_start(v, count);
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
args[i] = Evaluate(cookie, argv[i]);
|
args[i] = Evaluate(state, argv[i]);
|
||||||
if (args[i] == NULL) {
|
if (args[i] == NULL) {
|
||||||
va_end(v);
|
va_end(v);
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < i; ++j) {
|
for (j = 0; j < i; ++j) {
|
||||||
free(args[j]);
|
free(args[j]);
|
||||||
}
|
}
|
||||||
return -1;
|
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*
|
// Evaluate the expressions in argv, returning an array of char*
|
||||||
// results. If any evaluate to NULL, free the rest and return NULL.
|
// results. If any evaluate to NULL, free the rest and return NULL.
|
||||||
// The caller is responsible for freeing the returned array and the
|
// The caller is responsible for freeing the returned array and the
|
||||||
// strings it contains.
|
// strings it contains.
|
||||||
char** ReadVarArgs(void* cookie, int argc, Expr* argv[]) {
|
char** ReadVarArgs(State* state, int argc, Expr* argv[]) {
|
||||||
char** args = (char**)malloc(argc * sizeof(char*));
|
char** args = (char**)malloc(argc * sizeof(char*));
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (i = 0; i < argc; ++i) {
|
for (i = 0; i < argc; ++i) {
|
||||||
args[i] = Evaluate(cookie, argv[i]);
|
args[i] = Evaluate(state, argv[i]);
|
||||||
if (args[i] == NULL) {
|
if (args[i] == NULL) {
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < i; ++j) {
|
for (j = 0; j < i; ++j) {
|
||||||
free(args[j]);
|
free(args[j]);
|
||||||
}
|
}
|
||||||
free(args);
|
free(args);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return args;
|
||||||
return args;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-21
@@ -17,45 +17,64 @@
|
|||||||
#ifndef _EXPRESSION_H
|
#ifndef _EXPRESSION_H
|
||||||
#define _EXPRESSION_H
|
#define _EXPRESSION_H
|
||||||
|
|
||||||
|
#include "yydefs.h"
|
||||||
|
|
||||||
#define MAX_STRING_LEN 1024
|
#define MAX_STRING_LEN 1024
|
||||||
|
|
||||||
typedef struct Expr Expr;
|
typedef struct Expr Expr;
|
||||||
|
|
||||||
typedef char* (*Function)(const char* name, void* cookie,
|
typedef struct {
|
||||||
|
// Optional pointer to app-specific data; the core of edify never
|
||||||
|
// uses this value.
|
||||||
|
void* cookie;
|
||||||
|
|
||||||
|
// The source of the original script. Must be NULL-terminated,
|
||||||
|
// and in writable memory (Evaluate may make temporary changes to
|
||||||
|
// it but will restore it when done).
|
||||||
|
char* script;
|
||||||
|
|
||||||
|
// The error message (if any) returned if the evaluation aborts.
|
||||||
|
// Should be NULL initially, will be either NULL or a malloc'd
|
||||||
|
// pointer after Evaluate() returns.
|
||||||
|
char* errmsg;
|
||||||
|
} State;
|
||||||
|
|
||||||
|
typedef char* (*Function)(const char* name, State* state,
|
||||||
int argc, Expr* argv[]);
|
int argc, Expr* argv[]);
|
||||||
|
|
||||||
struct Expr {
|
struct Expr {
|
||||||
Function fn;
|
Function fn;
|
||||||
char* name;
|
char* name;
|
||||||
int argc;
|
int argc;
|
||||||
Expr** argv;
|
Expr** argv;
|
||||||
|
int start, end;
|
||||||
};
|
};
|
||||||
|
|
||||||
char* Evaluate(void* cookie, Expr* expr);
|
char* Evaluate(State* state, Expr* expr);
|
||||||
|
|
||||||
// Glue to make an Expr out of a literal.
|
// Glue to make an Expr out of a literal.
|
||||||
char* Literal(const char* name, void* cookie, int argc, Expr* argv[]);
|
char* Literal(const char* name, State* state, int argc, Expr* argv[]);
|
||||||
|
|
||||||
// Functions corresponding to various syntactic sugar operators.
|
// Functions corresponding to various syntactic sugar operators.
|
||||||
// ("concat" is also available as a builtin function, to concatenate
|
// ("concat" is also available as a builtin function, to concatenate
|
||||||
// more than two strings.)
|
// more than two strings.)
|
||||||
char* ConcatFn(const char* name, void* cookie, int argc, Expr* argv[]);
|
char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]);
|
||||||
char* LogicalAndFn(const char* name, void* cookie, int argc, Expr* argv[]);
|
char* LogicalAndFn(const char* name, State* state, int argc, Expr* argv[]);
|
||||||
char* LogicalOrFn(const char* name, void* cookie, int argc, Expr* argv[]);
|
char* LogicalOrFn(const char* name, State* state, int argc, Expr* argv[]);
|
||||||
char* LogicalNotFn(const char* name, void* cookie, int argc, Expr* argv[]);
|
char* LogicalNotFn(const char* name, State* state, int argc, Expr* argv[]);
|
||||||
char* SubstringFn(const char* name, void* cookie, int argc, Expr* argv[]);
|
char* SubstringFn(const char* name, State* state, int argc, Expr* argv[]);
|
||||||
char* EqualityFn(const char* name, void* cookie, int argc, Expr* argv[]);
|
char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]);
|
||||||
char* InequalityFn(const char* name, void* cookie, int argc, Expr* argv[]);
|
char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]);
|
||||||
char* SequenceFn(const char* name, void* cookie, int argc, Expr* argv[]);
|
char* SequenceFn(const char* name, State* state, int argc, Expr* argv[]);
|
||||||
|
|
||||||
// Convenience function for building expressions with a fixed number
|
// Convenience function for building expressions with a fixed number
|
||||||
// of arguments.
|
// of arguments.
|
||||||
Expr* Build(Function fn, int count, ...);
|
Expr* Build(Function fn, YYLTYPE loc, int count, ...);
|
||||||
|
|
||||||
// Global builtins, registered by RegisterBuiltins().
|
// Global builtins, registered by RegisterBuiltins().
|
||||||
char* IfElseFn(const char* name, void* cookie, int argc, Expr* argv[]);
|
char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]);
|
||||||
char* AssertFn(const char* name, void* cookie, int argc, Expr* argv[]);
|
char* AssertFn(const char* name, State* state, int argc, Expr* argv[]);
|
||||||
char* AbortFn(const char* name, void* cookie, int argc, Expr* argv[]);
|
char* AbortFn(const char* name, State* state, int argc, Expr* argv[]);
|
||||||
|
|
||||||
|
|
||||||
// For setting and getting the global error string (when returning
|
// For setting and getting the global error string (when returning
|
||||||
@@ -91,13 +110,13 @@ Function FindFunction(const char* name);
|
|||||||
// Evaluate the expressions in argv, giving 'count' char* (the ... is
|
// Evaluate the expressions in argv, giving 'count' char* (the ... is
|
||||||
// zero or more char** to put them in). If any expression evaluates
|
// zero or more char** to put them in). If any expression evaluates
|
||||||
// to NULL, free the rest and return -1. Return 0 on success.
|
// to NULL, free the rest and return -1. Return 0 on success.
|
||||||
int ReadArgs(void* cookie, Expr* argv[], int count, ...);
|
int ReadArgs(State* state, Expr* argv[], int count, ...);
|
||||||
|
|
||||||
// Evaluate the expressions in argv, returning an array of char*
|
// Evaluate the expressions in argv, returning an array of char*
|
||||||
// results. If any evaluate to NULL, free the rest and return NULL.
|
// results. If any evaluate to NULL, free the rest and return NULL.
|
||||||
// The caller is responsible for freeing the returned array and the
|
// The caller is responsible for freeing the returned array and the
|
||||||
// strings it contains.
|
// strings it contains.
|
||||||
char** ReadVarArgs(void* cookie, int argc, Expr* argv[]);
|
char** ReadVarArgs(State* state, int argc, Expr* argv[]);
|
||||||
|
|
||||||
|
|
||||||
#endif // _EXPRESSION_H
|
#endif // _EXPRESSION_H
|
||||||
|
|||||||
+30
-17
@@ -16,14 +16,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
|
#include "yydefs.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
int gLine = 1;
|
int gLine = 1;
|
||||||
int gColumn = 1;
|
int gColumn = 1;
|
||||||
|
int gPos = 0;
|
||||||
|
|
||||||
// TODO: enforce MAX_STRING_LEN during lexing
|
// TODO: enforce MAX_STRING_LEN during lexing
|
||||||
char string_buffer[MAX_STRING_LEN];
|
char string_buffer[MAX_STRING_LEN];
|
||||||
char* string_pos;
|
char* string_pos;
|
||||||
|
|
||||||
|
#define ADVANCE do {yylloc.start=gPos; yylloc.end=gPos+yyleng; \
|
||||||
|
gColumn+=yyleng; gPos+=yyleng;} while(0)
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%x STR
|
%x STR
|
||||||
@@ -34,27 +40,32 @@ char* string_pos;
|
|||||||
|
|
||||||
|
|
||||||
\" {
|
\" {
|
||||||
++gColumn;
|
|
||||||
BEGIN(STR);
|
BEGIN(STR);
|
||||||
string_pos = string_buffer;
|
string_pos = string_buffer;
|
||||||
|
yylloc.start = gPos;
|
||||||
|
++gColumn;
|
||||||
|
++gPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
<STR>{
|
<STR>{
|
||||||
\" {
|
\" {
|
||||||
++gColumn;
|
++gColumn;
|
||||||
|
++gPos;
|
||||||
BEGIN(INITIAL);
|
BEGIN(INITIAL);
|
||||||
*string_pos = '\0';
|
*string_pos = '\0';
|
||||||
yylval.str = strdup(string_buffer);
|
yylval.str = strdup(string_buffer);
|
||||||
|
yylloc.end = gPos;
|
||||||
return STRING;
|
return STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
\\n { gColumn += yyleng; *string_pos++ = '\n'; }
|
\\n { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\n'; }
|
||||||
\\t { gColumn += yyleng; *string_pos++ = '\t'; }
|
\\t { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\t'; }
|
||||||
\\\" { gColumn += yyleng; *string_pos++ = '\"'; }
|
\\\" { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\"'; }
|
||||||
\\\\ { gColumn += yyleng; *string_pos++ = '\\'; }
|
\\\\ { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\\'; }
|
||||||
|
|
||||||
\\x[0-9a-fA-F]{2} {
|
\\x[0-9a-fA-F]{2} {
|
||||||
gColumn += yyleng;
|
gColumn += yyleng;
|
||||||
|
gPos += yyleng;
|
||||||
int val;
|
int val;
|
||||||
sscanf(yytext+2, "%x", &val);
|
sscanf(yytext+2, "%x", &val);
|
||||||
*string_pos++ = val;
|
*string_pos++ = val;
|
||||||
@@ -62,36 +73,38 @@ char* string_pos;
|
|||||||
|
|
||||||
\n {
|
\n {
|
||||||
++gLine;
|
++gLine;
|
||||||
|
++gPos;
|
||||||
gColumn = 1;
|
gColumn = 1;
|
||||||
*string_pos++ = yytext[0];
|
*string_pos++ = yytext[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
. {
|
. {
|
||||||
++gColumn;
|
++gColumn;
|
||||||
|
++gPos;
|
||||||
*string_pos++ = yytext[0];
|
*string_pos++ = yytext[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if { gColumn += yyleng; return IF; }
|
if ADVANCE; return IF;
|
||||||
then { gColumn += yyleng; return THEN; }
|
then ADVANCE; return THEN;
|
||||||
else { gColumn += yyleng; return ELSE; }
|
else ADVANCE; return ELSE;
|
||||||
endif { gColumn += yyleng; return ENDIF; }
|
endif ADVANCE; return ENDIF;
|
||||||
|
|
||||||
[a-zA-Z0-9_:/.]+ {
|
[a-zA-Z0-9_:/.]+ {
|
||||||
gColumn += yyleng;
|
ADVANCE;
|
||||||
yylval.str = strdup(yytext);
|
yylval.str = strdup(yytext);
|
||||||
return STRING;
|
return STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
\&\& { gColumn += yyleng; return AND; }
|
\&\& ADVANCE; return AND;
|
||||||
\|\| { gColumn += yyleng; return OR; }
|
\|\| ADVANCE; return OR;
|
||||||
== { gColumn += yyleng; return EQ; }
|
== ADVANCE; return EQ;
|
||||||
!= { gColumn += yyleng; return NE; }
|
!= ADVANCE; return NE;
|
||||||
|
|
||||||
[+(),!;] { gColumn += yyleng; return yytext[0]; }
|
[+(),!;] ADVANCE; return yytext[0];
|
||||||
|
|
||||||
[ \t]+ gColumn += yyleng;
|
[ \t]+ ADVANCE;
|
||||||
|
|
||||||
(#.*)?\n { ++gLine; gColumn = 1; }
|
(#.*)?\n gPos += yyleng; ++gLine; gColumn = 1;
|
||||||
|
|
||||||
. return BAD;
|
. return BAD;
|
||||||
|
|||||||
+150
-119
@@ -21,152 +21,183 @@
|
|||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
|
extern int yyparse(Expr** root, int* error_count);
|
||||||
|
|
||||||
int expect(const char* expr_str, const char* expected, int* errors) {
|
int expect(const char* expr_str, const char* expected, int* errors) {
|
||||||
Expr* e;
|
Expr* e;
|
||||||
int error;
|
int error;
|
||||||
char* result;
|
char* result;
|
||||||
|
|
||||||
printf(".");
|
printf(".");
|
||||||
|
|
||||||
yy_scan_string(expr_str);
|
yy_scan_string(expr_str);
|
||||||
error = yyparse(&e);
|
int error_count = 0;
|
||||||
if (error > 0) {
|
error = yyparse(&e, &error_count);
|
||||||
fprintf(stderr, "error parsing \"%s\"\n", expr_str);
|
if (error > 0 || error_count > 0) {
|
||||||
++*errors;
|
fprintf(stderr, "error parsing \"%s\" (%d errors)\n",
|
||||||
return 0;
|
expr_str, error_count);
|
||||||
}
|
++*errors;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
result = Evaluate(NULL, e);
|
State state;
|
||||||
if (result == NULL && expected != NULL) {
|
state.cookie = NULL;
|
||||||
fprintf(stderr, "error evaluating \"%s\"\n", expr_str);
|
state.script = expr_str;
|
||||||
++*errors;
|
state.errmsg = NULL;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == NULL && expected == NULL) {
|
result = Evaluate(&state, e);
|
||||||
return 1;
|
free(state.errmsg);
|
||||||
}
|
if (result == NULL && expected != NULL) {
|
||||||
|
fprintf(stderr, "error evaluating \"%s\"\n", expr_str);
|
||||||
|
++*errors;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == NULL && expected == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(result, expected) != 0) {
|
||||||
|
fprintf(stderr, "evaluating \"%s\": expected \"%s\", got \"%s\"\n",
|
||||||
|
expr_str, expected, result);
|
||||||
|
++*errors;
|
||||||
|
free(result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(result, expected) != 0) {
|
|
||||||
fprintf(stderr, "evaluating \"%s\": expected \"%s\", got \"%s\"\n",
|
|
||||||
expr_str, expected, result);
|
|
||||||
++*errors;
|
|
||||||
free(result);
|
free(result);
|
||||||
return 0;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
free(result);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int test() {
|
int test() {
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
||||||
expect("a", "a", &errors);
|
expect("a", "a", &errors);
|
||||||
expect("\"a\"", "a", &errors);
|
expect("\"a\"", "a", &errors);
|
||||||
expect("\"\\x61\"", "a", &errors);
|
expect("\"\\x61\"", "a", &errors);
|
||||||
expect("# this is a comment\n"
|
expect("# this is a comment\n"
|
||||||
" a\n"
|
" a\n"
|
||||||
" \n",
|
" \n",
|
||||||
"a", &errors);
|
"a", &errors);
|
||||||
|
|
||||||
|
|
||||||
// sequence operator
|
// sequence operator
|
||||||
expect("a; b; c", "c", &errors);
|
expect("a; b; c", "c", &errors);
|
||||||
|
|
||||||
// string concat operator
|
// string concat operator
|
||||||
expect("a + b", "ab", &errors);
|
expect("a + b", "ab", &errors);
|
||||||
expect("a + \n \"b\"", "ab", &errors);
|
expect("a + \n \"b\"", "ab", &errors);
|
||||||
expect("a + b +\nc\n", "abc", &errors);
|
expect("a + b +\nc\n", "abc", &errors);
|
||||||
|
|
||||||
// string concat function
|
// string concat function
|
||||||
expect("concat(a, b)", "ab", &errors);
|
expect("concat(a, b)", "ab", &errors);
|
||||||
expect("concat(a,\n \"b\")", "ab", &errors);
|
expect("concat(a,\n \"b\")", "ab", &errors);
|
||||||
expect("concat(a + b,\nc,\"d\")", "abcd", &errors);
|
expect("concat(a + b,\nc,\"d\")", "abcd", &errors);
|
||||||
expect("\"concat\"(a + b,\nc,\"d\")", "abcd", &errors);
|
expect("\"concat\"(a + b,\nc,\"d\")", "abcd", &errors);
|
||||||
|
|
||||||
// logical and
|
// logical and
|
||||||
expect("a && b", "b", &errors);
|
expect("a && b", "b", &errors);
|
||||||
expect("a && \"\"", "", &errors);
|
expect("a && \"\"", "", &errors);
|
||||||
expect("\"\" && b", "", &errors);
|
expect("\"\" && b", "", &errors);
|
||||||
expect("\"\" && \"\"", "", &errors);
|
expect("\"\" && \"\"", "", &errors);
|
||||||
expect("\"\" && abort()", "", &errors); // test short-circuiting
|
expect("\"\" && abort()", "", &errors); // test short-circuiting
|
||||||
expect("t && abort()", NULL, &errors);
|
expect("t && abort()", NULL, &errors);
|
||||||
|
|
||||||
// logical or
|
// logical or
|
||||||
expect("a || b", "a", &errors);
|
expect("a || b", "a", &errors);
|
||||||
expect("a || \"\"", "a", &errors);
|
expect("a || \"\"", "a", &errors);
|
||||||
expect("\"\" || b", "b", &errors);
|
expect("\"\" || b", "b", &errors);
|
||||||
expect("\"\" || \"\"", "", &errors);
|
expect("\"\" || \"\"", "", &errors);
|
||||||
expect("a || abort()", "a", &errors); // test short-circuiting
|
expect("a || abort()", "a", &errors); // test short-circuiting
|
||||||
expect("\"\" || abort()", NULL, &errors);
|
expect("\"\" || abort()", NULL, &errors);
|
||||||
|
|
||||||
// logical not
|
// logical not
|
||||||
expect("!a", "", &errors);
|
expect("!a", "", &errors);
|
||||||
expect("! \"\"", "t", &errors);
|
expect("! \"\"", "t", &errors);
|
||||||
expect("!!a", "t", &errors);
|
expect("!!a", "t", &errors);
|
||||||
|
|
||||||
// precedence
|
// precedence
|
||||||
expect("\"\" == \"\" && b", "b", &errors);
|
expect("\"\" == \"\" && b", "b", &errors);
|
||||||
expect("a + b == ab", "t", &errors);
|
expect("a + b == ab", "t", &errors);
|
||||||
expect("ab == a + b", "t", &errors);
|
expect("ab == a + b", "t", &errors);
|
||||||
expect("a + (b == ab)", "a", &errors);
|
expect("a + (b == ab)", "a", &errors);
|
||||||
expect("(ab == a) + b", "b", &errors);
|
expect("(ab == a) + b", "b", &errors);
|
||||||
|
|
||||||
// substring function
|
// substring function
|
||||||
expect("is_substring(cad, abracadabra)", "t", &errors);
|
expect("is_substring(cad, abracadabra)", "t", &errors);
|
||||||
expect("is_substring(abrac, abracadabra)", "t", &errors);
|
expect("is_substring(abrac, abracadabra)", "t", &errors);
|
||||||
expect("is_substring(dabra, abracadabra)", "t", &errors);
|
expect("is_substring(dabra, abracadabra)", "t", &errors);
|
||||||
expect("is_substring(cad, abracxadabra)", "", &errors);
|
expect("is_substring(cad, abracxadabra)", "", &errors);
|
||||||
expect("is_substring(abrac, axbracadabra)", "", &errors);
|
expect("is_substring(abrac, axbracadabra)", "", &errors);
|
||||||
expect("is_substring(dabra, abracadabrxa)", "", &errors);
|
expect("is_substring(dabra, abracadabrxa)", "", &errors);
|
||||||
|
|
||||||
// ifelse function
|
// ifelse function
|
||||||
expect("ifelse(t, yes, no)", "yes", &errors);
|
expect("ifelse(t, yes, no)", "yes", &errors);
|
||||||
expect("ifelse(!t, yes, no)", "no", &errors);
|
expect("ifelse(!t, yes, no)", "no", &errors);
|
||||||
expect("ifelse(t, yes, abort())", "yes", &errors);
|
expect("ifelse(t, yes, abort())", "yes", &errors);
|
||||||
expect("ifelse(!t, abort(), no)", "no", &errors);
|
expect("ifelse(!t, abort(), no)", "no", &errors);
|
||||||
|
|
||||||
// if "statements"
|
// if "statements"
|
||||||
expect("if t then yes else no endif", "yes", &errors);
|
expect("if t then yes else no endif", "yes", &errors);
|
||||||
expect("if \"\" then yes else no endif", "no", &errors);
|
expect("if \"\" then yes else no endif", "no", &errors);
|
||||||
expect("if \"\" then yes endif", "", &errors);
|
expect("if \"\" then yes endif", "", &errors);
|
||||||
expect("if \"\"; t then yes endif", "yes", &errors);
|
expect("if \"\"; t then yes endif", "yes", &errors);
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExprDump(int depth, Expr* n, char* script) {
|
||||||
|
printf("%*s", depth*2, "");
|
||||||
|
char temp = script[n->end];
|
||||||
|
script[n->end] = '\0';
|
||||||
|
printf("%s %p (%d-%d) \"%s\"\n",
|
||||||
|
n->name == NULL ? "(NULL)" : n->name, n->fn, n->start, n->end,
|
||||||
|
script+n->start);
|
||||||
|
script[n->end] = temp;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < n->argc; ++i) {
|
||||||
|
ExprDump(depth+1, n->argv[i], script);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
RegisterBuiltins();
|
RegisterBuiltins();
|
||||||
FinishRegistration();
|
FinishRegistration();
|
||||||
|
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
return test() != 0;
|
return test() != 0;
|
||||||
}
|
|
||||||
|
|
||||||
FILE* f = fopen(argv[1], "r");
|
|
||||||
char buffer[8192];
|
|
||||||
int size = fread(buffer, 1, 8191, f);
|
|
||||||
fclose(f);
|
|
||||||
buffer[size] = '\0';
|
|
||||||
|
|
||||||
Expr* root;
|
|
||||||
int error_count = 0;
|
|
||||||
yy_scan_bytes(buffer, size);
|
|
||||||
int error = yyparse(&root, &error_count);
|
|
||||||
printf("parse returned %d; %d errors encountered\n", error, error_count);
|
|
||||||
if (error == 0 || error_count > 0) {
|
|
||||||
char* result = Evaluate(NULL, root);
|
|
||||||
if (result == NULL) {
|
|
||||||
char* errmsg = GetError();
|
|
||||||
printf("result was NULL, message is: %s\n",
|
|
||||||
(errmsg == NULL ? "(NULL)" : errmsg));
|
|
||||||
ClearError();
|
|
||||||
} else {
|
|
||||||
printf("result is [%s]\n", result);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return 0;
|
FILE* f = fopen(argv[1], "r");
|
||||||
|
char buffer[8192];
|
||||||
|
int size = fread(buffer, 1, 8191, f);
|
||||||
|
fclose(f);
|
||||||
|
buffer[size] = '\0';
|
||||||
|
|
||||||
|
Expr* root;
|
||||||
|
int error_count = 0;
|
||||||
|
yy_scan_bytes(buffer, size);
|
||||||
|
int error = yyparse(&root, &error_count);
|
||||||
|
printf("parse returned %d; %d errors encountered\n", error, error_count);
|
||||||
|
if (error == 0 || error_count > 0) {
|
||||||
|
|
||||||
|
ExprDump(0, root, buffer);
|
||||||
|
|
||||||
|
State state;
|
||||||
|
state.cookie = NULL;
|
||||||
|
state.script = buffer;
|
||||||
|
state.errmsg = NULL;
|
||||||
|
|
||||||
|
char* result = Evaluate(&state, root);
|
||||||
|
if (result == NULL) {
|
||||||
|
printf("result was NULL, message is: %s\n",
|
||||||
|
(state.errmsg == NULL ? "(NULL)" : state.errmsg));
|
||||||
|
free(state.errmsg);
|
||||||
|
} else {
|
||||||
|
printf("result is [%s]\n", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-12
@@ -20,6 +20,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
|
#include "yydefs.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
extern int gLine;
|
extern int gLine;
|
||||||
@@ -30,6 +31,8 @@ int yyparse(Expr** root, int* error_count);
|
|||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
%locations
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
char* str;
|
char* str;
|
||||||
Expr* expr;
|
Expr* expr;
|
||||||
@@ -68,19 +71,21 @@ expr: STRING {
|
|||||||
$$->name = $1;
|
$$->name = $1;
|
||||||
$$->argc = 0;
|
$$->argc = 0;
|
||||||
$$->argv = NULL;
|
$$->argv = NULL;
|
||||||
|
$$->start = @$.start;
|
||||||
|
$$->end = @$.end;
|
||||||
}
|
}
|
||||||
| '(' expr ')' { $$ = $2; }
|
| '(' expr ')' { $$ = $2; $$->start=@$.start; $$->end=@$.end; }
|
||||||
| expr ';' { $$ = $1; }
|
| expr ';' { $$ = $1; $$->start=@1.start; $$->end=@1.end; }
|
||||||
| expr ';' expr { $$ = Build(SequenceFn, 2, $1, $3); }
|
| expr ';' expr { $$ = Build(SequenceFn, @$, 2, $1, $3); }
|
||||||
| error ';' expr { $$ = $3; }
|
| error ';' expr { $$ = $3; $$->start=@$.start; $$->end=@$.end; }
|
||||||
| expr '+' expr { $$ = Build(ConcatFn, 2, $1, $3); }
|
| expr '+' expr { $$ = Build(ConcatFn, @$, 2, $1, $3); }
|
||||||
| expr EQ expr { $$ = Build(EqualityFn, 2, $1, $3); }
|
| expr EQ expr { $$ = Build(EqualityFn, @$, 2, $1, $3); }
|
||||||
| expr NE expr { $$ = Build(InequalityFn, 2, $1, $3); }
|
| expr NE expr { $$ = Build(InequalityFn, @$, 2, $1, $3); }
|
||||||
| expr AND expr { $$ = Build(LogicalAndFn, 2, $1, $3); }
|
| expr AND expr { $$ = Build(LogicalAndFn, @$, 2, $1, $3); }
|
||||||
| expr OR expr { $$ = Build(LogicalOrFn, 2, $1, $3); }
|
| expr OR expr { $$ = Build(LogicalOrFn, @$, 2, $1, $3); }
|
||||||
| '!' expr { $$ = Build(LogicalNotFn, 1, $2); }
|
| '!' expr { $$ = Build(LogicalNotFn, @$, 1, $2); }
|
||||||
| IF expr THEN expr ENDIF { $$ = Build(IfElseFn, 2, $2, $4); }
|
| IF expr THEN expr ENDIF { $$ = Build(IfElseFn, @$, 2, $2, $4); }
|
||||||
| IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, 3, $2, $4, $6); }
|
| IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, @$, 3, $2, $4, $6); }
|
||||||
| STRING '(' arglist ')' {
|
| STRING '(' arglist ')' {
|
||||||
$$ = malloc(sizeof(Expr));
|
$$ = malloc(sizeof(Expr));
|
||||||
$$->fn = FindFunction($1);
|
$$->fn = FindFunction($1);
|
||||||
@@ -93,6 +98,8 @@ expr: STRING {
|
|||||||
$$->name = $1;
|
$$->name = $1;
|
||||||
$$->argc = $3.argc;
|
$$->argc = $3.argc;
|
||||||
$$->argv = $3.argv;
|
$$->argv = $3.argv;
|
||||||
|
$$->start = @$.start;
|
||||||
|
$$->end = @$.end;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _YYDEFS_H_
|
||||||
|
#define _YYDEFS_H_
|
||||||
|
|
||||||
|
#define YYLTYPE YYLTYPE
|
||||||
|
typedef struct {
|
||||||
|
int start, end;
|
||||||
|
} YYLTYPE;
|
||||||
|
|
||||||
|
#define YYLLOC_DEFAULT(Current, Rhs, N) \
|
||||||
|
do { \
|
||||||
|
if (N) { \
|
||||||
|
(Current).start = YYRHSLOC(Rhs, 1).start; \
|
||||||
|
(Current).end = YYRHSLOC(Rhs, N).end; \
|
||||||
|
} else { \
|
||||||
|
(Current).start = YYRHSLOC(Rhs, 0).start; \
|
||||||
|
(Current).end = YYRHSLOC(Rhs, 0).end; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -196,6 +196,9 @@ try_update_binary(const char *path, ZipArchive *zip) {
|
|||||||
// arrange to install the contents of <filename> in the
|
// arrange to install the contents of <filename> in the
|
||||||
// given partition on reboot.
|
// given partition on reboot.
|
||||||
//
|
//
|
||||||
|
// ui_print <string>
|
||||||
|
// display <string> on the screen.
|
||||||
|
//
|
||||||
// - the name of the package zip file.
|
// - the name of the package zip file.
|
||||||
//
|
//
|
||||||
|
|
||||||
@@ -248,6 +251,13 @@ try_update_binary(const char *path, ZipArchive *zip) {
|
|||||||
firmware_filename = strdup(filename);
|
firmware_filename = strdup(filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (strcmp(command, "ui_print") == 0) {
|
||||||
|
char* str = strtok(NULL, "\n");
|
||||||
|
if (str) {
|
||||||
|
ui_print(str);
|
||||||
|
} else {
|
||||||
|
ui_print("\n");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGE("unknown command [%s]\n", command);
|
LOGE("unknown command [%s]\n", command);
|
||||||
}
|
}
|
||||||
|
|||||||
+104
-62
@@ -32,13 +32,14 @@
|
|||||||
#include "mtdutils/mtdutils.h"
|
#include "mtdutils/mtdutils.h"
|
||||||
#include "updater.h"
|
#include "updater.h"
|
||||||
|
|
||||||
char* ErrorAbort(void* cookie, char* format, ...) {
|
char* ErrorAbort(State* state, char* format, ...) {
|
||||||
char* buffer = malloc(4096);
|
char* buffer = malloc(4096);
|
||||||
va_list v;
|
va_list v;
|
||||||
va_start(v, format);
|
va_start(v, format);
|
||||||
vsnprintf(buffer, 4096, format, v);
|
vsnprintf(buffer, 4096, format, v);
|
||||||
va_end(v);
|
va_end(v);
|
||||||
SetError(buffer);
|
free(state->errmsg);
|
||||||
|
state->errmsg = buffer;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,28 +48,28 @@ char* ErrorAbort(void* cookie, char* format, ...) {
|
|||||||
//
|
//
|
||||||
// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem
|
// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem
|
||||||
// type="vfat" location="/dev/block/<whatever>" to mount a device
|
// type="vfat" location="/dev/block/<whatever>" to mount a device
|
||||||
char* MountFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
char* result = NULL;
|
char* result = NULL;
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
return ErrorAbort(cookie, "%s() expects 3 args, got %d", name, argc);
|
return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
|
||||||
}
|
}
|
||||||
char* type;
|
char* type;
|
||||||
char* location;
|
char* location;
|
||||||
char* mount_point;
|
char* mount_point;
|
||||||
if (ReadArgs(cookie, argv, 3, &type, &location, &mount_point) < 0) {
|
if (ReadArgs(state, argv, 3, &type, &location, &mount_point) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(type) == 0) {
|
if (strlen(type) == 0) {
|
||||||
ErrorAbort(cookie, "type argument to %s() can't be empty", name);
|
ErrorAbort(state, "type argument to %s() can't be empty", name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (strlen(location) == 0) {
|
if (strlen(location) == 0) {
|
||||||
ErrorAbort(cookie, "location argument to %s() can't be empty", name);
|
ErrorAbort(state, "location argument to %s() can't be empty", name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (strlen(mount_point) == 0) {
|
if (strlen(mount_point) == 0) {
|
||||||
ErrorAbort(cookie, "mount_point argument to %s() can't be empty", name);
|
ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,17 +110,17 @@ done:
|
|||||||
|
|
||||||
|
|
||||||
// is_mounted(mount_point)
|
// is_mounted(mount_point)
|
||||||
char* IsMountedFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
char* result = NULL;
|
char* result = NULL;
|
||||||
if (argc != 1) {
|
if (argc != 1) {
|
||||||
return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc);
|
return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
|
||||||
}
|
}
|
||||||
char* mount_point;
|
char* mount_point;
|
||||||
if (ReadArgs(cookie, argv, 1, &mount_point) < 0) {
|
if (ReadArgs(state, argv, 1, &mount_point) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (strlen(mount_point) == 0) {
|
if (strlen(mount_point) == 0) {
|
||||||
ErrorAbort(cookie, "mount_point argument to unmount() can't be empty");
|
ErrorAbort(state, "mount_point argument to unmount() can't be empty");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,17 +138,17 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char* UnmountFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
char* result = NULL;
|
char* result = NULL;
|
||||||
if (argc != 1) {
|
if (argc != 1) {
|
||||||
return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc);
|
return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
|
||||||
}
|
}
|
||||||
char* mount_point;
|
char* mount_point;
|
||||||
if (ReadArgs(cookie, argv, 1, &mount_point) < 0) {
|
if (ReadArgs(state, argv, 1, &mount_point) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (strlen(mount_point) == 0) {
|
if (strlen(mount_point) == 0) {
|
||||||
ErrorAbort(cookie, "mount_point argument to unmount() can't be empty");
|
ErrorAbort(state, "mount_point argument to unmount() can't be empty");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,23 +171,23 @@ done:
|
|||||||
// format(type, location)
|
// format(type, location)
|
||||||
//
|
//
|
||||||
// type="MTD" location=partition
|
// type="MTD" location=partition
|
||||||
char* FormatFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
char* result = NULL;
|
char* result = NULL;
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc);
|
return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
|
||||||
}
|
}
|
||||||
char* type;
|
char* type;
|
||||||
char* location;
|
char* location;
|
||||||
if (ReadArgs(cookie, argv, 2, &type, &location) < 0) {
|
if (ReadArgs(state, argv, 2, &type, &location) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(type) == 0) {
|
if (strlen(type) == 0) {
|
||||||
ErrorAbort(cookie, "type argument to %s() can't be empty", name);
|
ErrorAbort(state, "type argument to %s() can't be empty", name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (strlen(location) == 0) {
|
if (strlen(location) == 0) {
|
||||||
ErrorAbort(cookie, "location argument to %s() can't be empty", name);
|
ErrorAbort(state, "location argument to %s() can't be empty", name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,11 +229,11 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char* DeleteFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
char** paths = malloc(argc * sizeof(char*));
|
char** paths = malloc(argc * sizeof(char*));
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < argc; ++i) {
|
for (i = 0; i < argc; ++i) {
|
||||||
paths[i] = Evaluate(cookie, argv[i]);
|
paths[i] = Evaluate(state, argv[i]);
|
||||||
if (paths[i] == NULL) {
|
if (paths[i] == NULL) {
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < i; ++i) {
|
for (j = 0; j < i; ++i) {
|
||||||
@@ -259,20 +260,20 @@ char* DeleteFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char* ShowProgressFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc);
|
return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
|
||||||
}
|
}
|
||||||
char* frac_str;
|
char* frac_str;
|
||||||
char* sec_str;
|
char* sec_str;
|
||||||
if (ReadArgs(cookie, argv, 2, &frac_str, &sec_str) < 0) {
|
if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
double frac = strtod(frac_str, NULL);
|
double frac = strtod(frac_str, NULL);
|
||||||
int sec = strtol(sec_str, NULL, 10);
|
int sec = strtol(sec_str, NULL, 10);
|
||||||
|
|
||||||
UpdaterInfo* ui = (UpdaterInfo*)cookie;
|
UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
|
||||||
fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
|
fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
|
||||||
|
|
||||||
free(frac_str);
|
free(frac_str);
|
||||||
@@ -281,16 +282,16 @@ char* ShowProgressFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// package_extract_dir(package_path, destination_path)
|
// package_extract_dir(package_path, destination_path)
|
||||||
char* PackageExtractDirFn(const char* name, void* cookie,
|
char* PackageExtractDirFn(const char* name, State* state,
|
||||||
int argc, Expr* argv[]) {
|
int argc, Expr* argv[]) {
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc);
|
return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
|
||||||
}
|
}
|
||||||
char* zip_path;
|
char* zip_path;
|
||||||
char* dest_path;
|
char* dest_path;
|
||||||
if (ReadArgs(cookie, argv, 2, &zip_path, &dest_path) < 0) return NULL;
|
if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
|
||||||
|
|
||||||
ZipArchive* za = ((UpdaterInfo*)cookie)->package_zip;
|
ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
|
||||||
|
|
||||||
// To create a consistent system image, never use the clock for timestamps.
|
// To create a consistent system image, never use the clock for timestamps.
|
||||||
struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
|
struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
|
||||||
@@ -305,18 +306,18 @@ char* PackageExtractDirFn(const char* name, void* cookie,
|
|||||||
|
|
||||||
|
|
||||||
// package_extract_file(package_path, destination_path)
|
// package_extract_file(package_path, destination_path)
|
||||||
char* PackageExtractFileFn(const char* name, void* cookie,
|
char* PackageExtractFileFn(const char* name, State* state,
|
||||||
int argc, Expr* argv[]) {
|
int argc, Expr* argv[]) {
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc);
|
return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
|
||||||
}
|
}
|
||||||
char* zip_path;
|
char* zip_path;
|
||||||
char* dest_path;
|
char* dest_path;
|
||||||
if (ReadArgs(cookie, argv, 2, &zip_path, &dest_path) < 0) return NULL;
|
if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
ZipArchive* za = ((UpdaterInfo*)cookie)->package_zip;
|
ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
|
||||||
const ZipEntry* entry = mzFindZipEntry(za, zip_path);
|
const ZipEntry* entry = mzFindZipEntry(za, zip_path);
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
fprintf(stderr, "%s: no %s in package\n", name, zip_path);
|
fprintf(stderr, "%s: no %s in package\n", name, zip_path);
|
||||||
@@ -340,15 +341,15 @@ char* PackageExtractFileFn(const char* name, void* cookie,
|
|||||||
|
|
||||||
|
|
||||||
// symlink target src1 src2 ...
|
// symlink target src1 src2 ...
|
||||||
char* SymlinkFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
return ErrorAbort(cookie, "%s() expects 1+ args, got %d", name, argc);
|
return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
|
||||||
}
|
}
|
||||||
char* target;
|
char* target;
|
||||||
target = Evaluate(cookie, argv[0]);
|
target = Evaluate(state, argv[0]);
|
||||||
if (target == NULL) return NULL;
|
if (target == NULL) return NULL;
|
||||||
|
|
||||||
char** srcs = ReadVarArgs(cookie, argc-1, argv+1);
|
char** srcs = ReadVarArgs(state, argc-1, argv+1);
|
||||||
if (srcs == NULL) {
|
if (srcs == NULL) {
|
||||||
free(target);
|
free(target);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -364,16 +365,16 @@ char* SymlinkFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char* SetPermFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
char* result = NULL;
|
char* result = NULL;
|
||||||
bool recursive = (strcmp(name, "set_perm_recursive") == 0);
|
bool recursive = (strcmp(name, "set_perm_recursive") == 0);
|
||||||
|
|
||||||
int min_args = 4 + (recursive ? 1 : 0);
|
int min_args = 4 + (recursive ? 1 : 0);
|
||||||
if (argc < min_args) {
|
if (argc < min_args) {
|
||||||
return ErrorAbort(cookie, "%s() expects %d+ args, got %d", name, argc);
|
return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
|
||||||
}
|
}
|
||||||
|
|
||||||
char** args = ReadVarArgs(cookie, argc, argv);
|
char** args = ReadVarArgs(state, argc, argv);
|
||||||
if (args == NULL) return NULL;
|
if (args == NULL) return NULL;
|
||||||
|
|
||||||
char* end;
|
char* end;
|
||||||
@@ -381,26 +382,26 @@ char* SetPermFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
|||||||
|
|
||||||
int uid = strtoul(args[0], &end, 0);
|
int uid = strtoul(args[0], &end, 0);
|
||||||
if (*end != '\0' || args[0][0] == 0) {
|
if (*end != '\0' || args[0][0] == 0) {
|
||||||
ErrorAbort(cookie, "%s: \"%s\" not a valid uid", name, args[0]);
|
ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gid = strtoul(args[1], &end, 0);
|
int gid = strtoul(args[1], &end, 0);
|
||||||
if (*end != '\0' || args[1][0] == 0) {
|
if (*end != '\0' || args[1][0] == 0) {
|
||||||
ErrorAbort(cookie, "%s: \"%s\" not a valid gid", name, args[1]);
|
ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
int dir_mode = strtoul(args[2], &end, 0);
|
int dir_mode = strtoul(args[2], &end, 0);
|
||||||
if (*end != '\0' || args[2][0] == 0) {
|
if (*end != '\0' || args[2][0] == 0) {
|
||||||
ErrorAbort(cookie, "%s: \"%s\" not a valid dirmode", name, args[2]);
|
ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
int file_mode = strtoul(args[3], &end, 0);
|
int file_mode = strtoul(args[3], &end, 0);
|
||||||
if (*end != '\0' || args[3][0] == 0) {
|
if (*end != '\0' || args[3][0] == 0) {
|
||||||
ErrorAbort(cookie, "%s: \"%s\" not a valid filemode",
|
ErrorAbort(state, "%s: \"%s\" not a valid filemode",
|
||||||
name, args[3]);
|
name, args[3]);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -411,7 +412,7 @@ char* SetPermFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
|||||||
} else {
|
} else {
|
||||||
int mode = strtoul(args[2], &end, 0);
|
int mode = strtoul(args[2], &end, 0);
|
||||||
if (*end != '\0' || args[2][0] == 0) {
|
if (*end != '\0' || args[2][0] == 0) {
|
||||||
ErrorAbort(cookie, "%s: \"%s\" not a valid mode", name, args[2]);
|
ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,12 +433,12 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char* GetPropFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
if (argc != 1) {
|
if (argc != 1) {
|
||||||
return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc);
|
return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
|
||||||
}
|
}
|
||||||
char* key;
|
char* key;
|
||||||
key = Evaluate(cookie, argv[0]);
|
key = Evaluate(state, argv[0]);
|
||||||
if (key == NULL) return NULL;
|
if (key == NULL) return NULL;
|
||||||
|
|
||||||
char value[PROPERTY_VALUE_MAX];
|
char value[PROPERTY_VALUE_MAX];
|
||||||
@@ -457,21 +458,21 @@ static bool write_raw_image_cb(const unsigned char* data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write_raw_image(file, partition)
|
// write_raw_image(file, partition)
|
||||||
char* WriteRawImageFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
char* result = NULL;
|
char* result = NULL;
|
||||||
|
|
||||||
char* partition;
|
char* partition;
|
||||||
char* filename;
|
char* filename;
|
||||||
if (ReadArgs(cookie, argv, 2, &filename, &partition) < 0) {
|
if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(partition) == 0) {
|
if (strlen(partition) == 0) {
|
||||||
ErrorAbort(cookie, "partition argument to %s can't be empty", name);
|
ErrorAbort(state, "partition argument to %s can't be empty", name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (strlen(filename) == 0) {
|
if (strlen(filename) == 0) {
|
||||||
ErrorAbort(cookie, "file argument to %s can't be empty", name);
|
ErrorAbort(state, "file argument to %s can't be empty", name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,6 +516,13 @@ char* WriteRawImageFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
|||||||
free(buffer);
|
free(buffer);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
|
if (mtd_erase_blocks(ctx, -1) == -1) {
|
||||||
|
fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition);
|
||||||
|
}
|
||||||
|
if (mtd_write_close(ctx) != 0) {
|
||||||
|
fprintf(stderr, "%s: error closing write of %s\n", name, partition);
|
||||||
|
}
|
||||||
|
|
||||||
printf("%s %s partition from %s\n",
|
printf("%s %s partition from %s\n",
|
||||||
success ? "wrote" : "failed to write", partition, filename);
|
success ? "wrote" : "failed to write", partition, filename);
|
||||||
|
|
||||||
@@ -532,26 +540,26 @@ done:
|
|||||||
// file is not used until after updater exits
|
// file is not used until after updater exits
|
||||||
//
|
//
|
||||||
// TODO: this should live in some HTC-specific library
|
// TODO: this should live in some HTC-specific library
|
||||||
char* WriteFirmwareImageFn(const char* name, void* cookie,
|
char* WriteFirmwareImageFn(const char* name, State* state,
|
||||||
int argc, Expr* argv[]) {
|
int argc, Expr* argv[]) {
|
||||||
char* result = NULL;
|
char* result = NULL;
|
||||||
|
|
||||||
char* partition;
|
char* partition;
|
||||||
char* filename;
|
char* filename;
|
||||||
if (ReadArgs(cookie, argv, 2, &filename, &partition) < 0) {
|
if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(partition) == 0) {
|
if (strlen(partition) == 0) {
|
||||||
ErrorAbort(cookie, "partition argument to %s can't be empty", name);
|
ErrorAbort(state, "partition argument to %s can't be empty", name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (strlen(filename) == 0) {
|
if (strlen(filename) == 0) {
|
||||||
ErrorAbort(cookie, "file argument to %s can't be empty", name);
|
ErrorAbort(state, "file argument to %s can't be empty", name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* cmd = ((UpdaterInfo*)cookie)->cmd_pipe;
|
FILE* cmd = ((UpdaterInfo*)(state->cookie))->cmd_pipe;
|
||||||
fprintf(cmd, "firmware %s %s\n", partition, filename);
|
fprintf(cmd, "firmware %s %s\n", partition, filename);
|
||||||
|
|
||||||
printf("will write %s firmware from %s\n", partition, filename);
|
printf("will write %s firmware from %s\n", partition, filename);
|
||||||
@@ -569,7 +577,7 @@ extern int applypatch(int argc, char** argv);
|
|||||||
// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...)
|
// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...)
|
||||||
// apply_patch_check(file, sha1, ...)
|
// apply_patch_check(file, sha1, ...)
|
||||||
// apply_patch_space(bytes)
|
// apply_patch_space(bytes)
|
||||||
char* ApplyPatchFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
char* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
printf("in applypatchfn (%s)\n", name);
|
printf("in applypatchfn (%s)\n", name);
|
||||||
|
|
||||||
char* prepend = NULL;
|
char* prepend = NULL;
|
||||||
@@ -579,7 +587,7 @@ char* ApplyPatchFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
|||||||
prepend = "-s";
|
prepend = "-s";
|
||||||
}
|
}
|
||||||
|
|
||||||
char** args = ReadVarArgs(cookie, argc, argv);
|
char** args = ReadVarArgs(state, argc, argv);
|
||||||
if (args == NULL) return NULL;
|
if (args == NULL) return NULL;
|
||||||
|
|
||||||
// insert the "program name" argv[0] and a copy of the "prepend"
|
// insert the "program name" argv[0] and a copy of the "prepend"
|
||||||
@@ -610,10 +618,42 @@ char* ApplyPatchFn(const char* name, void* cookie, int argc, Expr* argv[]) {
|
|||||||
switch (result) {
|
switch (result) {
|
||||||
case 0: return strdup("t");
|
case 0: return strdup("t");
|
||||||
case 1: return strdup("");
|
case 1: return strdup("");
|
||||||
default: return ErrorAbort(cookie, "applypatch couldn't parse args");
|
default: return ErrorAbort(state, "applypatch couldn't parse args");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
|
char** args = ReadVarArgs(state, argc, argv);
|
||||||
|
if (args == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < argc; ++i) {
|
||||||
|
size += strlen(args[i]);
|
||||||
|
}
|
||||||
|
char* buffer = malloc(size+1);
|
||||||
|
size = 0;
|
||||||
|
for (i = 0; i < argc; ++i) {
|
||||||
|
strcpy(buffer+size, args[i]);
|
||||||
|
size += strlen(args[i]);
|
||||||
|
free(args[i]);
|
||||||
|
}
|
||||||
|
free(args);
|
||||||
|
buffer[size] = '\0';
|
||||||
|
|
||||||
|
char* line = strtok(buffer, "\n");
|
||||||
|
while (line) {
|
||||||
|
fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
|
||||||
|
"ui_print %s\n", line);
|
||||||
|
line = strtok(NULL, "\n");
|
||||||
|
}
|
||||||
|
fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void RegisterInstallFunctions() {
|
void RegisterInstallFunctions() {
|
||||||
RegisterFunction("mount", MountFn);
|
RegisterFunction("mount", MountFn);
|
||||||
@@ -636,4 +676,6 @@ void RegisterInstallFunctions() {
|
|||||||
RegisterFunction("apply_patch", ApplyPatchFn);
|
RegisterFunction("apply_patch", ApplyPatchFn);
|
||||||
RegisterFunction("apply_patch_check", ApplyPatchFn);
|
RegisterFunction("apply_patch_check", ApplyPatchFn);
|
||||||
RegisterFunction("apply_patch_space", ApplyPatchFn);
|
RegisterFunction("apply_patch_space", ApplyPatchFn);
|
||||||
|
|
||||||
|
RegisterFunction("ui_print", UIPrintFn);
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-5
@@ -94,12 +94,26 @@ int main(int argc, char** argv) {
|
|||||||
updater_info.cmd_pipe = cmd_pipe;
|
updater_info.cmd_pipe = cmd_pipe;
|
||||||
updater_info.package_zip = &za;
|
updater_info.package_zip = &za;
|
||||||
|
|
||||||
char* result = Evaluate(&updater_info, root);
|
State state;
|
||||||
|
state.cookie = &updater_info;
|
||||||
|
state.script = script;
|
||||||
|
state.errmsg = NULL;
|
||||||
|
|
||||||
|
char* result = Evaluate(&state, root);
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
const char* errmsg = GetError();
|
if (state.errmsg == NULL) {
|
||||||
fprintf(stderr, "script aborted with error: %s\n",
|
fprintf(stderr, "script aborted (no error message)\n");
|
||||||
errmsg == NULL ? "(none)" : errmsg);
|
fprintf(cmd_pipe, "ui_print script aborted (no error message)\n");
|
||||||
ClearError();
|
} else {
|
||||||
|
fprintf(stderr, "script aborted: %s\n", state.errmsg);
|
||||||
|
char* line = strtok(state.errmsg, "\n");
|
||||||
|
while (line) {
|
||||||
|
fprintf(cmd_pipe, "ui_print %s\n", line);
|
||||||
|
line = strtok(NULL, "\n");
|
||||||
|
}
|
||||||
|
fprintf(cmd_pipe, "ui_print\n");
|
||||||
|
}
|
||||||
|
free(state.errmsg);
|
||||||
return 7;
|
return 7;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "script result was [%s]\n", result);
|
fprintf(stderr, "script result was [%s]\n", result);
|
||||||
@@ -107,6 +121,7 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mzCloseZipArchive(&za);
|
mzCloseZipArchive(&za);
|
||||||
|
free(script);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user