1 /* 2 * Copyright (C) 2016 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 "AST.h" 18 19 #include <android-base/logging.h> 20 #include <android-base/macros.h> 21 #include <set> 22 #include <map> 23 #include <stdio.h> 24 #include <string> 25 #include <unistd.h> 26 #include <vector> 27 28 using namespace android; 29 30 extern status_t parseFile(android::AST *ast); 31 32 static void usage(const char *me) { 33 fprintf(stderr, 34 "usage: %s [-g] [-o dir] -p package (-r interface-root)+ (header-filepath)+\n", 35 me); 36 37 fprintf(stderr, " -h print this message\n"); 38 fprintf(stderr, " -o output path\n"); 39 fprintf(stderr, " (example: ~/android/master)\n"); 40 fprintf(stderr, " -p package\n"); 41 fprintf(stderr, " (example: android.hardware.baz@1.0)\n"); 42 fprintf(stderr, " -g (enable open-gl mode) \n"); 43 fprintf(stderr, " -r package:path root " 44 "(e.g., android.hardware:hardware/interfaces)\n"); 45 } 46 47 static void addPackageRootToMap(const std::string &val, 48 std::map<std::string, std::string> &packageRootPaths) { 49 auto index = val.find_first_of(':'); 50 CHECK(index != std::string::npos); 51 52 auto package = val.substr(0, index); 53 auto path = val.substr(index + 1); 54 55 packageRootPaths[package] = path; 56 } 57 58 static bool isPathPrefix(const std::string &prefix, const std::string &base) { 59 if (prefix.size() >= base.size()) { 60 LOG(DEBUG) << "Not long enough"; 61 return false; 62 } 63 64 if (base[prefix.size()] != '.') { 65 LOG(DEBUG) << "not full"; 66 return false; 67 } 68 69 return prefix == base.substr(0, prefix.size()); 70 } 71 72 static void applyPackageRootPath( 73 const std::map<std::string, std::string> &packageRootPaths, 74 const std::string &package, 75 std::string &outputPath) { 76 77 auto index = package.find_first_of('@'); 78 CHECK(index != std::string::npos); 79 80 auto packagePath = package.substr(0, index); 81 auto packageVersion = package.substr(index + 1); 82 83 for (auto const& pair : packageRootPaths) { 84 const std::string& rootPackage = pair.first; 85 const std::string& rootPath = pair.second; 86 87 if (isPathPrefix(rootPackage, packagePath)) { 88 89 packagePath = packagePath.substr(rootPackage.size() + 1); 90 std::replace(packagePath.begin(), packagePath.end(), '.', '/'); 91 packagePath += '/' + packageVersion; 92 93 if (outputPath.empty()) { 94 outputPath = rootPath; 95 } 96 97 outputPath += '/' + packagePath + '/'; 98 return; 99 } 100 } 101 102 CHECK(!outputPath.empty()) << "No package root path provided for: " << package; 103 104 outputPath += '/'; 105 } 106 107 // c2hal is intentionally leaky. Turn off LeakSanitizer by default. 108 extern "C" const char* __asan_default_options() { 109 return "detect_leaks=0"; 110 } 111 112 int main(int argc, char **argv) { 113 const char *me = argv[0]; 114 115 std::string outputDir; 116 std::string package; 117 std::map<std::string, std::string> packageRootPaths; 118 bool isOpenGl = false; 119 bool verbose = false; 120 121 int res; 122 while ((res = getopt(argc, argv, "ghvo:p:r:")) >= 0) { 123 switch (res) { 124 case 'o': { 125 outputDir = optarg; 126 break; 127 } 128 case 'p': { 129 package = optarg; 130 break; 131 } 132 case 'g': { 133 isOpenGl = true; 134 break; 135 } 136 case 'v': { 137 verbose = true; 138 break; 139 } 140 case 'r': 141 { 142 addPackageRootToMap(optarg, packageRootPaths); 143 break; 144 } 145 case 'h': 146 default: 147 { 148 usage(me); 149 exit(1); 150 break; 151 } 152 } 153 } 154 155 // if no arguments are provided, show usage instead of specific errors 156 if (optind == 1) { 157 usage(me); 158 exit(0); 159 } 160 161 if (verbose) { 162 SetMinimumLogSeverity(android::base::VERBOSE); 163 } 164 165 applyPackageRootPath(packageRootPaths, package, outputDir); 166 167 if (package.empty()) { 168 LOG(WARNING) << "You must provide a package."; 169 usage(me); 170 exit(0); 171 } 172 173 if (optind == argc) { 174 LOG(WARNING) << "You must provide a header-filepath."; 175 usage(me); 176 exit(0); 177 } 178 179 for(int i = optind; i < argc; i++) { 180 std::string path = argv[i]; 181 182 LOG(DEBUG) << "Processing " << path; 183 184 AST ast(path, outputDir, package, isOpenGl); 185 186 int res = parseFile(&ast); 187 188 if (res != 0) { 189 LOG(ERROR) << "Could not parse: " << res; 190 exit(1); 191 } 192 193 ast.processContents(); 194 195 ast.generateCode(); 196 } 197 198 return 0; 199 } 200