| /* |
| * 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 <android-base/logging.h> |
| #include <android-base/macros.h> |
| #include <set> |
| #include <map> |
| #include <stdio.h> |
| #include <string> |
| #include <unistd.h> |
| #include <vector> |
| |
| 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<std::string, std::string> &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<std::string, std::string> &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 += '/'; |
| } |
| |
| int main(int argc, char **argv) { |
| const char *me = argv[0]; |
| |
| std::string outputDir; |
| std::string package; |
| std::map<std::string, std::string> 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; |
| } |