• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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