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