XGCa
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 long long int string_to_param<long long int>(string& param){
157  change_D_to_E(param);
158  return stoll(param);
159 }
160 
161 template<>
162 float string_to_param<float>(string& param){
163  change_D_to_E(param);
164  return stof(param);
165 }
166 
167 template<>
168 double string_to_param<double>(string& param){
169  change_D_to_E(param);
170  return stod(param);
171 }
172 
173 template<>
174 string string_to_param<string>(string& param){
175  // Remove the quotes
176  return param.substr(1,param.size()-2);
177 }
178 
179 
180 template<typename T>
181 int find_case_insensitive_name_match(vector<T>& vec, const string& str){
182  // Make lower case version
183  const string lc_str = lower_case_copy(str);
184 
185  // Locate the requested parameter
186  typename vector<T>::iterator it = vec.begin();
187  while (it!=vec.end()) {
188  if (lower_case_copy((*it).name)==str) break;
189  ++it;
190  }
191 
192  if (it != vec.end())
193  return distance(vec.begin(), it);
194  else{
195  return -1;
196  }
197 }
198 
200  vector<NameList> namelists;
202  bool use_all;
204 
205  template<class T>
206  void parse_lines(T& newfile, const string& filename){
207  const bool verbose=false;
208  string line;
209  Expect expect = Ampersand;
210  int i_line=0;
211  while(getline(newfile, line)){ //read data from file object and put it into string.
212  i_line++;
213  trim(line); // Remove leading and trailing whitespace
214  for (string::size_type i = 0; i < line.size(); i++){
215  if (line[i]=='!'){
216  // Comment has begun
217  break;
218  }
219  if (expect==Ampersand){
220  if (line[i]=='&'){
221  expect=NLName;
222  }
223  } else if (expect==NLName){
224  string word = get_first_word(line,i);
225  if (word.size()>0){ // Found namelist name
226  expect = ParaNameOrEnd;
227  namelists.push_back(NameList(word));
228  if (verbose) cout << "Found namelist: " << word << "\n";
229  break;
230  }
231  } else if(expect==ParaNameOrEnd){
232  if (line[i]=='/'){ // End of namelist
233  expect=Ampersand;
234  break;
235  }
236 
237  string word = get_first_word(line,i);
238  if (word.size()>0){
239  i+=word.size()-1;
240  expect = Equals;
241  namelists[namelists.size()-1].add_param(word);
242  if (verbose) cout << " Found parameter: " << word << "\n";
243  }
244  } else if(expect==Equals){
245  if (line[i]=='='){
246  expect=Value;
247  }
248  } else if(expect==Value || expect == ValueOrEOL){
249  string word = get_first_value(line,i);
250  if (word.size()>0){
251  i+=word.size()-1;
252  expect = ValueOrEOL;
253  namelists[namelists.size()-1].add_value(word);
254  if (verbose) cout << " Found Value: " << word << "\n";
255  }
256  }
257  }
258  // Got to end of line
259  if (expect==NLName){
260  printf("\nParse failure reading %s at Line %d. Failed to find name of namelist.\n", filename.c_str(), i_line);
261  return;
262  } else if(expect==Equals){
263  printf("\nParse failure reading %s at Line %d. Expected parameter assignment.\n", filename.c_str(), i_line);
264  return;
265  } else if(expect==Value){
266  printf("\nParse failure reading %s at Line %d. Couldn't parse value assignment.\n", filename.c_str(), i_line);
267  return;
268  }
269  // Hit EOL, now expecting next parameter
270  if (expect==ValueOrEOL) expect = ParaNameOrEnd;
271  }
272  }
273 
274  void load(const string& filename){
275  fstream newfile;
276  newfile.open(filename,ios::in); //open a file to perform read operation using file object
277  if (!newfile.is_open()) return; //checking whether the file is open
278 
279  parse_lines(newfile,filename);
280 
281  newfile.close(); //close the file object.
282  }
283 
284  void load_from_string(const string& str){
285  istringstream f(str.c_str());
286 
287  parse_lines(f,"string input");
288  }
289 
290  public:
291 
292  enum Options{
293  Optional=0, // Namelist is optional, use the default of any requested parameter if the namelist is not present
294  Required=1
295  };
296 
297  NamelistReader(const string& filename)
298  : namelist_index(-1), use_all(false), modifiable(false)
299  {
300  load(filename);
301  }
302 
303  NamelistReader(const string& str_name, ReadFrom read_from)
304  : namelist_index(-1), use_all(false), modifiable(false)
305  {
306  if (read_from==ReadFromFile){
307  load(str_name);
308  }else{
309  load_from_string(str_name);
310  }
311  }
312 
314  : namelist_index(-1), use_all(false), modifiable(false)
315  {
316  if (create==CreateManually) modifiable = true;
317  }
318 
320  modifiable = true;
321  }
322 
323  void add_namelist(const string& namelist){
324  if (modifiable){
325  namelists.push_back(NameList(namelist));
326  namelist_index = namelists.size()-1; // Focus to the new namelist
327  } else {
328  printf("Warning: 'add_namelist' ignored, only valid if NamelistReader is in CreateManually mode");
329  }
330  }
331 
332  void add_to_namelist(const string& param, const string& val){
333  if (modifiable){
334  namelists[namelist_index].add_param(param);
335  namelists[namelist_index].add_value(val);
336  } else {
337  printf("Warning: 'add_to_namelist' ignored, only valid if NamelistReader is in CreateManually mode");
338  }
339  }
340 
341  void add_to_param(const string& val){
342  if (modifiable){
343  namelists[namelist_index].add_value(val);
344  } else {
345  printf("Warning: 'add_to_param' ignored, only valid if NamelistReader is in CreateManually mode");
346  }
347  }
348 
350  int n_unused=0;
351  for (vector<NameList>::iterator nl = namelists.begin(); nl != namelists.end(); ++nl) {
352  for (vector<Param>::iterator param = nl->params.begin(); param != nl->params.end(); ++param ) {
353  if (param->used==false){
354  printf("Warning: '%s' was present in '%s' but was not used.\n",param->name.c_str(), nl->name.c_str());
355  n_unused++;
356  }
357  }
358  }
359  return (n_unused==0);
360  }
361 
362  bool namelist_present(const string& namelist){
363  return (find_case_insensitive_name_match(namelists, namelist)!=-1);
364  }
365 
366  void use_namelist(const string& namelist, Options required = Required){
367  namelist_index = find_case_insensitive_name_match(namelists, namelist);
368  if(namelist_index==-1){
369  if(required==Required){
370  printf("\nNamelist '%s' not found in the file!",namelist.c_str());
371  exit(1);
372  }else{
373  // Use -2 to indicate that the defaults can be safely used if
374  // the namelist is not present
375  namelist_index = -2;
376  }
377  }
378  }
379 
380  bool present(const string& param){
381  if(namelist_index==-1){
382  printf("\nNeed to choose which namelist to use with use_namelist(const std::string&)!\n");
383  }else if(namelist_index==-2){
384  return false; // Namelist not present so param is also not present
385  }
386 
387  // Locate the requested parameter
388  return (find_case_insensitive_name_match(namelists[namelist_index].params, param)!=-1);
389  }
390 
391  template <typename T>
392  T get(const string& param, const T default_val, int val_ind=0){
393  if (namelist_index==-1){
394  printf("\nNeed to choose which namelist to use with use_namelist(const std::string&)!\n");
395  }else if(namelist_index==-2){
396  return default_val; // Namelist not present so return default
397  }
398 
399  // Locate the requested parameter
400  int param_index = find_case_insensitive_name_match(namelists[namelist_index].params, param);
401  if(param_index==-1){
402  return default_val;
403  }
404 
405  namelists[namelist_index].params[param_index].used=true;
406 
407  if (val_ind>=0 && val_ind<namelists[namelist_index].params[param_index].values.size()){
408  string str_var = namelists[namelist_index].params[param_index].values[val_ind];
409  return string_to_param<T>(str_var);
410  } else {
411  printf("\nParameter '%s' in namelist '%s' didn't have enough values!",param.c_str(),namelists[namelist_index].name.c_str());
412  exit(1);
413  return default_val;
414  }
415  }
416 
417  template <typename T>
418  T get_required(const string& param, int val_ind=0){
419  if (namelist_index==-1){
420  printf("\nNeed to choose which namelist to use with use_namelist(const std::string&)!\n");
421  exit(1);
422  }else if(namelist_index==-2){
423  printf("\nParameter '%s' not found since the namelist was not found.\n",param.c_str(),namelists[namelist_index].name.c_str());
424  exit(1);
425  }
426 
427  // Locate the requested parameter
428  int param_index = find_case_insensitive_name_match(namelists[namelist_index].params, param);
429  if(param_index==-1){
430  printf("\nParameter '%s' not found in namelist '%s'!",param.c_str(),namelists[namelist_index].name.c_str());
431  exit(1);
432  }
433 
434  namelists[namelist_index].params[param_index].used=true;
435 
436  if (val_ind>=0 && val_ind<namelists[namelist_index].params[param_index].values.size()){
437  string str_var = namelists[namelist_index].params[param_index].values[val_ind];
438  return string_to_param<T>(str_var);
439  } else {
440  printf("\nParameter '%s' in namelist '%s' didn't have enough values!",param.c_str(),namelists[namelist_index].name.c_str());
441  exit(1);
442  }
443  }
444 };
445 
446 }
447 #endif
Definition: NamelistReader.hpp:199
void add_to_param(const string &val)
Definition: NamelistReader.hpp:341
NamelistReader(Create create)
Definition: NamelistReader.hpp:313
void load_from_string(const string &str)
Definition: NamelistReader.hpp:284
vector< NameList > namelists
Definition: NamelistReader.hpp:200
NamelistReader(const string &filename)
Definition: NamelistReader.hpp:297
T get_required(const string &param, int val_ind=0)
Definition: NamelistReader.hpp:418
void load(const string &filename)
Definition: NamelistReader.hpp:274
void add_to_namelist(const string &param, const string &val)
Definition: NamelistReader.hpp:332
T get(const string &param, const T default_val, int val_ind=0)
Definition: NamelistReader.hpp:392
void enable_modifications()
Definition: NamelistReader.hpp:319
void add_namelist(const string &namelist)
Definition: NamelistReader.hpp:323
void use_namelist(const string &namelist, Options required=Required)
Definition: NamelistReader.hpp:366
int namelist_index
Definition: NamelistReader.hpp:201
Options
Definition: NamelistReader.hpp:292
void parse_lines(T &newfile, const string &filename)
Definition: NamelistReader.hpp:206
bool modifiable
Definition: NamelistReader.hpp:203
bool use_all
Definition: NamelistReader.hpp:202
bool present(const string &param)
Definition: NamelistReader.hpp:380
bool namelist_present(const string &namelist)
Definition: NamelistReader.hpp:362
NamelistReader(const string &str_name, ReadFrom read_from)
Definition: NamelistReader.hpp:303
bool check_all_used()
Definition: NamelistReader.hpp:349
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:162
string string_to_param< string >(string &param)
Definition: NamelistReader.hpp:174
int find_case_insensitive_name_match(vector< T > &vec, const string &str)
Definition: NamelistReader.hpp:181
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:168
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
long long int string_to_param< long long int >(string &param)
Definition: NamelistReader.hpp:156
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:103
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