OpenMEEG
Loading...
Searching...
No Matches
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
30namespace OpenMEEG {
31
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 List &options, const List &parms) const
Definition: commandline.h:128
char ** option(const Strings &options, const Strings &parms) const
Definition: commandline.h:104
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
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 std::string &name, const List &parms) const
Definition: commandline.h:127
void print() const
Definition: commandline.h:140
char ** option(const std::string &name, const Strings &parms) const
Definition: commandline.h:102
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