• 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