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