• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <option_parser.h>
17 
18 #include <iomanip>
19 #include <sstream>
20 
21 enum {
22     PARSER_NEXT = 0,
23     PARSER_ERROR = 1,
24     PARSER_PARSED = 2,
25     PARSER_PARSED_MORE = 3,
26 };
27 
ParseArgument(const char * arg,const char * arg2)28 int32_t OptionParser::ParseArgument(const char *arg, const char *arg2)
29 {
30     if (arguments.empty()) {
31         return PARSER_NEXT;
32     }
33 
34     std::stringstream ss(arg);
35     switch (arguments.front().type) {
36         case Argument::ValueType::i32:
37             ss >> std::setbase(0) >> arguments.front().result->i32;
38             break;
39         case Argument::ValueType::u32:
40             ss >> std::setbase(0) >> arguments.front().result->u32;
41             break;
42         case Argument::ValueType::i64:
43             ss >> std::setbase(0) >> arguments.front().result->i64;
44             break;
45         case Argument::ValueType::f64:
46             ss >> arguments.front().result->f64;
47             break;
48         case Argument::ValueType::str:
49             ss >> arguments.front().result->str;
50             break;
51     }
52 
53     if (!ss.eof() || !ss) {
54         error = "parse ";
55         error = error + arg + " error";
56         return PARSER_ERROR;
57     }
58 
59     arguments.pop_front();
60     return PARSER_PARSED;
61 }
62 
ParseArgc(const char * arg,const char * arg2)63 int32_t OptionParser::ParseArgc(const char *arg, const char *arg2)
64 {
65     if (arg[0] == 0) {
66         return PARSER_ERROR;
67     }
68 
69     if (arg[0] != '-') {
70         skipped.push_back(arg);
71         return PARSER_PARSED;
72     }
73 
74     if (arg[1] == 0) {
75         return PARSER_ERROR;
76     }
77     return PARSER_NEXT;
78 }
79 
ParseShortOption(const char * arg1,const char * arg2)80 int32_t OptionParser::ParseShortOption(const char *arg1, const char *arg2)
81 {
82     if (arg1[1] == '-') {
83         // long option
84         return PARSER_NEXT;
85     }
86 
87     for (const auto &option : options) {
88         if (option.so == &arg1[1]) {
89             if (option.type == Option::ValueType::bol) {
90                 option.result->bl = !option.result->bl;
91                 return PARSER_PARSED;
92             } else if (arg2 == nullptr) {
93                 error = option.so + " need argument";
94                 return PARSER_ERROR;
95             }
96 
97             std::stringstream ss(arg2);
98             switch (option.type) {
99                 case Option::ValueType::i32:
100                     ss >> std::setbase(0) >> option.result->i32;
101                     break;
102                 case Option::ValueType::u32:
103                     ss >> std::setbase(0) >> option.result->u32;
104                     break;
105                 case Option::ValueType::i64:
106                     ss >> std::setbase(0) >> option.result->i64;
107                     break;
108                 case Option::ValueType::f64:
109                     ss >> option.result->f64;
110                     break;
111                 case Option::ValueType::str:
112                     ss >> option.result->str;
113                     break;
114                 default:
115                     break;
116             }
117 
118             if (!ss.eof() || !ss) {
119                 error = "parse ";
120                 error = error + arg1 + " error, " + arg2;
121                 return PARSER_ERROR;
122             }
123 
124             return PARSER_PARSED_MORE;
125         }
126     }
127     return PARSER_NEXT;
128 }
129 
ParseLongEqualOption(const char * arg,const char * arg2)130 int32_t OptionParser::ParseLongEqualOption(const char *arg, const char *arg2)
131 {
132     if (arg[1] != '-') {
133         return PARSER_NEXT;
134     }
135 
136     int32_t ret = 0;
137     bool parsed = false;
138     for (const char *c = arg; *c; c++) {
139         if (*c == '=') {
140             std::string arg1(arg, c - arg);
141             std::string arg2(c + 1);
142             ret = ParseLongOption(arg1.c_str(), arg2.c_str());
143             parsed = true;
144             break;
145         }
146     }
147 
148     if (ret == PARSER_ERROR || ret == PARSER_NEXT) {
149         return ret;
150     }
151 
152     if (parsed) {
153         return PARSER_PARSED;
154     }
155     return PARSER_NEXT;
156 }
157 
ParseLongOption(const char * arg1,const char * arg2)158 int32_t OptionParser::ParseLongOption(const char *arg1, const char *arg2)
159 {
160     if (arg1[1] != '-') {
161         return PARSER_NEXT;
162     }
163 
164     for (const auto &option : options) {
165         if (option.lo == &arg1[0x2]) {
166             if (option.type == Option::ValueType::bol) {
167                 option.result->bl = !option.result->bl;
168                 return PARSER_PARSED;
169             } else if (arg2 == nullptr) {
170                 error = option.lo + " need argument";
171                 return PARSER_ERROR;
172             }
173 
174             std::stringstream ss(arg2);
175             switch (option.type) {
176                 case Option::ValueType::i32:
177                     ss >> std::setbase(0) >> option.result->i32;
178                     break;
179                 case Option::ValueType::u32:
180                     ss >> std::setbase(0) >> option.result->u32;
181                     break;
182                 case Option::ValueType::i64:
183                     ss >> std::setbase(0) >> option.result->i64;
184                     break;
185                 case Option::ValueType::f64:
186                     ss >> option.result->f64;
187                     break;
188                 case Option::ValueType::str:
189                     ss >> option.result->str;
190                     break;
191                 default:
192                     break;
193             }
194 
195             if (!ss.eof() || !ss) {
196                 error = "parse ";
197                 error = error + arg1 + " error, " + arg2;
198                 return PARSER_ERROR;
199             }
200             return PARSER_PARSED_MORE;
201         }
202     }
203     return PARSER_NEXT;
204 }
205 
AddSkipped(const char * arg,const char * arg2)206 int32_t OptionParser::AddSkipped(const char *arg, const char *arg2)
207 {
208     skipped.push_back(arg);
209     return PARSER_PARSED;
210 }
211 
Parse(int32_t argc,const char ** argv)212 int32_t OptionParser::Parse(int32_t argc, const char **argv)
213 {
214     int32_t (OptionParser:: *parsers[])(const char *, const char *) = {
215         &OptionParser::ParseArgument,
216         &OptionParser::ParseArgc,
217         &OptionParser::ParseShortOption,
218         &OptionParser::ParseLongEqualOption,
219         &OptionParser::ParseLongOption,
220         &OptionParser::AddSkipped,
221     };
222     for (int32_t i = 0; i < argc; i++) {
223         for (auto &parser : parsers) {
224             auto ret = (this->*parser)(argv[i], argv[i + 1]);
225             if (ret == PARSER_ERROR) {
226                 return ret;
227             } else if (ret == PARSER_PARSED_MORE) {
228                 i++;
229                 break;
230             } else if (ret == PARSER_PARSED) {
231                 break;
232             }
233         }
234     }
235 
236     if (!arguments.empty()) {
237         error = "need more arguments";
238         return 1;
239     } else {
240         skipped.push_back(nullptr);
241     }
242 
243     return 0;
244 }
245 
AddOption(const std::string & shortOpt,const std::string & longOpt,void * result,Option::ValueType type)246 int32_t OptionParser::AddOption(const std::string &shortOpt,
247     const std::string &longOpt, void *result, Option::ValueType type)
248 {
249     struct Option option = {
250         .so = shortOpt,
251         .lo = longOpt,
252         .result = reinterpret_cast<union Option::Value *>(result),
253         .type = type,
254     };
255     options.emplace_back(std::move(option));
256     return 0;
257 }
258 
AddArguments(void * result,Argument::ValueType type)259 int32_t OptionParser::AddArguments(void *result, Argument::ValueType type)
260 {
261     struct Argument argument = {
262         .result = reinterpret_cast<union Argument::Value *>(result),
263         .type = type,
264     };
265     arguments.emplace_back(std::move(argument));
266     return 0;
267 }
268 
GetErrorString()269 std::string OptionParser::GetErrorString()
270 {
271     return error;
272 }
273 
GetSkippedArgc()274 int32_t OptionParser::GetSkippedArgc()
275 {
276     return skipped.size() - 1;
277 }
278 
GetSkippedArgv()279 const char **OptionParser::GetSkippedArgv()
280 {
281     return skipped.data();
282 }
283