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