diff options
author | Tao Bao | 2015-08-20 14:10:46 -0500 |
---|---|---|
committer | Tao Bao | 2015-08-20 14:11:04 -0500 |
commit | 2a5a49d3376eae890d76bb560e0d8ffc264ff5a6 (patch) | |
tree | 2aa9d806b2c6f235ea79780f6f5452927fd80df7 /edify/expr.cpp | |
parent | ad509fd4a2c597ced8e53b0817f754cb2209b98a (diff) | |
download | platform-bootable-recovery-2a5a49d3376eae890d76bb560e0d8ffc264ff5a6.tar.gz platform-bootable-recovery-2a5a49d3376eae890d76bb560e0d8ffc264ff5a6.tar.xz platform-bootable-recovery-2a5a49d3376eae890d76bb560e0d8ffc264ff5a6.zip |
edify: Switch to C++.
Change-Id: I71aede6e29af1dc4bb858a62016c8035db5d3452
Diffstat (limited to 'edify/expr.cpp')
-rw-r--r-- | edify/expr.cpp | 507 |
1 files changed, 507 insertions, 0 deletions
diff --git a/edify/expr.cpp b/edify/expr.cpp new file mode 100644 index 00000000..cd1e0872 --- /dev/null +++ b/edify/expr.cpp | |||
@@ -0,0 +1,507 @@ | |||
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 | #include <string.h> | ||
18 | #include <stdbool.h> | ||
19 | #include <stdio.h> | ||
20 | #include <stdlib.h> | ||
21 | #include <stdarg.h> | ||
22 | #include <unistd.h> | ||
23 | |||
24 | #include "expr.h" | ||
25 | |||
26 | // Functions should: | ||
27 | // | ||
28 | // - return a malloc()'d string | ||
29 | // - if Evaluate() on any argument returns NULL, return NULL. | ||
30 | |||
31 | int BooleanString(const char* s) { | ||
32 | return s[0] != '\0'; | ||
33 | } | ||
34 | |||
35 | char* Evaluate(State* state, Expr* expr) { | ||
36 | Value* v = expr->fn(expr->name, state, expr->argc, expr->argv); | ||
37 | if (v == NULL) return NULL; | ||
38 | if (v->type != VAL_STRING) { | ||
39 | ErrorAbort(state, "expecting string, got value type %d", v->type); | ||
40 | FreeValue(v); | ||
41 | return NULL; | ||
42 | } | ||
43 | char* result = v->data; | ||
44 | free(v); | ||
45 | return result; | ||
46 | } | ||
47 | |||
48 | Value* EvaluateValue(State* state, Expr* expr) { | ||
49 | return expr->fn(expr->name, state, expr->argc, expr->argv); | ||
50 | } | ||
51 | |||
52 | Value* StringValue(char* str) { | ||
53 | if (str == NULL) return NULL; | ||
54 | Value* v = reinterpret_cast<Value*>(malloc(sizeof(Value))); | ||
55 | v->type = VAL_STRING; | ||
56 | v->size = strlen(str); | ||
57 | v->data = str; | ||
58 | return v; | ||
59 | } | ||
60 | |||
61 | void FreeValue(Value* v) { | ||
62 | if (v == NULL) return; | ||
63 | free(v->data); | ||
64 | free(v); | ||
65 | } | ||
66 | |||
67 | Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) { | ||
68 | if (argc == 0) { | ||
69 | return StringValue(strdup("")); | ||
70 | } | ||
71 | char** strings = reinterpret_cast<char**>(malloc(argc * sizeof(char*))); | ||
72 | int i; | ||
73 | for (i = 0; i < argc; ++i) { | ||
74 | strings[i] = NULL; | ||
75 | } | ||
76 | char* result = NULL; | ||
77 | int length = 0; | ||
78 | for (i = 0; i < argc; ++i) { | ||
79 | strings[i] = Evaluate(state, argv[i]); | ||
80 | if (strings[i] == NULL) { | ||
81 | goto done; | ||
82 | } | ||
83 | length += strlen(strings[i]); | ||
84 | } | ||
85 | |||
86 | result = reinterpret_cast<char*>(malloc(length+1)); | ||
87 | int p; | ||
88 | p = 0; | ||
89 | for (i = 0; i < argc; ++i) { | ||
90 | strcpy(result+p, strings[i]); | ||
91 | p += strlen(strings[i]); | ||
92 | } | ||
93 | result[p] = '\0'; | ||
94 | |||
95 | done: | ||
96 | for (i = 0; i < argc; ++i) { | ||
97 | free(strings[i]); | ||
98 | } | ||
99 | free(strings); | ||
100 | return StringValue(result); | ||
101 | } | ||
102 | |||
103 | Value* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) { | ||
104 | if (argc != 2 && argc != 3) { | ||
105 | free(state->errmsg); | ||
106 | state->errmsg = strdup("ifelse expects 2 or 3 arguments"); | ||
107 | return NULL; | ||
108 | } | ||
109 | char* cond = Evaluate(state, argv[0]); | ||
110 | if (cond == NULL) { | ||
111 | return NULL; | ||
112 | } | ||
113 | |||
114 | if (BooleanString(cond) == true) { | ||
115 | free(cond); | ||
116 | return EvaluateValue(state, argv[1]); | ||
117 | } else { | ||
118 | if (argc == 3) { | ||
119 | free(cond); | ||
120 | return EvaluateValue(state, argv[2]); | ||
121 | } else { | ||
122 | return StringValue(cond); | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | |||
127 | Value* AbortFn(const char* name, State* state, int argc, Expr* argv[]) { | ||
128 | char* msg = NULL; | ||
129 | if (argc > 0) { | ||
130 | msg = Evaluate(state, argv[0]); | ||
131 | } | ||
132 | free(state->errmsg); | ||
133 | if (msg) { | ||
134 | state->errmsg = msg; | ||
135 | } else { | ||
136 | state->errmsg = strdup("called abort()"); | ||
137 | } | ||
138 | return NULL; | ||
139 | } | ||
140 | |||
141 | Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]) { | ||
142 | int i; | ||
143 | for (i = 0; i < argc; ++i) { | ||
144 | char* v = Evaluate(state, argv[i]); | ||
145 | if (v == NULL) { | ||
146 | return NULL; | ||
147 | } | ||
148 | int b = BooleanString(v); | ||
149 | free(v); | ||
150 | if (!b) { | ||
151 | int prefix_len; | ||
152 | int len = argv[i]->end - argv[i]->start; | ||
153 | char* err_src = reinterpret_cast<char*>(malloc(len + 20)); | ||
154 | strcpy(err_src, "assert failed: "); | ||
155 | prefix_len = strlen(err_src); | ||
156 | memcpy(err_src + prefix_len, state->script + argv[i]->start, len); | ||
157 | err_src[prefix_len + len] = '\0'; | ||
158 | free(state->errmsg); | ||
159 | state->errmsg = err_src; | ||
160 | return NULL; | ||
161 | } | ||
162 | } | ||
163 | return StringValue(strdup("")); | ||
164 | } | ||
165 | |||
166 | Value* SleepFn(const char* name, State* state, int argc, Expr* argv[]) { | ||
167 | char* val = Evaluate(state, argv[0]); | ||
168 | if (val == NULL) { | ||
169 | return NULL; | ||
170 | } | ||
171 | int v = strtol(val, NULL, 10); | ||
172 | sleep(v); | ||
173 | return StringValue(val); | ||
174 | } | ||
175 | |||
176 | Value* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) { | ||
177 | int i; | ||
178 | for (i = 0; i < argc; ++i) { | ||
179 | char* v = Evaluate(state, argv[i]); | ||
180 | if (v == NULL) { | ||
181 | return NULL; | ||
182 | } | ||
183 | fputs(v, stdout); | ||
184 | free(v); | ||
185 | } | ||
186 | return StringValue(strdup("")); | ||
187 | } | ||
188 | |||
189 | Value* LogicalAndFn(const char* name, State* state, | ||
190 | int argc, Expr* argv[]) { | ||
191 | char* left = Evaluate(state, argv[0]); | ||
192 | if (left == NULL) return NULL; | ||
193 | if (BooleanString(left) == true) { | ||
194 | free(left); | ||
195 | return EvaluateValue(state, argv[1]); | ||
196 | } else { | ||
197 | return StringValue(left); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | Value* LogicalOrFn(const char* name, State* state, | ||
202 | int argc, Expr* argv[]) { | ||
203 | char* left = Evaluate(state, argv[0]); | ||
204 | if (left == NULL) return NULL; | ||
205 | if (BooleanString(left) == false) { | ||
206 | free(left); | ||
207 | return EvaluateValue(state, argv[1]); | ||
208 | } else { | ||
209 | return StringValue(left); | ||
210 | } | ||
211 | } | ||
212 | |||
213 | Value* LogicalNotFn(const char* name, State* state, | ||
214 | int argc, Expr* argv[]) { | ||
215 | char* val = Evaluate(state, argv[0]); | ||
216 | if (val == NULL) return NULL; | ||
217 | bool bv = BooleanString(val); | ||
218 | free(val); | ||
219 | return StringValue(strdup(bv ? "" : "t")); | ||
220 | } | ||
221 | |||
222 | Value* SubstringFn(const char* name, State* state, | ||
223 | int argc, Expr* argv[]) { | ||
224 | char* needle = Evaluate(state, argv[0]); | ||
225 | if (needle == NULL) return NULL; | ||
226 | char* haystack = Evaluate(state, argv[1]); | ||
227 | if (haystack == NULL) { | ||
228 | free(needle); | ||
229 | return NULL; | ||
230 | } | ||
231 | |||
232 | char* result = strdup(strstr(haystack, needle) ? "t" : ""); | ||
233 | free(needle); | ||
234 | free(haystack); | ||
235 | return StringValue(result); | ||
236 | } | ||
237 | |||
238 | Value* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) { | ||
239 | char* left = Evaluate(state, argv[0]); | ||
240 | if (left == NULL) return NULL; | ||
241 | char* right = Evaluate(state, argv[1]); | ||
242 | if (right == NULL) { | ||
243 | free(left); | ||
244 | return NULL; | ||
245 | } | ||
246 | |||
247 | char* result = strdup(strcmp(left, right) == 0 ? "t" : ""); | ||
248 | free(left); | ||
249 | free(right); | ||
250 | return StringValue(result); | ||
251 | } | ||
252 | |||
253 | Value* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) { | ||
254 | char* left = Evaluate(state, argv[0]); | ||
255 | if (left == NULL) return NULL; | ||
256 | char* right = Evaluate(state, argv[1]); | ||
257 | if (right == NULL) { | ||
258 | free(left); | ||
259 | return NULL; | ||
260 | } | ||
261 | |||
262 | char* result = strdup(strcmp(left, right) != 0 ? "t" : ""); | ||
263 | free(left); | ||
264 | free(right); | ||
265 | return StringValue(result); | ||
266 | } | ||
267 | |||
268 | Value* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) { | ||
269 | Value* left = EvaluateValue(state, argv[0]); | ||
270 | if (left == NULL) return NULL; | ||
271 | FreeValue(left); | ||
272 | return EvaluateValue(state, argv[1]); | ||
273 | } | ||
274 | |||
275 | Value* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) { | ||
276 | if (argc != 2) { | ||
277 | free(state->errmsg); | ||
278 | state->errmsg = strdup("less_than_int expects 2 arguments"); | ||
279 | return NULL; | ||
280 | } | ||
281 | |||
282 | char* left; | ||
283 | char* right; | ||
284 | if (ReadArgs(state, argv, 2, &left, &right) < 0) return NULL; | ||
285 | |||
286 | bool result = false; | ||
287 | char* end; | ||
288 | |||
289 | long l_int = strtol(left, &end, 10); | ||
290 | if (left[0] == '\0' || *end != '\0') { | ||
291 | goto done; | ||
292 | } | ||
293 | |||
294 | long r_int; | ||
295 | r_int = strtol(right, &end, 10); | ||
296 | if (right[0] == '\0' || *end != '\0') { | ||
297 | goto done; | ||
298 | } | ||
299 | |||
300 | result = l_int < r_int; | ||
301 | |||
302 | done: | ||
303 | free(left); | ||
304 | free(right); | ||
305 | return StringValue(strdup(result ? "t" : "")); | ||
306 | } | ||
307 | |||
308 | Value* GreaterThanIntFn(const char* name, State* state, | ||
309 | int argc, Expr* argv[]) { | ||
310 | if (argc != 2) { | ||
311 | free(state->errmsg); | ||
312 | state->errmsg = strdup("greater_than_int expects 2 arguments"); | ||
313 | return NULL; | ||
314 | } | ||
315 | |||
316 | Expr* temp[2]; | ||
317 | temp[0] = argv[1]; | ||
318 | temp[1] = argv[0]; | ||
319 | |||
320 | return LessThanIntFn(name, state, 2, temp); | ||
321 | } | ||
322 | |||
323 | Value* Literal(const char* name, State* state, int argc, Expr* argv[]) { | ||
324 | return StringValue(strdup(name)); | ||
325 | } | ||
326 | |||
327 | Expr* Build(Function fn, YYLTYPE loc, int count, ...) { | ||
328 | va_list v; | ||
329 | va_start(v, count); | ||
330 | Expr* e = reinterpret_cast<Expr*>(malloc(sizeof(Expr))); | ||
331 | e->fn = fn; | ||
332 | e->name = "(operator)"; | ||
333 | e->argc = count; | ||
334 | e->argv = reinterpret_cast<Expr**>(malloc(count * sizeof(Expr*))); | ||
335 | int i; | ||
336 | for (i = 0; i < count; ++i) { | ||
337 | e->argv[i] = va_arg(v, Expr*); | ||
338 | } | ||
339 | va_end(v); | ||
340 | e->start = loc.start; | ||
341 | e->end = loc.end; | ||
342 | return e; | ||
343 | } | ||
344 | |||
345 | // ----------------------------------------------------------------- | ||
346 | // the function table | ||
347 | // ----------------------------------------------------------------- | ||
348 | |||
349 | static int fn_entries = 0; | ||
350 | static int fn_size = 0; | ||
351 | NamedFunction* fn_table = NULL; | ||
352 | |||
353 | void RegisterFunction(const char* name, Function fn) { | ||
354 | if (fn_entries >= fn_size) { | ||
355 | fn_size = fn_size*2 + 1; | ||
356 | fn_table = reinterpret_cast<NamedFunction*>(realloc(fn_table, fn_size * sizeof(NamedFunction))); | ||
357 | } | ||
358 | fn_table[fn_entries].name = name; | ||
359 | fn_table[fn_entries].fn = fn; | ||
360 | ++fn_entries; | ||
361 | } | ||
362 | |||
363 | static int fn_entry_compare(const void* a, const void* b) { | ||
364 | const char* na = ((const NamedFunction*)a)->name; | ||
365 | const char* nb = ((const NamedFunction*)b)->name; | ||
366 | return strcmp(na, nb); | ||
367 | } | ||
368 | |||
369 | void FinishRegistration() { | ||
370 | qsort(fn_table, fn_entries, sizeof(NamedFunction), fn_entry_compare); | ||
371 | } | ||
372 | |||
373 | Function FindFunction(const char* name) { | ||
374 | NamedFunction key; | ||
375 | key.name = name; | ||
376 | NamedFunction* nf = reinterpret_cast<NamedFunction*>(bsearch(&key, fn_table, fn_entries, | ||
377 | sizeof(NamedFunction), fn_entry_compare)); | ||
378 | if (nf == NULL) { | ||
379 | return NULL; | ||
380 | } | ||
381 | return nf->fn; | ||
382 | } | ||
383 | |||
384 | void RegisterBuiltins() { | ||
385 | RegisterFunction("ifelse", IfElseFn); | ||
386 | RegisterFunction("abort", AbortFn); | ||
387 | RegisterFunction("assert", AssertFn); | ||
388 | RegisterFunction("concat", ConcatFn); | ||
389 | RegisterFunction("is_substring", SubstringFn); | ||
390 | RegisterFunction("stdout", StdoutFn); | ||
391 | RegisterFunction("sleep", SleepFn); | ||
392 | |||
393 | RegisterFunction("less_than_int", LessThanIntFn); | ||
394 | RegisterFunction("greater_than_int", GreaterThanIntFn); | ||
395 | } | ||
396 | |||
397 | |||
398 | // ----------------------------------------------------------------- | ||
399 | // convenience methods for functions | ||
400 | // ----------------------------------------------------------------- | ||
401 | |||
402 | // Evaluate the expressions in argv, giving 'count' char* (the ... is | ||
403 | // zero or more char** to put them in). If any expression evaluates | ||
404 | // to NULL, free the rest and return -1. Return 0 on success. | ||
405 | int ReadArgs(State* state, Expr* argv[], int count, ...) { | ||
406 | char** args = reinterpret_cast<char**>(malloc(count * sizeof(char*))); | ||
407 | va_list v; | ||
408 | va_start(v, count); | ||
409 | int i; | ||
410 | for (i = 0; i < count; ++i) { | ||
411 | args[i] = Evaluate(state, argv[i]); | ||
412 | if (args[i] == NULL) { | ||
413 | va_end(v); | ||
414 | int j; | ||
415 | for (j = 0; j < i; ++j) { | ||
416 | free(args[j]); | ||
417 | } | ||
418 | free(args); | ||
419 | return -1; | ||
420 | } | ||
421 | *(va_arg(v, char**)) = args[i]; | ||
422 | } | ||
423 | va_end(v); | ||
424 | free(args); | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | // Evaluate the expressions in argv, giving 'count' Value* (the ... is | ||
429 | // zero or more Value** to put them in). If any expression evaluates | ||
430 | // to NULL, free the rest and return -1. Return 0 on success. | ||
431 | int ReadValueArgs(State* state, Expr* argv[], int count, ...) { | ||
432 | Value** args = reinterpret_cast<Value**>(malloc(count * sizeof(Value*))); | ||
433 | va_list v; | ||
434 | va_start(v, count); | ||
435 | int i; | ||
436 | for (i = 0; i < count; ++i) { | ||
437 | args[i] = EvaluateValue(state, argv[i]); | ||
438 | if (args[i] == NULL) { | ||
439 | va_end(v); | ||
440 | int j; | ||
441 | for (j = 0; j < i; ++j) { | ||
442 | FreeValue(args[j]); | ||
443 | } | ||
444 | free(args); | ||
445 | return -1; | ||
446 | } | ||
447 | *(va_arg(v, Value**)) = args[i]; | ||
448 | } | ||
449 | va_end(v); | ||
450 | free(args); | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | // Evaluate the expressions in argv, returning an array of char* | ||
455 | // results. If any evaluate to NULL, free the rest and return NULL. | ||
456 | // The caller is responsible for freeing the returned array and the | ||
457 | // strings it contains. | ||
458 | char** ReadVarArgs(State* state, int argc, Expr* argv[]) { | ||
459 | char** args = (char**)malloc(argc * sizeof(char*)); | ||
460 | int i = 0; | ||
461 | for (i = 0; i < argc; ++i) { | ||
462 | args[i] = Evaluate(state, argv[i]); | ||
463 | if (args[i] == NULL) { | ||
464 | int j; | ||
465 | for (j = 0; j < i; ++j) { | ||
466 | free(args[j]); | ||
467 | } | ||
468 | free(args); | ||
469 | return NULL; | ||
470 | } | ||
471 | } | ||
472 | return args; | ||
473 | } | ||
474 | |||
475 | // Evaluate the expressions in argv, returning an array of Value* | ||
476 | // results. If any evaluate to NULL, free the rest and return NULL. | ||
477 | // The caller is responsible for freeing the returned array and the | ||
478 | // Values it contains. | ||
479 | Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]) { | ||
480 | Value** args = (Value**)malloc(argc * sizeof(Value*)); | ||
481 | int i = 0; | ||
482 | for (i = 0; i < argc; ++i) { | ||
483 | args[i] = EvaluateValue(state, argv[i]); | ||
484 | if (args[i] == NULL) { | ||
485 | int j; | ||
486 | for (j = 0; j < i; ++j) { | ||
487 | FreeValue(args[j]); | ||
488 | } | ||
489 | free(args); | ||
490 | return NULL; | ||
491 | } | ||
492 | } | ||
493 | return args; | ||
494 | } | ||
495 | |||
496 | // Use printf-style arguments to compose an error message to put into | ||
497 | // *state. Returns NULL. | ||
498 | Value* ErrorAbort(State* state, const char* format, ...) { | ||
499 | char* buffer = reinterpret_cast<char*>(malloc(4096)); | ||
500 | va_list v; | ||
501 | va_start(v, format); | ||
502 | vsnprintf(buffer, 4096, format, v); | ||
503 | va_end(v); | ||
504 | free(state->errmsg); | ||
505 | state->errmsg = buffer; | ||
506 | return NULL; | ||
507 | } | ||