| /* |
| * Copyright (C) 2011 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 "EntryPoint.h" |
| |
| #include "Parser.h" |
| #include "TypeFactory.h" |
| #include "strUtils.h" |
| |
| #include <sstream> |
| #include <string> |
| |
| #include <stdio.h> |
| |
| EntryPoint::EntryPoint() |
| { |
| reset(); |
| } |
| |
| EntryPoint::~EntryPoint() |
| { |
| } |
| |
| void EntryPoint::reset() |
| { |
| m_unsupported = false; |
| m_customDecoder = false; |
| m_notApi = false; |
| m_flushOnEncode = false; |
| m_vars.clear(); |
| } |
| |
| // return true for valid line (need to get into the entry points list) |
| bool EntryPoint::parse(unsigned int lc, const std::string & str) |
| { |
| size_t pos, last; |
| std::string field; |
| |
| reset(); |
| std::string linestr = trim(str); |
| |
| if (linestr.size() == 0) return false; |
| if (linestr.at(0) == '#') return false; |
| |
| // skip PREFIX |
| field = getNextToken(linestr, 0, &last, "("); |
| pos = last + 1; |
| // return type |
| field = getNextToken(linestr, pos, &last, ",)"); |
| |
| std::string error; |
| std::string retTypeName; |
| if (!parseTypeDeclaration(field, &retTypeName, &error)) { |
| fprintf(stderr, |
| "line: %d: Parsing error in field <%s>: %s\n", |
| lc, |
| field.c_str(), |
| error.c_str()); |
| return false; |
| } |
| pos = last + 1; |
| const VarType *theType = TypeFactory::instance()->getVarTypeByName(retTypeName); |
| if (theType->name() == "UNKNOWN") { |
| fprintf(stderr, "UNKNOWN retval: %s\n", linestr.c_str()); |
| } |
| |
| m_retval.init(std::string(""), |
| theType, |
| std::string(""), |
| Var::POINTER_OUT, |
| std::string(""), |
| std::string(""), |
| std::string("")); |
| |
| // function name |
| m_name = getNextToken(linestr, pos, &last, ",)"); |
| pos = last + 1; |
| |
| // parameters; |
| int nvars = 0; |
| while (pos < linestr.size() - 1) { |
| field = getNextToken(linestr, pos, &last, ",)"); |
| if (field == "void") { |
| // 'void' is used as a special case for functions that don't take |
| // parameters at all. |
| break; |
| } |
| std::string vartype, varname; |
| if (!parseParameterDeclaration(field, &vartype, &varname, &error)) { |
| fprintf(stderr, |
| "line: %d: Parsing error in field <%s> (%s)\n", |
| lc, |
| field.c_str(), |
| error.c_str()); |
| return false; |
| } |
| nvars++; |
| const VarType *v = TypeFactory::instance()->getVarTypeByName(vartype); |
| if (v->id() == 0) { |
| fprintf(stderr, "%d: Unknown type: %s\n", lc, vartype.c_str()); |
| } else { |
| if (varname == "" && |
| !(v->name() == "void" && !v->isPointer())) { |
| std::ostringstream oss; |
| oss << "var" << nvars; |
| varname = oss.str(); |
| } |
| |
| m_vars.push_back(Var(varname, v, std::string(""), Var::POINTER_IN, "", "", "")); |
| } |
| pos = last + 1; |
| } |
| return true; |
| } |
| |
| void EntryPoint::print(FILE *fp, bool newline, |
| const std::string & name_suffix, |
| const std::string & name_prefix, |
| const std::string & ctx_param ) const |
| { |
| fprintf(fp, "%s %s%s%s(", |
| m_retval.type()->name().c_str(), |
| name_prefix.c_str(), |
| m_name.c_str(), |
| name_suffix.c_str()); |
| |
| if (ctx_param != "") fprintf(fp, "%s ", ctx_param.c_str()); |
| |
| for (size_t i = 0; i < m_vars.size(); i++) { |
| if (m_vars[i].isVoid()) continue; |
| if (i != 0 || ctx_param != "") fprintf(fp, ", "); |
| fprintf(fp, "%s %s", m_vars[i].type()->name().c_str(), |
| m_vars[i].name().c_str()); |
| } |
| fprintf(fp, ")%s", newline? "\n" : ""); |
| } |
| |
| Var * EntryPoint::var(const std::string & name) |
| { |
| Var *v = NULL; |
| for (size_t i = 0; i < m_vars.size(); i++) { |
| if (m_vars[i].name() == name) { |
| v = &m_vars[i]; |
| break; |
| } |
| } |
| return v; |
| } |
| |
| const Var * EntryPoint::var(const std::string & name) const |
| { |
| const Var *v = NULL; |
| for (size_t i = 0; i < m_vars.size(); i++) { |
| if (m_vars[i].name() == name) { |
| v = &m_vars[i]; |
| break; |
| } |
| } |
| return v; |
| } |
| |
| bool EntryPoint::hasPointers() |
| { |
| bool pointers = false; |
| if (m_retval.isPointer()) pointers = true; |
| if (!pointers) { |
| for (size_t i = 0; i < m_vars.size(); i++) { |
| if (m_vars[i].isPointer()) { |
| pointers = true; |
| break; |
| } |
| } |
| } |
| return pointers; |
| } |
| |
| int EntryPoint::validateVarAttr(const std::string& varname, size_t lc) const { |
| if (varname.size() == 0) { |
| fprintf(stderr, "ERROR: %u: Missing variable name in attribute\n", (unsigned int)lc); |
| return -1; |
| } |
| const Var * v = var(varname); |
| if (v == NULL) { |
| fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n", |
| (unsigned int)lc, varname.c_str(), name().c_str()); |
| return -2; |
| } |
| return 0; |
| } |
| |
| int EntryPoint::setAttribute(const std::string &line, size_t lc) |
| { |
| size_t pos = 0; |
| size_t last; |
| std::string token = getNextToken(line, 0, &last, WHITESPACE); |
| int err = 0; |
| Var* v = nullptr; |
| |
| if (token == "len") { |
| pos = last; |
| std::string varname = getNextToken(line, pos, &last, WHITESPACE); |
| err = validateVarAttr(varname, lc); |
| if (err < 0) return err; |
| |
| // set the size expression into var |
| v = var(varname); |
| pos = last; |
| v->setLenExpression(line.substr(pos)); |
| } else if (token == "param_check") { |
| pos = last; |
| std::string varname = getNextToken(line, pos, &last, WHITESPACE); |
| err = validateVarAttr(varname, lc); |
| if (err < 0) return err; |
| |
| v = var(varname); |
| pos = last; |
| v->setParamCheckExpression(line.substr(pos)); |
| |
| } else if (token == "dir") { |
| pos = last; |
| std::string varname = getNextToken(line, pos, &last, WHITESPACE); |
| err = validateVarAttr(varname, lc); |
| if (err < 0) return err; |
| |
| v = var(varname); |
| pos = last; |
| |
| std::string pointerDirStr = getNextToken(line, pos, &last, WHITESPACE); |
| if (pointerDirStr.size() == 0) { |
| fprintf(stderr, "ERROR: %u: missing pointer directions\n", (unsigned int)lc); |
| return -3; |
| } |
| |
| if (pointerDirStr == "out") { |
| v->setPointerDir(Var::POINTER_OUT); |
| } else if (pointerDirStr == "inout") { |
| v->setPointerDir(Var::POINTER_INOUT); |
| } else if (pointerDirStr == "in") { |
| v->setPointerDir(Var::POINTER_IN); |
| } else { |
| fprintf(stderr, "ERROR: %u: unknown pointer direction %s\n", |
| (unsigned int)lc, pointerDirStr.c_str()); |
| } |
| } else if (token == "var_flag") { |
| pos = last; |
| std::string varname = getNextToken(line, pos, &last, WHITESPACE); |
| err = validateVarAttr(varname, lc); |
| if (err < 0) return err; |
| |
| v = var(varname); |
| int count = 0; |
| for (;;) { |
| pos = last; |
| std::string flag = getNextToken(line, pos, &last, WHITESPACE); |
| if (flag.size() == 0) { |
| if (count == 0) { |
| fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc); |
| return -3; |
| } |
| break; |
| } |
| count++; |
| |
| if (flag == "nullAllowed") { |
| if (v->isPointer()) { |
| v->setNullAllowed(true); |
| } else { |
| fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n", |
| (unsigned int) lc, v->name().c_str()); |
| } |
| } else if (flag == "isLarge") { |
| if (v->isPointer()) { |
| v->setIsLarge(true); |
| } else { |
| fprintf(stderr, "WARNING: %u: setting isLarge flag for a non-pointer variable %s\n", |
| (unsigned int) lc, v->name().c_str()); |
| } |
| } else if (flag == "DMA") { |
| v->setDMA(true); |
| } else { |
| fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str()); |
| } |
| } |
| } else if (token == "custom_pack") { |
| pos = last; |
| std::string varname = getNextToken(line, pos, &last, WHITESPACE); |
| err = validateVarAttr(varname, lc); |
| if (err < 0) return err; |
| |
| v = var(varname); |
| pos = last; |
| v->setPackExpression(line.substr(pos)); |
| } else if (token == "custom_unpack") { |
| pos = last; |
| std::string varname = getNextToken(line, pos, &last, WHITESPACE); |
| |
| err = validateVarAttr(varname, lc); |
| if (err < 0) return err; |
| |
| v = var(varname); |
| pos = last; |
| v->setUnpackExpression(line.substr(pos)); |
| } else if (token == "custom_host_pack_tmp_alloc") { |
| pos = last; |
| std::string varname = getNextToken(line, pos, &last, WHITESPACE); |
| err = validateVarAttr(varname, lc); |
| if (err < 0) return err; |
| |
| v = var(varname); |
| if (v->pointerDir() == Var::POINTER_IN) { |
| fprintf(stderr, "ERROR: %u: variable %s is not an output or inout\n", |
| (unsigned int)lc, varname.c_str()); |
| return -2; |
| } |
| |
| pos = last; |
| v->setHostPackTmpAllocExpression(line.substr(pos)); |
| } else if (token == "custom_host_pack") { |
| pos = last; |
| std::string varname = getNextToken(line, pos, &last, WHITESPACE); |
| err = validateVarAttr(varname, lc); |
| if (err < 0) return err; |
| |
| v = var(varname); |
| if (v->pointerDir() == Var::POINTER_IN) { |
| fprintf(stderr, "ERROR: %u: variable %s is not an output or inout\n", |
| (unsigned int)lc, varname.c_str()); |
| return -2; |
| } |
| |
| pos = last; |
| v->setHostPackExpression(line.substr(pos)); |
| } else if (token == "custom_guest_unpack") { |
| pos = last; |
| std::string varname = getNextToken(line, pos, &last, WHITESPACE); |
| err = validateVarAttr(varname, lc); |
| if (err < 0) return err; |
| |
| v = var(varname); |
| if (v->pointerDir() == Var::POINTER_IN) { |
| fprintf(stderr, "ERROR: %u: variable %s is not an output or inout\n", |
| (unsigned int)lc, varname.c_str()); |
| return -2; |
| } |
| |
| pos = last; |
| v->setGuestUnpackExpression(line.substr(pos)); |
| } else if (token == "custom_guest_pack") { |
| pos = last; |
| std::string varname = getNextToken(line, pos, &last, WHITESPACE); |
| err = validateVarAttr(varname, lc); |
| if (err < 0) return err; |
| |
| v = var(varname); |
| if (v->pointerDir() == Var::POINTER_OUT) { |
| fprintf(stderr, "ERROR: %u: variable %s is not an input or inout\n", |
| (unsigned int)lc, varname.c_str()); |
| return -2; |
| } |
| |
| pos = last; |
| v->setGuestPackExpression(line.substr(pos)); |
| } else if (token == "custom_write") { |
| pos = last; |
| std::string varname = getNextToken(line, pos, &last, WHITESPACE); |
| err = validateVarAttr(varname, lc); |
| if (err < 0) return err; |
| |
| // set the size expression into var |
| v = var(varname); |
| pos = last; |
| v->setWriteExpression(line.substr(pos)); |
| } else if (token == "flag") { |
| pos = last; |
| std::string flag = getNextToken(line, pos, &last, WHITESPACE); |
| if (flag.size() == 0) { |
| fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc); |
| return -4; |
| } |
| |
| if (flag == "unsupported") { |
| setUnsupported(true); |
| } else if (flag == "custom_decoder") { |
| setCustomDecoder(true); |
| } else if (flag == "not_api") { |
| setNotApi(true); |
| } else if (flag == "flushOnEncode") { |
| setFlushOnEncode(true); |
| } else { |
| fprintf(stderr, "WARNING: %u: unknown flag %s\n", (unsigned int)lc, flag.c_str()); |
| } |
| } else if (token == "custom_host_api") { |
| pos = last; |
| std::string apiname = getNextToken(line, pos, &last, WHITESPACE); |
| setCustomHostApi(apiname); |
| } else { |
| fprintf(stderr, "WARNING: %u: unknown attribute %s\n", (unsigned int)lc, token.c_str()); |
| } |
| |
| return 0; |
| } |