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 "Flags.h" 18 19 #include <iomanip> 20 #include <iostream> 21 #include <string> 22 #include <vector> 23 24 #include "androidfw/StringPiece.h" 25 26 #include "util/Util.h" 27 28 using android::StringPiece; 29 30 namespace aapt { 31 32 Flags& Flags::RequiredFlag(const StringPiece& name, 33 const StringPiece& description, std::string* value) { 34 auto func = [value](const StringPiece& arg) -> bool { 35 *value = arg.to_string(); 36 return true; 37 }; 38 39 flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false}); 40 return *this; 41 } 42 43 Flags& Flags::RequiredFlagList(const StringPiece& name, 44 const StringPiece& description, 45 std::vector<std::string>* value) { 46 auto func = [value](const StringPiece& arg) -> bool { 47 value->push_back(arg.to_string()); 48 return true; 49 }; 50 51 flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false}); 52 return *this; 53 } 54 55 Flags& Flags::OptionalFlag(const StringPiece& name, 56 const StringPiece& description, 57 Maybe<std::string>* value) { 58 auto func = [value](const StringPiece& arg) -> bool { 59 *value = arg.to_string(); 60 return true; 61 }; 62 63 flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false}); 64 return *this; 65 } 66 67 Flags& Flags::OptionalFlagList(const StringPiece& name, 68 const StringPiece& description, 69 std::vector<std::string>* value) { 70 auto func = [value](const StringPiece& arg) -> bool { 71 value->push_back(arg.to_string()); 72 return true; 73 }; 74 75 flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false}); 76 return *this; 77 } 78 79 Flags& Flags::OptionalFlagList(const StringPiece& name, 80 const StringPiece& description, 81 std::unordered_set<std::string>* value) { 82 auto func = [value](const StringPiece& arg) -> bool { 83 value->insert(arg.to_string()); 84 return true; 85 }; 86 87 flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false}); 88 return *this; 89 } 90 91 Flags& Flags::OptionalSwitch(const StringPiece& name, 92 const StringPiece& description, bool* value) { 93 auto func = [value](const StringPiece& arg) -> bool { 94 *value = true; 95 return true; 96 }; 97 98 flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 0, false}); 99 return *this; 100 } 101 102 void Flags::Usage(const StringPiece& command, std::ostream* out) { 103 constexpr size_t kWidth = 50; 104 105 *out << command << " [options]"; 106 for (const Flag& flag : flags_) { 107 if (flag.required) { 108 *out << " " << flag.name << " arg"; 109 } 110 } 111 112 *out << " files...\n\nOptions:\n"; 113 114 for (const Flag& flag : flags_) { 115 std::string argline = flag.name; 116 if (flag.num_args > 0) { 117 argline += " arg"; 118 } 119 120 // Split the description by newlines and write out the argument (which is 121 // empty after 122 // the first line) followed by the description line. This will make sure 123 // that multiline 124 // descriptions are still right justified and aligned. 125 for (StringPiece line : util::Tokenize(flag.description, '\n')) { 126 *out << " " << std::setw(kWidth) << std::left << argline << line << "\n"; 127 argline = " "; 128 } 129 } 130 *out << " " << std::setw(kWidth) << std::left << "-h" 131 << "Displays this help menu\n"; 132 out->flush(); 133 } 134 135 bool Flags::Parse(const StringPiece& command, 136 const std::vector<StringPiece>& args, 137 std::ostream* out_error) { 138 for (size_t i = 0; i < args.size(); i++) { 139 StringPiece arg = args[i]; 140 if (*(arg.data()) != '-') { 141 args_.push_back(arg.to_string()); 142 continue; 143 } 144 145 if (arg == "-h" || arg == "--help") { 146 Usage(command, out_error); 147 return false; 148 } 149 150 bool match = false; 151 for (Flag& flag : flags_) { 152 if (arg == flag.name) { 153 if (flag.num_args > 0) { 154 i++; 155 if (i >= args.size()) { 156 *out_error << flag.name << " missing argument.\n\n"; 157 Usage(command, out_error); 158 return false; 159 } 160 flag.action(args[i]); 161 } else { 162 flag.action({}); 163 } 164 flag.parsed = true; 165 match = true; 166 break; 167 } 168 } 169 170 if (!match) { 171 *out_error << "unknown option '" << arg << "'.\n\n"; 172 Usage(command, out_error); 173 return false; 174 } 175 } 176 177 for (const Flag& flag : flags_) { 178 if (flag.required && !flag.parsed) { 179 *out_error << "missing required flag " << flag.name << "\n\n"; 180 Usage(command, out_error); 181 return false; 182 } 183 } 184 return true; 185 } 186 187 const std::vector<std::string>& Flags::GetArgs() { return args_; } 188 189 } // namespace aapt 190