| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 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 | */ |
| Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 16 | |
| 17 | #include "options.h" |
| 18 | |
| Christopher Wiley | a590de8 | 2015-09-15 15:46:28 -0700 | [diff] [blame] | 19 | #include <iostream> |
| Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 20 | #include <stdio.h> |
| Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 21 | |
| Christopher Wiley | 4432ccf | 2015-09-18 18:32:08 -0700 | [diff] [blame] | 22 | #include "logging.h" |
| 23 | #include "os.h" |
| 24 | |
| Christopher Wiley | a590de8 | 2015-09-15 15:46:28 -0700 | [diff] [blame] | 25 | using std::cerr; |
| 26 | using std::endl; |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 27 | using std::string; |
| 28 | using std::unique_ptr; |
| Christopher Wiley | eb1acc1 | 2015-09-16 11:25:13 -0700 | [diff] [blame] | 29 | using std::vector; |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 30 | |
| 31 | namespace android { |
| 32 | namespace aidl { |
| 33 | namespace { |
| 34 | |
| Christopher Wiley | 89eaab5 | 2015-09-15 14:46:46 -0700 | [diff] [blame] | 35 | unique_ptr<JavaOptions> java_usage() { |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 36 | fprintf(stderr, |
| 37 | "usage: aidl OPTIONS INPUT [OUTPUT]\n" |
| 38 | " aidl --preprocess OUTPUT INPUT...\n" |
| 39 | "\n" |
| 40 | "OPTIONS:\n" |
| 41 | " -I<DIR> search path for import statements.\n" |
| 42 | " -d<FILE> generate dependency file.\n" |
| 43 | " -a generate dependency file next to the output file with " |
| 44 | "the name based on the input file.\n" |
| 45 | " -p<FILE> file created by --preprocess to import.\n" |
| 46 | " -o<FOLDER> base output folder for generated files.\n" |
| 47 | " -b fail when trying to compile a parcelable.\n" |
| 48 | "\n" |
| 49 | "INPUT:\n" |
| 50 | " An aidl interface file.\n" |
| 51 | "\n" |
| 52 | "OUTPUT:\n" |
| 53 | " The generated interface files.\n" |
| 54 | " If omitted and the -o option is not used, the input filename is " |
| 55 | "used, with the .aidl extension changed to a .java extension.\n" |
| 56 | " If the -o option is used, the generated files will be placed in " |
| 57 | "the base output folder, under their package folder\n"); |
| Christopher Wiley | 89eaab5 | 2015-09-15 14:46:46 -0700 | [diff] [blame] | 58 | return unique_ptr<JavaOptions>(nullptr); |
| Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 59 | } |
| 60 | |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 61 | } // namespace |
| Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 62 | |
| Christopher Wiley | 89eaab5 | 2015-09-15 14:46:46 -0700 | [diff] [blame] | 63 | unique_ptr<JavaOptions> JavaOptions::Parse(int argc, const char* const* argv) { |
| 64 | unique_ptr<JavaOptions> options(new JavaOptions()); |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 65 | int i = 1; |
| 66 | |
| 67 | if (argc >= 2 && 0 == strcmp(argv[1], "--preprocess")) { |
| 68 | if (argc < 4) { |
| Christopher Wiley | 89eaab5 | 2015-09-15 14:46:46 -0700 | [diff] [blame] | 69 | return java_usage(); |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 70 | } |
| Christopher Wiley | 8f8cc9b | 2015-09-14 13:47:40 -0700 | [diff] [blame] | 71 | options->output_file_name_ = argv[2]; |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 72 | for (int i = 3; i < argc; i++) { |
| Christopher Wiley | 8f8cc9b | 2015-09-14 13:47:40 -0700 | [diff] [blame] | 73 | options->files_to_preprocess_.push_back(argv[i]); |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 74 | } |
| 75 | options->task = PREPROCESS_AIDL; |
| 76 | return options; |
| 77 | } |
| 78 | |
| Christopher Wiley | d93c5b7 | 2015-09-14 13:21:37 -0700 | [diff] [blame] | 79 | options->task = COMPILE_AIDL_TO_JAVA; |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 80 | // OPTIONS |
| 81 | while (i < argc) { |
| 82 | const char* s = argv[i]; |
| Christopher Wiley | d93c5b7 | 2015-09-14 13:21:37 -0700 | [diff] [blame] | 83 | const size_t len = strlen(s); |
| 84 | if (s[0] != '-') { |
| 85 | break; |
| 86 | } |
| 87 | if (len <= 1) { |
| 88 | fprintf(stderr, "unknown option (%d): %s\n", i, s); |
| Christopher Wiley | 89eaab5 | 2015-09-15 14:46:46 -0700 | [diff] [blame] | 89 | return java_usage(); |
| Christopher Wiley | d93c5b7 | 2015-09-14 13:21:37 -0700 | [diff] [blame] | 90 | } |
| 91 | // -I<system-import-path> |
| 92 | if (s[1] == 'I') { |
| 93 | if (len > 2) { |
| 94 | options->import_paths_.push_back(s + 2); |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 95 | } else { |
| Christopher Wiley | d93c5b7 | 2015-09-14 13:21:37 -0700 | [diff] [blame] | 96 | fprintf(stderr, "-I option (%d) requires a path.\n", i); |
| Christopher Wiley | 89eaab5 | 2015-09-15 14:46:46 -0700 | [diff] [blame] | 97 | return java_usage(); |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 98 | } |
| Christopher Wiley | d93c5b7 | 2015-09-14 13:21:37 -0700 | [diff] [blame] | 99 | } else if (s[1] == 'd') { |
| 100 | if (len > 2) { |
| 101 | options->dep_file_name_ = s + 2; |
| 102 | } else { |
| 103 | fprintf(stderr, "-d option (%d) requires a file.\n", i); |
| Christopher Wiley | 89eaab5 | 2015-09-15 14:46:46 -0700 | [diff] [blame] | 104 | return java_usage(); |
| Christopher Wiley | d93c5b7 | 2015-09-14 13:21:37 -0700 | [diff] [blame] | 105 | } |
| 106 | } else if (strcmp(s, "-a") == 0) { |
| 107 | options->auto_dep_file_ = true; |
| 108 | } else if (s[1] == 'p') { |
| 109 | if (len > 2) { |
| 110 | options->preprocessed_files_.push_back(s + 2); |
| 111 | } else { |
| 112 | fprintf(stderr, "-p option (%d) requires a file.\n", i); |
| Christopher Wiley | 89eaab5 | 2015-09-15 14:46:46 -0700 | [diff] [blame] | 113 | return java_usage(); |
| Christopher Wiley | d93c5b7 | 2015-09-14 13:21:37 -0700 | [diff] [blame] | 114 | } |
| 115 | } else if (s[1] == 'o') { |
| 116 | if (len > 2) { |
| 117 | options->output_base_folder_= s + 2; |
| 118 | } else { |
| 119 | fprintf(stderr, "-o option (%d) requires a path.\n", i); |
| Christopher Wiley | 89eaab5 | 2015-09-15 14:46:46 -0700 | [diff] [blame] | 120 | return java_usage(); |
| Christopher Wiley | d93c5b7 | 2015-09-14 13:21:37 -0700 | [diff] [blame] | 121 | } |
| 122 | } else if (strcmp(s, "-b") == 0) { |
| 123 | options->fail_on_parcelable_ = true; |
| Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 124 | } else { |
| Christopher Wiley | d93c5b7 | 2015-09-14 13:21:37 -0700 | [diff] [blame] | 125 | // s[1] is not known |
| 126 | fprintf(stderr, "unknown option (%d): %s\n", i, s); |
| Christopher Wiley | 89eaab5 | 2015-09-15 14:46:46 -0700 | [diff] [blame] | 127 | return java_usage(); |
| Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 128 | } |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 129 | i++; |
| 130 | } |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 131 | // INPUT |
| 132 | if (i < argc) { |
| Christopher Wiley | 8f8cc9b | 2015-09-14 13:47:40 -0700 | [diff] [blame] | 133 | options->input_file_name_ = argv[i]; |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 134 | i++; |
| 135 | } else { |
| 136 | fprintf(stderr, "INPUT required\n"); |
| Christopher Wiley | 89eaab5 | 2015-09-15 14:46:46 -0700 | [diff] [blame] | 137 | return java_usage(); |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 138 | } |
| Christopher Wiley | 4432ccf | 2015-09-18 18:32:08 -0700 | [diff] [blame] | 139 | if (!EndsWith(options->input_file_name_, ".aidl")) { |
| 140 | cerr << "Expected .aidl file for input but got " |
| 141 | << options->input_file_name_ << endl; |
| 142 | return java_usage(); |
| 143 | } |
| Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 144 | |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 145 | // OUTPUT |
| 146 | if (i < argc) { |
| Christopher Wiley | 8f8cc9b | 2015-09-14 13:47:40 -0700 | [diff] [blame] | 147 | options->output_file_name_ = argv[i]; |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 148 | i++; |
| Christopher Wiley | d93c5b7 | 2015-09-14 13:21:37 -0700 | [diff] [blame] | 149 | } else if (options->output_base_folder_.empty()) { |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 150 | // copy input into output and change the extension from .aidl to .java |
| Christopher Wiley | 8f8cc9b | 2015-09-14 13:47:40 -0700 | [diff] [blame] | 151 | options->output_file_name_= options->input_file_name_; |
| Christopher Wiley | 4432ccf | 2015-09-18 18:32:08 -0700 | [diff] [blame] | 152 | if (!ReplaceSuffix(".aidl", ".java", &options->output_file_name_)) { |
| 153 | // we should never get here since we validated the suffix. |
| 154 | LOG(FATAL) << "Internal aidl error."; |
| Christopher Wiley | 89eaab5 | 2015-09-15 14:46:46 -0700 | [diff] [blame] | 155 | return java_usage(); |
| Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 156 | } |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 157 | } |
| Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 158 | |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 159 | // anything remaining? |
| 160 | if (i != argc) { |
| 161 | fprintf(stderr, "unknown option%s:", |
| 162 | (i == argc - 1 ? (const char*)"" : (const char*)"s")); |
| 163 | for (; i < argc - 1; i++) { |
| 164 | fprintf(stderr, " %s", argv[i]); |
| 165 | } |
| 166 | fprintf(stderr, "\n"); |
| Christopher Wiley | 89eaab5 | 2015-09-15 14:46:46 -0700 | [diff] [blame] | 167 | return java_usage(); |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 168 | } |
| 169 | |
| 170 | return options; |
| Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 171 | } |
| 172 | |
| Christopher Wiley | a590de8 | 2015-09-15 15:46:28 -0700 | [diff] [blame] | 173 | namespace { |
| 174 | |
| 175 | unique_ptr<CppOptions> cpp_usage() { |
| 176 | cerr << "usage: aidl-cpp INPUT_FILE OUTPUT_DIR" << endl |
| 177 | << endl |
| 178 | << "OPTIONS:" << endl |
| 179 | << " -I<DIR> search path for import statements" << endl |
| 180 | << " -d<FILE> generate dependency file" << endl |
| 181 | << endl |
| 182 | << "INPUT_FILE:" << endl |
| 183 | << " an aidl interface file" << endl |
| 184 | << "OUTPUT_DIR:" << endl |
| 185 | << " directory to put generated code" << endl; |
| 186 | return unique_ptr<CppOptions>(nullptr); |
| 187 | } |
| 188 | |
| 189 | } // namespace |
| 190 | |
| Christopher Wiley | a590de8 | 2015-09-15 15:46:28 -0700 | [diff] [blame] | 191 | unique_ptr<CppOptions> CppOptions::Parse(int argc, const char* const* argv) { |
| 192 | unique_ptr<CppOptions> options(new CppOptions()); |
| 193 | int i = 1; |
| 194 | |
| 195 | // Parse flags, all of which start with '-' |
| 196 | for ( ; i < argc; ++i) { |
| 197 | const size_t len = strlen(argv[i]); |
| 198 | const char *s = argv[i]; |
| 199 | if (s[0] != '-') { |
| 200 | break; // On to the positional arguments. |
| 201 | } |
| 202 | if (len < 2) { |
| 203 | cerr << "Invalid argument '" << s << "'." << endl; |
| 204 | return cpp_usage(); |
| 205 | } |
| 206 | const string the_rest = s + 2; |
| 207 | if (s[1] == 'I') { |
| 208 | options->import_paths_.push_back(the_rest); |
| 209 | } else if (s[1] == 'd') { |
| 210 | options->dep_file_name_ = the_rest; |
| 211 | } else { |
| 212 | cerr << "Invalid argument '" << s << "'." << endl; |
| 213 | return cpp_usage(); |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | // There are exactly two positional arguments. |
| 218 | const int remaining_args = argc - i; |
| 219 | if (remaining_args != 2) { |
| 220 | cerr << "Expected 2 positional arguments but got " << remaining_args << "." << endl; |
| 221 | return cpp_usage(); |
| 222 | } |
| 223 | options->input_file_name_ = argv[i]; |
| Christopher Wiley | 4432ccf | 2015-09-18 18:32:08 -0700 | [diff] [blame] | 224 | if (!EndsWith(options->input_file_name_, ".aidl")) { |
| 225 | cerr << "Expected .aidl file for input but got " |
| 226 | << options->input_file_name_ << endl; |
| 227 | return cpp_usage(); |
| 228 | } |
| 229 | |
| Christopher Wiley | a590de8 | 2015-09-15 15:46:28 -0700 | [diff] [blame] | 230 | options->output_base_folder_ = argv[i + 1]; |
| 231 | |
| Christopher Wiley | 4432ccf | 2015-09-18 18:32:08 -0700 | [diff] [blame] | 232 | // C++ generation drops 6 files with very similar names based on the name |
| 233 | // of the input .aidl file. If this file is called foo/Bar.aidl, extract |
| 234 | // the substring "Bar" and store it in output_base_name_. |
| 235 | string base_name = options->input_file_name_; |
| 236 | if (!ReplaceSuffix(".aidl", "", &base_name)) { |
| 237 | LOG(FATAL) << "Internal aidl error."; |
| 238 | return cpp_usage(); |
| 239 | } |
| 240 | auto pos = base_name.rfind(OS_PATH_SEPARATOR); |
| 241 | if (pos != string::npos) { |
| 242 | base_name = base_name.substr(pos + 1); |
| 243 | } |
| 244 | // If the .aidl file is named something like ITopic.aidl, strip off |
| 245 | // the 'I' so that we can generate BpTopic and BnTopic. |
| 246 | if (base_name.length() > 2 && |
| 247 | isupper(base_name[0]) && |
| 248 | isupper(base_name[1])) { |
| 249 | base_name = base_name.substr(1); |
| 250 | } |
| 251 | options->output_base_name_ = base_name; |
| 252 | |
| Christopher Wiley | a590de8 | 2015-09-15 15:46:28 -0700 | [diff] [blame] | 253 | return options; |
| 254 | } |
| 255 | |
| Christopher Wiley | 4432ccf | 2015-09-18 18:32:08 -0700 | [diff] [blame] | 256 | string CppOptions::InputFileName() const { |
| 257 | return input_file_name_; |
| 258 | } |
| 259 | |
| 260 | vector<string> CppOptions::ImportPaths() const { |
| 261 | return import_paths_; |
| 262 | } |
| 263 | |
| 264 | string CppOptions::ClientCppFileName() const { |
| 265 | return MakeOutputName("Bp", ".cpp"); |
| 266 | } |
| 267 | |
| 268 | string CppOptions::ClientHeaderFileName() const { |
| 269 | return MakeOutputName("Bp", ".h"); |
| 270 | } |
| 271 | |
| 272 | string CppOptions::ServerCppFileName() const { |
| 273 | return MakeOutputName("Bn", ".cpp"); |
| 274 | } |
| 275 | |
| 276 | string CppOptions::ServerHeaderFileName() const { |
| 277 | return MakeOutputName("Bn", ".h"); |
| 278 | } |
| 279 | |
| 280 | string CppOptions::InterfaceCppFileName() const { |
| 281 | // Note that here we're putting back the 'I' we stripped off earlier. |
| 282 | return MakeOutputName("I", ".cpp"); |
| 283 | } |
| 284 | |
| 285 | string CppOptions::InterfaceHeaderFileName() const { |
| 286 | return MakeOutputName("I", ".h"); |
| 287 | } |
| 288 | |
| 289 | string CppOptions::MakeOutputName(const std::string& prefix, |
| 290 | const std::string& suffix) const { |
| 291 | if (output_base_folder_ == "-") |
| 292 | return "-"; |
| 293 | return output_base_folder_ + OS_PATH_SEPARATOR + |
| 294 | prefix + output_base_name_ + suffix; |
| 295 | } |
| 296 | |
| 297 | bool EndsWith(const string& str, const string& suffix) { |
| 298 | if (str.length() < suffix.length()) { |
| 299 | return false; |
| 300 | } |
| 301 | return std::equal(str.crbegin(), str.crbegin() + suffix.length(), |
| 302 | suffix.crbegin()); |
| 303 | } |
| 304 | |
| 305 | bool ReplaceSuffix(const string& old_suffix, |
| 306 | const string& new_suffix, |
| 307 | string* str) { |
| 308 | if (!EndsWith(*str, old_suffix)) return false; |
| 309 | str->replace(str->length() - old_suffix.length(), |
| 310 | old_suffix.length(), |
| 311 | new_suffix); |
| 312 | return true; |
| 313 | } |
| 314 | |
| 315 | |
| 316 | |
| Christopher Wiley | 4427d86 | 2015-09-14 11:07:39 -0700 | [diff] [blame] | 317 | } // namespace android |
| 318 | } // namespace aidl |