xref: /aosp_15_r20/frameworks/native/cmds/idlcli/utils.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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