aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDoug Zongker2009-06-12 14:24:39 -0500
committerDoug Zongker2009-06-12 16:05:03 -0500
commitd9c9d10d9da76f067d3955bea71f7bb39e859fa5 (patch)
tree1e49a3a616c3147f871e79b1b15e2b2a63379cc1
parent8edb00c990e563e6f91b278a212f2edf877cf763 (diff)
downloadplatform-bootable-recovery-d9c9d10d9da76f067d3955bea71f7bb39e859fa5.tar.gz
platform-bootable-recovery-d9c9d10d9da76f067d3955bea71f7bb39e859fa5.tar.xz
platform-bootable-recovery-d9c9d10d9da76f067d3955bea71f7bb39e859fa5.zip
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".
-rw-r--r--edify/expr.c506
-rw-r--r--edify/expr.h61
-rw-r--r--edify/lexer.l47
-rw-r--r--edify/main.c301
-rw-r--r--edify/parser.y31
-rw-r--r--edify/yydefs.h36
-rw-r--r--install.c10
-rw-r--r--updater/install.c166
-rw-r--r--updater/updater.c25
9 files changed, 674 insertions, 509 deletions
diff --git a/edify/expr.c b/edify/expr.c
index 5470a2ba..406c67ea 100644
--- a/edify/expr.c
+++ b/edify/expr.c
@@ -29,249 +29,241 @@
29// - if Evaluate() on any argument returns NULL, return NULL. 29// - if Evaluate() on any argument returns NULL, return NULL.
30 30
31int BooleanString(const char* s) { 31int BooleanString(const char* s) {
32 return s[0] != '\0'; 32 return s[0] != '\0';
33} 33}
34 34
35char* Evaluate(void* cookie, Expr* expr) { 35char* Evaluate(State* state, Expr* expr) {
36 return expr->fn(expr->name, cookie, expr->argc, expr->argv); 36 return expr->fn(expr->name, state, expr->argc, expr->argv);
37} 37}
38 38
39char* ConcatFn(const char* name, void* cookie, int argc, Expr* argv[]) { 39char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
40 if (argc == 0) { 40 if (argc == 0) {
41 return strdup(""); 41 return strdup("");
42 } 42 }
43 char** strings = malloc(argc * sizeof(char*)); 43 char** strings = malloc(argc * sizeof(char*));
44 int i; 44 int i;
45 for (i = 0; i < argc; ++i) { 45 for (i = 0; i < argc; ++i) {
46 strings[i] = NULL; 46 strings[i] = NULL;
47 } 47 }
48 char* result = NULL; 48 char* result = NULL;
49 int length = 0; 49 int length = 0;
50 for (i = 0; i < argc; ++i) { 50 for (i = 0; i < argc; ++i) {
51 strings[i] = Evaluate(cookie, argv[i]); 51 strings[i] = Evaluate(state, argv[i]);
52 if (strings[i] == NULL) { 52 if (strings[i] == NULL) {
53 goto done; 53 goto done;
54 }
55 length += strlen(strings[i]);
56 }
57
58 result = malloc(length+1);
59 int p = 0;
60 for (i = 0; i < argc; ++i) {
61 strcpy(result+p, strings[i]);
62 p += strlen(strings[i]);
63 }
64 result[p] = '\0';
65
66 done:
67 for (i = 0; i < argc; ++i) {
68 free(strings[i]);
54 } 69 }
55 length += strlen(strings[i]); 70 return result;
56 }
57
58 result = malloc(length+1);
59 int p = 0;
60 for (i = 0; i < argc; ++i) {
61 strcpy(result+p, strings[i]);
62 p += strlen(strings[i]);
63 }
64 result[p] = '\0';
65
66done:
67 for (i = 0; i < argc; ++i) {
68 free(strings[i]);
69 }
70 return result;
71} 71}
72 72
73char* IfElseFn(const char* name, void* cookie, int argc, Expr* argv[]) { 73char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) {
74 if (argc != 2 && argc != 3) { 74 if (argc != 2 && argc != 3) {
75 return NULL; 75 return NULL;
76 } 76 }
77 char* cond = Evaluate(cookie, argv[0]); 77 char* cond = Evaluate(state, argv[0]);
78 if (cond == NULL) { 78 if (cond == NULL) {
79 return NULL; 79 return NULL;
80 } 80 }
81 81
82 if (BooleanString(cond) == true) { 82 if (BooleanString(cond) == true) {
83 free(cond); 83 free(cond);
84 return Evaluate(cookie, argv[1]); 84 return Evaluate(state, argv[1]);
85 } else {
86 if (argc == 3) {
87 free(cond);
88 return Evaluate(cookie, argv[2]);
89 } else { 85 } else {
90 return cond; 86 if (argc == 3) {
87 free(cond);
88 return Evaluate(state, argv[2]);
89 } else {
90 return cond;
91 }
91 } 92 }
92 }
93} 93}
94 94
95char* AbortFn(const char* name, void* cookie, int argc, Expr* argv[]) { 95char* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
96 char* msg = NULL; 96 char* msg = NULL;
97 if (argc > 0) { 97 if (argc > 0) {
98 msg = Evaluate(cookie, argv[0]); 98 msg = Evaluate(state, argv[0]);
99 } 99 }
100 SetError(msg == NULL ? "called abort()" : msg); 100 free(state->errmsg);
101 free(msg); 101 if (msg) {
102 return NULL; 102 state->errmsg = msg;
103 } else {
104 state->errmsg = strdup("called abort()");
105 }
106 return NULL;
103} 107}
104 108
105char* AssertFn(const char* name, void* cookie, int argc, Expr* argv[]) { 109char* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
106 int i; 110 int i;
107 for (i = 0; i < argc; ++i) { 111 for (i = 0; i < argc; ++i) {
108 char* v = Evaluate(cookie, argv[i]); 112 char* v = Evaluate(state, argv[i]);
109 if (v == NULL) { 113 if (v == NULL) {
110 return NULL; 114 return NULL;
111 } 115 }
112 int b = BooleanString(v); 116 int b = BooleanString(v);
113 free(v); 117 free(v);
114 if (!b) { 118 if (!b) {
115 SetError("assert() failed"); 119 int prefix_len;
116 return NULL; 120 int len = argv[i]->end - argv[i]->start;
121 char* err_src = malloc(len + 20);
122 strcpy(err_src, "assert failed: ");
123 prefix_len = strlen(err_src);
124 memcpy(err_src + prefix_len, state->script + argv[i]->start, len);
125 err_src[prefix_len + len] = '\0';
126 free(state->errmsg);
127 state->errmsg = err_src;
128 return NULL;
129 }
117 } 130 }
118 } 131 return strdup("");
119 return strdup("");
120} 132}
121 133
122char* SleepFn(const char* name, void* cookie, int argc, Expr* argv[]) { 134char* SleepFn(const char* name, State* state, int argc, Expr* argv[]) {
123 char* val = Evaluate(cookie, argv[0]); 135 char* val = Evaluate(state, argv[0]);
124 if (val == NULL) { 136 if (val == NULL) {
125 return NULL; 137 return NULL;
126 } 138 }
127 int v = strtol(val, NULL, 10); 139 int v = strtol(val, NULL, 10);
128 sleep(v); 140 sleep(v);
129 return val; 141 return val;
130} 142}
131 143
132char* PrintFn(const char* name, void* cookie, int argc, Expr* argv[]) { 144char* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) {
133 int i; 145 int i;
134 for (i = 0; i < argc; ++i) { 146 for (i = 0; i < argc; ++i) {
135 char* v = Evaluate(cookie, argv[i]); 147 char* v = Evaluate(state, argv[i]);
136 if (v == NULL) { 148 if (v == NULL) {
137 return NULL; 149 return NULL;
150 }
151 fputs(v, stdout);
152 free(v);
138 } 153 }
139 fputs(v, stdout); 154 return strdup("");
140 free(v);
141 }
142 return strdup("");
143} 155}
144 156
145char* LogicalAndFn(const char* name, void* cookie, 157char* LogicalAndFn(const char* name, State* state,
146 int argc, Expr* argv[]) { 158 int argc, Expr* argv[]) {
147 char* left = Evaluate(cookie, argv[0]); 159 char* left = Evaluate(state, argv[0]);
148 if (left == NULL) return NULL; 160 if (left == NULL) return NULL;
149 if (BooleanString(left) == true) { 161 if (BooleanString(left) == true) {
150 free(left); 162 free(left);
151 return Evaluate(cookie, argv[1]); 163 return Evaluate(state, argv[1]);
152 } else { 164 } else {
153 return left; 165 return left;
154 } 166 }
155} 167}
156 168
157char* LogicalOrFn(const char* name, void* cookie, 169char* LogicalOrFn(const char* name, State* state,
158 int argc, Expr* argv[]) { 170 int argc, Expr* argv[]) {
159 char* left = Evaluate(cookie, argv[0]); 171 char* left = Evaluate(state, argv[0]);
160 if (left == NULL) return NULL; 172 if (left == NULL) return NULL;
161 if (BooleanString(left) == false) { 173 if (BooleanString(left) == false) {
162 free(left); 174 free(left);
163 return Evaluate(cookie, argv[1]); 175 return Evaluate(state, argv[1]);
164 } else { 176 } else {
165 return left; 177 return left;
166 } 178 }
167} 179}
168 180
169char* LogicalNotFn(const char* name, void* cookie, 181char* LogicalNotFn(const char* name, State* state,
170 int argc, Expr* argv[]) { 182 int argc, Expr* argv[]) {
171 char* val = Evaluate(cookie, argv[0]); 183 char* val = Evaluate(state, argv[0]);
172 if (val == NULL) return NULL; 184 if (val == NULL) return NULL;
173 bool bv = BooleanString(val); 185 bool bv = BooleanString(val);
174 free(val); 186 free(val);
175 if (bv) { 187 if (bv) {
176 return strdup(""); 188 return strdup("");
177 } else { 189 } else {
178 return strdup("t"); 190 return strdup("t");
179 } 191 }
180} 192}
181 193
182char* SubstringFn(const char* name, void* cookie, 194char* SubstringFn(const char* name, State* state,
183 int argc, Expr* argv[]) { 195 int argc, Expr* argv[]) {
184 char* needle = Evaluate(cookie, argv[0]); 196 char* needle = Evaluate(state, argv[0]);
185 if (needle == NULL) return NULL; 197 if (needle == NULL) return NULL;
186 char* haystack = Evaluate(cookie, argv[1]); 198 char* haystack = Evaluate(state, argv[1]);
187 if (haystack == NULL) { 199 if (haystack == NULL) {
188 free(needle); 200 free(needle);
189 return NULL; 201 return NULL;
190 } 202 }
191 203
192 char* result = strdup(strstr(haystack, needle) ? "t" : ""); 204 char* result = strdup(strstr(haystack, needle) ? "t" : "");
193 free(needle); 205 free(needle);
194 free(haystack); 206 free(haystack);
195 return result; 207 return result;
196} 208}
197 209
198char* EqualityFn(const char* name, void* cookie, int argc, Expr* argv[]) { 210char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) {
199 char* left = Evaluate(cookie, argv[0]); 211 char* left = Evaluate(state, argv[0]);
200 if (left == NULL) return NULL; 212 if (left == NULL) return NULL;
201 char* right = Evaluate(cookie, argv[1]); 213 char* right = Evaluate(state, argv[1]);
202 if (right == NULL) { 214 if (right == NULL) {
203 free(left); 215 free(left);
204 return NULL; 216 return NULL;
205 } 217 }
206
207 char* result = strdup(strcmp(left, right) == 0 ? "t" : "");
208 free(left);
209 free(right);
210 return result;
211}
212 218
213char* InequalityFn(const char* name, void* cookie, int argc, Expr* argv[]) { 219 char* result = strdup(strcmp(left, right) == 0 ? "t" : "");
214 char* left = Evaluate(cookie, argv[0]);
215 if (left == NULL) return NULL;
216 char* right = Evaluate(cookie, argv[1]);
217 if (right == NULL) {
218 free(left); 220 free(left);
219 return NULL; 221 free(right);
220 } 222 return result;
221
222 char* result = strdup(strcmp(left, right) != 0 ? "t" : "");
223 free(left);
224 free(right);
225 return result;
226} 223}
227 224
228char* SequenceFn(const char* name, void* cookie, int argc, Expr* argv[]) { 225char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) {
229 char* left = Evaluate(cookie, argv[0]); 226 char* left = Evaluate(state, argv[0]);
230 if (left == NULL) return NULL; 227 if (left == NULL) return NULL;
231 free(left); 228 char* right = Evaluate(state, argv[1]);
232 return Evaluate(cookie, argv[1]); 229 if (right == NULL) {
233} 230 free(left);
234 231 return NULL;
235char* Literal(const char* name, void* cookie, int argc, Expr* argv[]) { 232 }
236 return strdup(name);
237}
238 233
239Expr* Build(Function fn, int count, ...) { 234 char* result = strdup(strcmp(left, right) != 0 ? "t" : "");
240 va_list v; 235 free(left);
241 va_start(v, count); 236 free(right);
242 Expr* e = malloc(sizeof(Expr)); 237 return result;
243 e->fn = fn;
244 e->name = "(operator)";
245 e->argc = count;
246 e->argv = malloc(count * sizeof(Expr*));
247 int i;
248 for (i = 0; i < count; ++i) {
249 e->argv[i] = va_arg(v, Expr*);
250 }
251 va_end(v);
252 return e;
253} 238}
254 239
255// ----------------------------------------------------------------- 240char* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) {
256// error reporting 241 char* left = Evaluate(state, argv[0]);
257// ----------------------------------------------------------------- 242 if (left == NULL) return NULL;
258 243 free(left);
259static char* error_message = NULL; 244 return Evaluate(state, argv[1]);
260
261void SetError(const char* message) {
262 if (error_message) {
263 free(error_message);
264 }
265 error_message = strdup(message);
266} 245}
267 246
268const char* GetError() { 247char* Literal(const char* name, State* state, int argc, Expr* argv[]) {
269 return error_message; 248 return strdup(name);
270} 249}
271 250
272void ClearError() { 251Expr* Build(Function fn, YYLTYPE loc, int count, ...) {
273 free(error_message); 252 va_list v;
274 error_message = NULL; 253 va_start(v, count);
254 Expr* e = malloc(sizeof(Expr));
255 e->fn = fn;
256 e->name = "(operator)";
257 e->argc = count;
258 e->argv = malloc(count * sizeof(Expr*));
259 int i;
260 for (i = 0; i < count; ++i) {
261 e->argv[i] = va_arg(v, Expr*);
262 }
263 va_end(v);
264 e->start = loc.start;
265 e->end = loc.end;
266 return e;
275} 267}
276 268
277// ----------------------------------------------------------------- 269// -----------------------------------------------------------------
@@ -283,44 +275,44 @@ static int fn_size = 0;
283NamedFunction* fn_table = NULL; 275NamedFunction* fn_table = NULL;
284 276
285void RegisterFunction(const char* name, Function fn) { 277void RegisterFunction(const char* name, Function fn) {
286 if (fn_entries >= fn_size) { 278 if (fn_entries >= fn_size) {
287 fn_size = fn_size*2 + 1; 279 fn_size = fn_size*2 + 1;
288 fn_table = realloc(fn_table, fn_size * sizeof(NamedFunction)); 280 fn_table = realloc(fn_table, fn_size * sizeof(NamedFunction));
289 } 281 }
290 fn_table[fn_entries].name = name; 282 fn_table[fn_entries].name = name;
291 fn_table[fn_entries].fn = fn; 283 fn_table[fn_entries].fn = fn;
292 ++fn_entries; 284 ++fn_entries;
293} 285}
294 286
295static int fn_entry_compare(const void* a, const void* b) { 287static int fn_entry_compare(const void* a, const void* b) {
296 const char* na = ((const NamedFunction*)a)->name; 288 const char* na = ((const NamedFunction*)a)->name;
297 const char* nb = ((const NamedFunction*)b)->name; 289 const char* nb = ((const NamedFunction*)b)->name;
298 return strcmp(na, nb); 290 return strcmp(na, nb);
299} 291}
300 292
301void FinishRegistration() { 293void FinishRegistration() {
302 qsort(fn_table, fn_entries, sizeof(NamedFunction), fn_entry_compare); 294 qsort(fn_table, fn_entries, sizeof(NamedFunction), fn_entry_compare);
303} 295}
304 296
305Function FindFunction(const char* name) { 297Function FindFunction(const char* name) {
306 NamedFunction key; 298 NamedFunction key;
307 key.name = name; 299 key.name = name;
308 NamedFunction* nf = bsearch(&key, fn_table, fn_entries, sizeof(NamedFunction), 300 NamedFunction* nf = bsearch(&key, fn_table, fn_entries,
309 fn_entry_compare); 301 sizeof(NamedFunction), fn_entry_compare);
310 if (nf == NULL) { 302 if (nf == NULL) {
311 return NULL; 303 return NULL;
312 } 304 }
313 return nf->fn; 305 return nf->fn;
314} 306}
315 307
316void RegisterBuiltins() { 308void RegisterBuiltins() {
317 RegisterFunction("ifelse", IfElseFn); 309 RegisterFunction("ifelse", IfElseFn);
318 RegisterFunction("abort", AbortFn); 310 RegisterFunction("abort", AbortFn);
319 RegisterFunction("assert", AssertFn); 311 RegisterFunction("assert", AssertFn);
320 RegisterFunction("concat", ConcatFn); 312 RegisterFunction("concat", ConcatFn);
321 RegisterFunction("is_substring", SubstringFn); 313 RegisterFunction("is_substring", SubstringFn);
322 RegisterFunction("print", PrintFn); 314 RegisterFunction("stdout", StdoutFn);
323 RegisterFunction("sleep", SleepFn); 315 RegisterFunction("sleep", SleepFn);
324} 316}
325 317
326 318
@@ -331,44 +323,44 @@ void RegisterBuiltins() {
331// Evaluate the expressions in argv, giving 'count' char* (the ... is 323// Evaluate the expressions in argv, giving 'count' char* (the ... is
332// zero or more char** to put them in). If any expression evaluates 324// zero or more char** to put them in). If any expression evaluates
333// to NULL, free the rest and return -1. Return 0 on success. 325// to NULL, free the rest and return -1. Return 0 on success.
334int ReadArgs(void* cookie, Expr* argv[], int count, ...) { 326int ReadArgs(State* state, Expr* argv[], int count, ...) {
335 char** args = malloc(count * sizeof(char*)); 327 char** args = malloc(count * sizeof(char*));
336 va_list v; 328 va_list v;
337 va_start(v, count); 329 va_start(v, count);
338 int i; 330 int i;
339 for (i = 0; i < count; ++i) { 331 for (i = 0; i < count; ++i) {
340 args[i] = Evaluate(cookie, argv[i]); 332 args[i] = Evaluate(state, argv[i]);
341 if (args[i] == NULL) { 333 if (args[i] == NULL) {
342 va_end(v); 334 va_end(v);
343 int j; 335 int j;
344 for (j = 0; j < i; ++j) { 336 for (j = 0; j < i; ++j) {
345 free(args[j]); 337 free(args[j]);
346 } 338 }
347 return -1; 339 return -1;
340 }
341 *(va_arg(v, char**)) = args[i];
348 } 342 }
349 *(va_arg(v, char**)) = args[i]; 343 va_end(v);
350 } 344 return 0;
351 va_end(v);
352 return 0;
353} 345}
354 346
355// Evaluate the expressions in argv, returning an array of char* 347// Evaluate the expressions in argv, returning an array of char*
356// results. If any evaluate to NULL, free the rest and return NULL. 348// results. If any evaluate to NULL, free the rest and return NULL.
357// The caller is responsible for freeing the returned array and the 349// The caller is responsible for freeing the returned array and the
358// strings it contains. 350// strings it contains.
359char** ReadVarArgs(void* cookie, int argc, Expr* argv[]) { 351char** ReadVarArgs(State* state, int argc, Expr* argv[]) {
360 char** args = (char**)malloc(argc * sizeof(char*)); 352 char** args = (char**)malloc(argc * sizeof(char*));
361 int i = 0; 353 int i = 0;
362 for (i = 0; i < argc; ++i) { 354 for (i = 0; i < argc; ++i) {
363 args[i] = Evaluate(cookie, argv[i]); 355 args[i] = Evaluate(state, argv[i]);
364 if (args[i] == NULL) { 356 if (args[i] == NULL) {
365 int j; 357 int j;
366 for (j = 0; j < i; ++j) { 358 for (j = 0; j < i; ++j) {
367 free(args[j]); 359 free(args[j]);
368 } 360 }
369 free(args); 361 free(args);
370 return NULL; 362 return NULL;
363 }
371 } 364 }
372 } 365 return args;
373 return args;
374} 366}
diff --git a/edify/expr.h b/edify/expr.h
index cfbef903..671b499b 100644
--- a/edify/expr.h
+++ b/edify/expr.h
@@ -17,45 +17,64 @@
17#ifndef _EXPRESSION_H 17#ifndef _EXPRESSION_H
18#define _EXPRESSION_H 18#define _EXPRESSION_H
19 19
20#include "yydefs.h"
21
20#define MAX_STRING_LEN 1024 22#define MAX_STRING_LEN 1024
21 23
22typedef struct Expr Expr; 24typedef struct Expr Expr;
23 25
24typedef char* (*Function)(const char* name, void* cookie, 26typedef struct {
27 // Optional pointer to app-specific data; the core of edify never
28 // uses this value.
29 void* cookie;
30
31 // The source of the original script. Must be NULL-terminated,
32 // and in writable memory (Evaluate may make temporary changes to
33 // it but will restore it when done).
34 char* script;
35
36 // The error message (if any) returned if the evaluation aborts.
37 // Should be NULL initially, will be either NULL or a malloc'd
38 // pointer after Evaluate() returns.
39 char* errmsg;
40} State;
41
42typedef char* (*Function)(const char* name, State* state,
25 int argc, Expr* argv[]); 43 int argc, Expr* argv[]);
26 44
27struct Expr { 45struct Expr {
28 Function fn; 46 Function fn;
29 char* name; 47 char* name;
30 int argc; 48 int argc;
31 Expr** argv; 49 Expr** argv;
50 int start, end;
32}; 51};
33 52
34char* Evaluate(void* cookie, Expr* expr); 53char* Evaluate(State* state, Expr* expr);
35 54
36// Glue to make an Expr out of a literal. 55// Glue to make an Expr out of a literal.
37char* Literal(const char* name, void* cookie, int argc, Expr* argv[]); 56char* Literal(const char* name, State* state, int argc, Expr* argv[]);
38 57
39// Functions corresponding to various syntactic sugar operators. 58// Functions corresponding to various syntactic sugar operators.
40// ("concat" is also available as a builtin function, to concatenate 59// ("concat" is also available as a builtin function, to concatenate
41// more than two strings.) 60// more than two strings.)
42char* ConcatFn(const char* name, void* cookie, int argc, Expr* argv[]); 61char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]);
43char* LogicalAndFn(const char* name, void* cookie, int argc, Expr* argv[]); 62char* LogicalAndFn(const char* name, State* state, int argc, Expr* argv[]);
44char* LogicalOrFn(const char* name, void* cookie, int argc, Expr* argv[]); 63char* LogicalOrFn(const char* name, State* state, int argc, Expr* argv[]);
45char* LogicalNotFn(const char* name, void* cookie, int argc, Expr* argv[]); 64char* LogicalNotFn(const char* name, State* state, int argc, Expr* argv[]);
46char* SubstringFn(const char* name, void* cookie, int argc, Expr* argv[]); 65char* SubstringFn(const char* name, State* state, int argc, Expr* argv[]);
47char* EqualityFn(const char* name, void* cookie, int argc, Expr* argv[]); 66char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]);
48char* InequalityFn(const char* name, void* cookie, int argc, Expr* argv[]); 67char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]);
49char* SequenceFn(const char* name, void* cookie, int argc, Expr* argv[]); 68char* SequenceFn(const char* name, State* state, int argc, Expr* argv[]);
50 69
51// Convenience function for building expressions with a fixed number 70// Convenience function for building expressions with a fixed number
52// of arguments. 71// of arguments.
53Expr* Build(Function fn, int count, ...); 72Expr* Build(Function fn, YYLTYPE loc, int count, ...);
54 73
55// Global builtins, registered by RegisterBuiltins(). 74// Global builtins, registered by RegisterBuiltins().
56char* IfElseFn(const char* name, void* cookie, int argc, Expr* argv[]); 75char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]);
57char* AssertFn(const char* name, void* cookie, int argc, Expr* argv[]); 76char* AssertFn(const char* name, State* state, int argc, Expr* argv[]);
58char* AbortFn(const char* name, void* cookie, int argc, Expr* argv[]); 77char* AbortFn(const char* name, State* state, int argc, Expr* argv[]);
59 78
60 79
61// For setting and getting the global error string (when returning 80// For setting and getting the global error string (when returning
@@ -91,13 +110,13 @@ Function FindFunction(const char* name);
91// Evaluate the expressions in argv, giving 'count' char* (the ... is 110// Evaluate the expressions in argv, giving 'count' char* (the ... is
92// zero or more char** to put them in). If any expression evaluates 111// zero or more char** to put them in). If any expression evaluates
93// to NULL, free the rest and return -1. Return 0 on success. 112// to NULL, free the rest and return -1. Return 0 on success.
94int ReadArgs(void* cookie, Expr* argv[], int count, ...); 113int ReadArgs(State* state, Expr* argv[], int count, ...);
95 114
96// Evaluate the expressions in argv, returning an array of char* 115// Evaluate the expressions in argv, returning an array of char*
97// results. If any evaluate to NULL, free the rest and return NULL. 116// results. If any evaluate to NULL, free the rest and return NULL.
98// The caller is responsible for freeing the returned array and the 117// The caller is responsible for freeing the returned array and the
99// strings it contains. 118// strings it contains.
100char** ReadVarArgs(void* cookie, int argc, Expr* argv[]); 119char** ReadVarArgs(State* state, int argc, Expr* argv[]);
101 120
102 121
103#endif // _EXPRESSION_H 122#endif // _EXPRESSION_H
diff --git a/edify/lexer.l b/edify/lexer.l
index cb5eb318..2c4489cc 100644
--- a/edify/lexer.l
+++ b/edify/lexer.l
@@ -16,14 +16,20 @@
16 */ 16 */
17 17
18#include "expr.h" 18#include "expr.h"
19#include "yydefs.h"
19#include "parser.h" 20#include "parser.h"
20 21
21int gLine = 1; 22int gLine = 1;
22int gColumn = 1; 23int gColumn = 1;
24int gPos = 0;
23 25
24// TODO: enforce MAX_STRING_LEN during lexing 26// TODO: enforce MAX_STRING_LEN during lexing
25char string_buffer[MAX_STRING_LEN]; 27char string_buffer[MAX_STRING_LEN];
26char* string_pos; 28char* string_pos;
29
30#define ADVANCE do {yylloc.start=gPos; yylloc.end=gPos+yyleng; \
31 gColumn+=yyleng; gPos+=yyleng;} while(0)
32
27%} 33%}
28 34
29%x STR 35%x STR
@@ -34,27 +40,32 @@ char* string_pos;
34 40
35 41
36\" { 42\" {
37 ++gColumn;
38 BEGIN(STR); 43 BEGIN(STR);
39 string_pos = string_buffer; 44 string_pos = string_buffer;
45 yylloc.start = gPos;
46 ++gColumn;
47 ++gPos;
40} 48}
41 49
42<STR>{ 50<STR>{
43 \" { 51 \" {
44 ++gColumn; 52 ++gColumn;
53 ++gPos;
45 BEGIN(INITIAL); 54 BEGIN(INITIAL);
46 *string_pos = '\0'; 55 *string_pos = '\0';
47 yylval.str = strdup(string_buffer); 56 yylval.str = strdup(string_buffer);
57 yylloc.end = gPos;
48 return STRING; 58 return STRING;
49 } 59 }
50 60
51 \\n { gColumn += yyleng; *string_pos++ = '\n'; } 61 \\n { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\n'; }
52 \\t { gColumn += yyleng; *string_pos++ = '\t'; } 62 \\t { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\t'; }
53 \\\" { gColumn += yyleng; *string_pos++ = '\"'; } 63 \\\" { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\"'; }
54 \\\\ { gColumn += yyleng; *string_pos++ = '\\'; } 64 \\\\ { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\\'; }
55 65
56 \\x[0-9a-fA-F]{2} { 66 \\x[0-9a-fA-F]{2} {
57 gColumn += yyleng; 67 gColumn += yyleng;
68 gPos += yyleng;
58 int val; 69 int val;
59 sscanf(yytext+2, "%x", &val); 70 sscanf(yytext+2, "%x", &val);
60 *string_pos++ = val; 71 *string_pos++ = val;
@@ -62,36 +73,38 @@ char* string_pos;
62 73
63 \n { 74 \n {
64 ++gLine; 75 ++gLine;
76 ++gPos;
65 gColumn = 1; 77 gColumn = 1;
66 *string_pos++ = yytext[0]; 78 *string_pos++ = yytext[0];
67 } 79 }
68 80
69 . { 81 . {
70 ++gColumn; 82 ++gColumn;
83 ++gPos;
71 *string_pos++ = yytext[0]; 84 *string_pos++ = yytext[0];
72 } 85 }
73} 86}
74 87
75if { gColumn += yyleng; return IF; } 88if ADVANCE; return IF;
76then { gColumn += yyleng; return THEN; } 89then ADVANCE; return THEN;
77else { gColumn += yyleng; return ELSE; } 90else ADVANCE; return ELSE;
78endif { gColumn += yyleng; return ENDIF; } 91endif ADVANCE; return ENDIF;
79 92
80[a-zA-Z0-9_:/.]+ { 93[a-zA-Z0-9_:/.]+ {
81 gColumn += yyleng; 94 ADVANCE;
82 yylval.str = strdup(yytext); 95 yylval.str = strdup(yytext);
83 return STRING; 96 return STRING;
84} 97}
85 98
86\&\& { gColumn += yyleng; return AND; } 99\&\& ADVANCE; return AND;
87\|\| { gColumn += yyleng; return OR; } 100\|\| ADVANCE; return OR;
88== { gColumn += yyleng; return EQ; } 101== ADVANCE; return EQ;
89!= { gColumn += yyleng; return NE; } 102!= ADVANCE; return NE;
90 103
91[+(),!;] { gColumn += yyleng; return yytext[0]; } 104[+(),!;] ADVANCE; return yytext[0];
92 105
93[ \t]+ gColumn += yyleng; 106[ \t]+ ADVANCE;
94 107
95(#.*)?\n { ++gLine; gColumn = 1; } 108(#.*)?\n gPos += yyleng; ++gLine; gColumn = 1;
96 109
97. return BAD; 110. return BAD;
diff --git a/edify/main.c b/edify/main.c
index 7da89e2e..03eefc69 100644
--- a/edify/main.c
+++ b/edify/main.c
@@ -21,152 +21,183 @@
21#include "expr.h" 21#include "expr.h"
22#include "parser.h" 22#include "parser.h"
23 23
24int expect(const char* expr_str, const char* expected, int* errors) { 24extern int yyparse(Expr** root, int* error_count);
25 Expr* e;
26 int error;
27 char* result;
28 25
29 printf("."); 26int expect(const char* expr_str, const char* expected, int* errors) {
27 Expr* e;
28 int error;
29 char* result;
30
31 printf(".");
32
33 yy_scan_string(expr_str);
34 int error_count = 0;
35 error = yyparse(&e, &error_count);
36 if (error > 0 || error_count > 0) {
37 fprintf(stderr, "error parsing \"%s\" (%d errors)\n",
38 expr_str, error_count);
39 ++*errors;
40 return 0;
41 }
30 42
31 yy_scan_string(expr_str); 43 State state;
32 error = yyparse(&e); 44 state.cookie = NULL;
33 if (error > 0) { 45 state.script = expr_str;
34 fprintf(stderr, "error parsing \"%s\"\n", expr_str); 46 state.errmsg = NULL;
35 ++*errors; 47
36 return 0; 48 result = Evaluate(&state, e);
37 } 49 free(state.errmsg);
50 if (result == NULL && expected != NULL) {
51 fprintf(stderr, "error evaluating \"%s\"\n", expr_str);
52 ++*errors;
53 return 0;
54 }
38 55
39 result = Evaluate(NULL, e); 56 if (result == NULL && expected == NULL) {
40 if (result == NULL && expected != NULL) { 57 return 1;
41 fprintf(stderr, "error evaluating \"%s\"\n", expr_str); 58 }
42 ++*errors;
43 return 0;
44 }
45 59
46 if (result == NULL && expected == NULL) { 60 if (strcmp(result, expected) != 0) {
47 return 1; 61 fprintf(stderr, "evaluating \"%s\": expected \"%s\", got \"%s\"\n",
48 } 62 expr_str, expected, result);
63 ++*errors;
64 free(result);
65 return 0;
66 }
49 67
50 if (strcmp(result, expected) != 0) {
51 fprintf(stderr, "evaluating \"%s\": expected \"%s\", got \"%s\"\n",
52 expr_str, expected, result);
53 ++*errors;
54 free(result); 68 free(result);
55 return 0; 69 return 1;
56 }
57
58 free(result);
59 return 1;
60} 70}
61 71
62int test() { 72int test() {
63 int errors = 0; 73 int errors = 0;
64 74
65 expect("a", "a", &errors); 75 expect("a", "a", &errors);
66 expect("\"a\"", "a", &errors); 76 expect("\"a\"", "a", &errors);
67 expect("\"\\x61\"", "a", &errors); 77 expect("\"\\x61\"", "a", &errors);
68 expect("# this is a comment\n" 78 expect("# this is a comment\n"
69 " a\n" 79 " a\n"
70 " \n", 80 " \n",
71 "a", &errors); 81 "a", &errors);
72 82
73 83
74 // sequence operator 84 // sequence operator
75 expect("a; b; c", "c", &errors); 85 expect("a; b; c", "c", &errors);
76 86
77 // string concat operator 87 // string concat operator
78 expect("a + b", "ab", &errors); 88 expect("a + b", "ab", &errors);
79 expect("a + \n \"b\"", "ab", &errors); 89 expect("a + \n \"b\"", "ab", &errors);
80 expect("a + b +\nc\n", "abc", &errors); 90 expect("a + b +\nc\n", "abc", &errors);
81 91
82 // string concat function 92 // string concat function
83 expect("concat(a, b)", "ab", &errors); 93 expect("concat(a, b)", "ab", &errors);
84 expect("concat(a,\n \"b\")", "ab", &errors); 94 expect("concat(a,\n \"b\")", "ab", &errors);
85 expect("concat(a + b,\nc,\"d\")", "abcd", &errors); 95 expect("concat(a + b,\nc,\"d\")", "abcd", &errors);
86 expect("\"concat\"(a + b,\nc,\"d\")", "abcd", &errors); 96 expect("\"concat\"(a + b,\nc,\"d\")", "abcd", &errors);
87 97
88 // logical and 98 // logical and
89 expect("a && b", "b", &errors); 99 expect("a && b", "b", &errors);
90 expect("a && \"\"", "", &errors); 100 expect("a && \"\"", "", &errors);
91 expect("\"\" && b", "", &errors); 101 expect("\"\" && b", "", &errors);
92 expect("\"\" && \"\"", "", &errors); 102 expect("\"\" && \"\"", "", &errors);
93 expect("\"\" && abort()", "", &errors); // test short-circuiting 103 expect("\"\" && abort()", "", &errors); // test short-circuiting
94 expect("t && abort()", NULL, &errors); 104 expect("t && abort()", NULL, &errors);
95 105
96 // logical or 106 // logical or
97 expect("a || b", "a", &errors); 107 expect("a || b", "a", &errors);
98 expect("a || \"\"", "a", &errors); 108 expect("a || \"\"", "a", &errors);
99 expect("\"\" || b", "b", &errors); 109 expect("\"\" || b", "b", &errors);
100 expect("\"\" || \"\"", "", &errors); 110 expect("\"\" || \"\"", "", &errors);
101 expect("a || abort()", "a", &errors); // test short-circuiting 111 expect("a || abort()", "a", &errors); // test short-circuiting
102 expect("\"\" || abort()", NULL, &errors); 112 expect("\"\" || abort()", NULL, &errors);
103 113
104 // logical not 114 // logical not
105 expect("!a", "", &errors); 115 expect("!a", "", &errors);
106 expect("! \"\"", "t", &errors); 116 expect("! \"\"", "t", &errors);
107 expect("!!a", "t", &errors); 117 expect("!!a", "t", &errors);
108 118
109 // precedence 119 // precedence
110 expect("\"\" == \"\" && b", "b", &errors); 120 expect("\"\" == \"\" && b", "b", &errors);
111 expect("a + b == ab", "t", &errors); 121 expect("a + b == ab", "t", &errors);
112 expect("ab == a + b", "t", &errors); 122 expect("ab == a + b", "t", &errors);
113 expect("a + (b == ab)", "a", &errors); 123 expect("a + (b == ab)", "a", &errors);
114 expect("(ab == a) + b", "b", &errors); 124 expect("(ab == a) + b", "b", &errors);
115 125
116 // substring function 126 // substring function
117 expect("is_substring(cad, abracadabra)", "t", &errors); 127 expect("is_substring(cad, abracadabra)", "t", &errors);
118 expect("is_substring(abrac, abracadabra)", "t", &errors); 128 expect("is_substring(abrac, abracadabra)", "t", &errors);
119 expect("is_substring(dabra, abracadabra)", "t", &errors); 129 expect("is_substring(dabra, abracadabra)", "t", &errors);
120 expect("is_substring(cad, abracxadabra)", "", &errors); 130 expect("is_substring(cad, abracxadabra)", "", &errors);
121 expect("is_substring(abrac, axbracadabra)", "", &errors); 131 expect("is_substring(abrac, axbracadabra)", "", &errors);
122 expect("is_substring(dabra, abracadabrxa)", "", &errors); 132 expect("is_substring(dabra, abracadabrxa)", "", &errors);
123 133
124 // ifelse function 134 // ifelse function
125 expect("ifelse(t, yes, no)", "yes", &errors); 135 expect("ifelse(t, yes, no)", "yes", &errors);
126 expect("ifelse(!t, yes, no)", "no", &errors); 136 expect("ifelse(!t, yes, no)", "no", &errors);
127 expect("ifelse(t, yes, abort())", "yes", &errors); 137 expect("ifelse(t, yes, abort())", "yes", &errors);
128 expect("ifelse(!t, abort(), no)", "no", &errors); 138 expect("ifelse(!t, abort(), no)", "no", &errors);
129 139
130 // if "statements" 140 // if "statements"
131 expect("if t then yes else no endif", "yes", &errors); 141 expect("if t then yes else no endif", "yes", &errors);
132 expect("if \"\" then yes else no endif", "no", &errors); 142 expect("if \"\" then yes else no endif", "no", &errors);
133 expect("if \"\" then yes endif", "", &errors); 143 expect("if \"\" then yes endif", "", &errors);
134 expect("if \"\"; t then yes endif", "yes", &errors); 144 expect("if \"\"; t then yes endif", "yes", &errors);
135 145
136 printf("\n"); 146 printf("\n");
137 147
138 return errors; 148 return errors;
149}
150
151void ExprDump(int depth, Expr* n, char* script) {
152 printf("%*s", depth*2, "");
153 char temp = script[n->end];
154 script[n->end] = '\0';
155 printf("%s %p (%d-%d) \"%s\"\n",
156 n->name == NULL ? "(NULL)" : n->name, n->fn, n->start, n->end,
157 script+n->start);
158 script[n->end] = temp;
159 int i;
160 for (i = 0; i < n->argc; ++i) {
161 ExprDump(depth+1, n->argv[i], script);
162 }
139} 163}
140 164
141int main(int argc, char** argv) { 165int main(int argc, char** argv) {
142 RegisterBuiltins(); 166 RegisterBuiltins();
143 FinishRegistration(); 167 FinishRegistration();
144 168
145 if (argc == 1) { 169 if (argc == 1) {
146 return test() != 0; 170 return test() != 0;
147 } 171 }
148 172
149 FILE* f = fopen(argv[1], "r"); 173 FILE* f = fopen(argv[1], "r");
150 char buffer[8192]; 174 char buffer[8192];
151 int size = fread(buffer, 1, 8191, f); 175 int size = fread(buffer, 1, 8191, f);
152 fclose(f); 176 fclose(f);
153 buffer[size] = '\0'; 177 buffer[size] = '\0';
154 178
155 Expr* root; 179 Expr* root;
156 int error_count = 0; 180 int error_count = 0;
157 yy_scan_bytes(buffer, size); 181 yy_scan_bytes(buffer, size);
158 int error = yyparse(&root, &error_count); 182 int error = yyparse(&root, &error_count);
159 printf("parse returned %d; %d errors encountered\n", error, error_count); 183 printf("parse returned %d; %d errors encountered\n", error, error_count);
160 if (error == 0 || error_count > 0) { 184 if (error == 0 || error_count > 0) {
161 char* result = Evaluate(NULL, root); 185
162 if (result == NULL) { 186 ExprDump(0, root, buffer);
163 char* errmsg = GetError(); 187
164 printf("result was NULL, message is: %s\n", 188 State state;
165 (errmsg == NULL ? "(NULL)" : errmsg)); 189 state.cookie = NULL;
166 ClearError(); 190 state.script = buffer;
167 } else { 191 state.errmsg = NULL;
168 printf("result is [%s]\n", result); 192
193 char* result = Evaluate(&state, root);
194 if (result == NULL) {
195 printf("result was NULL, message is: %s\n",
196 (state.errmsg == NULL ? "(NULL)" : state.errmsg));
197 free(state.errmsg);
198 } else {
199 printf("result is [%s]\n", result);
200 }
169 } 201 }
170 } 202 return 0;
171 return 0;
172} 203}
diff --git a/edify/parser.y b/edify/parser.y
index cf163c02..3f9ade14 100644
--- a/edify/parser.y
+++ b/edify/parser.y
@@ -20,6 +20,7 @@
20#include <string.h> 20#include <string.h>
21 21
22#include "expr.h" 22#include "expr.h"
23#include "yydefs.h"
23#include "parser.h" 24#include "parser.h"
24 25
25extern int gLine; 26extern int gLine;
@@ -30,6 +31,8 @@ int yyparse(Expr** root, int* error_count);
30 31
31%} 32%}
32 33
34%locations
35
33%union { 36%union {
34 char* str; 37 char* str;
35 Expr* expr; 38 Expr* expr;
@@ -68,19 +71,21 @@ expr: STRING {
68 $$->name = $1; 71 $$->name = $1;
69 $$->argc = 0; 72 $$->argc = 0;
70 $$->argv = NULL; 73 $$->argv = NULL;
74 $$->start = @$.start;
75 $$->end = @$.end;
71} 76}
72| '(' expr ')' { $$ = $2; } 77| '(' expr ')' { $$ = $2; $$->start=@$.start; $$->end=@$.end; }
73| expr ';' { $$ = $1; } 78| expr ';' { $$ = $1; $$->start=@1.start; $$->end=@1.end; }
74| expr ';' expr { $$ = Build(SequenceFn, 2, $1, $3); } 79| expr ';' expr { $$ = Build(SequenceFn, @$, 2, $1, $3); }
75| error ';' expr { $$ = $3; } 80| error ';' expr { $$ = $3; $$->start=@$.start; $$->end=@$.end; }
76| expr '+' expr { $$ = Build(ConcatFn, 2, $1, $3); } 81| expr '+' expr { $$ = Build(ConcatFn, @$, 2, $1, $3); }
77| expr EQ expr { $$ = Build(EqualityFn, 2, $1, $3); } 82| expr EQ expr { $$ = Build(EqualityFn, @$, 2, $1, $3); }
78| expr NE expr { $$ = Build(InequalityFn, 2, $1, $3); } 83| expr NE expr { $$ = Build(InequalityFn, @$, 2, $1, $3); }
79| expr AND expr { $$ = Build(LogicalAndFn, 2, $1, $3); } 84| expr AND expr { $$ = Build(LogicalAndFn, @$, 2, $1, $3); }
80| expr OR expr { $$ = Build(LogicalOrFn, 2, $1, $3); } 85| expr OR expr { $$ = Build(LogicalOrFn, @$, 2, $1, $3); }
81| '!' expr { $$ = Build(LogicalNotFn, 1, $2); } 86| '!' expr { $$ = Build(LogicalNotFn, @$, 1, $2); }
82| IF expr THEN expr ENDIF { $$ = Build(IfElseFn, 2, $2, $4); } 87| IF expr THEN expr ENDIF { $$ = Build(IfElseFn, @$, 2, $2, $4); }
83| IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, 3, $2, $4, $6); } 88| IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, @$, 3, $2, $4, $6); }
84| STRING '(' arglist ')' { 89| STRING '(' arglist ')' {
85 $$ = malloc(sizeof(Expr)); 90 $$ = malloc(sizeof(Expr));
86 $$->fn = FindFunction($1); 91 $$->fn = FindFunction($1);
@@ -93,6 +98,8 @@ expr: STRING {
93 $$->name = $1; 98 $$->name = $1;
94 $$->argc = $3.argc; 99 $$->argc = $3.argc;
95 $$->argv = $3.argv; 100 $$->argv = $3.argv;
101 $$->start = @$.start;
102 $$->end = @$.end;
96} 103}
97; 104;
98 105
diff --git a/edify/yydefs.h b/edify/yydefs.h
new file mode 100644
index 00000000..62578625
--- /dev/null
+++ b/edify/yydefs.h
@@ -0,0 +1,36 @@
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _YYDEFS_H_
18#define _YYDEFS_H_
19
20#define YYLTYPE YYLTYPE
21typedef struct {
22 int start, end;
23} YYLTYPE;
24
25#define YYLLOC_DEFAULT(Current, Rhs, N) \
26 do { \
27 if (N) { \
28 (Current).start = YYRHSLOC(Rhs, 1).start; \
29 (Current).end = YYRHSLOC(Rhs, N).end; \
30 } else { \
31 (Current).start = YYRHSLOC(Rhs, 0).start; \
32 (Current).end = YYRHSLOC(Rhs, 0).end; \
33 } \
34 } while (0)
35
36#endif
diff --git a/install.c b/install.c
index cca94002..c2e1385b 100644
--- a/install.c
+++ b/install.c
@@ -196,6 +196,9 @@ try_update_binary(const char *path, ZipArchive *zip) {
196 // arrange to install the contents of <filename> in the 196 // arrange to install the contents of <filename> in the
197 // given partition on reboot. 197 // given partition on reboot.
198 // 198 //
199 // ui_print <string>
200 // display <string> on the screen.
201 //
199 // - the name of the package zip file. 202 // - the name of the package zip file.
200 // 203 //
201 204
@@ -248,6 +251,13 @@ try_update_binary(const char *path, ZipArchive *zip) {
248 firmware_filename = strdup(filename); 251 firmware_filename = strdup(filename);
249 } 252 }
250 } 253 }
254 } else if (strcmp(command, "ui_print") == 0) {
255 char* str = strtok(NULL, "\n");
256 if (str) {
257 ui_print(str);
258 } else {
259 ui_print("\n");
260 }
251 } else { 261 } else {
252 LOGE("unknown command [%s]\n", command); 262 LOGE("unknown command [%s]\n", command);
253 } 263 }
diff --git a/updater/install.c b/updater/install.c
index 2e965cee..616cb2c8 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -32,13 +32,14 @@
32#include "mtdutils/mtdutils.h" 32#include "mtdutils/mtdutils.h"
33#include "updater.h" 33#include "updater.h"
34 34
35char* ErrorAbort(void* cookie, char* format, ...) { 35char* ErrorAbort(State* state, char* format, ...) {
36 char* buffer = malloc(4096); 36 char* buffer = malloc(4096);
37 va_list v; 37 va_list v;
38 va_start(v, format); 38 va_start(v, format);
39 vsnprintf(buffer, 4096, format, v); 39 vsnprintf(buffer, 4096, format, v);
40 va_end(v); 40 va_end(v);
41 SetError(buffer); 41 free(state->errmsg);
42 state->errmsg = buffer;
42 return NULL; 43 return NULL;
43} 44}
44 45
@@ -47,28 +48,28 @@ char* ErrorAbort(void* cookie, char* format, ...) {
47// 48//
48// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem 49// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem
49// type="vfat" location="/dev/block/<whatever>" to mount a device 50// type="vfat" location="/dev/block/<whatever>" to mount a device
50char* MountFn(const char* name, void* cookie, int argc, Expr* argv[]) { 51char* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
51 char* result = NULL; 52 char* result = NULL;
52 if (argc != 3) { 53 if (argc != 3) {
53 return ErrorAbort(cookie, "%s() expects 3 args, got %d", name, argc); 54 return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
54 } 55 }
55 char* type; 56 char* type;
56 char* location; 57 char* location;
57 char* mount_point; 58 char* mount_point;
58 if (ReadArgs(cookie, argv, 3, &type, &location, &mount_point) < 0) { 59 if (ReadArgs(state, argv, 3, &type, &location, &mount_point) < 0) {
59 return NULL; 60 return NULL;
60 } 61 }
61 62
62 if (strlen(type) == 0) { 63 if (strlen(type) == 0) {
63 ErrorAbort(cookie, "type argument to %s() can't be empty", name); 64 ErrorAbort(state, "type argument to %s() can't be empty", name);
64 goto done; 65 goto done;
65 } 66 }
66 if (strlen(location) == 0) { 67 if (strlen(location) == 0) {
67 ErrorAbort(cookie, "location argument to %s() can't be empty", name); 68 ErrorAbort(state, "location argument to %s() can't be empty", name);
68 goto done; 69 goto done;
69 } 70 }
70 if (strlen(mount_point) == 0) { 71 if (strlen(mount_point) == 0) {
71 ErrorAbort(cookie, "mount_point argument to %s() can't be empty", name); 72 ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
72 goto done; 73 goto done;
73 } 74 }
74 75
@@ -109,17 +110,17 @@ done:
109 110
110 111
111// is_mounted(mount_point) 112// is_mounted(mount_point)
112char* IsMountedFn(const char* name, void* cookie, int argc, Expr* argv[]) { 113char* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
113 char* result = NULL; 114 char* result = NULL;
114 if (argc != 1) { 115 if (argc != 1) {
115 return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc); 116 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
116 } 117 }
117 char* mount_point; 118 char* mount_point;
118 if (ReadArgs(cookie, argv, 1, &mount_point) < 0) { 119 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
119 return NULL; 120 return NULL;
120 } 121 }
121 if (strlen(mount_point) == 0) { 122 if (strlen(mount_point) == 0) {
122 ErrorAbort(cookie, "mount_point argument to unmount() can't be empty"); 123 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
123 goto done; 124 goto done;
124 } 125 }
125 126
@@ -137,17 +138,17 @@ done:
137} 138}
138 139
139 140
140char* UnmountFn(const char* name, void* cookie, int argc, Expr* argv[]) { 141char* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
141 char* result = NULL; 142 char* result = NULL;
142 if (argc != 1) { 143 if (argc != 1) {
143 return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc); 144 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
144 } 145 }
145 char* mount_point; 146 char* mount_point;
146 if (ReadArgs(cookie, argv, 1, &mount_point) < 0) { 147 if (ReadArgs(state, argv, 1, &mount_point) < 0) {
147 return NULL; 148 return NULL;
148 } 149 }
149 if (strlen(mount_point) == 0) { 150 if (strlen(mount_point) == 0) {
150 ErrorAbort(cookie, "mount_point argument to unmount() can't be empty"); 151 ErrorAbort(state, "mount_point argument to unmount() can't be empty");
151 goto done; 152 goto done;
152 } 153 }
153 154
@@ -170,23 +171,23 @@ done:
170// format(type, location) 171// format(type, location)
171// 172//
172// type="MTD" location=partition 173// type="MTD" location=partition
173char* FormatFn(const char* name, void* cookie, int argc, Expr* argv[]) { 174char* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
174 char* result = NULL; 175 char* result = NULL;
175 if (argc != 2) { 176 if (argc != 2) {
176 return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc); 177 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
177 } 178 }
178 char* type; 179 char* type;
179 char* location; 180 char* location;
180 if (ReadArgs(cookie, argv, 2, &type, &location) < 0) { 181 if (ReadArgs(state, argv, 2, &type, &location) < 0) {
181 return NULL; 182 return NULL;
182 } 183 }
183 184
184 if (strlen(type) == 0) { 185 if (strlen(type) == 0) {
185 ErrorAbort(cookie, "type argument to %s() can't be empty", name); 186 ErrorAbort(state, "type argument to %s() can't be empty", name);
186 goto done; 187 goto done;
187 } 188 }
188 if (strlen(location) == 0) { 189 if (strlen(location) == 0) {
189 ErrorAbort(cookie, "location argument to %s() can't be empty", name); 190 ErrorAbort(state, "location argument to %s() can't be empty", name);
190 goto done; 191 goto done;
191 } 192 }
192 193
@@ -228,11 +229,11 @@ done:
228} 229}
229 230
230 231
231char* DeleteFn(const char* name, void* cookie, int argc, Expr* argv[]) { 232char* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
232 char** paths = malloc(argc * sizeof(char*)); 233 char** paths = malloc(argc * sizeof(char*));
233 int i; 234 int i;
234 for (i = 0; i < argc; ++i) { 235 for (i = 0; i < argc; ++i) {
235 paths[i] = Evaluate(cookie, argv[i]); 236 paths[i] = Evaluate(state, argv[i]);
236 if (paths[i] == NULL) { 237 if (paths[i] == NULL) {
237 int j; 238 int j;
238 for (j = 0; j < i; ++i) { 239 for (j = 0; j < i; ++i) {
@@ -259,20 +260,20 @@ char* DeleteFn(const char* name, void* cookie, int argc, Expr* argv[]) {
259} 260}
260 261
261 262
262char* ShowProgressFn(const char* name, void* cookie, int argc, Expr* argv[]) { 263char* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
263 if (argc != 2) { 264 if (argc != 2) {
264 return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc); 265 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
265 } 266 }
266 char* frac_str; 267 char* frac_str;
267 char* sec_str; 268 char* sec_str;
268 if (ReadArgs(cookie, argv, 2, &frac_str, &sec_str) < 0) { 269 if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
269 return NULL; 270 return NULL;
270 } 271 }
271 272
272 double frac = strtod(frac_str, NULL); 273 double frac = strtod(frac_str, NULL);
273 int sec = strtol(sec_str, NULL, 10); 274 int sec = strtol(sec_str, NULL, 10);
274 275
275 UpdaterInfo* ui = (UpdaterInfo*)cookie; 276 UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
276 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec); 277 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
277 278
278 free(frac_str); 279 free(frac_str);
@@ -281,16 +282,16 @@ char* ShowProgressFn(const char* name, void* cookie, int argc, Expr* argv[]) {
281} 282}
282 283
283// package_extract_dir(package_path, destination_path) 284// package_extract_dir(package_path, destination_path)
284char* PackageExtractDirFn(const char* name, void* cookie, 285char* PackageExtractDirFn(const char* name, State* state,
285 int argc, Expr* argv[]) { 286 int argc, Expr* argv[]) {
286 if (argc != 2) { 287 if (argc != 2) {
287 return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc); 288 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
288 } 289 }
289 char* zip_path; 290 char* zip_path;
290 char* dest_path; 291 char* dest_path;
291 if (ReadArgs(cookie, argv, 2, &zip_path, &dest_path) < 0) return NULL; 292 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
292 293
293 ZipArchive* za = ((UpdaterInfo*)cookie)->package_zip; 294 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
294 295
295 // To create a consistent system image, never use the clock for timestamps. 296 // To create a consistent system image, never use the clock for timestamps.
296 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default 297 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
@@ -305,18 +306,18 @@ char* PackageExtractDirFn(const char* name, void* cookie,
305 306
306 307
307// package_extract_file(package_path, destination_path) 308// package_extract_file(package_path, destination_path)
308char* PackageExtractFileFn(const char* name, void* cookie, 309char* PackageExtractFileFn(const char* name, State* state,
309 int argc, Expr* argv[]) { 310 int argc, Expr* argv[]) {
310 if (argc != 2) { 311 if (argc != 2) {
311 return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc); 312 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
312 } 313 }
313 char* zip_path; 314 char* zip_path;
314 char* dest_path; 315 char* dest_path;
315 if (ReadArgs(cookie, argv, 2, &zip_path, &dest_path) < 0) return NULL; 316 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
316 317
317 bool success = false; 318 bool success = false;
318 319
319 ZipArchive* za = ((UpdaterInfo*)cookie)->package_zip; 320 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
320 const ZipEntry* entry = mzFindZipEntry(za, zip_path); 321 const ZipEntry* entry = mzFindZipEntry(za, zip_path);
321 if (entry == NULL) { 322 if (entry == NULL) {
322 fprintf(stderr, "%s: no %s in package\n", name, zip_path); 323 fprintf(stderr, "%s: no %s in package\n", name, zip_path);
@@ -340,15 +341,15 @@ char* PackageExtractFileFn(const char* name, void* cookie,
340 341
341 342
342// symlink target src1 src2 ... 343// symlink target src1 src2 ...
343char* SymlinkFn(const char* name, void* cookie, int argc, Expr* argv[]) { 344char* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
344 if (argc == 0) { 345 if (argc == 0) {
345 return ErrorAbort(cookie, "%s() expects 1+ args, got %d", name, argc); 346 return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
346 } 347 }
347 char* target; 348 char* target;
348 target = Evaluate(cookie, argv[0]); 349 target = Evaluate(state, argv[0]);
349 if (target == NULL) return NULL; 350 if (target == NULL) return NULL;
350 351
351 char** srcs = ReadVarArgs(cookie, argc-1, argv+1); 352 char** srcs = ReadVarArgs(state, argc-1, argv+1);
352 if (srcs == NULL) { 353 if (srcs == NULL) {
353 free(target); 354 free(target);
354 return NULL; 355 return NULL;
@@ -364,16 +365,16 @@ char* SymlinkFn(const char* name, void* cookie, int argc, Expr* argv[]) {
364} 365}
365 366
366 367
367char* SetPermFn(const char* name, void* cookie, int argc, Expr* argv[]) { 368char* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
368 char* result = NULL; 369 char* result = NULL;
369 bool recursive = (strcmp(name, "set_perm_recursive") == 0); 370 bool recursive = (strcmp(name, "set_perm_recursive") == 0);
370 371
371 int min_args = 4 + (recursive ? 1 : 0); 372 int min_args = 4 + (recursive ? 1 : 0);
372 if (argc < min_args) { 373 if (argc < min_args) {
373 return ErrorAbort(cookie, "%s() expects %d+ args, got %d", name, argc); 374 return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
374 } 375 }
375 376
376 char** args = ReadVarArgs(cookie, argc, argv); 377 char** args = ReadVarArgs(state, argc, argv);
377 if (args == NULL) return NULL; 378 if (args == NULL) return NULL;
378 379
379 char* end; 380 char* end;
@@ -381,26 +382,26 @@ char* SetPermFn(const char* name, void* cookie, int argc, Expr* argv[]) {
381 382
382 int uid = strtoul(args[0], &end, 0); 383 int uid = strtoul(args[0], &end, 0);
383 if (*end != '\0' || args[0][0] == 0) { 384 if (*end != '\0' || args[0][0] == 0) {
384 ErrorAbort(cookie, "%s: \"%s\" not a valid uid", name, args[0]); 385 ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
385 goto done; 386 goto done;
386 } 387 }
387 388
388 int gid = strtoul(args[1], &end, 0); 389 int gid = strtoul(args[1], &end, 0);
389 if (*end != '\0' || args[1][0] == 0) { 390 if (*end != '\0' || args[1][0] == 0) {
390 ErrorAbort(cookie, "%s: \"%s\" not a valid gid", name, args[1]); 391 ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
391 goto done; 392 goto done;
392 } 393 }
393 394
394 if (recursive) { 395 if (recursive) {
395 int dir_mode = strtoul(args[2], &end, 0); 396 int dir_mode = strtoul(args[2], &end, 0);
396 if (*end != '\0' || args[2][0] == 0) { 397 if (*end != '\0' || args[2][0] == 0) {
397 ErrorAbort(cookie, "%s: \"%s\" not a valid dirmode", name, args[2]); 398 ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
398 goto done; 399 goto done;
399 } 400 }
400 401
401 int file_mode = strtoul(args[3], &end, 0); 402 int file_mode = strtoul(args[3], &end, 0);
402 if (*end != '\0' || args[3][0] == 0) { 403 if (*end != '\0' || args[3][0] == 0) {
403 ErrorAbort(cookie, "%s: \"%s\" not a valid filemode", 404 ErrorAbort(state, "%s: \"%s\" not a valid filemode",
404 name, args[3]); 405 name, args[3]);
405 goto done; 406 goto done;
406 } 407 }
@@ -411,7 +412,7 @@ char* SetPermFn(const char* name, void* cookie, int argc, Expr* argv[]) {
411 } else { 412 } else {
412 int mode = strtoul(args[2], &end, 0); 413 int mode = strtoul(args[2], &end, 0);
413 if (*end != '\0' || args[2][0] == 0) { 414 if (*end != '\0' || args[2][0] == 0) {
414 ErrorAbort(cookie, "%s: \"%s\" not a valid mode", name, args[2]); 415 ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
415 goto done; 416 goto done;
416 } 417 }
417 418
@@ -432,12 +433,12 @@ done:
432} 433}
433 434
434 435
435char* GetPropFn(const char* name, void* cookie, int argc, Expr* argv[]) { 436char* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
436 if (argc != 1) { 437 if (argc != 1) {
437 return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc); 438 return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
438 } 439 }
439 char* key; 440 char* key;
440 key = Evaluate(cookie, argv[0]); 441 key = Evaluate(state, argv[0]);
441 if (key == NULL) return NULL; 442 if (key == NULL) return NULL;
442 443
443 char value[PROPERTY_VALUE_MAX]; 444 char value[PROPERTY_VALUE_MAX];
@@ -457,21 +458,21 @@ static bool write_raw_image_cb(const unsigned char* data,
457} 458}
458 459
459// write_raw_image(file, partition) 460// write_raw_image(file, partition)
460char* WriteRawImageFn(const char* name, void* cookie, int argc, Expr* argv[]) { 461char* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
461 char* result = NULL; 462 char* result = NULL;
462 463
463 char* partition; 464 char* partition;
464 char* filename; 465 char* filename;
465 if (ReadArgs(cookie, argv, 2, &filename, &partition) < 0) { 466 if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
466 return NULL; 467 return NULL;
467 } 468 }
468 469
469 if (strlen(partition) == 0) { 470 if (strlen(partition) == 0) {
470 ErrorAbort(cookie, "partition argument to %s can't be empty", name); 471 ErrorAbort(state, "partition argument to %s can't be empty", name);
471 goto done; 472 goto done;
472 } 473 }
473 if (strlen(filename) == 0) { 474 if (strlen(filename) == 0) {
474 ErrorAbort(cookie, "file argument to %s can't be empty", name); 475 ErrorAbort(state, "file argument to %s can't be empty", name);
475 goto done; 476 goto done;
476 } 477 }
477 478
@@ -515,6 +516,13 @@ char* WriteRawImageFn(const char* name, void* cookie, int argc, Expr* argv[]) {
515 free(buffer); 516 free(buffer);
516 fclose(f); 517 fclose(f);
517 518
519 if (mtd_erase_blocks(ctx, -1) == -1) {
520 fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition);
521 }
522 if (mtd_write_close(ctx) != 0) {
523 fprintf(stderr, "%s: error closing write of %s\n", name, partition);
524 }
525
518 printf("%s %s partition from %s\n", 526 printf("%s %s partition from %s\n",
519 success ? "wrote" : "failed to write", partition, filename); 527 success ? "wrote" : "failed to write", partition, filename);
520 528
@@ -532,26 +540,26 @@ done:
532// file is not used until after updater exits 540// file is not used until after updater exits
533// 541//
534// TODO: this should live in some HTC-specific library 542// TODO: this should live in some HTC-specific library
535char* WriteFirmwareImageFn(const char* name, void* cookie, 543char* WriteFirmwareImageFn(const char* name, State* state,
536 int argc, Expr* argv[]) { 544 int argc, Expr* argv[]) {
537 char* result = NULL; 545 char* result = NULL;
538 546
539 char* partition; 547 char* partition;
540 char* filename; 548 char* filename;
541 if (ReadArgs(cookie, argv, 2, &filename, &partition) < 0) { 549 if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
542 return NULL; 550 return NULL;
543 } 551 }
544 552
545 if (strlen(partition) == 0) { 553 if (strlen(partition) == 0) {
546 ErrorAbort(cookie, "partition argument to %s can't be empty", name); 554 ErrorAbort(state, "partition argument to %s can't be empty", name);
547 goto done; 555 goto done;
548 } 556 }
549 if (strlen(filename) == 0) { 557 if (strlen(filename) == 0) {
550 ErrorAbort(cookie, "file argument to %s can't be empty", name); 558 ErrorAbort(state, "file argument to %s can't be empty", name);
551 goto done; 559 goto done;
552 } 560 }
553 561
554 FILE* cmd = ((UpdaterInfo*)cookie)->cmd_pipe; 562 FILE* cmd = ((UpdaterInfo*)(state->cookie))->cmd_pipe;
555 fprintf(cmd, "firmware %s %s\n", partition, filename); 563 fprintf(cmd, "firmware %s %s\n", partition, filename);
556 564
557 printf("will write %s firmware from %s\n", partition, filename); 565 printf("will write %s firmware from %s\n", partition, filename);
@@ -569,7 +577,7 @@ extern int applypatch(int argc, char** argv);
569// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...) 577// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...)
570// apply_patch_check(file, sha1, ...) 578// apply_patch_check(file, sha1, ...)
571// apply_patch_space(bytes) 579// apply_patch_space(bytes)
572char* ApplyPatchFn(const char* name, void* cookie, int argc, Expr* argv[]) { 580char* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
573 printf("in applypatchfn (%s)\n", name); 581 printf("in applypatchfn (%s)\n", name);
574 582
575 char* prepend = NULL; 583 char* prepend = NULL;
@@ -579,7 +587,7 @@ char* ApplyPatchFn(const char* name, void* cookie, int argc, Expr* argv[]) {
579 prepend = "-s"; 587 prepend = "-s";
580 } 588 }
581 589
582 char** args = ReadVarArgs(cookie, argc, argv); 590 char** args = ReadVarArgs(state, argc, argv);
583 if (args == NULL) return NULL; 591 if (args == NULL) return NULL;
584 592
585 // insert the "program name" argv[0] and a copy of the "prepend" 593 // 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[]) {
610 switch (result) { 618 switch (result) {
611 case 0: return strdup("t"); 619 case 0: return strdup("t");
612 case 1: return strdup(""); 620 case 1: return strdup("");
613 default: return ErrorAbort(cookie, "applypatch couldn't parse args"); 621 default: return ErrorAbort(state, "applypatch couldn't parse args");
614 } 622 }
615} 623}
616 624
625char* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
626 char** args = ReadVarArgs(state, argc, argv);
627 if (args == NULL) {
628 return NULL;
629 }
630
631 int size = 0;
632 int i;
633 for (i = 0; i < argc; ++i) {
634 size += strlen(args[i]);
635 }
636 char* buffer = malloc(size+1);
637 size = 0;
638 for (i = 0; i < argc; ++i) {
639 strcpy(buffer+size, args[i]);
640 size += strlen(args[i]);
641 free(args[i]);
642 }
643 free(args);
644 buffer[size] = '\0';
645
646 char* line = strtok(buffer, "\n");
647 while (line) {
648 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
649 "ui_print %s\n", line);
650 line = strtok(NULL, "\n");
651 }
652 fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
653
654 return buffer;
655}
656
617 657
618void RegisterInstallFunctions() { 658void RegisterInstallFunctions() {
619 RegisterFunction("mount", MountFn); 659 RegisterFunction("mount", MountFn);
@@ -636,4 +676,6 @@ void RegisterInstallFunctions() {
636 RegisterFunction("apply_patch", ApplyPatchFn); 676 RegisterFunction("apply_patch", ApplyPatchFn);
637 RegisterFunction("apply_patch_check", ApplyPatchFn); 677 RegisterFunction("apply_patch_check", ApplyPatchFn);
638 RegisterFunction("apply_patch_space", ApplyPatchFn); 678 RegisterFunction("apply_patch_space", ApplyPatchFn);
679
680 RegisterFunction("ui_print", UIPrintFn);
639} 681}
diff --git a/updater/updater.c b/updater/updater.c
index 09776256..5a2ed2cc 100644
--- a/updater/updater.c
+++ b/updater/updater.c
@@ -94,12 +94,26 @@ int main(int argc, char** argv) {
94 updater_info.cmd_pipe = cmd_pipe; 94 updater_info.cmd_pipe = cmd_pipe;
95 updater_info.package_zip = &za; 95 updater_info.package_zip = &za;
96 96
97 char* result = Evaluate(&updater_info, root); 97 State state;
98 state.cookie = &updater_info;
99 state.script = script;
100 state.errmsg = NULL;
101
102 char* result = Evaluate(&state, root);
98 if (result == NULL) { 103 if (result == NULL) {
99 const char* errmsg = GetError(); 104 if (state.errmsg == NULL) {
100 fprintf(stderr, "script aborted with error: %s\n", 105 fprintf(stderr, "script aborted (no error message)\n");
101 errmsg == NULL ? "(none)" : errmsg); 106 fprintf(cmd_pipe, "ui_print script aborted (no error message)\n");
102 ClearError(); 107 } else {
108 fprintf(stderr, "script aborted: %s\n", state.errmsg);
109 char* line = strtok(state.errmsg, "\n");
110 while (line) {
111 fprintf(cmd_pipe, "ui_print %s\n", line);
112 line = strtok(NULL, "\n");
113 }
114 fprintf(cmd_pipe, "ui_print\n");
115 }
116 free(state.errmsg);
103 return 7; 117 return 7;
104 } else { 118 } else {
105 fprintf(stderr, "script result was [%s]\n", result); 119 fprintf(stderr, "script result was [%s]\n", result);
@@ -107,6 +121,7 @@ int main(int argc, char** argv) {
107 } 121 }
108 122
109 mzCloseZipArchive(&za); 123 mzCloseZipArchive(&za);
124 free(script);
110 125
111 return 0; 126 return 0;
112} 127}