μHAL (v2.7.9)
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 <sstream>
41 #include <string>
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\n"
68  << "#include <iosfwd> // for ostream\n"
69  << "\n"
70  << "#include <uhal/log/log_inserters.hpp>\n"
71  << "#include <uhal/log/LogLevels.hpp>\n"
72  << "#include <uhal/log/exception.hpp>\n"
73  << "\n"
74  << "\n"
75  << "namespace boost { class mutex; }\n"
76  << "\n"
77  << "namespace uhal{\n"
78  << "\n"
79  << "class DebugLevel;\n"
80  << "class InfoLevel;\n"
81  << "class NoticeLevel;\n"
82  << "class WarningLevel;\n"
83  << "class ErrorLevel;\n"
84  << "class FatalLevel;\n"
85  << "\n"
86  << gDivider
87  << "\n";
88  aHxxFile << "\n"
89  << "#include <sstream> // for ostream, stringstream, endl\n"
90  << "#include <string> // for operator+, basic_string\n"
91  << "\n"
92  << "#include <boost/thread/lock_guard.hpp> // for lock_guard\n"
93  << "#include <boost/thread/mutex.hpp> // for mutex\n"
94  << "\n"
95  << "#include \"uhal/log/exception.hpp\" // for exception\n"
96  << "#include \"uhal/log/LogLevels.hpp\" // for insert, ErrorLevel, DebugL...\n"
97  << "#include \"uhal/log/log_inserters.quote.hpp\" // for operator<<\n"
98  << "\n\n"
99  << "namespace uhal{\n"
100  << "\n"
101  << gDivider
102  << "\n";
103  aCppFile << "\n"
104  << "#include <stdlib.h> // for getenv\n"
105  << "\n"
106  << "#include <boost/thread/mutex.hpp> // for mutex\n"
107  << "\n"
108  << "#include \"uhal/log/LogLevels.hpp\" // for BaseLogLevel, Info, Info...\n"
109  << "#include \"uhal/log/log.hpp\" // for log\n"
110  << "#include \"uhal/log/log_inserters.quote.hpp\" // for operator<<, Quote\n"
111  << "\n\n"
112  << "namespace uhal{\n"
113  << "\n"
114  << gDivider
115  << "\n";
116 }
117 
118 
119 void log_configuration_functions ( std::ofstream& aHppFile , std::ofstream& aHxxFile , std::ofstream& aCppFile )
120 {
121  aHppFile << "/**\n"
122  << "\tFunction to specify that the logging level should be retrieved from an environment variable\n"
123  << "\t@param aEnvVar the name of the environment variable which is used to specify the logging level\n"
124  << "*/\n"
125  << "void setLogLevelFromEnvironment ( const char* aEnvVar );\n";
126  aCppFile << "void setLogLevelFromEnvironment ( const char* aEnvVar )\n"
127  << "{\n"
128  << "\tchar * lEnvVar = getenv ( aEnvVar );\n"
129  << "\tif( !lEnvVar )\n"
130  << "\t{\n"
131  // << "\t\t\n"
132  << "\t\tlog( Warning() , \"No environment variable \" , Quote( aEnvVar ) , \" set. Using level \" , Quote( \"Info\" ) , \" instead.\" );\n"
133  << "\t\tsetLogLevelTo ( " << gDefaultLevel << "() );\n"
134  << "\t\treturn;\n"
135  << "\t}\n"
136  << "\n"
137  << "\t//Just comparing the first letter of the environment variable for speed!!!\n"
138  << "\tswitch ( lEnvVar[0] )\n"
139  << "\t{\n";
140 
141  for ( std::vector< std::string >::const_iterator lIt = gLogLevels.begin() ; lIt != gLogLevels.end() ; ++lIt )
142  {
143  aCppFile << "\t\tcase '" << char ( std::tolower ( lIt->at ( 0 ) ) ) << "' :\n"
144  << "\t\tcase '" << char ( std::toupper ( lIt->at ( 0 ) ) ) << "' :\n"
145  << "\t\t\tsetLogLevelTo ( " << *lIt << "() );\n"
146  << "\t\t\tbreak;\n";
147  }
148 
149  aCppFile << "\t\tdefault:\n"
150  << "\t\t\t\n"
151  << "\t\t\tlog ( Warning() , \"Environment varible has invalid value \" , Quote( lEnvVar ) , \". Using level \" , Quote ( \"Info\" ) , \" instead.\" );\n"
152  << "\t\t\tsetLogLevelTo ( Info() );\n"
153  << "\t}\n"
154  << "}\n"
155  << "\n";
156  aCppFile << gDivider
157  << "\n";
158  // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
159  aHppFile << "/**\n"
160  << "\tFunction to disable all logging levels\n"
161  << "*/\n"
162  << "void disableLogging();\n";
163  aCppFile << "void disableLogging()\n"
164  << "{\n";
165 
166  for ( std::vector< std::string >::const_iterator lIt = gLogLevels.begin() ; lIt != gLogLevels.end() ; ++lIt )
167  {
168  aCppFile << "\tlog_configuration::mLoggingIncludes" << *lIt << " = false;\n";
169  }
170 
171  aCppFile << "}\n"
172  << "\n";
173  aCppFile << gDivider
174  << "\n";
175  // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
176  aHppFile << "/**\n"
177  << "\tFunction to retrieve the mutex lock used by the logger\n"
178  << "*/\n"
179  << "boost::mutex& GetLoggingMutex();\n";
180  aCppFile << "boost::mutex& GetLoggingMutex()\n"
181  << "{\n"
182  << "\treturn log_configuration::mMutex;\n"
183  << "}\n"
184  << "\n"
185  << gDivider
186  << "\n";
187  // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
188  std::stringstream lIfDefs, lIfDefs2, lEndIfs;
189 
190  for ( std::vector< std::string >::const_iterator lIt = gLogLevels.begin() ; lIt != gLogLevels.end() ; ++lIt )
191  {
192  lIfDefs << "\t#ifndef LOGGING_EXCLUDE_" << boost::to_upper_copy ( *lIt ) << "\n";
193  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"
194  << "\t\tlog_configuration::mLoggingIncludes" << *lIt << " = true;\n";
195  lEndIfs << "\t#endif\n";
196  // aHppFile << "//! Helper struct representing the " << *lIt << " log level to allow us to specialize functions according to their log level\n"
197  // << "class " << *lIt << "Level : public BaseLogLevel\n"
198  // << "\t{\n"
199  // << "\t\tpublic:\n"
200  // << "\t\t\t"<< *lIt << "Level( std::ostream& aStr ) : BaseLogLevel( aStr ){}\n"
201  // << "\t\t\t"<< *lIt << "Level& operator() (){ return *this; }\n"
202  // << "\t};\n"
203  // << "\n"
204  // << *lIt << "Level " << *lIt << "( std::cout );\n";
205  aHppFile << "/**\n"
206  << "\tFunction to specify, at runtime, that only messages with a severity level above " << *lIt << " should be logged\n"
207  << "*/\n"
208  << "void setLogLevelTo ( const " << *lIt << "Level& /**< a dummy parameter to choose the specialization of the function for the " << *lIt << " level */ );\n";
209  aCppFile << "void setLogLevelTo ( const " << *lIt << "Level& )\n"
210  << "{\n"
211  << lIfDefs2.str();
212 
213  for ( std::vector< std::string >::const_iterator lIt2 = lIt+1 ; lIt2 != gLogLevels.end() ; ++lIt2 )
214  {
215  aCppFile << "\t\tlog_configuration::mLoggingIncludes" << *lIt2 << " = false;\n";
216  }
217 
218  aCppFile << lEndIfs.str()
219  << "}\n"
220  << "\n";
221  aHppFile << "/**\n"
222  << "\tFunction to check at runtime whether the level " << *lIt << " is to be included in the log output\n"
223  << "\t@return whether the level " << *lIt << " is to be included in the log output\n"
224  << "*/\n"
225  << "const bool& LoggingIncludes ( const " << *lIt << "Level& /**< a dummy parameter to choose the specialization of the function for the " << *lIt << " level */ );\n"
226  << "\n";
227  aCppFile << "const bool& LoggingIncludes ( const " << *lIt << "Level& )\n"
228  << "{\n"
229  << lIfDefs.str()
230  << "\t\treturn log_configuration::mLoggingIncludes" << *lIt << ";\n"
231  << lEndIfs.str()
232  << "\treturn log_configuration::mFalse;\n"
233  << "}\n"
234  << "\n";
235  }
236 
237  aHppFile << "//! Class to restrict access to the log configuration parameters\n"
238  << "class log_configuration\n"
239  << "{\n"
240  << "\t//! Constructor\n"
241  << "\tlog_configuration();\n"
242  << "\t//! Destructor\n"
243  << "\tvirtual ~log_configuration();\n"
244  << "\n"
245  << "\tfriend void disableLogging();\n"
246  << "\n";
247  bool lIncludeLevelByDefault ( true );
248 
249  for ( std::vector< std::string >::const_iterator lIt = gLogLevels.begin() ; lIt != gLogLevels.end() ; ++lIt )
250  {
251  aHppFile << "\t//! static bool storing whether the " << *lIt << " level is to be included in the log output\n"
252  << "\tstatic bool mLoggingIncludes" << *lIt << ";\n";
253 
254  if ( lIncludeLevelByDefault )
255  {
256  aCppFile << "bool log_configuration::mLoggingIncludes" << *lIt << " = true; // No #ifdefs required here since they are implemented in all the access functions.\n";
257  }
258  else
259  {
260  aCppFile << "bool log_configuration::mLoggingIncludes" << *lIt << " = false; // No #ifdefs required here since they are implemented in all the access functions.\n";
261  }
262 
263  if ( *lIt == gDefaultLevel )
264  {
265  lIncludeLevelByDefault = false;
266  }
267 
268  aHppFile << "\t//!Make setLogLevelTo function a friend so it can access our private members\n"
269  << "\tfriend void setLogLevelTo ( const " << *lIt << "Level& );\n"
270  << "\t//!Make LoggingIncludes function a friend so it can access our private members\n"
271  << "\tfriend const bool& LoggingIncludes ( const " << *lIt << "Level& );\n"
272  << "\n";
273  }
274 
275  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"
276  << "\tstatic const bool mTrue;\n"
277  << "\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"
278  << "\tstatic const bool mFalse;\n"
279  << "\n"
280  << "\t//!Make GetLoggingMutex function a friend so it can access our private members\n"
281  << "\tfriend boost::mutex& GetLoggingMutex();\n"
282  << "\t//!Define a static Mutex lock for thread safe logging\n"
283  << "\tstatic boost::mutex mMutex;\n"
284  << "};\n"
285  << "\n";
286  aCppFile << "\n"
287  << "const bool log_configuration::mTrue = true;\n"
288  << "const bool log_configuration::mFalse = false;\n"
289  << "\n"
290  << "boost::mutex log_configuration::mMutex;\n"
291  << "\n";
292  aHppFile << gDivider
293  << "\n";
294  aCppFile << gDivider
295  << "\n";
296 }
297 
298 
299 std::string suffix ( uint32_t i )
300 {
301  i = i % 100;
302 
303  if ( i > 10 && i < 20 )
304  {
305  return "th";
306  }
307 
308  std::string lIndices[] = { "th" , "st" , "nd" , "rd" , "th" , "th" , "th" , "th" , "th" , "th" };
309  return lIndices[ i%10 ];
310 }
311 
312 
313 void log_functions ( std::ofstream& aHppFile , std::ofstream& aHxxFile , std::ofstream& aCppFile )
314 {
315  std::stringstream lIfDefs , lEndIfs;
316 
317  for ( std::vector< std::string >::const_iterator lIt = gLogLevels.begin() ; lIt != gLogLevels.end() ; ++lIt )
318  {
319  lIfDefs << "\t#ifndef LOGGING_EXCLUDE_" << boost::to_upper_copy ( *lIt ) << "\n";
320  lEndIfs << "\t#endif\n";
321  std::stringstream lTemplates;
322  std::stringstream lArgs;
323  std::stringstream lInstructions;
324  std::stringstream lDoxygen;
325  lDoxygen << "\t\tFunction to add a log entry at " << *lIt << " level\n"
326  << "\t\t@param a" << *lIt << " a dummy parameter to choose the specialization of the function for the " << *lIt << " level\n";
327 
328  for ( uint32_t i = 0 ; i!=MAX_NUM_ARGS ; ++i )
329  {
330  lTemplates << " typename T" << i << " ,";
331  std::string lTemplatesStr ( lTemplates.str() );
332  lTemplatesStr.resize ( lTemplatesStr.size()-1 );
333  lArgs << " const T" << i << "& aArg" << i << " ,";
334  std::string lArgsStr ( lArgs.str() );
335  lArgsStr.resize ( lArgsStr.size()-1 );
336  lInstructions << "\t\t\tinsert( lStr , aArg" << i << " );\n";
337  lDoxygen << "\t\t@param aArg" << i << " a templated argument to be added to the log " << ( i+1 ) << suffix ( i+1 ) <<"\n";
338  aHppFile << "\t/**\n"
339  << lDoxygen.str()
340  << "\t*/\n"
341  << "\ttemplate<" << lTemplatesStr << ">\n"
342  // << "\tvoid operator() ( const " <<*lIt << "& a" << *lIt << " ," << lArgsStr << ");\n"
343  << "\tvoid log ( " <<*lIt << "Level& a" << *lIt << " ," << lArgsStr << ");\n"
344  << "\n";
345  aHxxFile << "template<" << lTemplatesStr << ">\n"
346  // << "void logger::operator() ( const " <<*lIt << "& a" << *lIt << " ," << lArgsStr << " )\n"
347  << "void log ( " <<*lIt << "Level& a" << *lIt << " ," << lArgsStr << " )\n"
348  << "{\n"
349  << lIfDefs.str()
350  << "\t\tif( LoggingIncludes( a" << *lIt << " ) ){\n"
351  << "\t\t\tboost::lock_guard<boost::mutex> lLock ( GetLoggingMutex() );\n"
352  << "\t\t\tstd::ostream& lStr( a" << *lIt << ".stream() );\n"
353  << "\t\t\ta" << *lIt << ".head();\n"
354  << lInstructions.str()
355  << "\t\t\ta" << *lIt << ".tail();\n"
356  << "\t\t}\n"
357  << lEndIfs.str()
358  << "}\n"
359  << "\n";
360  }
361 
362  aHppFile << gDivider
363  << "\n";
364  aHxxFile << gDivider
365  << "\n";
366  }
367 
368  {
369  std::stringstream lTemplates;
370  std::stringstream lArgs;
371  std::stringstream lInstructions;
372  std::stringstream lDoxygen;
373 
374  for ( uint32_t i = 0 ; i!=MAX_NUM_ARGS ; ++i )
375  {
376  lTemplates << " typename T" << i << " ,";
377  std::string lTemplatesStr ( lTemplates.str() );
378  lTemplatesStr.resize ( lTemplatesStr.size()-1 );
379  lArgs << " const T" << i << "& aArg" << i << " ,";
380  std::string lArgsStr ( lArgs.str() );
381  lArgsStr.resize ( lArgsStr.size()-1 );
382  lInstructions << "\t\t\tinsert( lStr , aArg" << i << " );\n";
383  lDoxygen << "\t\t@param aArg" << i << " a templated argument to be added to the log " << ( i+1 ) << suffix ( i+1 ) <<"\n";
384  aHppFile << "\t/**\n"
385  << lDoxygen.str()
386  << "\t*/\n"
387  << "\ttemplate<" << lTemplatesStr << ">\n"
388  // << "\tvoid operator() ( const " <<*lIt << "& a" << *lIt << " ," << lArgsStr << ");\n"
389  << "\tvoid log ( exception::exception& aExc ," << lArgsStr << ");\n"
390  << "\n";
391  aHxxFile << "template<" << lTemplatesStr << ">\n"
392  // << "void logger::operator() ( const " <<*lIt << "& a" << *lIt << " ," << lArgsStr << " )\n"
393  << "void log ( exception::exception& aExc ," << lArgsStr << " )\n"
394  << "{\n"
395  << "\t\t\tstd::stringstream lStr;\n"
396  << "\t\t\t{\n"
397  << "\t\t\tboost::lock_guard<boost::mutex> lLock ( GetLoggingMutex() );\n"
398  << lInstructions.str()
399  << "\t\t\taExc.append( ( lStr.str() + \"\\n\" ).c_str() );\n"
400  << "\t\t\t}\n"
401  << "\t\t\tlog ( Error() , lStr.str() );\n"
402  << "}\n"
403  << "\n";
404  }
405 
406  aHppFile << gDivider
407  << "\n";
408  aHxxFile << gDivider
409  << "\n";
410  }
411 }
412 
413 
414 void fileFooters ( std::ofstream& aHppFile , std::ofstream& aHxxFile , std::ofstream& aCppFile )
415 {
416  aHppFile << "}\n\n"
417  << "#include \"uhal/log/log.hxx\"\n"
418  << "#endif\n\n";
419  aHxxFile << "}\n"
420  << "\n";
421  aCppFile << "}\n"
422  << "\n";
423 }
424 
425 
426 
427 int main ( int argc , char* argv[] )
428 {
429  try
430  {
431  std::ofstream lHppFile ( "include/uhal/log/log.hpp" );
432 
433  if ( !lHppFile.is_open() )
434  {
435  std::cout << "Unable to open HPP file" << std::endl;
436  return 1;
437  }
438 
439  std::ofstream lHxxFile ( "include/uhal/log/log.hxx" );
440 
441  if ( !lHxxFile.is_open() )
442  {
443  std::cout << "Unable to open HXX file" << std::endl;
444  return 1;
445  }
446 
447  std::ofstream lCppFile ( "src/common/log.cpp" );
448 
449  if ( !lCppFile.is_open() )
450  {
451  std::cout << "Unable to open CPP file" << std::endl;
452  return 1;
453  }
454 
455  fileHeaders ( lHppFile , lHxxFile , lCppFile );
456  log_configuration_functions ( lHppFile , lHxxFile , lCppFile );
457  log_functions ( lHppFile , lHxxFile , lCppFile );
458  fileFooters ( lHppFile , lHxxFile , lCppFile );
459  lHppFile.close();
460  lHxxFile.close();
461  lCppFile.close();
462  }
463  catch ( const std::exception& aExc )
464  {
465  std::cerr << "ERROR: Caught exception : " << aExc.what() << std::endl;
466  exit ( 1 );
467  }
468 }
469 
470 
fileFooters
void fileFooters(std::ofstream &aHppFile, std::ofstream &aHxxFile, std::ofstream &aCppFile)
Definition: generator.cxx:414
gDefaultLevel
static const std::string gDefaultLevel("Info")
fileHeaders
void fileHeaders(std::ofstream &aHppFile, std::ofstream &aHxxFile, std::ofstream &aCppFile)
Definition: generator.cxx:62
gLogLevelsChar
static const std::string gLogLevelsChar[]
Definition: generator.cxx:47
gDivider
std::string gDivider("// "+std::string(150,'=')+"\n"+"// WARNING! This file is automatically generated! Do not modify it! Any changes will be overwritten!\n"+"// "+std::string(150,'=')+"\n")
log_functions
void log_functions(std::ofstream &aHppFile, std::ofstream &aHxxFile, std::ofstream &aCppFile)
Definition: generator.cxx:313
gLogLevels
static const std::vector< std::string > gLogLevels(gLogLevelsChar, gLogLevelsChar+gNumberEntries)
main
int main(int argc, char *argv[])
Definition: generator.cxx:427
suffix
std::string suffix(uint32_t i)
Definition: generator.cxx:299
gNumberEntries
static const uint32_t gNumberEntries(6)
log_configuration_functions
void log_configuration_functions(std::ofstream &aHppFile, std::ofstream &aHxxFile, std::ofstream &aCppFile)
Definition: generator.cxx:119