• 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           "\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