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