1 /*
2 * Copyright (c) 2022 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 #ifndef COMMAND_LINE_FLAGS_H
17 #define COMMAND_LINE_FLAGS_H
18 #include <iostream>
19 #include <string>
20 #include <vector>
21 #include <unordered_map>
22 #include <cstddef>
23 #include <inttypes.h>
24 #include <cstdint>
25 #include <type_traits>
26 #include <typeinfo>
27 #include <cstdlib>
28 #include <climits>
29
30 namespace CommandLineFlags {
31 enum class FlagTypes {
32 FT_void,
33 FT_bool,
34 FT_int8,
35 FT_int16,
36 FT_int32,
37 FT_int64,
38 FT_uint8,
39 FT_uint16,
40 FT_uint32,
41 FT_uint64,
42 FT_double,
43 FT_string,
44 FT_bool_array,
45 FT_int8_array,
46 FT_int16_array,
47 FT_int32_array,
48 FT_int64_array,
49 FT_uint8_array,
50 FT_uint16_array,
51 FT_uint32_array,
52 FT_uint64_array,
53 FT_double_array,
54 FT_string_array,
55 };
56
57 struct MetaFlag {
58 FlagTypes type_ {FlagTypes::FT_void};
59 void* addr_ {nullptr};
60 MetaFlag() = default;
MetaFlagMetaFlag61 MetaFlag(const FlagTypes& flagType, void* flagPtr): type_ {flagType}, addr_ {flagPtr} {}
62 };
63
64 std::unordered_map<std::string, MetaFlag> flags_ {};
65
66 template<typename T>
67 class FlagRegesterer {
68 public:
FlagRegesterer(const std::string & name,const T & flag)69 FlagRegesterer(const std::string& name, const T& flag)
70 {
71 if (flags_.count(name) != 0) {
72 std::cout << "CommandLineFlags WARN: flag " << name << " redefined" << std::endl;
73 } else {
74 auto& metaFlag = flags_[name];
75 metaFlag.addr_ = (void*) &flag;
76
77 if (std::is_same<T, bool>::value) {
78 metaFlag.type_ = FlagTypes::FT_bool;
79 } else if (std::is_same<T, int8_t>::value) {
80 metaFlag.type_ = FlagTypes::FT_int8;
81 } else if (std::is_same<T, int16_t>::value) {
82 metaFlag.type_ = FlagTypes::FT_int16;
83 } else if (std::is_same<T, int32_t>::value) {
84 metaFlag.type_ = FlagTypes::FT_int32;
85 } else if (std::is_same<T, int64_t>::value) {
86 metaFlag.type_ = FlagTypes::FT_int64;
87 } else if (std::is_same<T, uint8_t>::value) {
88 metaFlag.type_ = FlagTypes::FT_uint8;
89 } else if (std::is_same<T, uint16_t>::value) {
90 metaFlag.type_ = FlagTypes::FT_uint16;
91 } else if (std::is_same<T, uint32_t>::value) {
92 metaFlag.type_ = FlagTypes::FT_uint32;
93 } else if (std::is_same<T, uint64_t>::value) {
94 metaFlag.type_ = FlagTypes::FT_uint64;
95 } else if (std::is_same<T, double>::value) {
96 metaFlag.type_ = FlagTypes::FT_double;
97 } else if (std::is_same<T, std::string>::value) {
98 metaFlag.type_ = FlagTypes::FT_string;
99 } else if (std::is_same<T, std::vector<bool>>::value) {
100 metaFlag.type_ = FlagTypes::FT_bool_array;
101 } else if (std::is_same<T, std::vector<int8_t>>::value) {
102 metaFlag.type_ = FlagTypes::FT_int8_array;
103 } else if (std::is_same<T, std::vector<int16_t>>::value) {
104 metaFlag.type_ = FlagTypes::FT_int16_array;
105 } else if (std::is_same<T, std::vector<int32_t>>::value) {
106 metaFlag.type_ = FlagTypes::FT_int32_array;
107 } else if (std::is_same<T, std::vector<int64_t>>::value) {
108 metaFlag.type_ = FlagTypes::FT_int64_array;
109 } else if (std::is_same<T, std::vector<uint8_t>>::value) {
110 metaFlag.type_ = FlagTypes::FT_uint8_array;
111 } else if (std::is_same<T, std::vector<uint16_t>>::value) {
112 metaFlag.type_ = FlagTypes::FT_uint16_array;
113 } else if (std::is_same<T, std::vector<uint32_t>>::value) {
114 metaFlag.type_ = FlagTypes::FT_uint32_array;
115 } else if (std::is_same<T, std::vector<uint64_t>>::value) {
116 metaFlag.type_ = FlagTypes::FT_uint64_array;
117 } else if (std::is_same<T, std::vector<double>>::value) {
118 metaFlag.type_ = FlagTypes::FT_double_array;
119 } else if (std::is_same<T, std::vector<std::string>>::value) {
120 metaFlag.type_ = FlagTypes::FT_string_array;
121 }
122 }
123 }
124 };
125
PrintArgFormat()126 static inline void PrintArgFormat()
127 {
128 std::string format {"Arguments Format: <command> -<character> <value> --<word>[-<word>] <value>"};
129 std::cout << format << std::endl;
130 return;
131 }
132
ConvertToFlagName(char * argStr,int argLen)133 static inline std::string ConvertToFlagName(char* argStr, int argLen)
134 {
135 for (int k = 0; k < argLen; ++k) {
136 if (argStr[k] == '-') {
137 if (argStr[k-1] == '-') {
138 // continuous '-', bad argument
139 return "";
140 }
141 argStr[k] = '_';
142 }
143 }
144 return std::string(argStr, argLen);
145 }
146
GetFlagName(char *** argv,int & argIndex,std::string & flagName)147 static int GetFlagName(
148 char*** argv,
149 int& argIndex,
150 std::string& flagName)
151 {
152 if ((*argv)[argIndex] == nullptr) {
153 // argument has been removed, skip it
154 flagName = "";
155 ++argIndex;
156 return 0;
157 }
158
159 // get argument prefix length and argument length
160 char* argStr = (*argv)[argIndex];
161 int prefix {0};
162 int argLen {0};
163 bool keepCounting {true};
164 for (; argStr[argLen] != '\0'; ++argLen) {
165 if (argStr[argLen] != '-') {
166 keepCounting = false;
167 }
168 if (keepCounting and argStr[argLen] == '-') {
169 ++prefix;
170 }
171 }
172 argLen -= prefix;
173
174 // short argument
175 constexpr int shortFlagLen {1};
176 if (prefix == shortFlagLen and argLen == shortFlagLen) {
177 flagName = std::string(argStr + prefix, argLen);
178 ++argIndex;
179 return 0;
180 }
181
182 // long argument
183 constexpr int longPrefix {2};
184 if (prefix == longPrefix and argLen > shortFlagLen) {
185 flagName = ConvertToFlagName(argStr + longPrefix, argLen);
186 if (flagName.empty()) {
187 // bad argument
188 std::cout << "CommandLineFlags ERROR: unrecognized argument format: "
189 << argStr << std::endl;
190 PrintArgFormat();
191 return -1;
192 }
193 ++argIndex;
194 return 0;
195 }
196 // bad argument
197 std::cout << "CommandLineFlags ERROR: unrecognized argument format: "
198 << argStr << std::endl;
199 PrintArgFormat();
200 return -1;
201 }
202
GetFlagValue(char *** argv,int & argIndex,std::string & flagValue)203 static int GetFlagValue(
204 char*** argv,
205 int& argIndex,
206 std::string& flagValue)
207 {
208 if ((*argv)[argIndex] == nullptr) {
209 // arg removed, skip it
210 flagValue = "";
211 ++argIndex;
212 return 0;
213 }
214 char* argStr = (*argv)[argIndex];
215 int argLen {0};
216 for (; argStr[argLen] != '\0'; ++argLen);
217 flagValue = std::string(argStr, argLen);
218 ++argIndex;
219 return 0;
220 }
221
ClearCString(char * str)222 static void ClearCString(char* str)
223 {
224 if (str == nullptr) {
225 return;
226 }
227 for (int k = 0; ; ++k) {
228 if (str[k] == '\0') {
229 break;
230 }
231 str[k] = '\0';
232 }
233 return;
234 }
235
GetNextFlag(char *** argv,int & argIndex,bool rm,std::string & flagName,std::string & flagValue)236 static int GetNextFlag(
237 char*** argv,
238 int& argIndex,
239 bool rm,
240 std::string& flagName,
241 std::string& flagValue)
242 {
243 if (GetFlagName(argv, argIndex, flagName) != 0) {
244 return -1;
245 }
246 GetFlagValue(argv, argIndex, flagValue);
247 // flag parsing done
248 if (rm and flags_.count(flagName) != 0) {
249 // remove parsed argument and its value
250 ClearCString((*argv)[argIndex - 1]);
251 ClearCString((*argv)[argIndex - 2]); // 2: point of args
252 }
253 return 0;
254 }
255
ParseBoolFlag(const std::string & flag,const std::string & valStr)256 static int ParseBoolFlag(const std::string& flag, const std::string& valStr)
257 {
258 bool *val = (bool*) flags_[flag].addr_;
259 if (valStr.compare("false") == 0) {
260 *val = false;
261 } else if (valStr.compare("true") == 0) {
262 *val = true;
263 } else {
264 std::cout << "CommandLineFlags ERROR: argument " << flag
265 << " of bool type should only be assigned with 'true' or 'false' but "
266 << valStr << " is given" << std::endl;
267 return -1;
268 }
269 return 0;
270 }
271
272 // we will not handle any exceptions thrown by std::stoi() series functions, we should
273 // just let exceptions abort the process.
ParseInt8Flag(const std::string & flag,const std::string & valStr)274 static int ParseInt8Flag(const std::string& flag, const std::string& valStr)
275 {
276 char* pos = nullptr;
277 long int tmpVal = strtol(valStr.c_str(), &pos, 10);
278 if (tmpVal == 0L || tmpVal == LONG_MAX || tmpVal == LONG_MIN) {
279 std::cout << "CommandLineFlags ERROR: argument " << flag
280 << " of numeric type should only be assigned with number but "
281 << valStr << " is given" << std::endl;
282 return -1;
283 }
284 int8_t* val = (int8_t*) flags_[flag].addr_;
285 *val = static_cast<int8_t>(tmpVal);
286 return 0;
287 }
288
ParseInt16Flag(const std::string & flag,const std::string & valStr)289 static int ParseInt16Flag(const std::string& flag, const std::string& valStr)
290 {
291 char* pos = nullptr;
292 long int tmpVal = strtol(valStr.c_str(), &pos, 10);
293 if (tmpVal == 0L || tmpVal == LONG_MAX || tmpVal == LONG_MIN) {
294 std::cout << "CommandLineFlags ERROR: argument " << flag
295 << " of numeric type should only be assigned with number but "
296 << valStr << " is given" << std::endl;
297 return -1;
298 }
299 int16_t* val = (int16_t*) flags_[flag].addr_;
300 *val = static_cast<int16_t>(tmpVal);
301 return 0;
302 }
303
ParseInt32Flag(const std::string & flag,const std::string & valStr)304 static int ParseInt32Flag(const std::string& flag, const std::string& valStr)
305 {
306 char* pos = nullptr;
307 long int tmpVal = strtol(valStr.c_str(), &pos, 10);
308 if (tmpVal == 0L || tmpVal == LONG_MAX || tmpVal == LONG_MIN) {
309 std::cout << "CommandLineFlags ERROR: argument " << flag
310 << " of numeric type should only be assigned with number but "
311 << valStr << " is given" << std::endl;
312 return -1;
313 }
314 int32_t* val = (int32_t*) flags_[flag].addr_;
315 *val = static_cast<int32_t>(tmpVal);
316 return 0;
317 }
318
ParseInt64Flag(const std::string & flag,const std::string & valStr)319 static int ParseInt64Flag(const std::string& flag, const std::string& valStr)
320 {
321 char* pos = nullptr;
322 long int tmpVal = strtol(valStr.c_str(), &pos, 10);
323 if (tmpVal == 0L || tmpVal == LONG_MAX || tmpVal == LONG_MIN) {
324 std::cout << "CommandLineFlags ERROR: argument " << flag
325 << " of numeric type should only be assigned with number but "
326 << valStr << " is given" << std::endl;
327 return -1;
328 }
329 int64_t* val = (int64_t*) flags_[flag].addr_;
330 *val = static_cast<int64_t>(tmpVal);
331 return 0;
332 }
333
ParseUint8Flag(const std::string & flag,const std::string & valStr)334 static int ParseUint8Flag(const std::string& flag, const std::string& valStr)
335 {
336 char* pos = nullptr;
337 unsigned long long int tmpVal = strtoull(valStr.c_str(), &pos, 10);
338 if (tmpVal == 0ULL || tmpVal == ULONG_MAX) {
339 std::cout << "CommandLineFlags ERROR: argument " << flag
340 << " of numeric type should only be assigned with number but "
341 << valStr << " is given" << std::endl;
342 return -1;
343 }
344 uint8_t* val = (uint8_t*) flags_[flag].addr_;
345 *val = static_cast<uint8_t>(tmpVal);
346 return 0;
347 }
348
ParseUint16Flag(const std::string & flag,const std::string & valStr)349 static int ParseUint16Flag(const std::string& flag, const std::string& valStr)
350 {
351 char* pos = nullptr;
352 unsigned long long int tmpVal = strtoull(valStr.c_str(), &pos, 10);
353 if (tmpVal == 0ULL || tmpVal == ULONG_MAX) {
354 std::cout << "CommandLineFlags ERROR: argument " << flag
355 << " of numeric type should only be assigned with number but "
356 << valStr << " is given" << std::endl;
357 return -1;
358 }
359 uint16_t* val = (uint16_t*) flags_[flag].addr_;
360 *val = static_cast<uint16_t>(tmpVal);
361 return 0;
362 }
363
ParseUint32Flag(const std::string & flag,const std::string & valStr)364 static int ParseUint32Flag(const std::string& flag, const std::string& valStr)
365 {
366 char* pos = nullptr;
367 unsigned long long int tmpVal = strtoull(valStr.c_str(), &pos, 10);
368 if (tmpVal == 0ULL || tmpVal == ULONG_MAX) {
369 std::cout << "CommandLineFlags ERROR: argument " << flag
370 << " of numeric type should only be assigned with number but "
371 << valStr << " is given" << std::endl;
372 return -1;
373 }
374 uint32_t* val = (uint32_t*) flags_[flag].addr_;
375 *val = static_cast<uint32_t>(tmpVal);
376 return 0;
377 }
378
ParseUint64Flag(const std::string & flag,const std::string & valStr)379 static int ParseUint64Flag(const std::string& flag, const std::string& valStr)
380 {
381 char* pos = nullptr;
382 unsigned long long int tmpVal = strtoull(valStr.c_str(), &pos, 10);
383 if (tmpVal == 0ULL || tmpVal == ULONG_MAX) {
384 std::cout << "CommandLineFlags ERROR: argument " << flag
385 << " of numeric type should only be assigned with number but "
386 << valStr << " is given" << std::endl;
387 return -1;
388 }
389 uint64_t* val = (uint64_t*) flags_[flag].addr_;
390 *val = static_cast<uint64_t>(tmpVal);
391 return 0;
392 }
393
ParseDoubleFlag(const std::string & flag,const std::string & valStr)394 static int ParseDoubleFlag(const std::string& flag, const std::string& valStr)
395 {
396 char* pos = nullptr;
397 double tmpVal = strtod(valStr.c_str(), &pos);
398 if (tmpVal == 0.0 || tmpVal == HUGE_VAL) {
399 std::cout << "CommandLineFlags ERROR: argument " << flag
400 << " of numeric type should only be assigned with number but "
401 << valStr << " is given" << std::endl;
402 return -1;
403 }
404 double* val = (double*) flags_[flag].addr_;
405 *val = tmpVal;
406 return 0;
407 }
408
ParseStringFlag(const std::string & flag,const std::string & valStr)409 static int ParseStringFlag(const std::string& flag, const std::string& valStr)
410 {
411 std::string* val = (std::string*) flags_[flag].addr_;
412 *val = valStr;
413 return 0;
414 }
415
ParseBoolArrayFlag(const std::string & flag,const std::string & valStr)416 static int ParseBoolArrayFlag(const std::string& flag, const std::string& valStr)
417 {
418 std::vector<bool>* val = (std::vector<bool>*) flags_[flag].addr_;
419 for (std::size_t start = 0, end = 0; end <= valStr.length(); ++end) {
420 if (valStr[end] == ',' or end == valStr.length()) {
421 if (start == end) {
422 ++start;
423 continue;
424 }
425 auto str = valStr.substr(start, end - start);
426 if (str.compare("false") == 0) {
427 val->push_back(false);
428 } else if (str.compare("true") == 0) {
429 val->push_back(true);
430 } else {
431 std::cout << "CommandLineFlags ERROR: argument " << flag
432 << " of bool type should only be assigned with 'true' or 'false' but "
433 << valStr << " is given" << std::endl;
434 val->clear();
435 return -1;
436 }
437 start = end + 1;
438 }
439 }
440 return 0;
441 }
442
ParseInt8ArrayFlag(const std::string & flag,const std::string & valStr)443 static int ParseInt8ArrayFlag(const std::string& flag, const std::string& valStr)
444 {
445 std::vector<int8_t>* val = (std::vector<int8_t>*) flags_[flag].addr_;
446 for (std::size_t start = 0, end = 0; end <= valStr.length(); ++end) {
447 if (valStr[end] == ',' or end == valStr.length()) {
448 if (start == end) {
449 ++start;
450 continue;
451 }
452 auto str = valStr.substr(start, end - start);
453 char* pos = nullptr;
454 long int tmpVal = strtol(valStr.c_str(), &pos, 10);
455 if (tmpVal == 0L || tmpVal == LONG_MAX || tmpVal == LONG_MIN) {
456 std::cout << "CommandLineFlags ERROR: argument " << flag
457 << " of numeric type should only be assigned with number but "
458 << valStr << " is given" << std::endl;
459 val->clear();
460 return -1;
461 }
462 val->push_back(static_cast<int8_t>(tmpVal));
463 start = end + 1;
464 }
465 }
466 return 0;
467 }
468
ParseInt16ArrayFlag(const std::string & flag,const std::string & valStr)469 static int ParseInt16ArrayFlag(const std::string& flag, const std::string& valStr)
470 {
471 std::vector<int16_t>* val = (std::vector<int16_t>*) flags_[flag].addr_;
472 for (std::size_t start = 0, end = 0; end <= valStr.length(); ++end) {
473 if (valStr[end] == ',' or end == valStr.length()) {
474 if (start == end) {
475 ++start;
476 continue;
477 }
478 auto str = valStr.substr(start, end - start);
479 char* pos = nullptr;
480 long int tmpVal = strtol(valStr.c_str(), &pos, 10);
481 if (tmpVal == 0L || tmpVal == LONG_MAX || tmpVal == LONG_MIN) {
482 std::cout << "CommandLineFlags ERROR: argument " << flag
483 << " of numeric type should only be assigned with number but "
484 << valStr << " is given" << std::endl;
485 val->clear();
486 return -1;
487 }
488 val->push_back(static_cast<int16_t>(tmpVal));
489 start = end + 1;
490 }
491 }
492 return 0;
493 }
494
ParseInt32ArrayFlag(const std::string & flag,const std::string & valStr)495 static int ParseInt32ArrayFlag(const std::string& flag, const std::string& valStr)
496 {
497 std::vector<int32_t>* val = (std::vector<int32_t>*) flags_[flag].addr_;
498 for (std::size_t start = 0, end = 0; end <= valStr.length(); ++end) {
499 if (valStr[end] == ',' or end == valStr.length()) {
500 if (start == end) {
501 ++start;
502 continue;
503 }
504 auto str = valStr.substr(start, end - start);
505 char* pos = nullptr;
506 long int tmpVal = strtol(valStr.c_str(), &pos, 10);
507 if (tmpVal == 0L || tmpVal == LONG_MAX || tmpVal == LONG_MIN) {
508 std::cout << "CommandLineFlags ERROR: argument " << flag
509 << " of numeric type should only be assigned with number but "
510 << valStr << " is given" << std::endl;
511 val->clear();
512 return -1;
513 }
514 val->push_back(static_cast<int32_t>(tmpVal));
515 start = end + 1;
516 }
517 }
518 return 0;
519 }
520
ParseInt64ArrayFlag(const std::string & flag,const std::string & valStr)521 static int ParseInt64ArrayFlag(const std::string& flag, const std::string& valStr)
522 {
523 std::vector<int64_t>* val = (std::vector<int64_t>*) flags_[flag].addr_;
524 for (std::size_t start = 0, end = 0; end <= valStr.length(); ++end) {
525 if (valStr[end] == ',' or end == valStr.length()) {
526 if (start == end) {
527 ++start;
528 continue;
529 }
530 auto str = valStr.substr(start, end - start);
531 char* pos = nullptr;
532 long int tmpVal = strtol(valStr.c_str(), &pos, 10);
533 if (tmpVal == 0L || tmpVal == LONG_MAX || tmpVal == LONG_MIN) {
534 std::cout << "CommandLineFlags ERROR: argument " << flag
535 << " of numeric type should only be assigned with number but "
536 << valStr << " is given" << std::endl;
537 val->clear();
538 return -1;
539 }
540 val->push_back(static_cast<int64_t>(tmpVal));
541 start = end + 1;
542 }
543 }
544 return 0;
545 }
546
ParseUint8ArrayFlag(const std::string & flag,const std::string & valStr)547 static int ParseUint8ArrayFlag(const std::string& flag, const std::string& valStr)
548 {
549 std::vector<uint8_t>* val = (std::vector<uint8_t>*) flags_[flag].addr_;
550 for (std::size_t start = 0, end = 0; end <= valStr.length(); ++end) {
551 if (valStr[end] == ',' or end == valStr.length()) {
552 if (start == end) {
553 ++start;
554 continue;
555 }
556 auto str = valStr.substr(start, end - start);
557 char* pos = nullptr;
558 unsigned long long int tmpVal = strtoull(valStr.c_str(), &pos, 10);
559 if (tmpVal == 0ULL || tmpVal == ULONG_MAX) {
560 std::cout << "CommandLineFlags ERROR: argument " << flag
561 << " of numeric type should only be assigned with number but "
562 << valStr << " is given" << std::endl;
563 val->clear();
564 return -1;
565 }
566 val->push_back(static_cast<uint8_t>(tmpVal));
567 start = end + 1;
568 }
569 }
570 return 0;
571 }
572
ParseUint16ArrayFlag(const std::string & flag,const std::string & valStr)573 static int ParseUint16ArrayFlag(const std::string& flag, const std::string& valStr)
574 {
575 std::vector<uint16_t>* val = (std::vector<uint16_t>*) flags_[flag].addr_;
576 for (std::size_t start = 0, end = 0; end <= valStr.length(); ++end) {
577 if (valStr[end] == ',' or end == valStr.length()) {
578 if (start == end) {
579 ++start;
580 continue;
581 }
582 auto str = valStr.substr(start, end - start);
583 char* pos = nullptr;
584 unsigned long long int tmpVal = strtoull(valStr.c_str(), &pos, 10);
585 if (tmpVal == 0ULL || tmpVal == ULONG_MAX) {
586 std::cout << "CommandLineFlags ERROR: argument " << flag
587 << " of numeric type should only be assigned with number but "
588 << valStr << " is given" << std::endl;
589 val->clear();
590 return -1;
591 }
592 val->push_back(static_cast<uint16_t>(tmpVal));
593 start = end + 1;
594 }
595 }
596 return 0;
597 }
598
ParseUint32ArrayFlag(const std::string & flag,const std::string & valStr)599 static int ParseUint32ArrayFlag(const std::string& flag, const std::string& valStr)
600 {
601 std::vector<uint32_t>* val = (std::vector<uint32_t>*) flags_[flag].addr_;
602 for (std::size_t start = 0, end = 0; end <= valStr.length(); ++end) {
603 if (valStr[end] == ',' or end == valStr.length()) {
604 if (start == end) {
605 ++start;
606 continue;
607 }
608 auto str = valStr.substr(start, end - start);
609 char* pos = nullptr;
610 unsigned long long int tmpVal = strtoull(valStr.c_str(), &pos, 10);
611 if (tmpVal == 0ULL || tmpVal == ULONG_MAX) {
612 std::cout << "CommandLineFlags ERROR: argument " << flag
613 << " of numeric type should only be assigned with number but "
614 << valStr << " is given" << std::endl;
615 val->clear();
616 return -1;
617 }
618 val->push_back(static_cast<uint32_t>(tmpVal));
619 start = end + 1;
620 }
621 }
622 return 0;
623 }
624
ParseUint64ArrayFlag(const std::string & flag,const std::string & valStr)625 static int ParseUint64ArrayFlag(const std::string& flag, const std::string& valStr)
626 {
627 std::vector<uint64_t>* val = (std::vector<uint64_t>*) flags_[flag].addr_;
628 for (std::size_t start = 0, end = 0; end <= valStr.length(); ++end) {
629 if (valStr[end] == ',' or end == valStr.length()) {
630 if (start == end) {
631 ++start;
632 continue;
633 }
634 auto str = valStr.substr(start, end - start);
635 char* pos = nullptr;
636 unsigned long long int tmpVal = strtoull(valStr.c_str(), &pos, 10);
637 if (tmpVal == 0ULL || tmpVal == ULONG_MAX) {
638 std::cout << "CommandLineFlags ERROR: argument " << flag
639 << " of numeric type should only be assigned with number but "
640 << valStr << " is given" << std::endl;
641 val->clear();
642 return -1;
643 }
644 val->push_back(static_cast<uint64_t>(tmpVal));
645 start = end + 1;
646 }
647 }
648 return 0;
649 }
650
ParseDoubleArrayFlag(const std::string & flag,const std::string & valStr)651 static int ParseDoubleArrayFlag(const std::string& flag, const std::string& valStr)
652 {
653 std::vector<double>* val = (std::vector<double>*) flags_[flag].addr_;
654 for (std::size_t start = 0, end = 0; end <= valStr.length(); ++end) {
655 if (valStr[end] == ',' or end == valStr.length()) {
656 if (start == end) {
657 ++start;
658 continue;
659 }
660 auto str = valStr.substr(start, end - start);
661 char* pos = nullptr;
662 double tmpVal = strtod(valStr.c_str(), &pos);
663 if (tmpVal == 0.0 || tmpVal == HUGE_VAL) {
664 std::cout << "CommandLineFlags ERROR: argument " << flag
665 << " of numeric type should only be assigned with number but "
666 << valStr << " is given" << std::endl;
667 val->clear();
668 return -1;
669 }
670 val->push_back(tmpVal);
671 start = end + 1;
672 }
673 }
674 return 0;
675 }
676
ParseStringArrayFlag(const std::string & flag,const std::string & valStr)677 static int ParseStringArrayFlag(const std::string& flag, const std::string& valStr)
678 {
679 std::vector<std::string>* val = (std::vector<std::string>*) flags_[flag].addr_;
680 for (std::size_t start = 0, end = 0; end <= valStr.length(); ++end) {
681 if (valStr[end] == ',' or end == valStr.length()) {
682 if (start == end) {
683 ++start;
684 continue;
685 }
686 val->emplace_back(valStr.c_str() + start, end - start);
687 start = end + 1;
688 }
689 }
690 return 0;
691 }
692
ParseFlag(const std::string & flagName,const std::string flagValue)693 static int ParseFlag(const std::string& flagName, const std::string flagValue)
694 {
695 int ret {0};
696 switch (flags_[flagName].type_) {
697 case FlagTypes::FT_bool: ret = ParseBoolFlag(flagName, flagValue); break;
698 case FlagTypes::FT_int8: ret = ParseInt8Flag(flagName, flagValue); break;
699 case FlagTypes::FT_int16: ret = ParseInt16Flag(flagName, flagValue); break;
700 case FlagTypes::FT_int32: ret = ParseInt32Flag(flagName, flagValue); break;
701 case FlagTypes::FT_int64: ret = ParseInt64Flag(flagName, flagValue); break;
702 case FlagTypes::FT_uint8: ret = ParseUint8Flag(flagName, flagValue); break;
703 case FlagTypes::FT_uint16: ret = ParseUint16Flag(flagName, flagValue); break;
704 case FlagTypes::FT_uint32: ret = ParseUint32Flag(flagName, flagValue); break;
705 case FlagTypes::FT_uint64: ret = ParseUint64Flag(flagName, flagValue); break;
706 case FlagTypes::FT_double: ret = ParseDoubleFlag(flagName, flagValue); break;
707 case FlagTypes::FT_string: ret = ParseStringFlag(flagName, flagValue); break;
708 case FlagTypes::FT_bool_array: ret = ParseInt8ArrayFlag(flagName, flagValue); break;
709 case FlagTypes::FT_int8_array: ret = ParseInt8ArrayFlag(flagName, flagValue); break;
710 case FlagTypes::FT_int16_array: ret = ParseInt16ArrayFlag(flagName, flagValue); break;
711 case FlagTypes::FT_int32_array: ret = ParseInt32ArrayFlag(flagName, flagValue); break;
712 case FlagTypes::FT_int64_array: ret = ParseInt64ArrayFlag(flagName, flagValue); break;
713 case FlagTypes::FT_uint8_array: ret = ParseUint8ArrayFlag(flagName, flagValue); break;
714 case FlagTypes::FT_uint16_array: ret = ParseUint16ArrayFlag(flagName, flagValue); break;
715 case FlagTypes::FT_uint32_array: ret = ParseUint32ArrayFlag(flagName, flagValue); break;
716 case FlagTypes::FT_uint64_array: ret = ParseUint64ArrayFlag(flagName, flagValue); break;
717 case FlagTypes::FT_double_array: ret = ParseDoubleArrayFlag(flagName, flagValue); break;
718 case FlagTypes::FT_string_array: ret = ParseStringArrayFlag(flagName, flagValue); break;
719 default: ret = -1;
720 }
721 return ret;
722 }
723
724 int ParseFlags(int *argc, char ***argv, bool rm = true)
725 {
726 std::string flagName {};
727 std::string flagValue {};
728 int argIndex {1};
729 if (((*argc) % 2) == 0) { // 2: double
730 std::cout << "CommandLineFlags ERROE: incorrect number of arguments" << std::endl;
731 PrintArgFormat();
732 return -1;
733 }
734 while (argIndex < (*argc) - 1) {
735 if (GetNextFlag(argv, argIndex, rm, flagName, flagValue) != 0) {
736 // argument format error
737 return -1;
738 }
739 if (flagName.empty() or flags_.count(flagName) == 0) {
740 // argument removed or undefined, skip it and continue;
741 continue;
742 }
743 if (ParseFlag(flagName, flagValue) != 0) {
744 // argument value error
745 return -1;
746 }
747 }
748
749 return 0;
750 }
751 } // end of namespace CommandLineFlags
752
753 #define HIEBPF_DEFINE_bool(name, default_val, help) \
754 namespace CommandLineFlags { \
755 namespace BoolFlags { \
756 static bool FLAGS_##name {default_val}; \
757 static std::string FLAGS_HELP_##name {help}; \
758 static FlagRegesterer<bool> name##_obj {#name, FLAGS_##name}; \
759 } \
760 } \
761 using CommandLineFlags::BoolFlags::FLAGS_##name;
762
763 #define HIEBPF_DEFINE_int8(name, default_val, help) \
764 namespace CommandLineFlags { \
765 namespace Int8Flags { \
766 static int8_t FLAGS_##name {default_val}; \
767 static std::string FLAGS_##name##_help {help}; \
768 static FlagRegesterer name##_obj {#name, FLAGS_##name}; \
769 } \
770 } \
771 using CommandLineFlags::Int8Flags::FLAGS_##name;
772
773 #define HIEBPF_DEFINE_int16(name, default_val, help) \
774 namespace CommandLineFlags { \
775 namespace Int16Flags { \
776 static int16_t FLAGS_##name {default_val}; \
777 static std::string FLAGS_##name##_help {help}; \
778 static FlagRegesterer name##_obj {#name, FLAGS_##name}; \
779 } \
780 } \
781 using CommandLineFlags::Int16Flags::FLAGS_##name;
782
783 #define HIEBPF_DEFINE_int32(name, default_val, help) \
784 namespace CommandLineFlags { \
785 namespace Int32Flags { \
786 static int32_t FLAGS_##name {default_val}; \
787 static std::string FLAGS_##name##_help {help}; \
788 static FlagRegesterer name##_obj {#name, FLAGS_##name}; \
789 } \
790 } \
791 using CommandLineFlags::Int32Flags::FLAGS_##name;
792
793 #define HIEBPF_DEFINE_int64(name, default_val, help) \
794 namespace CommandLineFlags { \
795 namespace Int64Flags { \
796 static int64_t FLAGS_##name {default_val}; \
797 static std::string FLAGS_##name##_help {help}; \
798 static FlagRegesterer name##_obj {#name, FLAGS_##name}; \
799 } \
800 } \
801 using CommandLineFlags::Int64Flags::FLAGS_##name;
802
803 #define HIEBPF_DEFINE_uint8(name, default_val, help) \
804 namespace CommandLineFlags { \
805 namespace Uint8Flags { \
806 static uint8_t FLAGS_##name {default_val}; \
807 static std::string FLAGS_##name##_help {help}; \
808 static FlagRegesterer name##_obj {#name, FLAGS_##name}; \
809 } \
810 } \
811 using CommandLineFlags::Uint8Flags::FLAGS_##name;
812
813 #define HIEBPF_DEFINE_uint16(name, default_val, help) \
814 namespace CommandLineFlags { \
815 namespace Uint16Flags { \
816 static uint16_t FLAGS_##name {default_val}; \
817 static std::string FLAGS_##name##_help {help}; \
818 static FlagRegesterer name##_obj {#name, FLAGS_##name}; \
819 } \
820 } \
821 using CommandLineFlags::Uint16Flags::FLAGS_##name;
822
823 #define HIEBPF_DEFINE_uint32(name, default_val, help) \
824 namespace CommandLineFlags { \
825 namespace Uint32Flags { \
826 static uint32_t FLAGS_##name {default_val}; \
827 static std::string FLAGS_##name##_help {help}; \
828 static FlagRegesterer name##_obj {#name, FLAGS_##name}; \
829 } \
830 } \
831 using CommandLineFlags::Uint32Flags::FLAGS_##name;
832
833 #define HIEBPF_DEFINE_uint64(name, default_val, help) \
834 namespace CommandLineFlags { \
835 namespace Uint64Flags { \
836 static uint64_t FLAGS_##name {default_val}; \
837 static std::string FLAGS_##name##_help {help}; \
838 static FlagRegesterer name##_obj {#name, FLAGS_##name}; \
839 } \
840 } \
841 using CommandLineFlags::Uint64Flags::FLAGS_##name;
842
843 #define HIEBPF_DEFINE_double(name, default_val, help) \
844 namespace CommandLineFlags { \
845 namespace DoubleFlags { \
846 static double FLAGS_##name {default_val}; \
847 static std::string FLAGS_##name##_help {help}; \
848 static FlagRegesterer name##_obj {#name, FLAGS_##name}; \
849 } \
850 } \
851 using CommandLineFlags::DoubleFlags::FLAGS_##name;
852
853 #define HIEBPF_DEFINE_string(name, default_val, help) \
854 namespace CommandLineFlags { \
855 namespace StringFlags { \
856 static std::string FLAGS_##name {default_val}; \
857 static std::string FLAGS_##name##_help {help}; \
858 static FlagRegesterer name##_obj {#name, FLAGS_##name}; \
859 } \
860 } \
861 using CommandLineFlags::StringFlags::FLAGS_##name;
862
863 #define HIEBPF_DEFINE_array(name, type, help) \
864 namespace CommandLineFlags { \
865 namespace ArrayFlags { \
866 using std::string; \
867 static std::vector<type> FLAGS_##name {}; \
868 static std::string FLAGS_##name##_help {help}; \
869 static FlagRegesterer name##_obj {#name, FLAGS_##name}; \
870 } \
871 } \
872 using CommandLineFlags::ArrayFlags::FLAGS_##name;
873
874 #define DECLARE_bool(name) \
875 extern bool CommandLineFlags::BoolFlags::FLAGS_##name; \
876 using CommandLineFlags::BoolFlags::FLAGS_##name;
877
878 #define DECLARE_int8(name) \
879 extern int8_t CommandLineFlags::BoolFlags::FLAGS_##name; \
880 using CommandLineFlags::BoolFlags::FLAGS_##name;
881
882 #define DECLARE_int16(name) \
883 extern int16_t CommandLineFlags::BoolFlags::FLAGS_##name; \
884 using CommandLineFlags::BoolFlags::FLAGS_##name;
885
886 #define DECLARE_int32(name) \
887 extern int32_t CommandLineFlags::BoolFlags::FLAGS_##name; \
888 using CommandLineFlags::BoolFlags::FLAGS_##name;
889
890 #define DECLARE_int64(name) \
891 extern int64_t CommandLineFlags::BoolFlags::FLAGS_##name; \
892 using CommandLineFlags::BoolFlags::FLAGS_##name;
893
894 #define DECLARE_uint8(name) \
895 extern uint8_t CommandLineFlags::BoolFlags::FLAGS_##name; \
896 using CommandLineFlags::BoolFlags::FLAGS_##name;
897
898 #define DECLARE_uint16(name) \
899 extern uint16_t CommandLineFlags::BoolFlags::FLAGS_##name; \
900 using CommandLineFlags::BoolFlags::FLAGS_##name;
901
902 #define DECLARE_uint32(name) \
903 extern uint32_t CommandLineFlags::BoolFlags::FLAGS_##name; \
904 using CommandLineFlags::BoolFlags::FLAGS_##name;
905
906 #define DECLARE_uint64(name) \
907 extern uint64_t CommandLineFlags::BoolFlags::FLAGS_##name; \
908 using CommandLineFlags::BoolFlags::FLAGS_##name;
909
910 #define DECLARE_double(name) \
911 extern double CommandLineFlags::BoolFlags::FLAGS_##name; \
912 using CommandLineFlags::BoolFlags::FLAGS_##name;
913
914 #define DECLARE_string(name) \
915 extern std::string CommandLineFlags::BoolFlags::FLAGS_##name; \
916 using CommandLineFlags::BoolFlags::FLAGS_##name;
917
918 #define DECLARE_array(name, type) \
919 using std::string; \
920 extern std::vector<type> CommandLineFlags::BoolFlags::FLAGS_##name; \
921 using CommandLineFlags::BoolFlags::FLAGS_##name;
922
923 #endif