NOMAD Source  Version 4.0.0 Beta
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
WriteAttributeDefinitionFile.cpp
Go to the documentation of this file.
1 // TODO: Put a nice description of what this code does
2 
3 #include <algorithm> // for for_each
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <fstream>
7 #include <iostream>
8 #include <sstream>
9 #include <string>
10 #include <map>
11 
12 // Registered attribute definition names
13 const std::string attributeDefinitionNames[6] = { "displayAttributesDefinition",
14  "evalAttributesDefinition",
15  "cacheAttributesDefinition",
16  "evaluatorControlAttributesDefinition",
17  "pbAttributesDefinition",
18  "runAttributesDefinition" };
19 
20 /// \brief Registered attribute flags and default value
21 /**
22 The order of the registered attribute flags is important for attribute definition in the parameter classes.
23 Default value for the registered flag is given here.
24  */
25 const std::map<std::string, bool> attributeFlagsRegistered {
26  {"RESTART_ATTRIBUTE", false},
27  {"ALGO_COMPATIBILITY_CHECK", false},
28  {"UNIQUE_ENTRY", true} };
29 
30 /// \brief Toupper utility
31 void toUpperCase(std::string& str)
32 {
33  for_each(str.begin(), str.end(), [](char& in){ in = std::toupper(in); });
34 }
35 
36 /// \brief Exception utility
37 class Exception : public std::exception
38 {
39 
40 private:
41 
42  mutable std::string _what; ///< Error message.
43  size_t _line; ///< Line number at which the exception is thrown.
44 
45 public:
46 
47  Exception ( size_t line , const std::string & msg )
48  : _what ( msg ) ,
49  _line ( line ) {}
50 
51  /// Destructor.
52  virtual ~Exception ( void ) {}
53 
54  /// Access to the error message.
55  /**
56  \return A string with the error message.
57  */
58  const char * what ( void ) const noexcept { return _what.c_str(); }
59  size_t getLineNumber ( void ) const noexcept { return _line; }
60 };
61 
62 
63 /// \brief Utility to interpret plural words
64 void duplicateParPlurals(std::string & blockOfStrings )
65 {
66  // Pad with blanks
67  blockOfStrings.insert(0," ");
68  blockOfStrings.append(" ");
69 
70  size_t posBegin = 0;
71 
72  // Loop on ()
73  while ( true )
74  {
75  size_t posPar1 = blockOfStrings.find( "(" , posBegin );
76  if ( posPar1 != std::string::npos )
77  {
78  size_t posBlank = blockOfStrings.rfind( " " , posPar1 );
79  size_t posPar2 = blockOfStrings.find( ")" ,posBegin );
80  if ( posPar2 != std::string::npos && posBlank < posPar2 )
81  {
82  // Word to duplicate
83  std::string word = blockOfStrings.substr(posBlank+1,posPar1-posBlank-1)+" ";
84 
85  // Remove parenthesis
86  blockOfStrings.erase(posPar2,1);
87  blockOfStrings.erase(posPar1,1);
88 
89  // Insert word without parenthesis
90  blockOfStrings.insert(posBlank+1,word);
91 
92  posBegin = posBlank;
93  }
94  else
95  break;
96  }
97  else
98  break;
99 
100  }
101 }
102 
103 
104 /// \brief Utility to read a block of lines
105 std::string readBlockOfLines(std::ifstream & fin,
106  size_t & lineNumber,
107  const std::string & blockDelimiterOpen,
108  const std::string & blockDelimiterClose)
109 
110 {
111  std::string line;
112 
113  std::getline(fin, line);
114  lineNumber++;
115 
116 
117  if ( fin.fail() )
118  throw ( Exception(lineNumber,"Cannot read file") );
119 
120  // The block must be provided between delimiters
121  if (line.find( blockDelimiterOpen ) != 0)
122  {
123  std::string errMsg = " Cannot find opening delimiter ";
124  errMsg = errMsg.append(blockDelimiterOpen) ;
125  throw ( Exception(lineNumber,errMsg) );
126  }
127  std::string blockOfLines = line + " \\n ";
128 
129  // Take the content of line and put it in string
130  // with end of line
131  while ( line.empty() || line.find( blockDelimiterClose ) == std::string::npos )
132  {
133  std::getline(fin, line);
134  lineNumber++;
135 
136  if ( fin.fail() )
137  {
138  std::string errMsg = " Reached end of file without finding end delimiter ";
139  errMsg = errMsg.append(blockDelimiterClose) ;
140  throw ( Exception(lineNumber,errMsg) );
141  }
142 
143  blockOfLines += line + " \\n ";
144 
145  }
146 
147  // Remove block delimiters
148  blockOfLines.erase(0,blockDelimiterOpen.size() );
149  size_t posEnd = blockOfLines.find( blockDelimiterClose );
150  blockOfLines.erase(posEnd);
151 
152  return blockOfLines;
153 }
154 
155 
156 int main(int argc, char *argv[])
157 {
158  // Get directory where the input .txt files are.
159  std::string inputDir, outputDir;
160  if (argc > 1)
161  {
162  std::string s = argv[1];
163  // Ensure directory ends with '/'.
164  if (s[s.size()-1] != '/')
165  {
166  s += '/';
167  }
168  inputDir = s;
169  outputDir = s;
170  }
171 
172  std::ifstream fin;
173  std::ofstream fout;
174  std::string errMsg ;
175 
176  std::istringstream iss;
177  std::ostringstream oss;
178 
179  std::map<std::string,bool> attributeFlags;
180 
181  for ( auto attDefName : attributeDefinitionNames )
182  {
183  std::string attDefFile = inputDir + attDefName + ".txt";
184  std::string attDefHeader = outputDir + attDefName + ".hpp";
185 
186  // Clear input stream
187  iss.str("");
188  iss.clear();
189 
190  // Clear output stream
191  oss.str("");
192  oss.clear();
193  std::string UpperAttDefName = attDefName ;
194  for (auto & c: UpperAttDefName) c = toupper(c);
195 
196  oss << "//////////// THIS FILE MUST BE CREATED BY EXECUTING WriteAttributeDefinitionFile ////////////" << std::endl;
197  oss << "//////////// DO NOT MODIFY THIS FILE MANUALLY ///////////////////////////////////////////////" << std::endl << std::endl;
198 
199  oss << "#ifndef __NOMAD400_"<< UpperAttDefName << "__" << std::endl;
200  oss << "#define __NOMAD400_"<< UpperAttDefName << "__" << std::endl << std::endl;
201  oss << "_definition = {" ;
202 
203  bool flagInFile;
204  try
205  {
206  flagInFile=true;
207 
208  // Default error message for problem opening file
209  errMsg = " Failed to open file " + attDefFile + ".";
210 
211  size_t lineNumber=0;
212  fin.open ( attDefFile );
213 
214  if ( !fin.fail() )
215  {
216  errMsg.clear();
217  }
218  if ( !errMsg.empty() )
219  {
220  throw ( Exception( 0,errMsg ) );
221  }
222 
223  std::string line;
224  bool firstAttribute = true;
225 
226  while ( fin.good() && !fin.eof() )
227  {
228 
229  // Read attribute name
230  if ( firstAttribute )
231  {
232  getline(fin, line);
233  lineNumber++;
234  }
235 
236  // the previous getline may have reached end of file
237  if ( fin.eof() )
238  {
239  continue;
240  }
241 
242  if ( fin.fail() )
243  {
244  errMsg = " Failed to read file " + attDefFile + ".";
245  throw ( Exception(lineNumber,errMsg) );
246  }
247 
248  if ( line.size() > 0 && line.find_first_of("#")== 0 )
249  {
250  if (!firstAttribute)
251  {
252  getline(fin, line);
253  lineNumber++;
254  }
255  continue;
256  }
257 
258  // After the first attribute we need comma separation between attributes
259  if ( ! firstAttribute )
260  oss << "," << std::endl;
261  else
262  oss << std::endl;
263 
264  std::string attributeName;
265  iss.clear();
266  iss.str(line);
267  iss >> attributeName;
268 
269  if ( attributeName.size()==0)
270  {
271  errMsg = " The first word after a comment must be an attribute name. \n An empty line is not valid.";
272  throw ( Exception(lineNumber,errMsg) );
273  }
274  oss << "{ \"" << attributeName << "\", ";
275 
276  // Read attribute type
277  getline(fin, line);
278  lineNumber++;
279 
280  if ( fin.fail() || line.empty() )
281  {
282  errMsg = "Failed to read file " + attDefFile + ".";
283  throw ( Exception(lineNumber,errMsg) );
284  }
285 
286  std::string attributeType;
287  iss.clear();
288  iss.str(line);
289 
290  iss >> attributeType ;
291 
292  if ( attributeType.size()==0 )
293  {
294  errMsg = " The next word after an attribute name must be the attribute type. \n An empty line is not valid.";
295  throw ( Exception(lineNumber,errMsg) );
296  }
297  oss << " \"" << attributeType << "\", " ;
298 
299  // Read attribute default value (can be undefined)
300  getline(fin, line);
301  lineNumber++;
302 
303  if ( fin.fail() || line.empty() )
304  {
305  errMsg = " Failed to read file " + attDefFile + ".";
306  throw ( Exception(lineNumber,errMsg) );
307  }
308 
309  std::string attributeDefault;
310  iss.clear();
311  iss.str(line);
312  iss >> attributeDefault ;
313 
314  // Special case: attributeType is std::string and attributeDefault
315  // is set to a string meaning no default: set attributeDefault to empty string.
316  if ("std::string" == attributeType)
317  {
318  if ("\"\"" == attributeDefault || "-" == attributeDefault || "N/A" == attributeDefault)
319  {
320  attributeDefault.clear();
321  }
322  }
323 
324  oss << " \"" << attributeDefault << "\", ";
325 
326  // Read attribute short info
327  // The block delimiter string must be "\(" and "\)" in the text
328  // file but the string passed to the function must be preceeded
329  // by the escape symbol "\"
330  // We use raw string literals (R) to avoid escaping of any character. Anything between the delimiters becomes part of the string.
331  std::string attributeShortInfo = readBlockOfLines( fin, lineNumber ,R"f(\()f" , R"f(\))f" );
332  oss << " \"" << attributeShortInfo << "\", " ;
333 
334 
335  // Read attribute help info
336  // The block delimiter string must be "\(" and "\)" in the text
337  // file but the string passed to the function must be preceeded
338  // by the escape symbol "\"
339  // We use raw string literals (R) to avoid escaping of any character. Anything between the delimiters becomes part of the string.
340  std::string attributeHelpInfo = readBlockOfLines( fin , lineNumber , R"f(\()f", R"f(\))f");
341  oss << " \"" << attributeHelpInfo << "\", ";
342 
343  // Read keywords
344  // The block delimiter string must be "\(" and "\)" in the text
345  // file but the string passed to the function must be preceeded
346  // by the escape symbol "\"
347  // We use raw string literals (R) to avoid escaping of any character. Anything between the delimiters becomes part of the string.
348  std::string attributeKeywords = readBlockOfLines( fin , lineNumber , R"f(\()f", R"f(\))f");
349  duplicateParPlurals(attributeKeywords);
350  oss << " \"" << attributeKeywords << "\" ";
351 
352 
353  // Read optional flags for attribute
354  getline(fin, line);
355  lineNumber++;
356  std::string attributeFlagName,attributeFlagValue;
357 
358  // Set the flag value to default
359  attributeFlags = attributeFlagsRegistered ;
360 
361  while ( line.size() > 0 && line.find_first_of("#") != 0 )
362  {
363  iss.clear();
364  iss.str(line);
365  iss >> attributeFlagName >> attributeFlagValue;
366 
367  if ( attributeFlagName.size()==0 || attributeFlagValue.size()==0 )
368  {
369  errMsg = " An attribute flag name and value (bool) is expected (ex. RESTART_ATTRIBUTE yes). \n An empty line or a missing flag value (bool) is not valid.";
370  throw ( Exception(lineNumber,errMsg) );
371  }
372 
373  // Toupper the attribute flag name
374  toUpperCase( attributeFlagName );
375 
376  if ( attributeFlags.find(attributeFlagName) != attributeFlags.end() )
377  {
378  // The flag name is registered --> update the flag value
379 
380  toUpperCase( attributeFlagValue );
381  if ( attributeFlagValue.compare("YES")==0 || attributeFlagValue.compare("TRUE")==0 )
382  attributeFlags[attributeFlagName] = true;
383  else if ( attributeFlagValue.compare("NO")==0 || attributeFlagValue.compare("FALSE")==0 )
384  attributeFlags[attributeFlagName] = false;
385  else
386  {
387  errMsg = " An attribute flag name and value (bool) is expected (ex. RESTART_ATTRIBUTE yes). \n The value must be YES/TRUE or NO/FALSE.";
388  throw ( Exception(lineNumber,errMsg) );
389  }
390  }
391  else
392  {
393  errMsg = " An attribute flag name and value (bool) is expected (ex. RESTART_ATTRIBUTE yes).\n This flag name: " + attributeFlagName + " is not registered.";
394  throw ( Exception(lineNumber,errMsg) );
395  }
396 
397  getline(fin, line);
398  lineNumber++;
399  }
400 
401  // Write the flag in the registered order
402  for ( auto attFlag : attributeFlags )
403  {
404  oss << " , \"" << ((attFlag.second) ? "true":"false") << "\"";
405  }
406  oss << " }";
407 
408  getline(fin, line);
409  lineNumber++;
410 
411  firstAttribute = false;
412 
413  }
414  oss << " };";
415  oss << std::endl << std::endl << "#endif" << std::endl;
416 
417 
418  // input file is closed:
419  fin.close();
420 
421  // write header
422  // Default error message for problem opening file
423  fout.open( attDefHeader );
424 
425  if ( fout.fail() )
426  {
427  errMsg = " Failed to open the header file for writing attribute definition.";
428  throw ( Exception(0,errMsg) );
429  }
430  fout << oss.str() ;
431  fout.close();
432 
433  flagInFile = false;
434 
435  }
436  catch ( Exception & e)
437  {
438  fin.close();
439  std::cerr << "ERROR: Problem handling file for attribute definition: " << ((flagInFile) ? attDefFile:attDefHeader) << " at line " << e.getLineNumber() << ". \n" << e.what() << std::endl << std::endl;
440  return -1;
441  }
442  }
443  return 0;
444 }
445 
Exception utility.
std::string _what
Error message.
virtual ~Exception(void)
Destructor.
void toupper(std::string &s)
Put a string into upper cases.
Definition: utils.cpp:36
void duplicateParPlurals(std::string &blockOfStrings)
Utility to interpret plural words.
const char * what(void) const noexcept
Access to the error message.
const std::string attributeDefinitionNames[6]
size_t getLineNumber(void) const noexcept
std::string readBlockOfLines(std::ifstream &fin, size_t &lineNumber, const std::string &blockDelimiterOpen, const std::string &blockDelimiterClose)
Utility to read a block of lines.
int main(int argc, char *argv[])
void toUpperCase(std::string &str)
Toupper utility.
Exception(size_t line, const std::string &msg)
const std::map< std::string, bool > attributeFlagsRegistered
Registered attribute flags and default value.
size_t _line
Line number at which the exception is thrown.