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