1 /* 2 * Copyright (C) 2015, 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 "options.h" 18 19 #include <cstring> 20 #include <iostream> 21 #include <stdio.h> 22 23 #include "logging.h" 24 #include "os.h" 25 26 using std::cerr; 27 using std::endl; 28 using std::string; 29 using std::unique_ptr; 30 using std::vector; 31 32 namespace android { 33 namespace aidl { 34 namespace { 35 36 unique_ptr<JavaOptions> java_usage() { 37 fprintf(stderr, 38 "usage: aidl OPTIONS INPUT [OUTPUT]\n" 39 " aidl --preprocess OUTPUT INPUT...\n" 40 "\n" 41 "OPTIONS:\n" 42 " -I<DIR> search path for import statements.\n" 43 " -d<FILE> generate dependency file.\n" 44 " -a generate dependency file next to the output file with " 45 "the name based on the input file.\n" 46 " -ninja generate dependency file in a format ninja " 47 "understands.\n" 48 " -p<FILE> file created by --preprocess to import.\n" 49 " -o<FOLDER> base output folder for generated files.\n" 50 " -b fail when trying to compile a parcelable.\n" 51 " -t include tracing code for systrace. Note that if either " 52 "the client or server code is not auto-generated by this tool, that " 53 "part will not be traced.\n" 54 "\n" 55 "INPUT:\n" 56 " An aidl interface file.\n" 57 "\n" 58 "OUTPUT:\n" 59 " The generated interface files.\n" 60 " If omitted and the -o option is not used, the input filename is " 61 "used, with the .aidl extension changed to a .java extension.\n" 62 " If the -o option is used, the generated files will be placed in " 63 "the base output folder, under their package folder\n"); 64 return unique_ptr<JavaOptions>(nullptr); 65 } 66 67 } // namespace 68 69 unique_ptr<JavaOptions> JavaOptions::Parse(int argc, const char* const* argv) { 70 unique_ptr<JavaOptions> options(new JavaOptions()); 71 int i = 1; 72 73 if (argc >= 2 && 0 == strcmp(argv[1], "--preprocess")) { 74 if (argc < 4) { 75 return java_usage(); 76 } 77 options->output_file_name_ = argv[2]; 78 for (int i = 3; i < argc; i++) { 79 options->files_to_preprocess_.push_back(argv[i]); 80 } 81 options->task = PREPROCESS_AIDL; 82 return options; 83 } 84 85 options->task = COMPILE_AIDL_TO_JAVA; 86 // OPTIONS 87 while (i < argc) { 88 const char* s = argv[i]; 89 const size_t len = strlen(s); 90 if (s[0] != '-') { 91 break; 92 } 93 if (len <= 1) { 94 fprintf(stderr, "unknown option (%d): %s\n", i, s); 95 return java_usage(); 96 } 97 // -I<system-import-path> 98 if (s[1] == 'I') { 99 if (len > 2) { 100 options->import_paths_.push_back(s + 2); 101 } else { 102 fprintf(stderr, "-I option (%d) requires a path.\n", i); 103 return java_usage(); 104 } 105 } else if (s[1] == 'd') { 106 if (len > 2) { 107 options->dep_file_name_ = s + 2; 108 } else { 109 fprintf(stderr, "-d option (%d) requires a file.\n", i); 110 return java_usage(); 111 } 112 } else if (strcmp(s, "-a") == 0) { 113 options->auto_dep_file_ = true; 114 } else if (s[1] == 'p') { 115 if (len > 2) { 116 options->preprocessed_files_.push_back(s + 2); 117 } else { 118 fprintf(stderr, "-p option (%d) requires a file.\n", i); 119 return java_usage(); 120 } 121 } else if (s[1] == 'o') { 122 if (len > 2) { 123 options->output_base_folder_= s + 2; 124 } else { 125 fprintf(stderr, "-o option (%d) requires a path.\n", i); 126 return java_usage(); 127 } 128 } else if (strcmp(s, "-b") == 0) { 129 options->fail_on_parcelable_ = true; 130 } else if (strcmp(s, "-ninja") == 0) { 131 options->dep_file_ninja_ = true; 132 } else if (strcmp(s, "-t") == 0) { 133 options->gen_traces_ = true; 134 } else { 135 // s[1] is not known 136 fprintf(stderr, "unknown option (%d): %s\n", i, s); 137 return java_usage(); 138 } 139 i++; 140 } 141 // INPUT 142 if (i < argc) { 143 options->input_file_name_ = argv[i]; 144 i++; 145 } else { 146 fprintf(stderr, "INPUT required\n"); 147 return java_usage(); 148 } 149 if (!EndsWith(options->input_file_name_, ".aidl")) { 150 cerr << "Expected .aidl file for input but got " 151 << options->input_file_name_ << endl; 152 return java_usage(); 153 } 154 155 // OUTPUT 156 if (i < argc) { 157 options->output_file_name_ = argv[i]; 158 i++; 159 } else if (options->output_base_folder_.empty()) { 160 // copy input into output and change the extension from .aidl to .java 161 options->output_file_name_= options->input_file_name_; 162 if (!ReplaceSuffix(".aidl", ".java", &options->output_file_name_)) { 163 // we should never get here since we validated the suffix. 164 LOG(FATAL) << "Internal aidl error."; 165 return java_usage(); 166 } 167 } 168 169 // anything remaining? 170 if (i != argc) { 171 fprintf(stderr, "unknown option%s:", 172 (i == argc - 1 ? (const char*)"" : (const char*)"s")); 173 for (; i < argc - 1; i++) { 174 fprintf(stderr, " %s", argv[i]); 175 } 176 fprintf(stderr, "\n"); 177 return java_usage(); 178 } 179 180 return options; 181 } 182 183 string JavaOptions::DependencyFilePath() const { 184 if (auto_dep_file_) { 185 return output_file_name_ + ".d"; 186 } 187 return dep_file_name_; 188 } 189 190 namespace { 191 192 unique_ptr<CppOptions> cpp_usage() { 193 cerr << "usage: aidl-cpp INPUT_FILE HEADER_DIR OUTPUT_FILE" << endl 194 << endl 195 << "OPTIONS:" << endl 196 << " -I<DIR> search path for import statements" << endl 197 << " -d<FILE> generate dependency file" << endl 198 << " -t include tracing code for systrace. Note that if the " 199 "client or server code is not auto-generated by this tool, that part " 200 "will not be traced." << endl 201 << " -ninja generate dependency file in a format ninja " 202 "understands" << endl 203 << endl 204 << "INPUT_FILE:" << endl 205 << " an aidl interface file" << endl 206 << "HEADER_DIR:" << endl 207 << " empty directory to put generated headers" << endl 208 << "OUTPUT_FILE:" << endl 209 << " path to write generated .cpp code" << endl; 210 return unique_ptr<CppOptions>(nullptr); 211 } 212 213 } // namespace 214 215 unique_ptr<CppOptions> CppOptions::Parse(int argc, const char* const* argv) { 216 unique_ptr<CppOptions> options(new CppOptions()); 217 int i = 1; 218 219 // Parse flags, all of which start with '-' 220 for ( ; i < argc; ++i) { 221 const size_t len = strlen(argv[i]); 222 const char *s = argv[i]; 223 if (s[0] != '-') { 224 break; // On to the positional arguments. 225 } 226 if (len < 2) { 227 cerr << "Invalid argument '" << s << "'." << endl; 228 return cpp_usage(); 229 } 230 const string the_rest = s + 2; 231 if (s[1] == 'I') { 232 options->import_paths_.push_back(the_rest); 233 } else if (s[1] == 'd') { 234 options->dep_file_name_ = the_rest; 235 } else if (s[1] == 't') { 236 options->gen_traces_ = true; 237 } else if (strcmp(s, "-ninja") == 0) { 238 options->dep_file_ninja_ = true; 239 } else { 240 cerr << "Invalid argument '" << s << "'." << endl; 241 return cpp_usage(); 242 } 243 } 244 245 // There are exactly three positional arguments. 246 const int remaining_args = argc - i; 247 if (remaining_args != 3) { 248 cerr << "Expected 3 positional arguments but got " << remaining_args << "." << endl; 249 return cpp_usage(); 250 } 251 252 options->input_file_name_ = argv[i]; 253 options->output_header_dir_ = argv[i + 1]; 254 options->output_file_name_ = argv[i + 2]; 255 256 if (!EndsWith(options->input_file_name_, ".aidl")) { 257 cerr << "Expected .aidl file for input but got " << options->input_file_name_ << endl; 258 return cpp_usage(); 259 } 260 261 return options; 262 } 263 264 bool EndsWith(const string& str, const string& suffix) { 265 if (str.length() < suffix.length()) { 266 return false; 267 } 268 return std::equal(str.crbegin(), str.crbegin() + suffix.length(), 269 suffix.crbegin()); 270 } 271 272 bool ReplaceSuffix(const string& old_suffix, 273 const string& new_suffix, 274 string* str) { 275 if (!EndsWith(*str, old_suffix)) return false; 276 str->replace(str->length() - old_suffix.length(), 277 old_suffix.length(), 278 new_suffix); 279 return true; 280 } 281 282 283 284 } // namespace android 285 } // namespace aidl 286