/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "edify/expr.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "otautil/error_code.h" // Functions should: // // - return a malloc()'d string // - if Evaluate() on any argument returns nullptr, return nullptr. static bool BooleanString(const std::string& s) { return !s.empty(); } bool Evaluate(State* state, const std::unique_ptr& expr, std::string* result) { if (result == nullptr) { return false; } std::unique_ptr v(expr->fn(expr->name.c_str(), state, expr->argv)); if (!v) { return false; } if (v->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "expecting string, got value type %d", v->type); return false; } *result = v->data; return true; } Value* EvaluateValue(State* state, const std::unique_ptr& expr) { return expr->fn(expr->name.c_str(), state, expr->argv); } Value* StringValue(const char* str) { if (str == nullptr) { return nullptr; } return new Value(VAL_STRING, str); } Value* StringValue(const std::string& str) { return StringValue(str.c_str()); } Value* ConcatFn(const char* name, State* state, const std::vector>& argv) { if (argv.empty()) { return StringValue(""); } std::string result; for (size_t i = 0; i < argv.size(); ++i) { std::string str; if (!Evaluate(state, argv[i], &str)) { return nullptr; } result += str; } return StringValue(result); } Value* IfElseFn(const char* name, State* state, const std::vector>& argv) { if (argv.size() != 2 && argv.size() != 3) { state->errmsg = "ifelse expects 2 or 3 arguments"; return nullptr; } std::string cond; if (!Evaluate(state, argv[0], &cond)) { return nullptr; } if (!cond.empty()) { return EvaluateValue(state, argv[1]); } else if (argv.size() == 3) { return EvaluateValue(state, argv[2]); } return StringValue(""); } Value* AbortFn(const char* name, State* state, const std::vector>& argv) { std::string msg; if (!argv.empty() && Evaluate(state, argv[0], &msg)) { state->errmsg += msg; } else { state->errmsg += "called abort()"; } return nullptr; } Value* AssertFn(const char* name, State* state, const std::vector>& argv) { for (size_t i = 0; i < argv.size(); ++i) { std::string result; if (!Evaluate(state, argv[i], &result)) { return nullptr; } if (result.empty()) { int len = argv[i]->end - argv[i]->start; state->errmsg = "assert failed: " + state->script.substr(argv[i]->start, len); return nullptr; } } return StringValue(""); } Value* SleepFn(const char* name, State* state, const std::vector>& argv) { std::string val; if (!Evaluate(state, argv[0], &val)) { return nullptr; } int v; if (!android::base::ParseInt(val.c_str(), &v, 0)) { return nullptr; } sleep(v); return StringValue(val); } Value* StdoutFn(const char* name, State* state, const std::vector>& argv) { for (size_t i = 0; i < argv.size(); ++i) { std::string v; if (!Evaluate(state, argv[i], &v)) { return nullptr; } fputs(v.c_str(), stdout); } return StringValue(""); } Value* LogicalAndFn(const char* name, State* state, const std::vector>& argv) { std::string left; if (!Evaluate(state, argv[0], &left)) { return nullptr; } if (BooleanString(left)) { return EvaluateValue(state, argv[1]); } else { return StringValue(""); } } Value* LogicalOrFn(const char* name, State* state, const std::vector>& argv) { std::string left; if (!Evaluate(state, argv[0], &left)) { return nullptr; } if (!BooleanString(left)) { return EvaluateValue(state, argv[1]); } else { return StringValue(left); } } Value* LogicalNotFn(const char* name, State* state, const std::vector>& argv) { std::string val; if (!Evaluate(state, argv[0], &val)) { return nullptr; } return StringValue(BooleanString(val) ? "" : "t"); } Value* SubstringFn(const char* name, State* state, const std::vector>& argv) { std::string needle; if (!Evaluate(state, argv[0], &needle)) { return nullptr; } std::string haystack; if (!Evaluate(state, argv[1], &haystack)) { return nullptr; } std::string result = (haystack.find(needle) != std::string::npos) ? "t" : ""; return StringValue(result); } Value* EqualityFn(const char* name, State* state, const std::vector>& argv) { std::string left; if (!Evaluate(state, argv[0], &left)) { return nullptr; } std::string right; if (!Evaluate(state, argv[1], &right)) { return nullptr; } const char* result = (left == right) ? "t" : ""; return StringValue(result); } Value* InequalityFn(const char* name, State* state, const std::vector>& argv) { std::string left; if (!Evaluate(state, argv[0], &left)) { return nullptr; } std::string right; if (!Evaluate(state, argv[1], &right)) { return nullptr; } const char* result = (left != right) ? "t" : ""; return StringValue(result); } Value* SequenceFn(const char* name, State* state, const std::vector>& argv) { std::unique_ptr left(EvaluateValue(state, argv[0])); if (!left) { return nullptr; } return EvaluateValue(state, argv[1]); } Value* LessThanIntFn(const char* name, State* state, const std::vector>& argv) { if (argv.size() != 2) { state->errmsg = "less_than_int expects 2 arguments"; return nullptr; } std::vector args; if (!ReadArgs(state, argv, &args)) { return nullptr; } // Parse up to at least long long or 64-bit integers. int64_t l_int; if (!android::base::ParseInt(args[0].c_str(), &l_int)) { state->errmsg = "failed to parse int in " + args[0]; return nullptr; } int64_t r_int; if (!android::base::ParseInt(args[1].c_str(), &r_int)) { state->errmsg = "failed to parse int in " + args[1]; return nullptr; } return StringValue(l_int < r_int ? "t" : ""); } Value* GreaterThanIntFn(const char* name, State* state, const std::vector>& argv) { if (argv.size() != 2) { state->errmsg = "greater_than_int expects 2 arguments"; return nullptr; } std::vector args; if (!ReadArgs(state, argv, &args)) { return nullptr; } // Parse up to at least long long or 64-bit integers. int64_t l_int; if (!android::base::ParseInt(args[0].c_str(), &l_int)) { state->errmsg = "failed to parse int in " + args[0]; return nullptr; } int64_t r_int; if (!android::base::ParseInt(args[1].c_str(), &r_int)) { state->errmsg = "failed to parse int in " + args[1]; return nullptr; } return StringValue(l_int > r_int ? "t" : ""); } Value* Literal(const char* name, State* state, const std::vector>& argv) { return StringValue(name); } // ----------------------------------------------------------------- // the function table // ----------------------------------------------------------------- static std::unordered_map fn_table; void RegisterFunction(const std::string& name, Function fn) { fn_table[name] = fn; } Function FindFunction(const std::string& name) { if (fn_table.find(name) == fn_table.end()) { return nullptr; } else { return fn_table[name]; } } void RegisterBuiltins() { RegisterFunction("ifelse", IfElseFn); RegisterFunction("abort", AbortFn); RegisterFunction("assert", AssertFn); RegisterFunction("concat", ConcatFn); RegisterFunction("is_substring", SubstringFn); RegisterFunction("stdout", StdoutFn); RegisterFunction("sleep", SleepFn); RegisterFunction("less_than_int", LessThanIntFn); RegisterFunction("greater_than_int", GreaterThanIntFn); } // ----------------------------------------------------------------- // convenience methods for functions // ----------------------------------------------------------------- // Evaluate the expressions in argv, and put the results of strings in args. If any expression // evaluates to nullptr, return false. Return true on success. bool ReadArgs(State* state, const std::vector>& argv, std::vector* args) { return ReadArgs(state, argv, args, 0, argv.size()); } bool ReadArgs(State* state, const std::vector>& argv, std::vector* args, size_t start, size_t len) { if (args == nullptr) { return false; } if (start + len > argv.size()) { return false; } for (size_t i = start; i < start + len; ++i) { std::string var; if (!Evaluate(state, argv[i], &var)) { args->clear(); return false; } args->push_back(var); } return true; } // Evaluate the expressions in argv, and put the results of Value* in args. If any expression // evaluate to nullptr, return false. Return true on success. bool ReadValueArgs(State* state, const std::vector>& argv, std::vector>* args) { return ReadValueArgs(state, argv, args, 0, argv.size()); } bool ReadValueArgs(State* state, const std::vector>& argv, std::vector>* args, size_t start, size_t len) { if (args == nullptr) { return false; } if (len == 0 || start + len > argv.size()) { return false; } for (size_t i = start; i < start + len; ++i) { std::unique_ptr v(EvaluateValue(state, argv[i])); if (!v) { args->clear(); return false; } args->push_back(std::move(v)); } return true; } // Use printf-style arguments to compose an error message to put into // *state. Returns nullptr. Value* ErrorAbort(State* state, const char* format, ...) { va_list ap; va_start(ap, format); android::base::StringAppendV(&state->errmsg, format, ap); va_end(ap); return nullptr; } Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...) { std::string err_message; va_list ap; va_start(ap, format); android::base::StringAppendV(&err_message, format, ap); va_end(ap); // Ensure that there's exactly one line break at the end of the error message. state->errmsg = android::base::Trim(err_message) + "\n"; state->cause_code = cause_code; return nullptr; } State::State(const std::string& script, void* cookie) : script(script), cookie(cookie), error_code(kNoError), cause_code(kNoCause) {}