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