OpenMEEG
commandline.h
Go to the documentation of this file.
1 // Project Name: OpenMEEG (http://openmeeg.github.io)
2 // © INRIA and ENPC under the French open source license CeCILL-B.
3 // See full copyright notice in the file LICENSE.txt
4 // If you make a copy of this file, you must either:
5 // - provide also LICENSE.txt and modify this header to refer to it.
6 // - replace this header by the LICENSE.txt content.
7 
8 #pragma once
9 
10 #include <iostream>
11 #include <filesystem>
12 #include <iomanip>
13 #include <string>
14 #include <vector>
15 #include <sstream>
16 #include <initializer_list>
17 
18 #ifndef WIN32
19 #define use_color_terminal
20 #endif
21 
22 #include "OpenMEEGConfigure.h"
23 
24 #ifdef USE_OMP
25 #include <omp.h>
26 #endif
27 
28 #include <filenames.h>
29 
30 namespace OpenMEEG {
31 
32  class CommandLine {
33 
34  typedef std::vector<const char*> Strings;
35 
36  // Workaround a bug in old gcc compilers which does not allow the conversion of
37  // const std::initializer_list<const char* const> to const Strings.
38 
39  typedef std::initializer_list<const char* const> List;
40 
41  static Strings build_strings(const List& list) {
42  Strings strs;
43  strs.reserve(list.size());
44  for (const auto& item : list)
45  strs.push_back(item);
46  return strs;
47  }
48 
49  public:
50 
51  CommandLine(const int argc,char* argv[],const std::string& usage=""): n(argc),args(argv) {
52  help = find_argument("-h")!=end() || find_argument("--help")!=end();
53  if (help) {
54  std::cerr << red << std::filesystem::path(args[0]).filename() << normal;
55  if (usage!="")
56  std::cerr << ": " << usage;
57  std::cerr << std::endl << std::endl;
58  }
59  }
60 
61  bool help_mode() const { return help; }
62 
63  template <typename T>
64  T option(const std::string& name,const T defaultvalue,const std::string usage) const {
65  char** arg = find_argument(name);
66  const T result = (arg==end()) ? defaultvalue : parse_value(arg+1,defaultvalue);
67  if (help)
68  std::cerr << " " << bold << std::left << std::setw(8) << name << normal
69  << " = " << std::left << std::setw(12) << value(result) << purple << usage << normal << std::endl;
70  return result;
71  }
72 
73  bool option(const std::string& name,const bool defaultvalue,const std::string usage) const {
74  char** arg = find_argument(name);
75  const bool result = (arg==end()) ? defaultvalue : !defaultvalue;
76  if (help)
77  std::cerr << " " << bold << std::left << std::setw(8) << name << normal
78  << " = " << std::left << std::setw(12) << value(result) << purple << usage << normal << std::endl;
79  return result;
80  }
81 
82  char** option(const std::string& option,const Strings& parms,const std::size_t num_mandatory_parms) const {
83  char** arg = find_argument(option);
84  if (arg==end())
85  return nullptr;
86 
87  const std::size_t num_parms = num_args(arg);
88  if (num_parms<num_mandatory_parms) {
89  std::cerr << "\'" << args[0] << "\' option \'" << option << "\' expects at least "
90  << num_mandatory_parms << " arguments (";
91  if (parms.size()!=0) {
92  std::cerr << parms[0];
93  for (unsigned i=1; i<parms.size(); ++i)
94  std::cerr << ", " << parms[i];
95  }
96  std::cerr << ") and you gave only " << num_parms << " arguments." << std::endl;
97  exit(1);
98  }
99  return arg;
100  }
101 
102  char** option(const std::string& name,const Strings& parms) const { return option(name,parms,parms.size()); }
103 
104  char** option(const Strings& options,const Strings& parms) const {
105  std::size_t num_mandatory_parms = parms.size();
106  for (const auto& parm : parms)
107  if (parm[0]=='[')
108  --num_mandatory_parms;
109 
110  char** mandatory_args = nullptr;
111  for (const char* opt : options) {
112  char** arg = option(opt,parms,num_mandatory_parms);
113  if (arg!=nullptr) {
114  if (mandatory_args!=nullptr) {
115  std::cerr << "Warning: option " << *(options.begin()) << " provided multiple times!" << std::endl;
116  exit(1);
117  }
118  mandatory_args = arg;
119  }
120  }
121  return mandatory_args;
122  }
123 
124  // Workaround a bug in old gcc compilers which does not allow the conversion of
125  // const std::initializer_list<const char* const> to const Strings.
126 
127  char** option(const std::string& name,const List& parms) const { return option(name,build_strings(parms)); }
128  char** option(const List& options,const List& parms) const { return option(build_strings(options),build_strings(parms)); }
129 
130  // End of workaround.
131 
132  unsigned num_args(char** argument) const {
133  unsigned res = 0;
134  for (char** arg=argument+1; arg!=end(); ++arg,++res)
135  if ((*arg)[0]=='-')
136  break;
137  return res;
138  }
139 
140  void print() const {
141  std::cout << std::endl << "| ------ " << args[0] << std::endl;
142  for (unsigned i=1; i<n; ++i)
143  std::cout << "| " << args[i] << std::endl;
144  std::cout << "| -----------------------" << std::endl;
145  }
146 
147  private:
148 
149  template <typename T>
150  static T value(const T val) { return val; }
151 
152  static std::string value(const bool val) { return (val) ? "true" : "false"; }
153 
154  static std::string value(const std::string& val) { return '"'+val+'"'; }
155 
156  char** end() const { return args+n; }
157 
158  char** find_argument(const std::string& name) const {
159  for (auto arg = args; arg!=end(); ++arg)
160  if (name==*arg)
161  return arg;
162  return end();
163  }
164 
165  template <typename T>
166  T parse_value(char* arg[],const T defaultvalue) const {
167  if (arg==end())
168  return defaultvalue;
169  std::istringstream iss(*arg);
170  T value = defaultvalue;
171  iss >> value;
172  return value;
173  }
174 
175  #ifndef WIN32
176  static constexpr char normal[9] = { 0x1b, '[', '0', ';', '0', ';', '0', 'm', '\0' };
177  static constexpr char red[11] = { 0x1b, '[', '4', ';', '3', '1', ';', '5', '9', 'm', '\0' };
178  static constexpr char bold[5] = { 0x1b, '[', '1', 'm', '\0' };
179  static constexpr char purple[11] = { 0x1b, '[', '0', ';', '3', '5', ';', '5', '9', 'm', '\0' };
180  static constexpr char path_delimiter = '/';
181  #else
182  static constexpr char normal[1] = { '\0' };
183  static constexpr char red[1] = { '\0' };
184  static constexpr char bold[1] = { '\0' };
185  static constexpr char purple[1] = { '\0' };
186  static constexpr char path_delimiter = '\\';
187  #endif
188 
189  unsigned n;
190  char** args;
191  bool help;
192  };
193 
194  inline void print_version(const char* cmd) {
195  #ifdef USE_OMP
196  std::string omp_support = " using OpenMP\n Executing using " + std::to_string(omp_get_max_threads()) + " threads.";
197  #else
198  std::string omp_support = "";
199  #endif
200 
201  std::ostringstream display_info;
202  display_info << cmd;
203  display_info << " version " << version;
204  display_info << " compiled at " << __DATE__ << " " << __TIME__;
205  display_info << omp_support;
206  std::cout << display_info.str() << std::endl << std::endl;
207  }
208 
209  // Some command have mutually exclusive options.
210  // This helper function ensures that.
211  // The counter num_options is counting options in each exclusive group.
212 
213  inline void assert_non_conflicting_options(const char* command,const unsigned num_options) {
214  if (num_options!=1) {
215  std::cerr << "Error: providing mutually exclusive options to " << command << "!" << std::endl;
216  exit(1);
217  }
218  }
219 }
char ** option(const std::string &name, const List &parms) const
Definition: commandline.h:127
unsigned num_args(char **argument) const
Definition: commandline.h:132
T option(const std::string &name, const T defaultvalue, const std::string usage) const
Definition: commandline.h:64
CommandLine(const int argc, char *argv[], const std::string &usage="")
Definition: commandline.h:51
bool help_mode() const
Definition: commandline.h:61
char ** option(const List &options, const List &parms) const
Definition: commandline.h:128
bool option(const std::string &name, const bool defaultvalue, const std::string usage) const
Definition: commandline.h:73
char ** option(const std::string &option, const Strings &parms, const std::size_t num_mandatory_parms) const
Definition: commandline.h:82
char ** option(const Strings &options, const Strings &parms) const
Definition: commandline.h:104
char ** option(const std::string &name, const Strings &parms) const
Definition: commandline.h:102
void print() const
Definition: commandline.h:140
void assert_non_conflicting_options(const char *command, const unsigned num_options)
Definition: commandline.h:213
void print_version(const char *cmd)
Definition: commandline.h:194