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 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 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 174 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 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 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 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 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