/* * Copyright (C) 2016 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 "AST.h" #include #include #include #include #include #include #include #include using namespace android; extern status_t parseFile(android::AST *ast); static void usage(const char *me) { fprintf(stderr, "usage: %s [-g] [-o dir] -p package (-r interface-root)+ (header-filepath)+\n", me); fprintf(stderr, " -h print this message\n"); fprintf(stderr, " -o output path\n"); fprintf(stderr, " (example: ~/android/master)\n"); fprintf(stderr, " -p package\n"); fprintf(stderr, " (example: android.hardware.baz@1.0)\n"); fprintf(stderr, " -g (enable open-gl mode) \n"); fprintf(stderr, " -r package:path root " "(e.g., android.hardware:hardware/interfaces)\n"); } static void addPackageRootToMap(const std::string &val, std::map &packageRootPaths) { auto index = val.find_first_of(':'); CHECK(index != std::string::npos); auto package = val.substr(0, index); auto path = val.substr(index + 1); packageRootPaths[package] = path; } static bool isPathPrefix(const std::string &prefix, const std::string &base) { if (prefix.size() >= base.size()) { LOG(DEBUG) << "Not long enough"; return false; } if (base[prefix.size()] != '.') { LOG(DEBUG) << "not full"; return false; } return prefix == base.substr(0, prefix.size()); } static void applyPackageRootPath( const std::map &packageRootPaths, const std::string &package, std::string &outputPath) { auto index = package.find_first_of('@'); CHECK(index != std::string::npos); auto packagePath = package.substr(0, index); auto packageVersion = package.substr(index + 1); for (auto const& pair : packageRootPaths) { const std::string& rootPackage = pair.first; const std::string& rootPath = pair.second; if (isPathPrefix(rootPackage, packagePath)) { packagePath = packagePath.substr(rootPackage.size() + 1); std::replace(packagePath.begin(), packagePath.end(), '.', '/'); packagePath += '/' + packageVersion; if (outputPath.empty()) { outputPath = rootPath; } outputPath += '/' + packagePath + '/'; return; } } CHECK(!outputPath.empty()) << "No package root path provided for: " << package; outputPath += '/'; } // c2hal is intentionally leaky. Turn off LeakSanitizer by default. extern "C" const char* __asan_default_options() { return "detect_leaks=0"; } int main(int argc, char **argv) { const char *me = argv[0]; std::string outputDir; std::string package; std::map packageRootPaths; bool isOpenGl = false; bool verbose = false; int res; while ((res = getopt(argc, argv, "ghvo:p:r:")) >= 0) { switch (res) { case 'o': { outputDir = optarg; break; } case 'p': { package = optarg; break; } case 'g': { isOpenGl = true; break; } case 'v': { verbose = true; break; } case 'r': { addPackageRootToMap(optarg, packageRootPaths); break; } case 'h': default: { usage(me); exit(1); break; } } } // if no arguments are provided, show usage instead of specific errors if (optind == 1) { usage(me); exit(0); } if (verbose) { SetMinimumLogSeverity(android::base::VERBOSE); } applyPackageRootPath(packageRootPaths, package, outputDir); if (package.empty()) { LOG(WARNING) << "You must provide a package."; usage(me); exit(0); } if (optind == argc) { LOG(WARNING) << "You must provide a header-filepath."; usage(me); exit(0); } for(int i = optind; i < argc; i++) { std::string path = argv[i]; LOG(DEBUG) << "Processing " << path; AST ast(path, outputDir, package, isOpenGl); int res = parseFile(&ast); if (res != 0) { LOG(ERROR) << "Could not parse: " << res; exit(1); } ast.processContents(); ast.generateCode(); } return 0; }