• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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