ParamKit
A small library helping to parse commandline parameters (for Windows).
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
params.h
Go to the documentation of this file.
1 
6 #pragma once
7 
8 #include <windows.h>
9 
10 #include <iostream>
11 #include <string>
12 #include <sstream>
13 #include <map>
14 
15 #include "pk_util.h"
16 #include "color_scheme.h"
17 #include "param.h"
18 #include "param_group.h"
19 //--
20 
21 #define PARAM_HELP1 "?"
22 #define PARAM_HELP2 "help"
23 #define PARAM_VERSION "version"
24 #define PARAM_VERSION2 "ver"
25 
26 namespace paramkit {
27 
29  class Params {
30  public:
31  Params(const std::string &version = "")
32  : generalGroup(nullptr), versionStr(version),
33  paramHelp(PARAM_HELP2, false), paramHelpP(PARAM_HELP2, false), paramInfoP("<param> ?", false),
36  {
37  paramHelp.m_info = "Print complete help.";
38  paramHelpP.m_info = "Print help about a given keyword.";
39  paramInfoP.m_info = "Print details of a given parameter.";
40  paramVersion.m_info = "Print version info.";
41  }
42 
43  virtual ~Params()
44  {
45  releaseGroups();
46  releaseParams();
47  }
48 
49  virtual void printBanner()
50  {
51  return;
52  }
53 
54  virtual void printVersionInfo()
55  {
56  if (versionStr.length()) {
57  std::cout << versionStr << std::endl;
58  }
59  }
60 
61  bool addGroup(ParamGroup *group)
62  {
63  if(!group) return false;
64  if (this->paramGroups.find(group->name) != this->paramGroups.end()) {
65  return false;
66  }
67  this->paramGroups[group->name] = group;
68  return true;
69  }
70 
71  ParamGroup* getParamGroup(const std::string &str)
72  {
73  std::map<std::string, ParamGroup*>::iterator itr = this->paramGroups.find(str);
74  if (itr != this->paramGroups.end()) {
75  return itr->second;
76  }
77  return nullptr;
78  }
79 
80  bool addParamToGroup(const std::string paramName, const std::string groupName)
81  {
82  Param* param = this->getParam(paramName);
83  ParamGroup *group = this->getParamGroup(groupName);
84  return addParamToGroup(param, group);
85  }
86 
88 
91  void addParam(Param* param)
92  {
93  if (!param) return;
94  const std::string argStr = param->argStr;
95  this->myParams[argStr] = param;
96  if (!generalGroup) {
97  generalGroup = new ParamGroup("");
98  this->addGroup(generalGroup);
99  }
100  this->addParamToGroup(param, this->generalGroup);
101  }
102 
104 
110  bool setInfo(const std::string& paramName, const std::string& basic_info, const std::string& extended_info = "")
111  {
112  Param *p = getParam(paramName);
113  if (!p) return false;
114 
115  p->m_info = basic_info;
116  p->m_extInfo = extended_info;
117  return false;
118  }
119 
121 
126  void printInfo(bool hilightMissing=false, const std::string &filter = "", bool isExtended = true)
127  {
128  std::cout << "---" << std::endl;
129  _info(true, hilightMissing, filter, isExtended);
130  _info(false, hilightMissing, filter, isExtended);
131  const bool extendedInfoS = (filter.empty() && !hilightMissing) ? isExtended : false;
132  printInfoSection(extendedInfoS);
133  std::cout << "---" << std::endl;
134  }
135 
138  {
139  printInfo(false, "", false);
140  }
141 
143 
148  bool setIntValue(const std::string& paramName, uint64_t val)
149  {
150  Param *p = getParam(paramName);
151  if (!p) return false;
152 
153  IntParam *param = dynamic_cast<IntParam*>(p);
154  if (!param) {
155  return false;
156  }
157  param->value = val;
158  return true;
159  }
160 
162 
165  uint64_t getIntValue(const std::string& paramName)
166  {
167  std::map<std::string, Param*>::iterator itr = this->myParams.find(paramName);
168  if (itr == this->myParams.end()) return PARAM_UNINITIALIZED;
169 
170  IntParam *param = dynamic_cast<IntParam*>(itr->second);
171  if (!param) {
172  return 0;
173  }
174  return param->value;
175  }
176 
178 
182  virtual bool isSet(const std::string& paramName)
183  {
184  std::map<std::string, Param*>::iterator itr = this->myParams.find(paramName);
185  if (itr == this->myParams.end()) return false;
186 
187  Param *param = itr->second;
188  if (!param) {
189  return false;
190  }
191  return param->isSet();
192  }
193 
195  virtual bool hasRequiredFilled()
196  {
197  std::map<std::string, Param*>::iterator itr;
198  for (itr = myParams.begin(); itr != myParams.end(); itr++) {
199  Param *param = itr->second;
200  if (param->isRequired && param->isActive() && !param->isSet()) {
201  return false;
202  }
203  }
204  return true;
205  }
206 
209  {
210  paramToGroup.clear();
211  this->generalGroup = nullptr;
212  std::map<std::string, ParamGroup*>::iterator itr;
213  for (itr = paramGroups.begin(); itr != paramGroups.end(); ++itr) {
214  ParamGroup *group = itr->second;
215  group->params.clear();
216  delete group;
217  }
218  paramGroups.clear();
219  }
220 
223  {
224  std::map<std::string, Param*>::iterator itr;
225  for (itr = myParams.begin(); itr != myParams.end(); itr++) {
226  Param *param = itr->second;
227  delete param;
228  }
229  myParams.clear();
230  }
231 
233  template <typename T_CHAR>
234  bool parse(int argc, T_CHAR* argv[])
235  {
236  bool helpRequested = false;
237  size_t count = 0;
238  for (int i = 1; i < argc; i++) {
239  std::string param_str = to_string(argv[i]);
240  if (!isParam(param_str)) {
241  printUnknownArgument(param_str);
242  continue;
243  }
244  bool found = false;
245  param_str = skipParamPrefix(param_str);
246 
247  std::map<std::string, Param*>::iterator itr;
248  for (itr = myParams.begin(); itr != myParams.end(); ++itr) {
249  bool paramHelp = false;
250  Param *param = itr->second;
251  if (param_str == PARAM_HELP2 || param_str == PARAM_HELP1) {
252  if (param_str == PARAM_HELP2) {
253  const bool hasArg = (i + 1) < argc && !(isParam(to_string(argv[i + 1])));
254  if (hasArg) {
255  const std::string nextVal = to_string(argv[i + 1]);
256  printHelp(nextVal, true);
257  return false;
258  }
259  }
260  const bool shouldExpand = (param_str == PARAM_HELP1) ? false : true;
261  printHelp("", shouldExpand);
262  return false;
263  }
264  if (this->versionStr.length()) {
265  if (param_str == PARAM_VERSION || param_str == PARAM_VERSION2) {
266  this->printVersionInfo();
267  return false;
268  }
269  }
270  if (param_str == param->argStr) {
271  if (!param->isActive()) {
272  paramkit::print_in_color(RED, "WARNING: chosen inactive parameter: " + param_str + "\n");
273  }
274  // has an argument:
275  const bool hasArg = (i + 1) < argc &&
276  ( param->requiredArg || !(isParam(to_string(argv[i + 1]))) );
277  if (hasArg) {
278  const std::string nextVal = to_string(argv[i + 1]);
279  i++; // increment index: move to the next argument
280  found = true;
281  bool isParsed = false;
282 
283  if (nextVal == PARAM_HELP1) {
284  paramHelp = true;
285  helpRequested = true;
286  isParsed = true;
287  }
288  else {
289  isParsed = param->parse(nextVal.c_str());
290  if (!isParsed) {
291  paramHelp = true;
292  helpRequested = true;
293  }
294  }
295 
296  //help requested explicitly or parsing failed
297  if (paramHelp) {
298  if (!isParsed) {
299  paramkit::print_in_color(RED, "Parsing the parameter failed. Correct options:\n");
300  }
301  paramkit::print_in_color(RED, param_str);
302  param->printDesc();
303  break;
304  }
305  break;
306  }
307  // does not require an argument:
308  if (!param->requiredArg) {
309  param->parse((char*)nullptr);
310  found = true;
311  break;
312  }
313  // requires an argument, but it is missing:
314  paramkit::print_in_color(RED, param_str);
315  paramHelp = true;
316  helpRequested = true;
317  param->printDesc();
318  found = true;
319  break;
320  }
321  }
322  if (found) {
323  count++;
324  }
325  else {
326  printUnknownParam(param_str);
327  print_in_color(HILIGHTED_COLOR, "Similar parameters:\n");
328  this->printInfo(false, param_str, true);
329  return false;
330  }
331  }
332  if (helpRequested) {
333  return false;
334  }
335  if (!this->hasRequiredFilled()) {
336  print_in_color(WARNING_COLOR, "Missing required parameters:\n");
337  this->printInfo(true, "", true);
338  return false;
339  }
340  if (this->countCategory(true) == 0 && countFilled(false) == 0) {
341  std::stringstream ss1;
342  ss1 << "Run with parameter " << PARAM_SWITCH1 << PARAM_HELP1 << " or " << PARAM_SWITCH1 << PARAM_HELP2 << " to see the options...\n";
343  print_in_color(YELLOW, ss1.str());
344  }
345  return true;
346  }
347 
349  void print()
350  {
351  const int paramColor = HILIGHTED_COLOR;
352  std::map<std::string, Param*>::iterator itr;
353  for (itr = myParams.begin(); itr != myParams.end(); itr++) {
354  if (!isSet(itr->first)) continue;
355 
356  Param *param = itr->second;
357  if (!param) continue; //should never happen
358 
359  param->printInColor(paramColor);
360  std::cout << ": ";
361  std::cout << std::hex << param->valToString() << "\n";
362  }
363  }
364 
365  template <class PARAM_T, typename FIELD_T>
366  bool copyVal(const std::string &paramId, FIELD_T &toFill)
367  {
368  PARAM_T *myParam = dynamic_cast<PARAM_T*>(this->getParam(paramId));
369  if (!myParam) {
370  return false;
371  }
372  if (!myParam->isSet()) {
373  return false;
374  }
375  toFill = static_cast<FIELD_T>(myParam->value);
376  return true;
377  }
378 
379  template <class PARAM_T, typename FIELD_T>
380  bool copyCStr(const std::string &paramId, FIELD_T &toFill, size_t toFillLen)
381  {
382  PARAM_T *myStr = dynamic_cast<PARAM_T*>(this->getParam(paramId));
383  if (!myStr || !myStr->isSet()) {
384  return false;
385  }
386  myStr->copyToCStr(toFill, toFillLen);
387  return true;
388  }
389 
390  protected:
391 
392  virtual size_t countFilled(bool isRequired)
393  {
394  size_t count = 0;
395  std::map<std::string, Param*>::iterator itr;
396  for (itr = myParams.begin(); itr != myParams.end(); itr++) {
397  Param *param = itr->second;
398  if (param->isRequired != isRequired) continue;
399  if (param->isSet()) {
400  count++;
401  }
402  }
403  return count;
404  }
405 
406  size_t _info(bool isRequired, bool hilightMissing, const std::string &filter, bool isExtended)
407  {
408  const bool has_filter = filter.length() > 0 ? true : false;
409  std::map<std::string, Param*>::iterator itr;
410  size_t printed = 0;
411  if (countCategory(isRequired) > 0) {
412  const std::string desc = isRequired ? "Required:" : "Optional:";
413  print_in_color(hdrColor, "\n"+ desc + "\n");
414 
415  size_t total_count = 0;
416  bool printGroupName = (countGroups(isRequired, hilightMissing, filter)) ? true : false;
417  if (paramGroups.size() > 0) {
418  std::map<std::string, ParamGroup*>::iterator groupItr;
419  for (groupItr = this->paramGroups.begin(); groupItr != paramGroups.end(); ++groupItr) {
420  ParamGroup* group = groupItr->second;
421  if (!group) continue; //should never happen
422  printed += group->printGroup(printGroupName, isRequired, hilightMissing, filter, isExtended);
423  total_count += group->countParams(isRequired, false, "");
424  }
425  if (printed < total_count) {
426  print_in_color(INACTIVE_COLOR, "\n[...]\n");
427  }
428  }
429  }
430  return printed;
431  }
432 
433  bool printHelp(const std::string helpArg, bool shouldExpand)
434  {
435  if (helpArg.empty()) {
436  this->printBanner();
437  this->printInfo(false, "", shouldExpand);
438  return false;
439  }
440  if (helpArg == PARAM_HELP1 || helpArg == PARAM_HELP2) {
441  printBanner();
442  printInfoSection(true);
443  return true;
444  }
445  if (helpArg == PARAM_VERSION || helpArg == PARAM_VERSION2) {
446  if (this->versionStr.length()) {
448  paramVersion.printDesc(true);
449  }
450  else {
451  std::cout << "Application version is not set\n";
452  }
453  return true;
454  }
455  this->printInfo(false, helpArg, shouldExpand);
456  return true;
457  }
458 
459  void printInfoSection(bool isExtended)
460  {
461  if (isExtended) {
462  // make an example:
463  if (myParams.size()) {
464  std::map<std::string, Param*>::iterator itr = myParams.begin();
465  std::stringstream ss1;
466  ss1 << INFO_SPACER << "Example: " << PARAM_SWITCH1 << itr->first << " ?";
467  paramInfoP.m_extInfo = ss1.str();
468  }
469  }
470  print_in_color(hdrColor, "\nInfo:\n");
472  paramHelp.printDesc(isExtended);
474  paramHelpP.printDesc(isExtended);
476  paramInfoP.printDesc(isExtended);
477  if (this->versionStr.length()) {
479  paramVersion.printDesc(isExtended);
480  }
481  }
482 
483  bool addParamToGroup(Param *param, ParamGroup *group)
484  {
485  if (!param || !group) {
486  return false;
487  }
488  std::map<Param*, ParamGroup*>::iterator itr = paramToGroup.find(param);
489  if (itr != paramToGroup.end()) {
490  ParamGroup* currentGroup = itr->second;
491  if (currentGroup != group) {
492  currentGroup->removeParam(param);
493  paramToGroup.erase(param);
494  }
495  }
496  group->params.insert(param);
497  paramToGroup[param] = group;
498  return true;
499  }
500 
501  size_t countGroups(bool required, bool hilightMissing, const std::string &filter) const
502  {
503  size_t groups_count = 0;
504  std::map<std::string, ParamGroup*>::const_iterator itr;
505  for (itr = paramGroups.begin(); itr != paramGroups.end(); ++itr) {
506  ParamGroup *group = itr->second;
507  if (group == this->generalGroup) continue; //skip the general
508  if (group->countParams(required, hilightMissing, filter) > 0) {
509  groups_count++;
510  }
511  }
512  return groups_count;
513  }
514 
516  size_t countCategory(bool isRequired)
517  {
518  size_t count = 0;
519  std::map<std::string, Param*>::iterator itr;
520  for (itr = myParams.begin(); itr != myParams.end(); itr++) {
521  Param *param = itr->second;
522  if (param->isRequired == isRequired) count++;
523  }
524  return count;
525  }
526 
527  void printUnknownParam(const std::string &param)
528  {
529  print_in_color(WARNING_COLOR, "Invalid parameter: ");
530  std::cout << param << "\n";
531  }
532 
533  void printUnknownArgument(const std::string &str)
534  {
535  print_in_color(WARNING_COLOR, "Redundant argument: ");
536  std::cout << str << "\n";
537  }
538 
540  Param* getParam(const std::string &str)
541  {
542  std::map<std::string, Param*>::iterator itr = this->myParams.find(str);
543  if (itr != this->myParams.end()) {
544  return itr->second;
545  }
546  return nullptr;
547  }
548 
550  static bool isParam(const std::string &str)
551  {
552  const size_t prefixLen = 1;
553  const size_t len = str.length();
554  if (len <= prefixLen) return false;
555 
556  if (str[0] == PARAM_SWITCH1 || str[0] == PARAM_SWITCH2) {
557  return true;
558  }
559  return false;
560  }
561 
563  std::string skipParamPrefix(std::string &str)
564  {
565  size_t prefixLen = 1;
566  const size_t len = str.length();
567  if (len < prefixLen) return str;
568 
569  if (str[0] != PARAM_SWITCH1 && str[0] != PARAM_SWITCH2) {
570  return str;
571  }
572  if (len > 2 && str[0] == PARAM_SWITCH2) {
573  if (str[1] == PARAM_SWITCH2) { // double prefix: "--", i.e. "--param"
574  prefixLen = 2;
575  }
576  }
577  return str.substr(prefixLen); // skip the first char
578  }
579 
580  std::string versionStr;
581  std::map<std::string, Param*> myParams;
582 
586 
589  std::map<Param*, ParamGroup*> paramToGroup;
590  std::map<std::string, ParamGroup*> paramGroups;
591 
592  const int hdrColor;
593  const int paramColor;
594  };
595 };
596 
A parameter storing a boolean value.
Definition: param.h:371
A parameter storing an integer value.
Definition: param.h:188
uint64_t value
Definition: param.h:272
The class responsible for grouping parameters (objects of the type Param)
Definition: param_group.h:24
size_t countParams(bool printRequired, bool hilightMissing, const std::string &filter)
Definition: param_group.h:92
std::set< Param *, ParamCompare > params
Definition: param_group.h:146
size_t printGroup(bool printGroupName, bool printRequired, bool hilightMissing, const std::string &filter="", bool isExtended=false)
Prints the whole group of parameters (their names and descriptions), optionally with the group name.
Definition: param_group.h:45
bool removeParam(Param *param)
Definition: param_group.h:135
The base class of a parameter.
Definition: param.h:30
virtual bool parse(const char *arg)=0
Parses the parameter from the given string.
std::string argStr
a unique name of the parameter
Definition: param.h:160
std::string m_extInfo
an extended information about the the parameter's purpose
Definition: param.h:164
virtual std::string valToString() const =0
Returns the string representation of the parameter's value.
bool isRequired
a flag indicating if this parameter is required
Definition: param.h:166
virtual bool isSet() const =0
Returns true if the parameter is filled, false otherwise.
bool requiredArg
a flag indicating if this parameter needs to be followed by a value
Definition: param.h:167
void printInColor(int color)
Prints the parameter using the given color. Appends the parameter switch to the name.
Definition: param.h:106
virtual bool isActive() const
Returns true if the parameter is active, false otherwise.
Definition: param.h:84
std::string m_info
a basic information about the the parameter's purpose
Definition: param.h:163
void printDesc(bool isExtended=true) const
Prints a formatted description of the parameter, including its unique name, type, and the info.
Definition: param.h:114
The class responsible for storing and parsing parameters (objects of the type Param),...
Definition: params.h:29
std::string skipParamPrefix(std::string &str)
Skip the parameter prefix. Example: "/param", '-param', or "--param" is converted to "param".
Definition: params.h:563
std::map< std::string, Param * > myParams
Definition: params.h:581
bool addGroup(ParamGroup *group)
Definition: params.h:61
bool addParamToGroup(const std::string paramName, const std::string groupName)
Definition: params.h:80
void printUnknownParam(const std::string &param)
Definition: params.h:527
BoolParam paramVersion
Definition: params.h:587
static bool isParam(const std::string &str)
Checks if the string starts from the parameter switch.
Definition: params.h:550
void printInfoSection(bool isExtended)
Definition: params.h:459
void printInfo(bool hilightMissing=false, const std::string &filter="", bool isExtended=true)
Prints info about all the parameters. Optionally hilights the required ones that are missing.
Definition: params.h:126
virtual void printBanner()
Definition: params.h:49
bool setInfo(const std::string &paramName, const std::string &basic_info, const std::string &extended_info="")
Sets the information about the parameter, defined by its name.
Definition: params.h:110
size_t _info(bool isRequired, bool hilightMissing, const std::string &filter, bool isExtended)
Definition: params.h:406
Param * getParam(const std::string &str)
Retrieve the parameter by its unique name. Returns nullptr if such parameter does not exist.
Definition: params.h:540
bool printHelp(const std::string helpArg, bool shouldExpand)
Definition: params.h:433
virtual size_t countFilled(bool isRequired)
Definition: params.h:392
uint64_t getIntValue(const std::string &paramName)
Gets an integer value of the IntParam defined by its name. If such parameter does not exist,...
Definition: params.h:165
void print()
Prints the values of all the parameters that are currently set.
Definition: params.h:349
bool addParamToGroup(Param *param, ParamGroup *group)
Definition: params.h:483
void printUnknownArgument(const std::string &str)
Definition: params.h:533
BoolParam paramInfoP
Definition: params.h:585
size_t countCategory(bool isRequired)
Returns the number of parameters of particular category: required or optional.
Definition: params.h:516
bool setIntValue(const std::string &paramName, uint64_t val)
Fills an IntParam defined by its name with the given value. If such parameter does not exist,...
Definition: params.h:148
bool copyCStr(const std::string &paramId, FIELD_T &toFill, size_t toFillLen)
Definition: params.h:380
BoolParam paramHelp
Definition: params.h:583
ParamGroup * generalGroup
Definition: params.h:588
size_t countGroups(bool required, bool hilightMissing, const std::string &filter) const
Definition: params.h:501
void releaseParams()
Deletes all the added parameters.
Definition: params.h:222
virtual bool hasRequiredFilled()
Checks if all the required parameters are filled.
Definition: params.h:195
virtual bool isSet(const std::string &paramName)
Checks if the parameter with the given name is set (filled).
Definition: params.h:182
ParamGroup * getParamGroup(const std::string &str)
Definition: params.h:71
const int paramColor
Definition: params.h:593
virtual void printVersionInfo()
Definition: params.h:54
const int hdrColor
Definition: params.h:592
Params(const std::string &version="")
Definition: params.h:31
bool copyVal(const std::string &paramId, FIELD_T &toFill)
Definition: params.h:366
void addParam(Param *param)
Adds a parameter into the storage.
Definition: params.h:91
void printBriefInfo()
Prints brief info about all the parameters. Wrapper for printInfo.
Definition: params.h:137
std::map< Param *, ParamGroup * > paramToGroup
Definition: params.h:589
virtual ~Params()
Definition: params.h:43
StringParam paramHelpP
Definition: params.h:584
std::string versionStr
Definition: params.h:580
void releaseGroups()
Deletes all the parameters groups.
Definition: params.h:208
std::map< std::string, ParamGroup * > paramGroups
Definition: params.h:590
bool parse(int argc, T_CHAR *argv[])
Parses the parameters. Prints a warning if an undefined parameter was supplied.
Definition: params.h:234
A parameter storing a string value.
Definition: param.h:276
const WORD HEADER_COLOR
Definition: color_scheme.h:11
const WORD WARNING_COLOR
Definition: color_scheme.h:8
void print_in_color(int color, const std::string &text)
Definition: pk_util.cpp:93
const WORD INACTIVE_COLOR
Definition: color_scheme.h:13
std::string to_string(T_CHAR *str1)
Definition: pk_util.h:36
const WORD HILIGHTED_COLOR
Definition: color_scheme.h:9
Basic parameter types.
#define PARAM_UNINITIALIZED
Definition: param.h:19
#define INFO_SPACER
Definition: param.h:20
#define PARAM_SWITCH1
The switch used to recognize that the given string should be treated as a parameter (variant 1)
Definition: param.h:22
#define PARAM_SWITCH2
The switch used to recognize that the given string should be treated as a parameter (variant 2)
Definition: param.h:23
unsigned __int64 uint64_t
Definition: param.h:25
The group of parameters.
#define PARAM_HELP2
Definition: params.h:22
#define PARAM_VERSION2
Definition: params.h:24
#define PARAM_HELP1
Definition: params.h:21
#define PARAM_VERSION
Definition: params.h:23
The set of utility functions used by the ParamKit.
#define RED
Definition: term_colors.h:23
#define YELLOW
Definition: term_colors.h:25