HILA
Loading...
Searching...
No Matches
input.cpp
1#include <sstream>
2#include <iostream>
3#include <fstream>
4#include <regex>
5#include <type_traits>
6#include "defs.h"
7#include "input.h"
8#include <errno.h>
9#include <iomanip>
10
11#define COMMENT_CHAR '#'
12
13//////////////////////////////////////////////////////////////////////////////
14/// Parameter file input system
15/// Check input.h for user instructions
16//////////////////////////////////////////////////////////////////////////////
17
18namespace hila {
19
20static std::string empty_key("");
21
22bool input::open(const std::string &file_name, bool use_cmdline, bool exit_on_error) {
23 extern const char *input_file;
24
25 std::string fname;
26
27 if (use_cmdline && input_file != nullptr) {
28
29 fname = input_file;
30 input_file = nullptr; // set this null, so that it is not used again
31 } else {
32 fname = file_name;
33 }
34
35 bool got_error = false;
36 if (hila::myrank() == 0) {
37 if (is_initialized) {
38 if (speaking)
39 hila::out0 << "Error: file '" << fname << "' cannot be opened because '" << filename
40 << "' is open in this input variable\n";
41
42 got_error = true;
43 } else {
44 filename = fname;
45 if (fname == "-") {
46 use_cin = true;
47 if (speaking)
48 print_dashed_line("Reading from standard input");
49 } else {
50 use_cin = false;
51 inputfile.open(fname);
52 if (inputfile.is_open()) {
53 is_initialized = true;
54
55 if (speaking)
56 print_dashed_line("Reading file " + filename);
57
58 } else {
59
60 if (speaking) {
61 if (exit_on_error)
62 hila::out0 << "ERROR: ";
63 hila::out0 << "Input file '" << fname << "' could not be opened\n";
64 }
65
66 got_error = true;
67 }
68 }
69 }
70 }
71 hila::broadcast(got_error);
72 if (got_error && exit_on_error) {
74 }
75
76 return !got_error;
77}
78
80 if (is_initialized && !use_cin) {
81 inputfile.close();
82 is_initialized = false;
83 }
84 if (speaking)
85 print_dashed_line();
86
87 // automatic cleaning of other vars
88}
89
90// read one line skipping comments and initial whitespace
91bool input::get_line() {
92 if (hila::myrank() == 0) {
93 do {
94 std::istream *inptr;
95
96 if (use_cin)
97 inptr = &std::cin;
98 else
99 inptr = &inputfile;
100
101 *inptr >> std::ws; // remove initial whitespace
102 if (!std::getline(*inptr, linebuffer)) {
103 linebuffer.clear();
104 lb_start = 0;
105 return false;
106 }
107 } while (linebuffer.at(0) == COMMENT_CHAR);
108 size_t i = linebuffer.find(COMMENT_CHAR);
109 if (i != std::string::npos)
110 linebuffer.resize(i);
111 lb_start = 0;
112
113 is_line_printed = false; // not yet printed
114 }
115 return true; // sync this at another spot
116}
117
118// print the read-in line with a bit special formatting
119void input::print_linebuf(int end_of_key) {
120 if (hila::myrank() == 0 && speaking) {
121
122 if (is_line_printed)
123 return;
124 is_line_printed = true;
125
126 int i = 0;
127 while (i < linebuffer.size() && std::isspace(linebuffer[i]))
128 i++;
129 for (; i < linebuffer.size() && i < end_of_key; i++) {
130 hila::out0 << linebuffer[i];
131 }
132 hila::out0 << ' ';
133 if (end_of_key > 0) {
134 for (int j = i; j < 20; j++)
135 hila::out0 << ' ';
136 }
137
138 while (i < linebuffer.size() && std::isspace(linebuffer[i]))
139 i++;
140 if (i < linebuffer.size()) {
141 hila::out0 << linebuffer.substr(i);
142 }
143 hila::out0 << std::endl; // use endl to show output here
144 }
145}
146
147// remove leading whitespace, incl. lines
148bool input::remove_whitespace() {
149 if (hila::myrank() == 0) {
150 while (lb_start < linebuffer.size() && std::isspace(linebuffer[lb_start]))
151 lb_start++;
152 if (lb_start == linebuffer.size())
153 return get_line();
154 }
155 return true; // do not broadcast yet, should be used only in node 0
156}
157
158// returns true if line contains the word list at the beginning of line. list
159// contains the word separated by whitespace. If match found, advances the
160// lb_start to new position. end_of_key is the index where key match on line ends
161
162bool input::contains_word_list(const std::string &list, int &end_of_key) {
163 const char *p = linebuffer.c_str() + lb_start;
164 const char *q = list.c_str();
165 while (std::isspace(*p))
166 p++;
167 while (std::isspace(*q))
168 q++;
169
170 bool last_space = false;
171 char last_char = 0;
172 while (*p && *q) {
173 // compare non-space chars
174 while (*p && *q && *p == *q && !std::isspace(*q)) {
175 last_char = *p;
176 p++;
177 q++;
178 last_space = false;
179 }
180 if (std::isspace(*q) && std::isspace(*p)) {
181 // matching spaces, skip
182 while (std::isspace(*p))
183 p++;
184 while (std::isspace(*q))
185 q++;
186 last_space = true;
187 }
188
189 if (*p != *q)
190 break;
191 }
192 // if line contained the words in list, *q = 0.
193
194 while (std::isspace(*q))
195 q++;
196 // if *q != 0 then some chars do not match
197 // if *q == 0 then p has to fully match. This is true if
198 // the last match was space or *p == 0 or *p is space or comma (,)
199 if (*q != 0 || !(last_space || *p == 0 || std::isspace(*p) || last_char == ',' || *p == ','))
200 return false;
201
202 end_of_key = p - linebuffer.c_str();
203
204 while (std::isspace(*p))
205 p++;
206 lb_start = p - linebuffer.c_str();
207 return true;
208}
209
210// find tokens separated by whitespace or ,
211// inside of " .. " is one token too.
212// returns true if the next token (on the same line) is found
213
214bool input::peek_token(std::string &tok) {
215 if (!remove_whitespace())
216 return false;
217 size_t i;
218 bool in_quotes = false;
219 for (i = lb_start; i < linebuffer.size() &&
220 ((!std::isspace(linebuffer[i]) && linebuffer[i] != ',') || in_quotes);
221 i++) {
222 if (linebuffer[i] == '"') {
223 in_quotes = !in_quotes;
224 }
225 }
226 if (i == lb_start && linebuffer[i] == ',')
227 i++; // this happens for only ,
228
229 if (in_quotes) {
230 hila::out0 << "Error: unbalanced quotes\n";
231 exit(1); // unclean exit
232 }
233 tok = linebuffer.substr(lb_start, i - lb_start);
234 return true;
235}
236
237// consumes the token too
238
239bool input::get_token(std::string &tok) {
240 if (peek_token(tok)) {
241 lb_start += tok.size();
242 return true;
243 }
244 return false;
245}
246
247// match_token returns true and consumes the token if it matches the argument
248
249bool input::match_token(const std::string &tok) {
250 std::string s;
251 if (peek_token(s) && s == tok) {
252 lb_start += tok.size();
253 return true;
254 }
255 return false;
256}
257
258// require the (typically beginning of line) key for parameters
259
260bool input::handle_key(const std::string &key) {
261 if (hila::myrank() == 0) {
262 // check the linebuffer for stuff
263 remove_whitespace();
264
265 int end_of_key = 0;
266 if (key.size() > 0 && !contains_word_list(key, end_of_key)) {
267 if (speaking) {
268 hila::out0 << "Error: expecting key '" << key << "', found instead:\n";
269 print_linebuf(0);
270 }
271 return false;
272 }
273
274 print_linebuf(end_of_key);
275 }
276 return true;
277}
278
279// is the input string int/double/string and return it
280
281
282// a trivial function, useful for template
283bool input::is_value(const std::string &str, std::string &val) {
284 val = remove_quotes(str);
285 return true;
286}
287
288std::string input::remove_quotes(const std::string &val) {
289 size_t i, j;
290 std::string res;
291 res = val;
292 for (j = i = 0; i < val.size(); i++)
293 if (val[i] != '"')
294 res[j++] = val[i];
295 res.resize(j);
296 return res;
297}
298
299// expects "label <item>" -line, where <item> matches one of the std::strings in
300// items. returns the index of the item. If not found, errors out
301
302int input::get_item(const std::string &label, const std::vector<std::string> &items, bool bcast) {
303
304 bool no_error = handle_key(label);
305 int item = -1;
306 double d;
307 std::string s;
308
309 if (hila::myrank() == 0) {
310 if (no_error && peek_token(s)) {
311
312 for (int i = 0; i < items.size() && item < 0; i++) {
313 double dval;
314 long lval;
315 int end_of_key;
316
317 // clang-format off
318 if ((items[i] == "%s") ||
319 (items[i] == "%f" && is_value(s,dval)) ||
320 (items[i] == "%i" && is_value(s,lval)) ||
321 contains_word_list(items[i],end_of_key)) {
322 item = i;
323 }
324 // clang-format on
325 }
326 }
327
328 if (item < 0) {
329
330 // error, nothing was found
331 no_error = false;
332 if (speaking) {
333 hila::out0 << "Input '" << label << "' must be one of: ";
334 for (int i = 0; i < items.size(); i++) {
335 if (items[i] == "%s")
336 hila::out0 << "<string> ";
337 else if (items[i] == "%f")
338 hila::out0 << "<float/double> ";
339 else if (items[i] == "%i")
340 hila::out0 << "<int/long> ";
341 else
342 hila::out0 << '\'' << items[i] << "' ";
343 }
344 hila::out0 << '\n';
345 }
346 }
347 }
348
349 if (bcast) {
350 hila::broadcast2(item, no_error);
351
352 // with broadcast exit on error
353 if (!no_error)
355 }
356
357 return item;
358}
359
360} // namespace hila
void close()
Closes input parameter file.
Definition input.cpp:79
bool open(const std::string &fname, bool use_cmdline=true, bool exit_on_error=true)
Open file that parameters are read from.
Definition input.cpp:22
int get_item(const std::string &label, const std::vector< std::string > &items, bool bcast=true)
Identify item from a list.
Definition input.cpp:302
This file defines all includes for HILA.
Invert diagonal + const. matrix using Sherman-Morrison formula.
Definition array.h:920
int myrank()
rank of this node
Definition com_mpi.cpp:235
std::ostream out0
This writes output only from main process (node 0)
T broadcast(T &var, int rank=0)
Broadcast the value of var to all MPI ranks from rank (default=0).
Definition com_mpi.h:153
void finishrun()
Normal, controlled exit - all nodes must call this. Prints timing information and information about c...
void broadcast2(T &t, U &u, int rank=0)
and broadcast with two values
Definition com_mpi.h:226