blob: cd1e0872696d2059d45c4721e6028dcaaf5e4dc5 [file] [log] [blame]
Doug Zongker37bee622009-06-08 17:35:39 -07001/*
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>
Doug Zongker9931f7f2009-06-10 14:11:53 -070022#include <unistd.h>
Doug Zongker37bee622009-06-08 17:35:39 -070023
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
31int BooleanString(const char* s) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070032 return s[0] != '\0';
Doug Zongker37bee622009-06-08 17:35:39 -070033}
34
Doug Zongkerd9c9d102009-06-12 12:24:39 -070035char* Evaluate(State* state, Expr* expr) {
Doug Zongker512536a2010-02-17 16:11:44 -080036 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
48Value* EvaluateValue(State* state, Expr* expr) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070049 return expr->fn(expr->name, state, expr->argc, expr->argv);
Doug Zongker37bee622009-06-08 17:35:39 -070050}
51
Doug Zongker512536a2010-02-17 16:11:44 -080052Value* StringValue(char* str) {
Doug Zongker5b695f32010-02-24 15:03:47 -080053 if (str == NULL) return NULL;
Tao Bao2a5a49d2015-08-20 12:10:46 -070054 Value* v = reinterpret_cast<Value*>(malloc(sizeof(Value)));
Doug Zongker512536a2010-02-17 16:11:44 -080055 v->type = VAL_STRING;
56 v->size = strlen(str);
57 v->data = str;
58 return v;
59}
60
61void FreeValue(Value* v) {
62 if (v == NULL) return;
63 free(v->data);
64 free(v);
65}
66
67Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -070068 if (argc == 0) {
Doug Zongker512536a2010-02-17 16:11:44 -080069 return StringValue(strdup(""));
Doug Zongker37bee622009-06-08 17:35:39 -070070 }
Tao Bao2a5a49d2015-08-20 12:10:46 -070071 char** strings = reinterpret_cast<char**>(malloc(argc * sizeof(char*)));
Doug Zongkerd9c9d102009-06-12 12:24:39 -070072 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 }
Doug Zongker37bee622009-06-08 17:35:39 -070085
Tao Bao2a5a49d2015-08-20 12:10:46 -070086 result = reinterpret_cast<char*>(malloc(length+1));
87 int p;
88 p = 0;
Doug Zongkerd9c9d102009-06-12 12:24:39 -070089 for (i = 0; i < argc; ++i) {
90 strcpy(result+p, strings[i]);
91 p += strlen(strings[i]);
92 }
93 result[p] = '\0';
Doug Zongker37bee622009-06-08 17:35:39 -070094
Doug Zongkerd9c9d102009-06-12 12:24:39 -070095 done:
96 for (i = 0; i < argc; ++i) {
97 free(strings[i]);
98 }
Kenny Root21854cc2010-02-17 18:31:48 -080099 free(strings);
Doug Zongker512536a2010-02-17 16:11:44 -0800100 return StringValue(result);
Doug Zongker37bee622009-06-08 17:35:39 -0700101}
102
Doug Zongker512536a2010-02-17 16:11:44 -0800103Value* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700104 if (argc != 2 && argc != 3) {
Doug Zongkere3da02e2009-06-12 16:13:52 -0700105 free(state->errmsg);
106 state->errmsg = strdup("ifelse expects 2 or 3 arguments");
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700107 return NULL;
108 }
109 char* cond = Evaluate(state, argv[0]);
110 if (cond == NULL) {
111 return NULL;
112 }
Doug Zongker37bee622009-06-08 17:35:39 -0700113
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700114 if (BooleanString(cond) == true) {
115 free(cond);
Doug Zongker512536a2010-02-17 16:11:44 -0800116 return EvaluateValue(state, argv[1]);
Doug Zongker37bee622009-06-08 17:35:39 -0700117 } else {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700118 if (argc == 3) {
119 free(cond);
Doug Zongker512536a2010-02-17 16:11:44 -0800120 return EvaluateValue(state, argv[2]);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700121 } else {
Doug Zongker512536a2010-02-17 16:11:44 -0800122 return StringValue(cond);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700123 }
Doug Zongker37bee622009-06-08 17:35:39 -0700124 }
Doug Zongker37bee622009-06-08 17:35:39 -0700125}
126
Doug Zongker512536a2010-02-17 16:11:44 -0800127Value* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700128 char* msg = NULL;
129 if (argc > 0) {
130 msg = Evaluate(state, argv[0]);
Doug Zongker37bee622009-06-08 17:35:39 -0700131 }
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700132 free(state->errmsg);
133 if (msg) {
134 state->errmsg = msg;
135 } else {
136 state->errmsg = strdup("called abort()");
Doug Zongker37bee622009-06-08 17:35:39 -0700137 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700138 return NULL;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700139}
140
Doug Zongker512536a2010-02-17 16:11:44 -0800141Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700142 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;
Tao Bao2a5a49d2015-08-20 12:10:46 -0700153 char* err_src = reinterpret_cast<char*>(malloc(len + 20));
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700154 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 }
Doug Zongker37bee622009-06-08 17:35:39 -0700162 }
Doug Zongker512536a2010-02-17 16:11:44 -0800163 return StringValue(strdup(""));
Doug Zongker37bee622009-06-08 17:35:39 -0700164}
165
Doug Zongker512536a2010-02-17 16:11:44 -0800166Value* SleepFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700167 char* val = Evaluate(state, argv[0]);
168 if (val == NULL) {
169 return NULL;
170 }
171 int v = strtol(val, NULL, 10);
172 sleep(v);
Doug Zongker512536a2010-02-17 16:11:44 -0800173 return StringValue(val);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700174}
175
Doug Zongker512536a2010-02-17 16:11:44 -0800176Value* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700177 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 }
Doug Zongker512536a2010-02-17 16:11:44 -0800186 return StringValue(strdup(""));
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700187}
188
Doug Zongker512536a2010-02-17 16:11:44 -0800189Value* LogicalAndFn(const char* name, State* state,
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700190 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);
Doug Zongker512536a2010-02-17 16:11:44 -0800195 return EvaluateValue(state, argv[1]);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700196 } else {
Doug Zongker512536a2010-02-17 16:11:44 -0800197 return StringValue(left);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700198 }
199}
200
Doug Zongker512536a2010-02-17 16:11:44 -0800201Value* LogicalOrFn(const char* name, State* state,
202 int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700203 char* left = Evaluate(state, argv[0]);
204 if (left == NULL) return NULL;
205 if (BooleanString(left) == false) {
206 free(left);
Doug Zongker512536a2010-02-17 16:11:44 -0800207 return EvaluateValue(state, argv[1]);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700208 } else {
Doug Zongker512536a2010-02-17 16:11:44 -0800209 return StringValue(left);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700210 }
211}
212
Doug Zongker512536a2010-02-17 16:11:44 -0800213Value* LogicalNotFn(const char* name, State* state,
214 int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700215 char* val = Evaluate(state, argv[0]);
216 if (val == NULL) return NULL;
217 bool bv = BooleanString(val);
218 free(val);
Doug Zongker512536a2010-02-17 16:11:44 -0800219 return StringValue(strdup(bv ? "" : "t"));
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700220}
221
Doug Zongker512536a2010-02-17 16:11:44 -0800222Value* SubstringFn(const char* name, State* state,
223 int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700224 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" : "");
Doug Zongker37bee622009-06-08 17:35:39 -0700233 free(needle);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700234 free(haystack);
Doug Zongker512536a2010-02-17 16:11:44 -0800235 return StringValue(result);
Doug Zongker37bee622009-06-08 17:35:39 -0700236}
237
Doug Zongker512536a2010-02-17 16:11:44 -0800238Value* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700239 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" : "");
Doug Zongker37bee622009-06-08 17:35:39 -0700248 free(left);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700249 free(right);
Doug Zongker512536a2010-02-17 16:11:44 -0800250 return StringValue(result);
Doug Zongker37bee622009-06-08 17:35:39 -0700251}
252
Doug Zongker512536a2010-02-17 16:11:44 -0800253Value* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700254 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" : "");
Doug Zongker37bee622009-06-08 17:35:39 -0700263 free(left);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700264 free(right);
Doug Zongker512536a2010-02-17 16:11:44 -0800265 return StringValue(result);
Doug Zongker37bee622009-06-08 17:35:39 -0700266}
267
Doug Zongker512536a2010-02-17 16:11:44 -0800268Value* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) {
269 Value* left = EvaluateValue(state, argv[0]);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700270 if (left == NULL) return NULL;
Doug Zongker512536a2010-02-17 16:11:44 -0800271 FreeValue(left);
272 return EvaluateValue(state, argv[1]);
Doug Zongker37bee622009-06-08 17:35:39 -0700273}
274
Doug Zongker512536a2010-02-17 16:11:44 -0800275Value* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
Doug Zongkere3da02e2009-06-12 16:13:52 -0700276 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') {
Doug Zongkere3da02e2009-06-12 16:13:52 -0700291 goto done;
292 }
293
Tao Bao2a5a49d2015-08-20 12:10:46 -0700294 long r_int;
295 r_int = strtol(right, &end, 10);
Doug Zongkere3da02e2009-06-12 16:13:52 -0700296 if (right[0] == '\0' || *end != '\0') {
Doug Zongkere3da02e2009-06-12 16:13:52 -0700297 goto done;
298 }
299
300 result = l_int < r_int;
301
302 done:
303 free(left);
304 free(right);
Doug Zongker512536a2010-02-17 16:11:44 -0800305 return StringValue(strdup(result ? "t" : ""));
Doug Zongkere3da02e2009-06-12 16:13:52 -0700306}
307
Doug Zongker512536a2010-02-17 16:11:44 -0800308Value* GreaterThanIntFn(const char* name, State* state,
309 int argc, Expr* argv[]) {
Doug Zongkere3da02e2009-06-12 16:13:52 -0700310 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
Doug Zongker512536a2010-02-17 16:11:44 -0800323Value* Literal(const char* name, State* state, int argc, Expr* argv[]) {
324 return StringValue(strdup(name));
Doug Zongker37bee622009-06-08 17:35:39 -0700325}
326
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700327Expr* Build(Function fn, YYLTYPE loc, int count, ...) {
328 va_list v;
329 va_start(v, count);
Tao Bao2a5a49d2015-08-20 12:10:46 -0700330 Expr* e = reinterpret_cast<Expr*>(malloc(sizeof(Expr)));
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700331 e->fn = fn;
332 e->name = "(operator)";
333 e->argc = count;
Tao Bao2a5a49d2015-08-20 12:10:46 -0700334 e->argv = reinterpret_cast<Expr**>(malloc(count * sizeof(Expr*)));
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700335 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;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700343}
344
345// -----------------------------------------------------------------
346// the function table
347// -----------------------------------------------------------------
348
Doug Zongker37bee622009-06-08 17:35:39 -0700349static int fn_entries = 0;
350static int fn_size = 0;
351NamedFunction* fn_table = NULL;
352
353void RegisterFunction(const char* name, Function fn) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700354 if (fn_entries >= fn_size) {
355 fn_size = fn_size*2 + 1;
Tao Bao2a5a49d2015-08-20 12:10:46 -0700356 fn_table = reinterpret_cast<NamedFunction*>(realloc(fn_table, fn_size * sizeof(NamedFunction)));
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700357 }
358 fn_table[fn_entries].name = name;
359 fn_table[fn_entries].fn = fn;
360 ++fn_entries;
Doug Zongker37bee622009-06-08 17:35:39 -0700361}
362
363static int fn_entry_compare(const void* a, const void* b) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700364 const char* na = ((const NamedFunction*)a)->name;
365 const char* nb = ((const NamedFunction*)b)->name;
366 return strcmp(na, nb);
Doug Zongker37bee622009-06-08 17:35:39 -0700367}
368
369void FinishRegistration() {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700370 qsort(fn_table, fn_entries, sizeof(NamedFunction), fn_entry_compare);
Doug Zongker37bee622009-06-08 17:35:39 -0700371}
372
373Function FindFunction(const char* name) {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700374 NamedFunction key;
375 key.name = name;
Tao Bao2a5a49d2015-08-20 12:10:46 -0700376 NamedFunction* nf = reinterpret_cast<NamedFunction*>(bsearch(&key, fn_table, fn_entries,
377 sizeof(NamedFunction), fn_entry_compare));
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700378 if (nf == NULL) {
379 return NULL;
380 }
381 return nf->fn;
Doug Zongker37bee622009-06-08 17:35:39 -0700382}
383
384void RegisterBuiltins() {
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700385 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);
Doug Zongkere3da02e2009-06-12 16:13:52 -0700392
393 RegisterFunction("less_than_int", LessThanIntFn);
394 RegisterFunction("greater_than_int", GreaterThanIntFn);
Doug Zongker9931f7f2009-06-10 14:11:53 -0700395}
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.
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700405int ReadArgs(State* state, Expr* argv[], int count, ...) {
Tao Bao2a5a49d2015-08-20 12:10:46 -0700406 char** args = reinterpret_cast<char**>(malloc(count * sizeof(char*)));
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700407 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 }
Kenny Root21854cc2010-02-17 18:31:48 -0800418 free(args);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700419 return -1;
420 }
421 *(va_arg(v, char**)) = args[i];
Doug Zongker9931f7f2009-06-10 14:11:53 -0700422 }
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700423 va_end(v);
Kenny Root21854cc2010-02-17 18:31:48 -0800424 free(args);
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700425 return 0;
Doug Zongker9931f7f2009-06-10 14:11:53 -0700426}
427
Doug Zongker512536a2010-02-17 16:11:44 -0800428// 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.
431int ReadValueArgs(State* state, Expr* argv[], int count, ...) {
Tao Bao2a5a49d2015-08-20 12:10:46 -0700432 Value** args = reinterpret_cast<Value**>(malloc(count * sizeof(Value*)));
Doug Zongker512536a2010-02-17 16:11:44 -0800433 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
Doug Zongker9931f7f2009-06-10 14:11:53 -0700454// 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.
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700458char** 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 }
Doug Zongker9931f7f2009-06-10 14:11:53 -0700471 }
Doug Zongkerd9c9d102009-06-12 12:24:39 -0700472 return args;
Doug Zongker37bee622009-06-08 17:35:39 -0700473}
Doug Zongker47cace92009-06-18 10:11:50 -0700474
Doug Zongker512536a2010-02-17 16:11:44 -0800475// 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.
479Value** 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
Doug Zongker47cace92009-06-18 10:11:50 -0700496// Use printf-style arguments to compose an error message to put into
497// *state. Returns NULL.
Doug Zongkere5d5ac72012-04-12 11:01:22 -0700498Value* ErrorAbort(State* state, const char* format, ...) {
Tao Bao2a5a49d2015-08-20 12:10:46 -0700499 char* buffer = reinterpret_cast<char*>(malloc(4096));
Doug Zongker47cace92009-06-18 10:11:50 -0700500 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}