μHAL (v2.6.5)
Part of the IPbus software repository
generator.cxx
Go to the documentation of this file.
1 /*
2 ---------------------------------------------------------------------------
3 
4  This file is part of uHAL.
5 
6  uHAL is a hardware access library and programming framework
7  originally developed for upgrades of the Level-1 trigger of the CMS
8  experiment at CERN.
9 
10  uHAL is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  uHAL is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with uHAL. If not, see <http://www.gnu.org/licenses/>.
22 
23 
24  Andrew Rose, Imperial College, London
25  email: awr01 <AT> imperial.ac.uk
26 
27  Marc Magrans de Abril, CERN
28  email: marc.magrans.de.abril <AT> cern.ch
29 
30 ---------------------------------------------------------------------------
31 */
32 
33 
34 #include <cctype>
35 #include <exception>
36 #include <fstream>
37 #include <iostream>
38 #include <stdint.h>
39 #include <stdlib.h>
40 #include <string>
41 #include <sstream>
42 #include <vector>
43 
44 #include <boost/algorithm/string/case_conv.hpp>
45 
46 
47 static const std::string gLogLevelsChar[] = { "Fatal" , "Error" , "Warning" , "Notice" , "Info" , "Debug" };
48 static const uint32_t gNumberEntries ( 6 );
49 
50 static const std::string gDefaultLevel ( "Info" );
51 
52 static const std::vector< std::string > gLogLevels ( gLogLevelsChar , gLogLevelsChar+gNumberEntries );
53 
54 
55 
56 std::string gDivider ( "// " + std::string ( 150,'=' ) + "\n" +
57  "// WARNING! This file is automatically generated! Do not modify it! Any changes will be overwritten!\n" +
58  "// " + std::string ( 150,'=' ) + "\n" );
59 
60 
61 
62 void fileHeaders ( std::ofstream& aHppFile , std::ofstream& aHxxFile , std::ofstream& aCppFile )
63 {
64  aHppFile << "\n"
65  << "#ifndef _uhal_log_log_hpp_\n"
66  << "#define _uhal_log_log_hpp_\n"
67  << "\n"
68  << "#include <iosfwd> // for ostream\n"
69  << "#include <boost/thread/mutex.hpp>\n"
70  << "#include <boost/thread/lock_guard.hpp>\n"
71  << "#include <uhal/log/log_inserters.hpp>\n"
72  << "#include <uhal/log/LogLevels.hpp>\n"
73  << "#include <uhal/log/exception.hpp>\n"
74  << "\n"
75  // << "#define logging() logger log( ThisLocation() );\n"
76  << "#define logging()\n"
77  << "\n"
78  << "namespace boost { class mutex; }\n"
79  << "\n"
80  << "namespace uhal{\n"
81  << "\n"
82  << "class DebugLevel;\n"
83  << "class InfoLevel;\n"
84  << "class NoticeLevel;\n"
85  << "class WarningLevel;\n"
86  << "class ErrorLevel;\n"
87  << "class FatalLevel;\n"
88  << "\n"
89  << gDivider
90  << "\n";
91  aHxxFile << "\n"
92  << "#include <sstream> // for ostream, stringstream, endl\n"
93  << "#include <string> // for operator+, basic_string\n"
94  << "\n"
95  << "#include <boost/thread/lock_guard.hpp> // for lock_guard\n"
96  << "#include <boost/thread/mutex.hpp> // for mutex\n"
97  << "\n"
98  << "#include \"uhal/log/exception.hpp\" // for exception\n"
99  << "#include \"uhal/log/LogLevels.hpp\" // for insert, ErrorLevel, DebugL...\n"
100  << "#include \"uhal/log/log_inserters.quote.hpp\" // for operator<<\n"
101  << "\n"
102  << "namespace uhal{\n"
103  << "\n"
104  << gDivider
105  << "\n";
106  aCppFile << "\n"
107  << "#include <stdlib.h> // for getenv\n"
108  << "#include <boost/thread/mutex.hpp> // for mutex\n"
109  << "#include \"uhal/log/LogLevels.hpp\" // for BaseLogLevel, Info, Info...\n"
110  << "#include \"uhal/log/log.hpp\" // for log\n"
111  << "#include \"uhal/log/log_inserters.quote.hpp\" // for operator<<, Quote\n"
112  << "\n"
113  << "namespace uhal{\n"
114  << "\n"
115  << gDivider
116  << "\n";
117 }
118 
119 
120 void log_configuration_functions ( std::ofstream& aHppFile , std::ofstream& aHxxFile , std::ofstream& aCppFile )
121 {
122  aHppFile << "/**\n"
123  << "\tFunction to specify that the logging level should be retrieved from an environment variable\n"
124  << "\t@param aEnvVar the name of the environment variable which is used to specify the logging level\n"
125  << "*/\n"
126  << "void setLogLevelFromEnvironment ( const char* aEnvVar );\n";
127  aCppFile << "void setLogLevelFromEnvironment ( const char* aEnvVar )\n"
128  << "{\n"
129  << "\tchar * lEnvVar = getenv ( aEnvVar );\n"
130  << "\tif( !lEnvVar )\n"
131  << "\t{\n"
132  // << "\t\t\n"
133  << "\t\tlog( Warning() , \"No environment variable \" , Quote( aEnvVar ) , \" set. Using level \" , Quote( \"Info\" ) , \" instead.\" );\n"
134  << "\t\tsetLogLevelTo ( " << gDefaultLevel << "() );\n"
135  << "\t\treturn;\n"
136  << "\t}\n"
137  << "\n"
138  << "\t//Just comparing the first letter of the environment variable for speed!!!\n"
139  << "\tswitch ( lEnvVar[0] )\n"
140  << "\t{\n";
141 
142  for ( std::vector< std::string >::const_iterator lIt = gLogLevels.begin() ; lIt != gLogLevels.end() ; ++lIt )
143  {
144  aCppFile << "\t\tcase '" << char ( std::tolower ( lIt->at ( 0 ) ) ) << "' :\n"
145  << "\t\tcase '" << char ( std::toupper ( lIt->at ( 0 ) ) ) << "' :\n"
146  << "\t\t\tsetLogLevelTo ( " << *lIt << "() );\n"
147  << "\t\t\tbreak;\n";
148  }
149 
150  aCppFile << "\t\tdefault:\n"
151  << "\t\t\t\n"
152  << "\t\t\tlog ( Warning() , \"Environment varible has invalid value \" , Quote( lEnvVar ) , \". Using level \" , Quote ( \"Info\" ) , \" instead.\" );\n"
153  << "\t\t\tsetLogLevelTo ( Info() );\n"
154  << "\t}\n"
155  << "}\n"
156  << "\n";
157  aCppFile << gDivider
158  << "\n";
159  // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
160  aHppFile << "/**\n"
161  << "\tFunction to disable all logging levels\n"
162  << "*/\n"
163  << "void disableLogging();\n";
164  aCppFile << "void disableLogging()\n"
165  << "{\n";
166 
167  for ( std::vector< std::string >::const_iterator lIt = gLogLevels.begin() ; lIt != gLogLevels.end() ; ++lIt )
168  {
169  aCppFile << "\tlog_configuration::mLoggingIncludes" << *lIt << " = false;\n";
170  }
171 
172  aCppFile << "}\n"
173  << "\n";
174  aCppFile << gDivider
175  << "\n";
176  // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
177  aHppFile << "/**\n"
178  << "\tFunction to retrieve the mutex lock used by the logger\n"
179  << "*/\n"
180  << "boost::mutex& GetLoggingMutex();\n";
181  aCppFile << "boost::mutex& GetLoggingMutex()\n"
182  << "{\n"
183  << "\treturn log_configuration::mMutex;\n"
184  << "}\n"
185  << "\n"
186  << gDivider
187  << "\n";
188  // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
189  std::stringstream lIfDefs, lIfDefs2, lEndIfs;
190 
191  for ( std::vector< std::string >::const_iterator lIt = gLogLevels.begin() ; lIt != gLogLevels.end() ; ++lIt )
192  {
193  lIfDefs << "\t#ifndef LOGGING_EXCLUDE_" << boost::to_upper_copy ( *lIt ) << "\n";
194  lIfDefs2 << "\t#ifndef LOGGING_EXCLUDE_" << boost::to_upper_copy ( *lIt ) << " // A waste of time to change any level below this if it is going to disabled by compile-time checking anyway... \n"
195  << "\t\tlog_configuration::mLoggingIncludes" << *lIt << " = true;\n";
196  lEndIfs << "\t#endif\n";
197  // aHppFile << "//! Helper struct representing the " << *lIt << " log level to allow us to specialize functions according to their log level\n"
198  // << "class " << *lIt << "Level : public BaseLogLevel\n"
199  // << "\t{\n"
200  // << "\t\tpublic:\n"
201  // << "\t\t\t"<< *lIt << "Level( std::ostream& aStr ) : BaseLogLevel( aStr ){}\n"
202  // << "\t\t\t"<< *lIt << "Level& operator() (){ return *this; }\n"
203  // << "\t};\n"
204  // << "\n"
205  // << *lIt << "Level " << *lIt << "( std::cout );\n";
206  aHppFile << "/**\n"
207  << "\tFunction to specify, at runtime, that only messages with a severity level above " << *lIt << " should be logged\n"
208  << "*/\n"
209  << "void setLogLevelTo ( const " << *lIt << "Level& /**< a dummy parameter to choose the specialization of the function for the " << *lIt << " level */ );\n";
210  aCppFile << "void setLogLevelTo ( const " << *lIt << "Level& )\n"
211  << "{\n"
212  << lIfDefs2.str();
213 
214  for ( std::vector< std::string >::const_iterator lIt2 = lIt+1 ; lIt2 != gLogLevels.end() ; ++lIt2 )
215  {
216  aCppFile << "\t\tlog_configuration::mLoggingIncludes" << *lIt2 << " = false;\n";
217  }
218 
219  aCppFile << lEndIfs.str()
220  << "}\n"
221  << "\n";
222  aHppFile << "/**\n"
223  << "\tFunction to check at runtime whether the level " << *lIt << " is to be included in the log output\n"
224  << "\t@return whether the level " << *lIt << " is to be included in the log output\n"
225  << "*/\n"
226  << "const bool& LoggingIncludes ( const " << *lIt << "Level& /**< a dummy parameter to choose the specialization of the function for the " << *lIt << " level */ );\n"
227  << "\n";
228  aCppFile << "const bool& LoggingIncludes ( const " << *lIt << "Level& )\n"
229  << "{\n"
230  << lIfDefs.str()
231  << "\t\treturn log_configuration::mLoggingIncludes" << *lIt << ";\n"
232  << lEndIfs.str()
233  << "\treturn log_configuration::mFalse;\n"
234  << "}\n"
235  << "\n";
236  }
237 
238  aHppFile << "//! Class to restrict access to the log configuration parameters\n"
239  << "class log_configuration\n"
240  << "{\n"
241  << "\t//! Constructor\n"
242  << "\tlog_configuration();\n"
243  << "\t//! Destructor\n"
244  << "\tvirtual ~log_configuration();\n"
245  << "\n"
246  << "\tfriend void disableLogging();\n"
247  << "\n";
248  bool lIncludeLevelByDefault ( true );
249 
250  for ( std::vector< std::string >::const_iterator lIt = gLogLevels.begin() ; lIt != gLogLevels.end() ; ++lIt )
251  {
252  aHppFile << "\t//! static bool storing whether the " << *lIt << " level is to be included in the log output\n"
253  << "\tstatic bool mLoggingIncludes" << *lIt << ";\n";
254 
255  if ( lIncludeLevelByDefault )
256  {
257  aCppFile << "bool log_configuration::mLoggingIncludes" << *lIt << " = true; // No #ifdefs required here since they are implemented in all the access functions.\n";
258  }
259  else
260  {
261  aCppFile << "bool log_configuration::mLoggingIncludes" << *lIt << " = false; // No #ifdefs required here since they are implemented in all the access functions.\n";
262  }
263 
264  if ( *lIt == gDefaultLevel )
265  {
266  lIncludeLevelByDefault = false;
267  }
268 
269  aHppFile << "\t//!Make setLogLevelTo function a friend so it can access our private members\n"
270  << "\tfriend void setLogLevelTo ( const " << *lIt << "Level& );\n"
271  << "\t//!Make LoggingIncludes function a friend so it can access our private members\n"
272  << "\tfriend const bool& LoggingIncludes ( const " << *lIt << "Level& );\n"
273  << "\n";
274  }
275 
276  aHppFile << "\t//!Define a static const member variable to have a value of true so that we can safely return a const reference to true\n"
277  << "\tstatic const bool mTrue;\n"
278  << "\t//!Define a static const member variable to have a value of false so that we can safely return a const reference to false\n"
279  << "\tstatic const bool mFalse;\n"
280  << "\n"
281  << "\t//!Make GetLoggingMutex function a friend so it can access our private members\n"
282  << "\tfriend boost::mutex& GetLoggingMutex();\n"
283  << "\t//!Define a static Mutex lock for thread safe logging\n"
284  << "\tstatic boost::mutex mMutex;\n"
285  << "};\n"
286  << "\n";
287  aCppFile << "\n"
288  << "const bool log_configuration::mTrue = true;\n"
289  << "const bool log_configuration::mFalse = false;\n"
290  << "\n"
291  << "boost::mutex log_configuration::mMutex;\n"
292  << "\n";
293  aHppFile << gDivider
294  << "\n";
295  aCppFile << gDivider
296  << "\n";
297 }
298 
299 
300 std::string suffix ( uint32_t i )
301 {
302  i = i % 100;
303 
304  if ( i > 10 && i < 20 )
305  {
306  return "th";
307  }
308 
309  std::string lIndices[] = { "th" , "st" , "nd" , "rd" , "th" , "th" , "th" , "th" , "th" , "th" };
310  return lIndices[ i%10 ];
311 }
312 
313 
314 void log_functions ( std::ofstream& aHppFile , std::ofstream& aHxxFile , std::ofstream& aCppFile )
315 {
316  std::stringstream lIfDefs , lEndIfs;
317 
318  for ( std::vector< std::string >::const_iterator lIt = gLogLevels.begin() ; lIt != gLogLevels.end() ; ++lIt )
319  {
320  lIfDefs << "\t#ifndef LOGGING_EXCLUDE_" << boost::to_upper_copy ( *lIt ) << "\n";
321  lEndIfs << "\t#endif\n";
322  std::stringstream lTemplates;
323  std::stringstream lArgs;
324  std::stringstream lInstructions;
325  std::stringstream lDoxygen;
326  lDoxygen << "\t\tFunction to add a log entry at " << *lIt << " level\n"
327  << "\t\t@param a" << *lIt << " a dummy parameter to choose the specialization of the function for the " << *lIt << " level\n";
328 
329  for ( uint32_t i = 0 ; i!=MAX_NUM_ARGS ; ++i )
330  {
331  lTemplates << " typename T" << i << " ,";
332  std::string lTemplatesStr ( lTemplates.str() );
333  lTemplatesStr.resize ( lTemplatesStr.size()-1 );
334  lArgs << " const T" << i << "& aArg" << i << " ,";
335  std::string lArgsStr ( lArgs.str() );
336  lArgsStr.resize ( lArgsStr.size()-1 );
337  lInstructions << "\t\t\tinsert( lStr , aArg" << i << " );\n";
338  lDoxygen << "\t\t@param aArg" << i << " a templated argument to be added to the log " << ( i+1 ) << suffix ( i+1 ) <<"\n";
339  aHppFile << "\t/**\n"
340  << lDoxygen.str()
341  << "\t*/\n"
342  << "\ttemplate<" << lTemplatesStr << ">\n"
343  // << "\tvoid operator() ( const " <<*lIt << "& a" << *lIt << " ," << lArgsStr << ");\n"
344  << "\tvoid log ( " <<*lIt << "Level& a" << *lIt << " ," << lArgsStr << ");\n"
345  << "\n";
346  aHxxFile << "template<" << lTemplatesStr << ">\n"
347  // << "void logger::operator() ( const " <<*lIt << "& a" << *lIt << " ," << lArgsStr << " )\n"
348  << "void log ( " <<*lIt << "Level& a" << *lIt << " ," << lArgsStr << " )\n"
349  << "{\n"
350  << lIfDefs.str()
351  << "\t\tif( LoggingIncludes( a" << *lIt << " ) ){\n"
352  << "\t\t\tboost::lock_guard<boost::mutex> lLock ( GetLoggingMutex() );\n"
353  << "\t\t\tstd::ostream& lStr( a" << *lIt << ".stream() );\n"
354  << "\t\t\ta" << *lIt << ".head();\n"
355  << lInstructions.str()
356  << "\t\t\ta" << *lIt << ".tail();\n"
357  << "\t\t}\n"
358  << lEndIfs.str()
359  << "}\n"
360  << "\n";
361  }
362 
363  aHppFile << gDivider
364  << "\n";
365  aHxxFile << gDivider
366  << "\n";
367  }
368 
369  {
370  std::stringstream lTemplates;
371  std::stringstream lArgs;
372  std::stringstream lInstructions;
373  std::stringstream lDoxygen;
374 
375  for ( uint32_t i = 0 ; i!=MAX_NUM_ARGS ; ++i )
376  {
377  lTemplates << " typename T" << i << " ,";
378  std::string lTemplatesStr ( lTemplates.str() );
379  lTemplatesStr.resize ( lTemplatesStr.size()-1 );
380  lArgs << " const T" << i << "& aArg" << i << " ,";
381  std::string lArgsStr ( lArgs.str() );
382  lArgsStr.resize ( lArgsStr.size()-1 );
383  lInstructions << "\t\t\tinsert( lStr , aArg" << i << " );\n";
384  lDoxygen << "\t\t@param aArg" << i << " a templated argument to be added to the log " << ( i+1 ) << suffix ( i+1 ) <<"\n";
385  aHppFile << "\t/**\n"
386  << lDoxygen.str()
387  << "\t*/\n"
388  << "\ttemplate<" << lTemplatesStr << ">\n"
389  // << "\tvoid operator() ( const " <<*lIt << "& a" << *lIt << " ," << lArgsStr << ");\n"
390  << "\tvoid log ( exception::exception& aExc ," << lArgsStr << ");\n"
391  << "\n";
392  aHxxFile << "template<" << lTemplatesStr << ">\n"
393  // << "void logger::operator() ( const " <<*lIt << "& a" << *lIt << " ," << lArgsStr << " )\n"
394  << "void log ( exception::exception& aExc ," << lArgsStr << " )\n"
395  << "{\n"
396  << "\t\t\tstd::stringstream lStr;\n"
397  << "\t\t\t{\n"
398  << "\t\t\tboost::lock_guard<boost::mutex> lLock ( GetLoggingMutex() );\n"
399  << lInstructions.str()
400  << "\t\t\taExc.append( ( lStr.str() + \"\\n\" ).c_str() );\n"
401  << "\t\t\t}\n"
402  << "\t\t\tlog ( Error() , lStr.str() );\n"
403  << "}\n"
404  << "\n";
405  }
406 
407  aHppFile << gDivider
408  << "\n";
409  aHxxFile << gDivider
410  << "\n";
411  }
412 
413  {
414  std::stringstream lTemplates;
415  std::stringstream lArgs;
416  std::stringstream lInstructions;
417  std::stringstream lDoxygen;
418 
419  for ( uint32_t i = 0 ; i!=MAX_NUM_ARGS ; ++i )
420  {
421  lTemplates << " typename T" << i << " ,";
422  std::string lTemplatesStr ( lTemplates.str() );
423  lTemplatesStr.resize ( lTemplatesStr.size()-1 );
424  lArgs << " const T" << i << "& aArg" << i << " ,";
425  std::string lArgsStr ( lArgs.str() );
426  lArgsStr.resize ( lArgsStr.size()-1 );
427  lInstructions << "\t\t\tinsert( aStr , aArg" << i << " );\n";
428  lDoxygen << "\t\t@param aArg" << i << " a templated argument to be added to the log " << ( i+1 ) << suffix ( i+1 ) <<"\n";
429  aHppFile << "\t/**\n"
430  << lDoxygen.str()
431  << "\t*/\n"
432  << "\ttemplate<" << lTemplatesStr << ">\n"
433  // << "\tvoid operator() ( const " <<*lIt << "& a" << *lIt << " ," << lArgsStr << ");\n"
434  << "\tvoid log ( std::ostream& aStr ," << lArgsStr << ");\n"
435  << "\n";
436  aHxxFile << "template<" << lTemplatesStr << ">\n"
437  // << "void logger::operator() ( const " <<*lIt << "& a" << *lIt << " ," << lArgsStr << " )\n"
438  << "void log ( std::ostream& aStr ," << lArgsStr << " )\n"
439  << "{\n"
440  << "\t\t\tboost::lock_guard<boost::mutex> lLock ( GetLoggingMutex() );\n"
441  << lInstructions.str()
442  << "\t\t\taStr << std::endl;\n"
443  << "}\n"
444  << "\n";
445  }
446 
447  aHppFile << gDivider
448  << "\n";
449  aHxxFile << gDivider
450  << "\n";
451  }
452 
453  //aHppFile << "};\n"
454  // << "\n";
455 }
456 
457 
458 void fileFooters ( std::ofstream& aHppFile , std::ofstream& aHxxFile , std::ofstream& aCppFile )
459 {
460  aHppFile << "}\n\n"
461  << "#include \"uhal/log/log.hxx\"\n"
462  << "#endif\n\n";
463  aHxxFile << "}\n"
464  << "\n";
465  aCppFile << "}\n"
466  << "\n";
467 }
468 
469 
470 
471 int main ( int argc , char* argv[] )
472 {
473  try
474  {
475  std::ofstream lHppFile ( "include/uhal/log/log.hpp" );
476 
477  if ( !lHppFile.is_open() )
478  {
479  std::cout << "Unable to open HPP file" << std::endl;
480  return 1;
481  }
482 
483  std::ofstream lHxxFile ( "include/uhal/log/log.hxx" );
484 
485  if ( !lHxxFile.is_open() )
486  {
487  std::cout << "Unable to open HXX file" << std::endl;
488  return 1;
489  }
490 
491  std::ofstream lCppFile ( "src/common/log.cpp" );
492 
493  if ( !lCppFile.is_open() )
494  {
495  std::cout << "Unable to open CPP file" << std::endl;
496  return 1;
497  }
498 
499  fileHeaders ( lHppFile , lHxxFile , lCppFile );
500  log_configuration_functions ( lHppFile , lHxxFile , lCppFile );
501  log_functions ( lHppFile , lHxxFile , lCppFile );
502  fileFooters ( lHppFile , lHxxFile , lCppFile );
503  lHppFile.close();
504  lHxxFile.close();
505  lCppFile.close();
506  }
507  catch ( const std::exception& aExc )
508  {
509  std::cerr << "ERROR: Caught exception : " << aExc.what() << std::endl;
510  exit ( 1 );
511  }
512 }
513 
514 
std::string gDivider("// "+std::string(150,'=')+"\+"//WARNING! This file is automatically generated! Do not modify it! Any changes will be overwritten!\"+"//"+std::string(150,'=')+"\")
void log_configuration_functions(std::ofstream &aHppFile, std::ofstream &aHxxFile, std::ofstream &aCppFile)
Definition: generator.cxx:120
std::string suffix(uint32_t i)
Definition: generator.cxx:300
static const std::string gLogLevelsChar[]
Definition: generator.cxx:47
void fileFooters(std::ofstream &aHppFile, std::ofstream &aHxxFile, std::ofstream &aCppFile)
Definition: generator.cxx:458
static const uint32_t gNumberEntries(6)
int main(int argc, char *argv[])
Definition: generator.cxx:471
static const std::string gDefaultLevel("Info")
void fileHeaders(std::ofstream &aHppFile, std::ofstream &aHxxFile, std::ofstream &aCppFile)
Definition: generator.cxx:62
void log_functions(std::ofstream &aHppFile, std::ofstream &aHxxFile, std::ofstream &aCppFile)
Definition: generator.cxx:314
static const std::vector< std::string > gLogLevels(gLogLevelsChar, gLogLevelsChar+gNumberEntries)