• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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