1 /* 2 * Copyright (C) 2019 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 #ifndef FRAMEWORK_NATIVE_CMDS_IDLCLI_UTILS_H_ 18 #define FRAMEWORK_NATIVE_CMDS_IDLCLI_UTILS_H_ 19 20 #include <android/binder_enums.h> 21 #include <hidl/HidlSupport.h> 22 23 #include <iomanip> 24 #include <iostream> 25 #include <map> 26 #include <sstream> 27 #include <string> 28 #include <vector> 29 30 namespace android { 31 namespace idlcli { 32 33 namespace overrides { 34 35 namespace details { 36 37 template <typename T> 38 inline std::istream &operator>>(std::istream &stream, T &out) { 39 auto pos = stream.tellg(); 40 auto tmp = +out; 41 auto min = +std::numeric_limits<T>::min(); 42 auto max = +std::numeric_limits<T>::max(); 43 stream >> tmp; 44 if (!stream) { 45 return stream; 46 } 47 if (tmp < min || tmp > max) { 48 stream.seekg(pos); 49 stream.setstate(std::ios_base::failbit); 50 return stream; 51 } 52 out = tmp; 53 return stream; 54 } 55 56 } // namespace details 57 58 // override for default behavior of treating as a character 59 inline std::istream &operator>>(std::istream &stream, int8_t &out) { 60 return details::operator>>(stream, out); 61 } 62 63 // override for default behavior of treating as a character 64 inline std::istream &operator>>(std::istream &stream, uint8_t &out) { 65 return details::operator>>(stream, out); 66 } 67 68 } // namespace overrides 69 70 template <typename T, typename R = ndk::enum_range<T>> 71 inline std::istream &operator>>(std::istream &stream, T &out) { 72 using overrides::operator>>; 73 auto validRange = R(); 74 auto pos = stream.tellg(); 75 std::underlying_type_t<T> in; 76 T tmp; 77 stream >> in; 78 if (!stream) { 79 return stream; 80 } 81 tmp = static_cast<T>(in); 82 if (tmp < *validRange.begin() || tmp > *std::prev(validRange.end())) { 83 stream.seekg(pos); 84 stream.setstate(std::ios_base::failbit); 85 return stream; 86 } 87 out = tmp; 88 return stream; 89 } 90 91 enum Status : unsigned int { 92 OK, 93 USAGE, 94 UNAVAILABLE, 95 ERROR, 96 }; 97 98 class Args { 99 public: Args(const int argc,const char * const argv[])100 Args(const int argc, const char *const argv[]) { 101 for (int argi = 0; argi < argc; argi++) { 102 mArgs.emplace_back(std::string_view(argv[argi])); 103 } 104 } 105 106 template <typename T = std::string> get()107 std::optional<T> get() { 108 return get<T>(false); 109 } 110 111 template <typename T = std::string> pop()112 std::optional<T> pop() { 113 return get<T>(true); 114 } 115 empty()116 bool empty() { return mArgs.empty(); } 117 118 private: 119 template <typename T> get(bool erase)120 std::optional<T> get(bool erase) { 121 using idlcli::operator>>; 122 using overrides::operator>>; 123 T retValue; 124 125 if (mArgs.empty()) { 126 return {}; 127 } 128 129 std::stringstream stream{std::string{mArgs.front()}}; 130 stream >> std::setbase(0) >> retValue; 131 if (!stream || !stream.eof()) { 132 return {}; 133 } 134 135 if (erase) { 136 mArgs.erase(mArgs.begin()); 137 } 138 139 return retValue; 140 } 141 142 std::vector<std::string_view> mArgs; 143 }; 144 145 class Command { 146 protected: 147 struct Usage { 148 std::string name; 149 std::vector<std::string> details; 150 }; 151 using UsageDetails = std::vector<Usage>; 152 153 public: 154 virtual ~Command() = default; 155 main(Args && args)156 Status main(Args &&args) { 157 Status status = doArgsAndMain(std::move(args)); 158 if (status == USAGE) { 159 printUsage(); 160 return ERROR; 161 } 162 if (status == UNAVAILABLE) { 163 std::cerr << "The requested operation is unavailable." << std::endl; 164 return ERROR; 165 } 166 return status; 167 } 168 169 private: 170 virtual std::string getDescription() const = 0; 171 virtual std::string getUsageSummary() const = 0; 172 virtual UsageDetails getUsageDetails() const = 0; 173 virtual Status doArgs(Args &args) = 0; 174 virtual Status doMain(Args &&args) = 0; 175 printUsage()176 void printUsage() const { 177 std::cerr << "Description:\n " << getDescription() << std::endl; 178 std::cerr << "Usage:\n " << mName << " " << getUsageSummary() << std::endl; 179 180 std::cerr << "Details:" << std::endl; 181 size_t entryNameWidth = 0; 182 for (auto &entry : getUsageDetails()) { 183 entryNameWidth = std::max(entryNameWidth, entry.name.length()); 184 } 185 for (auto &entry : getUsageDetails()) { 186 auto prefix = entry.name; 187 for (auto &line : entry.details) { 188 std::cerr << " " << std::left << std::setw(entryNameWidth + 8) << prefix << line 189 << std::endl; 190 prefix = ""; 191 } 192 } 193 } 194 doArgsAndMain(Args && args)195 Status doArgsAndMain(Args &&args) { 196 Status status; 197 mName = *args.pop(); 198 if ((status = doArgs(args)) != OK) { 199 return status; 200 } 201 if ((status = doMain(std::move(args))) != OK) { 202 return status; 203 } 204 return OK; 205 } 206 207 protected: 208 std::string mName; 209 }; 210 211 template <typename T> 212 class CommandRegistry { 213 private: 214 using CommandCreator = std::function<std::unique_ptr<Command>()>; 215 216 public: 217 template <typename U> Register(const std::string name)218 static CommandCreator Register(const std::string name) { 219 Instance()->mCommands[name] = [] { return std::make_unique<U>(); }; 220 return Instance()->mCommands[name]; 221 } 222 Create(const std::string name)223 static std::unique_ptr<Command> Create(const std::string name) { 224 auto it = Instance()->mCommands.find(name); 225 if (it == Instance()->mCommands.end()) { 226 return nullptr; 227 } 228 return it->second(); 229 } 230 List()231 static auto List() { 232 std::vector<std::string> list; 233 for (auto &it : Instance()->mCommands) { 234 list.push_back(it.first); 235 } 236 std::sort(list.begin(), list.end()); 237 return list; 238 } 239 240 private: Instance()241 static CommandRegistry *Instance() { 242 static CommandRegistry sRegistry; 243 return &sRegistry; 244 } 245 246 private: 247 std::map<const std::string, CommandCreator> mCommands; 248 }; 249 250 template <typename T> 251 class CommandWithSubcommands : public Command { 252 protected: doArgs(Args & args)253 Status doArgs(Args &args) override { 254 mCommand = CommandRegistry<T>::Create(*args.get()); 255 if (!mCommand) { 256 std::cerr << "Invalid Command!" << std::endl; 257 return USAGE; 258 } 259 return OK; 260 } 261 doMain(Args && args)262 Status doMain(Args &&args) override { return mCommand->main(std::move(args)); } 263 264 protected: 265 std::unique_ptr<Command> mCommand; 266 }; 267 268 } // namespace idlcli 269 } // namespace android 270 271 #endif // FRAMEWORK_NATIVE_CMDS_IDLCLI_UTILS_H_ 272