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
java_usage()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
Parse(int argc,const char * const * argv)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
DependencyFilePath() const183 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
cpp_usage()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
Parse(int argc,const char * const * argv)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
EndsWith(const string & str,const string & suffix)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
ReplaceSuffix(const string & old_suffix,const string & new_suffix,string * str)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