XGC1
NamelistReader.hpp
Go to the documentation of this file.
1 #ifndef NAMELISTREADER_HPP
2 #define NAMELISTREADER_HPP
3 
4 #include <iostream>
5 #include <sstream>
6 #include <fstream>
7 #include <string>
8 #include <vector>
9 #include <algorithm>
10 #include <cctype>
11 
12 namespace NLReader{
13 
14 using namespace std;
15 
16 enum Expect {
23 };
24 
25 enum ReadFrom {
28 };
29 
30 enum Create {
32 };
33 
34 // trim from left
35 inline string& ltrim(string& s, const char* t = " \t\n\r\f\v")
36 {
37  s.erase(0, s.find_first_not_of(t));
38  return s;
39 }
40 
41 // trim from right
42 inline string& rtrim(string& s, const char* t = " \t\n\r\f\v")
43 {
44  s.erase(s.find_last_not_of(t) + 1);
45  return s;
46 }
47 
48 // trim from left & right
49 inline string& trim(string& s, const char* t = " \t\n\r\f\v")
50 {
51  return ltrim(rtrim(s, t), t);
52 }
53 
54 struct Param{
55  string name;
56  bool used;
57  vector<string> values;
58 
59  Param(string name)
60  : name(name), used(false)
61  {}
62 };
63 
64 struct NameList{
65  string name;
66  vector<Param> params;
67 
68  NameList(string name)
69  : name(name)
70  {}
71 
72  void add_param(string word)
73  {
74  params.push_back(Param(word));
75  }
76 
77  void add_value(string word)
78  {
79  params[params.size()-1].values.push_back(word);
80  }
81 };
82 
83 static inline string get_first_word(string& str, int start){
84  for (string::size_type i = start; i < str.size(); i++){
85  if ((str[i]>=48 && str[i]<=57) || (str[i]>=65 && str[i]<=90) ||
86  (str[i]>=97 && str[i]<=122) || str[i]==95){
87  // still in word (0-9, A-Z, a-z, _)
88  } else {
89  // Not in word
90  return str.substr(start, i-start);
91  }
92  }
93  return str.substr(start,str.size()-start);
94 }
95 
96 static inline string get_first_value(string& str, int start){
97  bool in_squote=false;
98  bool in_dquote=false;
99  for (string::size_type i = start; i < str.size(); i++){
100  if (in_dquote==true || in_squote==true){
101  if (str[i]==34) in_dquote=false;
102  if (str[i]==39) in_squote=false;
103  } else {
104  if (str[i]==34) in_dquote=true;
105  if (str[i]==39) in_squote=true;
106  if (str[i]=='!' || str[i]==' ' || str[i]=='\t'|| str[i]=='\r'|| str[i]=='\f'|| str[i]=='\v'){
107  // Not in word
108  return str.substr(start, i-start);
109  }
110  }
111  }
112  return str.substr(start,str.size()-start);
113 }
114 
115 static inline string lower_case_copy(const string& str){
116  // Make copy
117  string lc_str = str;
118 
119  // Make lower case
120  for (int i = 0; i<lc_str.size(); i++)
121  lc_str[i]=tolower(lc_str[i]);
122 
123  return lc_str;
124 }
125 
126 template<typename T>
127 static inline T string_to_param(string& param);
128 
129 template<>
130 bool string_to_param<bool>(string& param){
131  // Make lower case copy
132  const string lc_param = lower_case_copy(param);
133 
134  if (lc_param==".false."){
135  return false;
136  } else if (lc_param==".true."){
137  return true;
138  } else {
139  printf("Error, couldn't parse %s \n", param.c_str());
140  return false;
141  }
142 }
143 
144 static inline void change_D_to_E(string& param){
145  for (int i = 0; i<param.size(); i++)
146  if (param[i]=='D' || param[i]=='d') param[i]='e';
147 }
148 
149 template<>
150 int string_to_param<int>(string& param){
151  change_D_to_E(param);
152  return stoi(param);
153 }
154 
155 template<>
156 float string_to_param<float>(string& param){
157  change_D_to_E(param);
158  return stof(param);
159 }
160 
161 template<>
162 double string_to_param<double>(string& param){
163  change_D_to_E(param);
164  return stod(param);
165 }
166 
167 template<>
168 string string_to_param<string>(string& param){
169  // Remove the quotes
170  return param.substr(1,param.size()-2);
171 }
172 
173 
174 template<typename T>
175 int find_case_insensitive_name_match(vector<T>& vec, const string& str){
176  // Make lower case version
177  const string lc_str = lower_case_copy(str);
178 
179  // Locate the requested parameter
180  typename vector<T>::iterator it = vec.begin();
181  while (it!=vec.end()) {
182  if (lower_case_copy((*it).name)==str) break;
183  ++it;
184  }
185 
186  if (it != vec.end())
187  return distance(vec.begin(), it);
188  else{
189  return -1;
190  }
191 }
192 
194  vector<NameList> namelists;
196  bool use_all;
198 
199  template<class T>
200  void parse_lines(T& newfile, const string& filename){
201  const bool verbose=false;
202  string line;
203  Expect expect = Ampersand;
204  int i_line=0;
205  while(getline(newfile, line)){ //read data from file object and put it into string.
206  i_line++;
207  trim(line); // Remove leading and trailing whitespace
208  for (string::size_type i = 0; i < line.size(); i++){
209  if (line[i]=='!'){
210  // Comment has begun
211  break;
212  }
213  if (expect==Ampersand){
214  if (line[i]=='&'){
215  expect=NLName;
216  }
217  } else if (expect==NLName){
218  string word = get_first_word(line,i);
219  if (word.size()>0){ // Found namelist name
220  expect = ParaNameOrEnd;
221  namelists.push_back(NameList(word));
222  if (verbose) cout << "Found namelist: " << word << "\n";
223  break;
224  }
225  } else if(expect==ParaNameOrEnd){
226  if (line[i]=='/'){ // End of namelist
227  expect=Ampersand;
228  break;
229  }
230 
231  string word = get_first_word(line,i);
232  if (word.size()>0){
233  i+=word.size()-1;
234  expect = Equals;
235  namelists[namelists.size()-1].add_param(word);
236  if (verbose) cout << " Found parameter: " << word << "\n";
237  }
238  } else if(expect==Equals){
239  if (line[i]=='='){
240  expect=Value;
241  }
242  } else if(expect==Value || expect == ValueOrEOL){
243  string word = get_first_value(line,i);
244  if (word.size()>0){
245  i+=word.size()-1;
246  expect = ValueOrEOL;
247  namelists[namelists.size()-1].add_value(word);
248  if (verbose) cout << " Found Value: " << word << "\n";
249  }
250  }
251  }
252  // Got to end of line
253  if (expect==NLName){
254  printf("\nParse failure reading %s at Line %d. Failed to find name of namelist.\n", filename.c_str(), i_line);
255  return;
256  } else if(expect==Equals){
257  printf("\nParse failure reading %s at Line %d. Expected parameter assignment.\n", filename.c_str(), i_line);
258  return;
259  } else if(expect==Value){
260  printf("\nParse failure reading %s at Line %d. Couldn't parse value assignment.\n", filename.c_str(), i_line);
261  return;
262  }
263  // Hit EOL, now expecting next parameter
264  if (expect==ValueOrEOL) expect = ParaNameOrEnd;
265  }
266  }
267 
268  void load(const string& filename){
269  fstream newfile;
270  newfile.open(filename,ios::in); //open a file to perform read operation using file object
271  if (!newfile.is_open()) return; //checking whether the file is open
272 
273  parse_lines(newfile,filename);
274 
275  newfile.close(); //close the file object.
276  }
277 
278  void load_from_string(const string& str){
279  istringstream f(str.c_str());
280 
281  parse_lines(f,"string input");
282  }
283 
284  public:
285 
286  enum Options{
287  Optional=0, // Namelist is optional, use the default of any requested parameter if the namelist is not present
288  Required=1
289  };
290 
291  NamelistReader(const string& filename)
292  : namelist_index(-1), use_all(false), modifiable(false)
293  {
294  load(filename);
295  }
296 
297  NamelistReader(const string& str_name, ReadFrom read_from)
298  : namelist_index(-1), use_all(false), modifiable(false)
299  {
300  if (read_from==ReadFromFile){
301  load(str_name);
302  }else{
303  load_from_string(str_name);
304  }
305  }
306 
308  : namelist_index(-1), use_all(false), modifiable(false)
309  {
310  if (create==CreateManually) modifiable = true;
311  }
312 
314  modifiable = true;
315  }
316 
317  void add_namelist(const string& namelist){
318  if (modifiable){
319  namelists.push_back(NameList(namelist));
320  namelist_index = namelists.size()-1; // Focus to the new namelist
321  } else {
322  printf("Warning: 'add_namelist' ignored, only valid if NamelistReader is in CreateManually mode");
323  }
324  }
325 
326  void add_to_namelist(const string& param, const string& val){
327  if (modifiable){
328  namelists[namelist_index].add_param(param);
329  namelists[namelist_index].add_value(val);
330  } else {
331  printf("Warning: 'add_to_namelist' ignored, only valid if NamelistReader is in CreateManually mode");
332  }
333  }
334 
335  void add_to_param(const string& val){
336  if (modifiable){
337  namelists[namelist_index].add_value(val);
338  } else {
339  printf("Warning: 'add_to_param' ignored, only valid if NamelistReader is in CreateManually mode");
340  }
341  }
342 
344  int n_unused=0;
345  for (vector<NameList>::iterator nl = namelists.begin(); nl != namelists.end(); ++nl) {
346  for (vector<Param>::iterator param = nl->params.begin(); param != nl->params.end(); ++param ) {
347  if (param->used==false){
348  printf("Warning: '%s' was present in '%s' but was not used.\n",param->name.c_str(), nl->name.c_str());
349  n_unused++;
350  }
351  }
352  }
353  return (n_unused==0);
354  }
355 
356  bool namelist_present(const string& namelist){
357  return (find_case_insensitive_name_match(namelists, namelist)!=-1);
358  }
359 
360  void use_namelist(const string& namelist, Options required = Required){
361  namelist_index = find_case_insensitive_name_match(namelists, namelist);
362  if(namelist_index==-1){
363  if(required==Required){
364  printf("\nNamelist '%s' not found in the file!",namelist.c_str());
365  exit(1);
366  }else{
367  // Use -2 to indicate that the defaults can be safely used if
368  // the namelist is not present
369  namelist_index = -2;
370  }
371  }
372  }
373 
374  bool present(const string& param){
375  if(namelist_index==-1){
376  printf("\nNeed to choose which namelist to use with use_namelist(const std::string&)!\n");
377  }else if(namelist_index==-2){
378  return false; // Namelist not present so param is also not present
379  }
380 
381  // Locate the requested parameter
382  return (find_case_insensitive_name_match(namelists[namelist_index].params, param)!=-1);
383  }
384 
385  template <typename T>
386  T get(const string& param, const T default_val, int val_ind=0){
387  if (namelist_index==-1){
388  printf("\nNeed to choose which namelist to use with use_namelist(const std::string&)!\n");
389  }else if(namelist_index==-2){
390  return default_val; // Namelist not present so return default
391  }
392 
393  // Locate the requested parameter
394  int param_index = find_case_insensitive_name_match(namelists[namelist_index].params, param);
395  if(param_index==-1){
396  return default_val;
397  }
398 
399  namelists[namelist_index].params[param_index].used=true;
400 
401  if (val_ind>=0 && val_ind<namelists[namelist_index].params[param_index].values.size()){
402  string str_var = namelists[namelist_index].params[param_index].values[val_ind];
403  return string_to_param<T>(str_var);
404  } else {
405  printf("\nParameter '%s' in namelist '%s' didn't have enough values!",param.c_str(),namelists[namelist_index].name.c_str());
406  exit(1);
407  return default_val;
408  }
409  }
410 
411  template <typename T>
412  T get_required(const string& param, int val_ind=0){
413  if (namelist_index==-1){
414  printf("\nNeed to choose which namelist to use with use_namelist(const std::string&)!\n");
415  exit(1);
416  }else if(namelist_index==-2){
417  printf("\nParameter '%s' not found since the namelist was not found.\n",param.c_str(),namelists[namelist_index].name.c_str());
418  exit(1);
419  }
420 
421  // Locate the requested parameter
422  int param_index = find_case_insensitive_name_match(namelists[namelist_index].params, param);
423  if(param_index==-1){
424  printf("\nParameter '%s' not found in namelist '%s'!",param.c_str(),namelists[namelist_index].name.c_str());
425  exit(1);
426  }
427 
428  namelists[namelist_index].params[param_index].used=true;
429 
430  if (val_ind>=0 && val_ind<namelists[namelist_index].params[param_index].values.size()){
431  string str_var = namelists[namelist_index].params[param_index].values[val_ind];
432  return string_to_param<T>(str_var);
433  } else {
434  printf("\nParameter '%s' in namelist '%s' didn't have enough values!",param.c_str(),namelists[namelist_index].name.c_str());
435  exit(1);
436  }
437  }
438 };
439 
440 }
441 #endif
Definition: NamelistReader.hpp:193
void add_to_param(const string &val)
Definition: NamelistReader.hpp:335
NamelistReader(Create create)
Definition: NamelistReader.hpp:307
void load_from_string(const string &str)
Definition: NamelistReader.hpp:278
vector< NameList > namelists
Definition: NamelistReader.hpp:194
NamelistReader(const string &filename)
Definition: NamelistReader.hpp:291
T get_required(const string &param, int val_ind=0)
Definition: NamelistReader.hpp:412
void load(const string &filename)
Definition: NamelistReader.hpp:268
void add_to_namelist(const string &param, const string &val)
Definition: NamelistReader.hpp:326
T get(const string &param, const T default_val, int val_ind=0)
Definition: NamelistReader.hpp:386
void enable_modifications()
Definition: NamelistReader.hpp:313
void add_namelist(const string &namelist)
Definition: NamelistReader.hpp:317
void use_namelist(const string &namelist, Options required=Required)
Definition: NamelistReader.hpp:360
int namelist_index
Definition: NamelistReader.hpp:195
Options
Definition: NamelistReader.hpp:286
void parse_lines(T &newfile, const string &filename)
Definition: NamelistReader.hpp:200
bool modifiable
Definition: NamelistReader.hpp:197
bool use_all
Definition: NamelistReader.hpp:196
bool present(const string &param)
Definition: NamelistReader.hpp:374
bool namelist_present(const string &namelist)
Definition: NamelistReader.hpp:356
NamelistReader(const string &str_name, ReadFrom read_from)
Definition: NamelistReader.hpp:297
bool check_all_used()
Definition: NamelistReader.hpp:343
int size_type
Definition: col_grid_matrix.hpp:19
Definition: NamelistReader.hpp:12
static string get_first_value(string &str, int start)
Definition: NamelistReader.hpp:96
ReadFrom
Definition: NamelistReader.hpp:25
@ ReadFromFile
Definition: NamelistReader.hpp:26
@ ReadFromString
Definition: NamelistReader.hpp:27
Create
Definition: NamelistReader.hpp:30
@ CreateManually
Definition: NamelistReader.hpp:31
string & trim(string &s, const char *t=" \t\n\r\f\v")
Definition: NamelistReader.hpp:49
static string lower_case_copy(const string &str)
Definition: NamelistReader.hpp:115
static void change_D_to_E(string &param)
Definition: NamelistReader.hpp:144
float string_to_param< float >(string &param)
Definition: NamelistReader.hpp:156
string string_to_param< string >(string &param)
Definition: NamelistReader.hpp:168
int find_case_insensitive_name_match(vector< T > &vec, const string &str)
Definition: NamelistReader.hpp:175
string & rtrim(string &s, const char *t=" \t\n\r\f\v")
Definition: NamelistReader.hpp:42
double string_to_param< double >(string &param)
Definition: NamelistReader.hpp:162
static string get_first_word(string &str, int start)
Definition: NamelistReader.hpp:83
static T string_to_param(string &param)
bool string_to_param< bool >(string &param)
Definition: NamelistReader.hpp:130
int string_to_param< int >(string &param)
Definition: NamelistReader.hpp:150
string & ltrim(string &s, const char *t=" \t\n\r\f\v")
Definition: NamelistReader.hpp:35
Expect
Definition: NamelistReader.hpp:16
@ Value
Definition: NamelistReader.hpp:21
@ Equals
Definition: NamelistReader.hpp:20
@ ParaNameOrEnd
Definition: NamelistReader.hpp:19
@ NLName
Definition: NamelistReader.hpp:18
@ Ampersand
Definition: NamelistReader.hpp:17
@ ValueOrEOL
Definition: NamelistReader.hpp:22
logical false
Definition: module.F90:102
Definition: NamelistReader.hpp:64
vector< Param > params
Definition: NamelistReader.hpp:66
void add_value(string word)
Definition: NamelistReader.hpp:77
string name
Definition: NamelistReader.hpp:65
void add_param(string word)
Definition: NamelistReader.hpp:72
NameList(string name)
Definition: NamelistReader.hpp:68
Definition: NamelistReader.hpp:54
bool used
Definition: NamelistReader.hpp:56
string name
Definition: NamelistReader.hpp:55
vector< string > values
Definition: NamelistReader.hpp:57
Param(string name)
Definition: NamelistReader.hpp:59