Home | History | Annotate | Download | only in aidl
      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