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:
Doug Zongker 2009-06-12 12:24:39 -07:00
parent 8edb00c990
commit d9c9d10d9d
9 changed files with 665 additions and 500 deletions

View file

@ -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]);
}
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';
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;
done:
for (i = 0; i < argc; ++i) {
free(strings[i]);
}
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;
}
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(cookie, argv[1]);
} else {
if (argc == 3) {
free(cond);
return Evaluate(cookie, argv[2]);
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* 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;
char* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
char* msg = NULL;
if (argc > 0) {
msg = Evaluate(state, argv[0]);
}
int b = BooleanString(v);
free(v);
if (!b) {
SetError("assert() failed");
return NULL;
free(state->errmsg);
if (msg) {
state->errmsg = msg;
} else {
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;
}
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* 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;
}
}
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("");
} 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[]) {
char* needle = Evaluate(cookie, argv[0]);
if (needle == NULL) return NULL;
char* haystack = Evaluate(cookie, argv[1]);
if (haystack == NULL) {
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, 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);
return NULL;
}
char* result = strdup(strstr(haystack, needle) ? "t" : "");
free(needle);
free(haystack);
return result;
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) {
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* 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* 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* 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;
}
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* 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]);
}
char* Literal(const char* name, void* cookie, int argc, Expr* argv[]) {
return strdup(name);
char* Literal(const char* name, State* state, int argc, Expr* argv[]) {
return strdup(name);
}
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;
}
// -----------------------------------------------------------------
// 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;
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;
}

View file

@ -17,45 +17,64 @@
#ifndef _EXPRESSION_H
#define _EXPRESSION_H
#include "yydefs.h"
#define MAX_STRING_LEN 1024
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[]);
struct Expr {
Function fn;
char* name;
int argc;
Expr** argv;
Function fn;
char* name;
int argc;
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.
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.
// ("concat" is also available as a builtin function, to concatenate
// more than two strings.)
char* ConcatFn(const char* name, void* cookie, int argc, Expr* argv[]);
char* LogicalAndFn(const char* name, void* cookie, int argc, Expr* argv[]);
char* LogicalOrFn(const char* name, void* cookie, int argc, Expr* argv[]);
char* LogicalNotFn(const char* name, void* cookie, int argc, Expr* argv[]);
char* SubstringFn(const char* name, void* cookie, int argc, Expr* argv[]);
char* EqualityFn(const char* name, void* cookie, int argc, Expr* argv[]);
char* InequalityFn(const char* name, void* cookie, int argc, Expr* argv[]);
char* SequenceFn(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, State* state, int argc, Expr* argv[]);
char* LogicalOrFn(const char* name, State* state, int argc, Expr* argv[]);
char* LogicalNotFn(const char* name, State* state, int argc, Expr* argv[]);
char* SubstringFn(const char* name, State* state, int argc, Expr* argv[]);
char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]);
char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]);
char* SequenceFn(const char* name, State* state, int argc, Expr* argv[]);
// Convenience function for building expressions with a fixed number
// of arguments.
Expr* Build(Function fn, int count, ...);
Expr* Build(Function fn, YYLTYPE loc, int count, ...);
// Global builtins, registered by RegisterBuiltins().
char* IfElseFn(const char* name, void* cookie, int argc, Expr* argv[]);
char* AssertFn(const char* name, void* cookie, int argc, Expr* argv[]);
char* AbortFn(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, State* state, 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
@ -91,13 +110,13 @@ Function FindFunction(const char* name);
// 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, ...);
int ReadArgs(State* state, Expr* argv[], int count, ...);
// 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** ReadVarArgs(State* state, int argc, Expr* argv[]);
#endif // _EXPRESSION_H

View file

@ -16,14 +16,20 @@
*/
#include "expr.h"
#include "yydefs.h"
#include "parser.h"
int gLine = 1;
int gColumn = 1;
int gPos = 0;
// TODO: enforce MAX_STRING_LEN during lexing
char string_buffer[MAX_STRING_LEN];
char* string_pos;
#define ADVANCE do {yylloc.start=gPos; yylloc.end=gPos+yyleng; \
gColumn+=yyleng; gPos+=yyleng;} while(0)
%}
%x STR
@ -34,27 +40,32 @@ char* string_pos;
\" {
++gColumn;
BEGIN(STR);
string_pos = string_buffer;
yylloc.start = gPos;
++gColumn;
++gPos;
}
<STR>{
\" {
++gColumn;
++gPos;
BEGIN(INITIAL);
*string_pos = '\0';
yylval.str = strdup(string_buffer);
yylloc.end = gPos;
return STRING;
}
\\n { gColumn += yyleng; *string_pos++ = '\n'; }
\\t { gColumn += yyleng; *string_pos++ = '\t'; }
\\\" { gColumn += yyleng; *string_pos++ = '\"'; }
\\\\ { gColumn += yyleng; *string_pos++ = '\\'; }
\\n { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\n'; }
\\t { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\t'; }
\\\" { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\"'; }
\\\\ { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\\'; }
\\x[0-9a-fA-F]{2} {
gColumn += yyleng;
gPos += yyleng;
int val;
sscanf(yytext+2, "%x", &val);
*string_pos++ = val;
@ -62,36 +73,38 @@ char* string_pos;
\n {
++gLine;
++gPos;
gColumn = 1;
*string_pos++ = yytext[0];
}
. {
++gColumn;
++gPos;
*string_pos++ = yytext[0];
}
}
if { gColumn += yyleng; return IF; }
then { gColumn += yyleng; return THEN; }
else { gColumn += yyleng; return ELSE; }
endif { gColumn += yyleng; return ENDIF; }
if ADVANCE; return IF;
then ADVANCE; return THEN;
else ADVANCE; return ELSE;
endif ADVANCE; return ENDIF;
[a-zA-Z0-9_:/.]+ {
gColumn += yyleng;
ADVANCE;
yylval.str = strdup(yytext);
return STRING;
}
\&\& { gColumn += yyleng; return AND; }
\|\| { gColumn += yyleng; return OR; }
== { gColumn += yyleng; return EQ; }
!= { gColumn += yyleng; return NE; }
\&\& ADVANCE; return AND;
\|\| ADVANCE; return OR;
== ADVANCE; return EQ;
!= 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;

View file

@ -21,152 +21,183 @@
#include "expr.h"
#include "parser.h"
extern int yyparse(Expr** root, int* error_count);
int expect(const char* expr_str, const char* expected, int* errors) {
Expr* e;
int error;
char* result;
Expr* e;
int error;
char* result;
printf(".");
printf(".");
yy_scan_string(expr_str);
error = yyparse(&e);
if (error > 0) {
fprintf(stderr, "error parsing \"%s\"\n", expr_str);
++*errors;
return 0;
}
yy_scan_string(expr_str);
int error_count = 0;
error = yyparse(&e, &error_count);
if (error > 0 || error_count > 0) {
fprintf(stderr, "error parsing \"%s\" (%d errors)\n",
expr_str, error_count);
++*errors;
return 0;
}
result = Evaluate(NULL, e);
if (result == NULL && expected != NULL) {
fprintf(stderr, "error evaluating \"%s\"\n", expr_str);
++*errors;
return 0;
}
State state;
state.cookie = NULL;
state.script = expr_str;
state.errmsg = NULL;
if (result == NULL && expected == NULL) {
return 1;
}
result = Evaluate(&state, e);
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);
return 0;
}
free(result);
return 1;
return 1;
}
int test() {
int errors = 0;
int errors = 0;
expect("a", "a", &errors);
expect("\"a\"", "a", &errors);
expect("\"\\x61\"", "a", &errors);
expect("# this is a comment\n"
" a\n"
" \n",
"a", &errors);
expect("a", "a", &errors);
expect("\"a\"", "a", &errors);
expect("\"\\x61\"", "a", &errors);
expect("# this is a comment\n"
" a\n"
" \n",
"a", &errors);
// sequence operator
expect("a; b; c", "c", &errors);
// sequence operator
expect("a; b; c", "c", &errors);
// string concat operator
expect("a + b", "ab", &errors);
expect("a + \n \"b\"", "ab", &errors);
expect("a + b +\nc\n", "abc", &errors);
// string concat operator
expect("a + b", "ab", &errors);
expect("a + \n \"b\"", "ab", &errors);
expect("a + b +\nc\n", "abc", &errors);
// string concat function
expect("concat(a, 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);
// string concat function
expect("concat(a, 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);
// logical and
expect("a && b", "b", &errors);
expect("a && \"\"", "", &errors);
expect("\"\" && b", "", &errors);
expect("\"\" && \"\"", "", &errors);
expect("\"\" && abort()", "", &errors); // test short-circuiting
expect("t && abort()", NULL, &errors);
// logical and
expect("a && b", "b", &errors);
expect("a && \"\"", "", &errors);
expect("\"\" && b", "", &errors);
expect("\"\" && \"\"", "", &errors);
expect("\"\" && abort()", "", &errors); // test short-circuiting
expect("t && abort()", NULL, &errors);
// logical or
expect("a || b", "a", &errors);
expect("a || \"\"", "a", &errors);
expect("\"\" || b", "b", &errors);
expect("\"\" || \"\"", "", &errors);
expect("a || abort()", "a", &errors); // test short-circuiting
expect("\"\" || abort()", NULL, &errors);
// logical or
expect("a || b", "a", &errors);
expect("a || \"\"", "a", &errors);
expect("\"\" || b", "b", &errors);
expect("\"\" || \"\"", "", &errors);
expect("a || abort()", "a", &errors); // test short-circuiting
expect("\"\" || abort()", NULL, &errors);
// logical not
expect("!a", "", &errors);
expect("! \"\"", "t", &errors);
expect("!!a", "t", &errors);
// logical not
expect("!a", "", &errors);
expect("! \"\"", "t", &errors);
expect("!!a", "t", &errors);
// precedence
expect("\"\" == \"\" && b", "b", &errors);
expect("a + b == ab", "t", &errors);
expect("ab == a + b", "t", &errors);
expect("a + (b == ab)", "a", &errors);
expect("(ab == a) + b", "b", &errors);
// precedence
expect("\"\" == \"\" && b", "b", &errors);
expect("a + b == ab", "t", &errors);
expect("ab == a + b", "t", &errors);
expect("a + (b == ab)", "a", &errors);
expect("(ab == a) + b", "b", &errors);
// substring function
expect("is_substring(cad, abracadabra)", "t", &errors);
expect("is_substring(abrac, abracadabra)", "t", &errors);
expect("is_substring(dabra, abracadabra)", "t", &errors);
expect("is_substring(cad, abracxadabra)", "", &errors);
expect("is_substring(abrac, axbracadabra)", "", &errors);
expect("is_substring(dabra, abracadabrxa)", "", &errors);
// substring function
expect("is_substring(cad, abracadabra)", "t", &errors);
expect("is_substring(abrac, abracadabra)", "t", &errors);
expect("is_substring(dabra, abracadabra)", "t", &errors);
expect("is_substring(cad, abracxadabra)", "", &errors);
expect("is_substring(abrac, axbracadabra)", "", &errors);
expect("is_substring(dabra, abracadabrxa)", "", &errors);
// ifelse function
expect("ifelse(t, yes, no)", "yes", &errors);
expect("ifelse(!t, yes, no)", "no", &errors);
expect("ifelse(t, yes, abort())", "yes", &errors);
expect("ifelse(!t, abort(), no)", "no", &errors);
// ifelse function
expect("ifelse(t, yes, no)", "yes", &errors);
expect("ifelse(!t, yes, no)", "no", &errors);
expect("ifelse(t, yes, abort())", "yes", &errors);
expect("ifelse(!t, abort(), no)", "no", &errors);
// if "statements"
expect("if t then yes else no endif", "yes", &errors);
expect("if \"\" then yes else no endif", "no", &errors);
expect("if \"\" then yes endif", "", &errors);
expect("if \"\"; t then yes endif", "yes", &errors);
// if "statements"
expect("if t then yes else no endif", "yes", &errors);
expect("if \"\" then yes else no endif", "no", &errors);
expect("if \"\" then yes endif", "", &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) {
RegisterBuiltins();
FinishRegistration();
RegisterBuiltins();
FinishRegistration();
if (argc == 1) {
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);
if (argc == 1) {
return test() != 0;
}
}
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;
}

View file

@ -20,6 +20,7 @@
#include <string.h>
#include "expr.h"
#include "yydefs.h"
#include "parser.h"
extern int gLine;
@ -30,6 +31,8 @@ int yyparse(Expr** root, int* error_count);
%}
%locations
%union {
char* str;
Expr* expr;
@ -68,19 +71,21 @@ expr: STRING {
$$->name = $1;
$$->argc = 0;
$$->argv = NULL;
$$->start = @$.start;
$$->end = @$.end;
}
| '(' expr ')' { $$ = $2; }
| expr ';' { $$ = $1; }
| expr ';' expr { $$ = Build(SequenceFn, 2, $1, $3); }
| error ';' expr { $$ = $3; }
| expr '+' expr { $$ = Build(ConcatFn, 2, $1, $3); }
| expr EQ expr { $$ = Build(EqualityFn, 2, $1, $3); }
| expr NE expr { $$ = Build(InequalityFn, 2, $1, $3); }
| expr AND expr { $$ = Build(LogicalAndFn, 2, $1, $3); }
| expr OR expr { $$ = Build(LogicalOrFn, 2, $1, $3); }
| '!' expr { $$ = Build(LogicalNotFn, 1, $2); }
| IF expr THEN expr ENDIF { $$ = Build(IfElseFn, 2, $2, $4); }
| IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, 3, $2, $4, $6); }
| '(' expr ')' { $$ = $2; $$->start=@$.start; $$->end=@$.end; }
| expr ';' { $$ = $1; $$->start=@1.start; $$->end=@1.end; }
| expr ';' expr { $$ = Build(SequenceFn, @$, 2, $1, $3); }
| error ';' expr { $$ = $3; $$->start=@$.start; $$->end=@$.end; }
| expr '+' expr { $$ = Build(ConcatFn, @$, 2, $1, $3); }
| expr EQ expr { $$ = Build(EqualityFn, @$, 2, $1, $3); }
| expr NE expr { $$ = Build(InequalityFn, @$, 2, $1, $3); }
| expr AND expr { $$ = Build(LogicalAndFn, @$, 2, $1, $3); }
| expr OR expr { $$ = Build(LogicalOrFn, @$, 2, $1, $3); }
| '!' expr { $$ = Build(LogicalNotFn, @$, 1, $2); }
| IF expr THEN expr ENDIF { $$ = Build(IfElseFn, @$, 2, $2, $4); }
| IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, @$, 3, $2, $4, $6); }
| STRING '(' arglist ')' {
$$ = malloc(sizeof(Expr));
$$->fn = FindFunction($1);
@ -93,6 +98,8 @@ expr: STRING {
$$->name = $1;
$$->argc = $3.argc;
$$->argv = $3.argv;
$$->start = @$.start;
$$->end = @$.end;
}
;

36
edify/yydefs.h Normal file
View file

@ -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

View file

@ -196,6 +196,9 @@ try_update_binary(const char *path, ZipArchive *zip) {
// arrange to install the contents of <filename> in the
// given partition on reboot.
//
// ui_print <string>
// display <string> on the screen.
//
// - the name of the package zip file.
//
@ -248,6 +251,13 @@ try_update_binary(const char *path, ZipArchive *zip) {
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 {
LOGE("unknown command [%s]\n", command);
}

View file

@ -32,13 +32,14 @@
#include "mtdutils/mtdutils.h"
#include "updater.h"
char* ErrorAbort(void* cookie, char* format, ...) {
char* ErrorAbort(State* state, char* format, ...) {
char* buffer = malloc(4096);
va_list v;
va_start(v, format);
vsnprintf(buffer, 4096, format, v);
va_end(v);
SetError(buffer);
free(state->errmsg);
state->errmsg = buffer;
return NULL;
}
@ -47,28 +48,28 @@ char* ErrorAbort(void* cookie, char* format, ...) {
//
// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem
// 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;
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* location;
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;
}
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;
}
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;
}
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;
}
@ -109,17 +110,17 @@ done:
// 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;
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;
if (ReadArgs(cookie, argv, 1, &mount_point) < 0) {
if (ReadArgs(state, argv, 1, &mount_point) < 0) {
return NULL;
}
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;
}
@ -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;
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;
if (ReadArgs(cookie, argv, 1, &mount_point) < 0) {
if (ReadArgs(state, argv, 1, &mount_point) < 0) {
return NULL;
}
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;
}
@ -170,23 +171,23 @@ done:
// format(type, location)
//
// 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;
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* location;
if (ReadArgs(cookie, argv, 2, &type, &location) < 0) {
if (ReadArgs(state, argv, 2, &type, &location) < 0) {
return NULL;
}
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;
}
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;
}
@ -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*));
int i;
for (i = 0; i < argc; ++i) {
paths[i] = Evaluate(cookie, argv[i]);
paths[i] = Evaluate(state, argv[i]);
if (paths[i] == NULL) {
int j;
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) {
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* sec_str;
if (ReadArgs(cookie, argv, 2, &frac_str, &sec_str) < 0) {
if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
return NULL;
}
double frac = strtod(frac_str, NULL);
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);
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)
char* PackageExtractDirFn(const char* name, void* cookie,
char* PackageExtractDirFn(const char* name, State* state,
int argc, Expr* argv[]) {
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* 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.
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)
char* PackageExtractFileFn(const char* name, void* cookie,
char* PackageExtractFileFn(const char* name, State* state,
int argc, Expr* argv[]) {
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* 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;
ZipArchive* za = ((UpdaterInfo*)cookie)->package_zip;
ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
const ZipEntry* entry = mzFindZipEntry(za, zip_path);
if (entry == NULL) {
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 ...
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) {
return ErrorAbort(cookie, "%s() expects 1+ args, got %d", name, argc);
return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
}
char* target;
target = Evaluate(cookie, argv[0]);
target = Evaluate(state, argv[0]);
if (target == NULL) return NULL;
char** srcs = ReadVarArgs(cookie, argc-1, argv+1);
char** srcs = ReadVarArgs(state, argc-1, argv+1);
if (srcs == NULL) {
free(target);
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;
bool recursive = (strcmp(name, "set_perm_recursive") == 0);
int min_args = 4 + (recursive ? 1 : 0);
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;
char* end;
@ -381,26 +382,26 @@ char* SetPermFn(const char* name, void* cookie, int argc, Expr* argv[]) {
int uid = strtoul(args[0], &end, 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;
}
int gid = strtoul(args[1], &end, 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;
}
if (recursive) {
int dir_mode = strtoul(args[2], &end, 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;
}
int file_mode = strtoul(args[3], &end, 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]);
goto done;
}
@ -411,7 +412,7 @@ char* SetPermFn(const char* name, void* cookie, int argc, Expr* argv[]) {
} else {
int mode = strtoul(args[2], &end, 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;
}
@ -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) {
return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc);
return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
}
char* key;
key = Evaluate(cookie, argv[0]);
key = Evaluate(state, argv[0]);
if (key == NULL) return NULL;
char value[PROPERTY_VALUE_MAX];
@ -457,21 +458,21 @@ static bool write_raw_image_cb(const unsigned char* data,
}
// 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* partition;
char* filename;
if (ReadArgs(cookie, argv, 2, &filename, &partition) < 0) {
if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
return NULL;
}
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;
}
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;
}
@ -515,6 +516,13 @@ char* WriteRawImageFn(const char* name, void* cookie, int argc, Expr* argv[]) {
free(buffer);
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",
success ? "wrote" : "failed to write", partition, filename);
@ -532,26 +540,26 @@ done:
// file is not used until after updater exits
//
// 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[]) {
char* result = NULL;
char* partition;
char* filename;
if (ReadArgs(cookie, argv, 2, &filename, &partition) < 0) {
if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
return NULL;
}
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;
}
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;
}
FILE* cmd = ((UpdaterInfo*)cookie)->cmd_pipe;
FILE* cmd = ((UpdaterInfo*)(state->cookie))->cmd_pipe;
fprintf(cmd, "firmware %s %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_check(file, sha1, ...)
// 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);
char* prepend = NULL;
@ -579,7 +587,7 @@ char* ApplyPatchFn(const char* name, void* cookie, int argc, Expr* argv[]) {
prepend = "-s";
}
char** args = ReadVarArgs(cookie, argc, argv);
char** args = ReadVarArgs(state, argc, argv);
if (args == NULL) return NULL;
// 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) {
case 0: return strdup("t");
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() {
RegisterFunction("mount", MountFn);
@ -636,4 +676,6 @@ void RegisterInstallFunctions() {
RegisterFunction("apply_patch", ApplyPatchFn);
RegisterFunction("apply_patch_check", ApplyPatchFn);
RegisterFunction("apply_patch_space", ApplyPatchFn);
RegisterFunction("ui_print", UIPrintFn);
}

View file

@ -94,12 +94,26 @@ int main(int argc, char** argv) {
updater_info.cmd_pipe = cmd_pipe;
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) {
const char* errmsg = GetError();
fprintf(stderr, "script aborted with error: %s\n",
errmsg == NULL ? "(none)" : errmsg);
ClearError();
if (state.errmsg == NULL) {
fprintf(stderr, "script aborted (no error message)\n");
fprintf(cmd_pipe, "ui_print script aborted (no error message)\n");
} 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;
} else {
fprintf(stderr, "script result was [%s]\n", result);
@ -107,6 +121,7 @@ int main(int argc, char** argv) {
}
mzCloseZipArchive(&za);
free(script);
return 0;
}