blob: d9669999a142bcf1938ad49c02e35c5d16ab0d78 [file] [log] [blame]
Christopher Wiley4427d862015-09-14 11:07:39 -07001/*
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 Lesinskiffa16862014-01-23 18:17:42 -080016
17#include "options.h"
18
Christopher Wileya590de82015-09-15 15:46:28 -070019#include <iostream>
Adam Lesinskiffa16862014-01-23 18:17:42 -080020#include <stdio.h>
Adam Lesinskiffa16862014-01-23 18:17:42 -080021
Christopher Wiley4432ccf2015-09-18 18:32:08 -070022#include "logging.h"
23#include "os.h"
24
Christopher Wileya590de82015-09-15 15:46:28 -070025using std::cerr;
26using std::endl;
Christopher Wiley4427d862015-09-14 11:07:39 -070027using std::string;
28using std::unique_ptr;
Christopher Wileyeb1acc12015-09-16 11:25:13 -070029using std::vector;
Christopher Wiley4427d862015-09-14 11:07:39 -070030
31namespace android {
32namespace aidl {
33namespace {
34
Christopher Wiley89eaab52015-09-15 14:46:46 -070035unique_ptr<JavaOptions> java_usage() {
Christopher Wiley4427d862015-09-14 11:07:39 -070036 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 Wiley89eaab52015-09-15 14:46:46 -070058 return unique_ptr<JavaOptions>(nullptr);
Adam Lesinskiffa16862014-01-23 18:17:42 -080059}
60
Christopher Wiley4427d862015-09-14 11:07:39 -070061} // namespace
Adam Lesinskiffa16862014-01-23 18:17:42 -080062
Christopher Wiley89eaab52015-09-15 14:46:46 -070063unique_ptr<JavaOptions> JavaOptions::Parse(int argc, const char* const* argv) {
64 unique_ptr<JavaOptions> options(new JavaOptions());
Christopher Wiley4427d862015-09-14 11:07:39 -070065 int i = 1;
66
67 if (argc >= 2 && 0 == strcmp(argv[1], "--preprocess")) {
68 if (argc < 4) {
Christopher Wiley89eaab52015-09-15 14:46:46 -070069 return java_usage();
Christopher Wiley4427d862015-09-14 11:07:39 -070070 }
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -070071 options->output_file_name_ = argv[2];
Christopher Wiley4427d862015-09-14 11:07:39 -070072 for (int i = 3; i < argc; i++) {
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -070073 options->files_to_preprocess_.push_back(argv[i]);
Christopher Wiley4427d862015-09-14 11:07:39 -070074 }
75 options->task = PREPROCESS_AIDL;
76 return options;
77 }
78
Christopher Wileyd93c5b72015-09-14 13:21:37 -070079 options->task = COMPILE_AIDL_TO_JAVA;
Christopher Wiley4427d862015-09-14 11:07:39 -070080 // OPTIONS
81 while (i < argc) {
82 const char* s = argv[i];
Christopher Wileyd93c5b72015-09-14 13:21:37 -070083 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 Wiley89eaab52015-09-15 14:46:46 -070089 return java_usage();
Christopher Wileyd93c5b72015-09-14 13:21:37 -070090 }
91 // -I<system-import-path>
92 if (s[1] == 'I') {
93 if (len > 2) {
94 options->import_paths_.push_back(s + 2);
Christopher Wiley4427d862015-09-14 11:07:39 -070095 } else {
Christopher Wileyd93c5b72015-09-14 13:21:37 -070096 fprintf(stderr, "-I option (%d) requires a path.\n", i);
Christopher Wiley89eaab52015-09-15 14:46:46 -070097 return java_usage();
Christopher Wiley4427d862015-09-14 11:07:39 -070098 }
Christopher Wileyd93c5b72015-09-14 13:21:37 -070099 } 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 Wiley89eaab52015-09-15 14:46:46 -0700104 return java_usage();
Christopher Wileyd93c5b72015-09-14 13:21:37 -0700105 }
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 Wiley89eaab52015-09-15 14:46:46 -0700113 return java_usage();
Christopher Wileyd93c5b72015-09-14 13:21:37 -0700114 }
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 Wiley89eaab52015-09-15 14:46:46 -0700120 return java_usage();
Christopher Wileyd93c5b72015-09-14 13:21:37 -0700121 }
122 } else if (strcmp(s, "-b") == 0) {
123 options->fail_on_parcelable_ = true;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800124 } else {
Christopher Wileyd93c5b72015-09-14 13:21:37 -0700125 // s[1] is not known
126 fprintf(stderr, "unknown option (%d): %s\n", i, s);
Christopher Wiley89eaab52015-09-15 14:46:46 -0700127 return java_usage();
Adam Lesinskiffa16862014-01-23 18:17:42 -0800128 }
Christopher Wiley4427d862015-09-14 11:07:39 -0700129 i++;
130 }
Christopher Wiley4427d862015-09-14 11:07:39 -0700131 // INPUT
132 if (i < argc) {
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700133 options->input_file_name_ = argv[i];
Christopher Wiley4427d862015-09-14 11:07:39 -0700134 i++;
135 } else {
136 fprintf(stderr, "INPUT required\n");
Christopher Wiley89eaab52015-09-15 14:46:46 -0700137 return java_usage();
Christopher Wiley4427d862015-09-14 11:07:39 -0700138 }
Christopher Wiley4432ccf2015-09-18 18:32:08 -0700139 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 Lesinskiffa16862014-01-23 18:17:42 -0800144
Christopher Wiley4427d862015-09-14 11:07:39 -0700145 // OUTPUT
146 if (i < argc) {
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700147 options->output_file_name_ = argv[i];
Christopher Wiley4427d862015-09-14 11:07:39 -0700148 i++;
Christopher Wileyd93c5b72015-09-14 13:21:37 -0700149 } else if (options->output_base_folder_.empty()) {
Christopher Wiley4427d862015-09-14 11:07:39 -0700150 // copy input into output and change the extension from .aidl to .java
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700151 options->output_file_name_= options->input_file_name_;
Christopher Wiley4432ccf2015-09-18 18:32:08 -0700152 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 Wiley89eaab52015-09-15 14:46:46 -0700155 return java_usage();
Adam Lesinskiffa16862014-01-23 18:17:42 -0800156 }
Christopher Wiley4427d862015-09-14 11:07:39 -0700157 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800158
Christopher Wiley4427d862015-09-14 11:07:39 -0700159 // 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 Wiley89eaab52015-09-15 14:46:46 -0700167 return java_usage();
Christopher Wiley4427d862015-09-14 11:07:39 -0700168 }
169
170 return options;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800171}
172
Christopher Wileya590de82015-09-15 15:46:28 -0700173namespace {
174
175unique_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 Wileya590de82015-09-15 15:46:28 -0700191unique_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 Wiley4432ccf2015-09-18 18:32:08 -0700224 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 Wileya590de82015-09-15 15:46:28 -0700230 options->output_base_folder_ = argv[i + 1];
231
Christopher Wiley4432ccf2015-09-18 18:32:08 -0700232 // 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 Wileya590de82015-09-15 15:46:28 -0700253 return options;
254}
255
Christopher Wiley4432ccf2015-09-18 18:32:08 -0700256string CppOptions::InputFileName() const {
257 return input_file_name_;
258}
259
260vector<string> CppOptions::ImportPaths() const {
261 return import_paths_;
262}
263
264string CppOptions::ClientCppFileName() const {
265 return MakeOutputName("Bp", ".cpp");
266}
267
268string CppOptions::ClientHeaderFileName() const {
269 return MakeOutputName("Bp", ".h");
270}
271
272string CppOptions::ServerCppFileName() const {
273 return MakeOutputName("Bn", ".cpp");
274}
275
276string CppOptions::ServerHeaderFileName() const {
277 return MakeOutputName("Bn", ".h");
278}
279
280string CppOptions::InterfaceCppFileName() const {
281 // Note that here we're putting back the 'I' we stripped off earlier.
282 return MakeOutputName("I", ".cpp");
283}
284
285string CppOptions::InterfaceHeaderFileName() const {
286 return MakeOutputName("I", ".h");
287}
288
289string 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
297bool 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
305bool 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 Wiley4427d862015-09-14 11:07:39 -0700317} // namespace android
318} // namespace aidl