HILA
Loading...
Searching...
No Matches
cmdline.cpp
1#include <stdio.h>
2#include <stdlib.h>
3#include <string>
4#include <map>
5#include <vector>
6#include <regex>
7#include "hila.h"
8
9using strvec = std::vector<std::string>;
10
11////////////////////////////////////////////////////////////////////////////////
12/// @brief Prints the help texts associated with recognized flags and quits the
13/// program
14////////////////////////////////////////////////////////////////////////////////
15void cmdlinearguments::quit_with_help() {
16 print_help();
18}
19
20////////////////////////////////////////////////////////////////////////////////
21/// @struct argmap_val
22/// @brief Struct to hold structured information on used command line arguments
23///
24/// @var strvec argmap_val::val_strings
25/// @brief Strings corresponding to read in cmdline parameters
26///
27/// @var std::string argmap_val::help_text
28/// @brief A string describing the use of the flag
29///
30/// @var bool argmap_val::present
31/// @brief A boolean telling whether the flag was found in argv
32////////////////////////////////////////////////////////////////////////////////
33struct argmap_val {
35 std::string help_text;
36 bool present;
37};
38
39// class instance cmdline is globally available through hila.h
40namespace hila {
41cmdlinearguments cmdline;
42}
43
44cmdlinearguments::cmdlinearguments() {}
45
46////////////////////////////////////////////////////////////////////////////////
47/// @brief Copies provided argc and argv into internal variables.
48///
49/// @param argc length of argv
50/// @param argv array of pointers to command-line arguments
51////////////////////////////////////////////////////////////////////////////////
52void cmdlinearguments::initialise_args(int argc0, char **argv0) {
53 argc = argc0;
54 argv = (const char **)malloc(argc * sizeof(const char *));
55 for (int i = 0; i < argc; i++)
56 argv[i] = argv0[i];
57
58 // Proceed to parse argv
59 fill_argmap();
60}
61
62////////////////////////////////////////////////////////////////////////////////
63/// @brief Returns the vector of strings associated with flag 'flag'.
64///
65/// @param flag flag given as string
66/// @return vector of arguments
67////////////////////////////////////////////////////////////////////////////////
68strvec cmdlinearguments::values(std::string flag) {
69 strvec valvec = argmap[flag].val_strings;
70 if (argmap.count(flag) == 0) {
71 hila::out0 << "Flag '" << flag << "' is not recognized!\n";
72 quit_with_help();
73 }
74
75 if (valvec.size() == 0) {
76 hila::out0 << "\n\nFlag '" << flag << "' has no entries"
77 << " and the associated vector of strings is of length zero!\n\n";
78 }
79 return valvec;
80}
81
82////////////////////////////////////////////////////////////////////////////////
83/// @brief Adds a new recognized flag 'flag' and associated information to the
84/// argmap.
85///
86/// @param flag string with the name of the flag, always of format "^-[a-z].*"
87/// (no whitespace allowed), e.g. '-my_flag123'
88/// @param help_text a string containing useful knowledge of the usage of the flag.
89/// Will be printed when error occurs. For formatting, a newline
90/// can be used to split the help_text, as it will help with
91/// correct formatting in print_help().
92////////////////////////////////////////////////////////////////////////////////
93void cmdlinearguments::add_flag(std::string flag, std::string help_text) {
94 if (argmap.count(flag) > 0) {
95 hila::out0 << "\n###################################################\n";
96 hila::out0 << "# Flag " << flag << " is already set! Terminating.\n";
97 hila::out0 << "###################################################\n\n";
98 quit_with_help();
99 } else {
100 argmap[flag] = {std::vector<std::string>(), help_text, false};
101 }
102}
103
104////////////////////////////////////////////////////////////////////////////////
105/// @brief Given flag '-flag' argv is scanned for valid entries that follow.
106/// @details Once '-flag' is found the following strings are scanned. If they
107/// are not in the format of a flag (described in add_flag()) they are
108/// considered valid input. argv with
109/// "-flag a -b_flag b -flag c d -flag -flag 4"
110/// should result in {"a", "c", "d", "4"}.
111///
112/// @param flag string corresponding to the flag
113/// @return Vector containing the found entries.
114////////////////////////////////////////////////////////////////////////////////
115strvec cmdlinearguments::read_arg_vector(const char *flag) {
116 strvec uargs;
117
118 std::vector<int> u_ind(argc);
119 for (int i = 0; i < argc; i++)
120 u_ind[i] = -1;
121 int *p_ind = u_ind.data();
122
123 // Anything of the format "-[a letter][whatever]" is parsed as a flag
124 const std::regex forbidden_user_input("^-[a-zA-Z].*");
125
126 for (int i = 0; i < argc; i++) {
127 const char *p = argv[i];
128 // check if its the flag
129 if (std::strcmp(p, flag) == 0) {
130 // Indicate that the flag has been spotted in argv
131 argmap[flag].present = true;
132 // Slate for removal and move onto the
133 // options
134 *(p_ind++) = 1;
135 i++;
136 if (i < argc)
137 p = argv[i];
138 else {
139 break;
140 }
141 // Check if the string is a valid input
142 // (Not of type ^-[a-zA-Z].*)
143 // and push into vector uargs
144 while (!std::regex_match(p, forbidden_user_input)) {
145 *(p_ind++) = 1;
146 uargs.push_back(std::string(p));
147 i++;
148 if (i < argc)
149 p = argv[i];
150 else
151 break;
152 }
153
154 // If we stopped on another 'flag' for whatever
155 // reason, set the current index to be removed
156 // and compensate for the for loop increase in
157 // i and p_ind
158 if (std::strcmp(p, flag) == 0) {
159 *(p_ind--) = 1;
160 i--;
161 }
162 }
163 p_ind++;
164 }
165 // Effectively remove user arguments from argv
166 int j = 0;
167 for (int i = 0; i < argc; i++)
168 if (u_ind[i] < 0)
169 argv[j++] = argv[i];
170 argc = j;
171
172 return uargs;
173}
174
175////////////////////////////////////////////////////////////////////////////////
176/// @brief Loops over the known flags and fills the argmap struct from argv
177////////////////////////////////////////////////////////////////////////////////
178void cmdlinearguments::fill_argmap() {
179 // Loop through the flags (keys of the map)
180 for (auto const &p : argmap) {
181 // Get corresponding input and set it to uarg[flag]
182 std::vector<std::string> arg_vec = read_arg_vector(p.first.c_str());
183 argmap[std::string(p.first)].val_strings = arg_vec;
184 }
185 if (argc > 1) {
186 hila::out0 << "There remain unprocessed command-line arguments:\n";
187 for (int i = 1; i < argc; i++)
188 hila::out0 << "'" << argv[i] << "', ";
189 hila::out0 << "\n";
190 hila::out0 << "Terminating.\n";
191 quit_with_help();
192 }
193}
194
195////////////////////////////////////////////////////////////////////////////////
196/// @brief Splits a help_text string into a vector of strings at newline.
197/// @return A vector containing the lines.
198////////////////////////////////////////////////////////////////////////////////
199strvec cmdlinearguments::parse_help(std::string help_text) {
200 strvec lines;
201 std::stringstream stream(help_text);
202 std::string line;
203
204 while (std::getline(stream, line)) {
205 lines.push_back(line);
206 }
207
208 return lines;
209}
210
211////////////////////////////////////////////////////////////////////////////////
212/// @brief Prints the recognized flags and their help texts.
213////////////////////////////////////////////////////////////////////////////////
214void cmdlinearguments::print_help() {
215 hila::out0 << "Recognized command-line flags and their possible arguments:\n";
216
217 for (auto const &p : argmap) {
218 std::string flag = p.first;
219 std::string help = p.second.help_text;
220 strvec help_vec = parse_help(help);
221 hila::out0 << " " << flag << std::setw(20 - flag.length()) << ": " << help_vec[0]
222 << "\n";
223 for (int i = 1; i < help_vec.size(); i++) {
224 std::string padding = " ";
225 hila::out0 << padding << help_vec[i] << "\n";
226 }
227 }
228}
229
230////////////////////////////////////////////////////////////////////////////////
231/// @brief Checks whether a flag has entries by returning the count. Does not
232/// differentiate on whether the flag is known.
233///
234/// @param flag
235////////////////////////////////////////////////////////////////////////////////
236int cmdlinearguments::flag_set(const char *flag) {
237 if (argmap.count(flag) > 0)
238 return argmap[flag].val_strings.size();
239 else
240 return 0;
241}
242
243////////////////////////////////////////////////////////////////////////////////
244/// @brief Checks if a flag has been found in argv
245///
246/// @return Boolean indicating the statement.
247////////////////////////////////////////////////////////////////////////////////
248bool cmdlinearguments::flag_present(const char *flag) {
249 return argmap[flag].present;
250}
251
252////////////////////////////////////////////////////////////////////////////////
253/// @brief Attempts to return a long integer from i:th entry of flag 'flag'.
254/// Failure results in terminating the program.
255/// @param flag
256/// @param i index of the desired entry (default = 0);
257/// @return long conversion of the desired entry
258////////////////////////////////////////////////////////////////////////////////
259long cmdlinearguments::get_int(const char *flag, int i) {
260 // If flag is found and non-empty
261 int set = flag_set(flag);
262 if (set) {
263 std::string opt;
264 if (i < set)
265 opt = argmap[flag].val_strings[i];
266 else {
267 hila::out0 << "Flag '" << flag << "' has only " << set + 1
268 << " entries. Can't return index " << i << ".\n";
269 hila::out0 << "Terminating.\n";
270 quit_with_help();
271 }
272
273 long val = 0;
274 // Check for format
275 const std::regex permitted_user_input("^[+-]?[0-9]+");
276 if (std::regex_match(opt, permitted_user_input)) {
277 val = std::stol(opt);
278 } else {
279 hila::out0 << "Expected a number (integer) after command line parameter '" << flag
280 << "'\n";
281 quit_with_help();
282 }
283 return val;
284 } else {
285 hila::out0 << "Flag '" << flag << "' is missing an entry!\n";
286 hila::out0 << "Terminating.\n";
287 quit_with_help();
288 return -1;
289 }
290}
291
292////////////////////////////////////////////////////////////////////////////////
293/// @brief Attempts to return a double from i:th entry of flag 'flag'.
294/// Failure results in terminating the program. If std::stod
295/// doesn't complain, the conversion is considered valid.
296/// @param flag
297/// @param i index of the desired entry (default = 0);
298/// @return double conversion of the desired entry
299////////////////////////////////////////////////////////////////////////////////
300double cmdlinearguments::get_double(const char *flag, int i) {
301 // If flag is found and non-empty
302 int set = flag_set(flag);
303 if (set) {
304 std::string opt;
305 if (i < set)
306 opt = argmap[flag].val_strings[i];
307 else {
308 hila::out0 << "Flag '" << flag << "' has only " << set
309 << " entries. Can't return index " << i << ".\n";
310 hila::out0 << "Terminating.\n";
311 quit_with_help();
312 return -1;
313 }
314
315 double val;
316 // We're not going to manually check the format for this
317 try {
318 val = std::stod(opt);
319 } catch (std::exception &e) {
320 hila::out0 << "Expected a number (double) after command line parameter '" << flag
321 << "'\n";
322 quit_with_help();
323 }
324 return val;
325 }
326 // if not found
327 else {
328 hila::out0 << "Flag '" << flag << "' is missing an entry!\n";
329 hila::out0 << "Terminating.\n";
330 quit_with_help();
331 return -1;
332 }
333}
334
335////////////////////////////////////////////////////////////////////////////////
336/// @brief Attempts to return the i:th entry of flag 'flag'.
337/// Failure results in terminating the program.
338///
339/// @param flag
340/// @param i index of the desired entry (default = 0);
341/// @return the desired entry
342////////////////////////////////////////////////////////////////////////////////
343std::string cmdlinearguments::get_string(const char *flag, int i) {
344 int set = flag_set(flag);
345 if (set) {
346 if (i < set)
347 return argmap[flag].val_strings[i];
348 else {
349 hila::out0 << "Flag '" << flag << "' has only " << set + 1
350 << " entries. Can't return index " << i << ".\n";
351 hila::out0 << "Terminating.\n";
352 quit_with_help();
353 return "";
354 }
355 } else {
356 hila::out0 << "Flag '" << flag << "' is missing an entry!\n";
357 hila::out0 << "Terminating.\n";
358 quit_with_help();
359 return "";
360 }
361}
Implement hila::swap for gauge fields.
Definition array.h:981
std::ostream out0
This writes output only from main process (node 0)
void finishrun()
Normal, controlled exit - all nodes must call this. Prints timing information and information about c...
Struct to hold structured information on used command line arguments.
Definition cmdline.cpp:33
bool present
A boolean telling whether the flag was found in argv.
Definition cmdline.cpp:36
strvec val_strings
Strings corresponding to read in cmdline parameters.
Definition cmdline.cpp:34
std::string help_text
A string describing the use of the flag.
Definition cmdline.cpp:35