/* * freescope - Free source browser * Copyright (C) 2001 Olivier Deme * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ // FILE: trace.cpp /************/ /* INCLUDES */ /************/ #ifndef NOT_BSD #include #endif // NOT_BSD #include #include "trace.h" /*******************/ /* INITIALIZATIONS */ /*******************/ Trace::Flags Trace::m_flags = Trace::FLAGS_TIME_LOCAL; unsigned int Trace::m_locLine = 0; char* Trace::m_locFile = ""; Trace::Module Trace::m_module = 0; Trace::Level Trace::m_level = 0; Trace* Trace::m_instance = 0; const Trace::Module Trace::GLOBAL = 0; /************************/ /* FUNCTION DEFINITIONS */ /************************/ /* * FUNCTION: Trace::Trace * * DESCRIPTION: Constructor * * IN: * IN-OUT: * RETURN CODE: */ Trace::Trace () throw() : HEADER_DELIMITER('-'), LEVEL_ERROR(-1), m_start(true), m_streams(OSTREAM_STDOUT), m_moduleMaxLength(0), m_levelMaxLength(0) { for (unsigned int i = 0; i < sizeof(Module)*8; ++i) { m_modules[i].levels = 0; m_modules[i].levDescrBits = 0; m_modules[i].descriptionSet = false; } // Initialize a lookup table for level indexes int powerOfTwo = 1; for (unsigned int i = 0; i < sizeof(Level)*8; ++i) { m_lookupLevel[i] = powerOfTwo; powerOfTwo *= 2; } m_modules[GLOBAL].descriptionSet = true; m_modules[GLOBAL].description = "GLOBAL"; cout.setf(ios::uppercase); cerr.setf(ios::uppercase); } /* * FUNCTION: Trace::set_program_name * * DESCRIPTION: Set the program name * * IN: name The prohram name * IN-OUT: * RETURN CODE: */ void Trace::set_program_name ( const string& name) throw () { m_programName = name; } /* * FUNCTION: Trace::add_to_mask * * DESCRIPTION: This function ORwises the bits passed as argument * with the mask associated with the specified module. * * IN: module The module * levels The level(s) to add to the mask(s) * IN-OUT: * RETURN CODE: The old mask value */ Trace::Level Trace::add_to_mask (const Module module, const Level levels) throw () { // Check module has valid value if ((size_t)module >= sizeof(Module)*8) return LEVEL_ERROR; Level old_mask = m_modules[module].levels; m_modules[module].levels |= levels; return old_mask; } /* * FUNCTION: Trace::remove_from_mask * * DESCRIPTION: This function removes levels from the masks associated * with the specified module. * * IN: module The module * levels The level(s) to remove from the mask(s) * IN-OUT: * RETURN CODE: */ Trace::Level Trace::remove_from_mask (const Module module, const Level levels) throw () { // Check module has valid value if ((size_t)module >= sizeof(Module)*8) return LEVEL_ERROR; Level old_mask = m_modules[module].levels; m_modules[module].levels &= ~levels; return old_mask; } /* * FUNCTION: Trace::set_mask * * DESCRIPTION: This function sets the mask for the specified module * * IN: module The module * levels The new mask * IN-OUT: * RETURN CODE: */ Trace::Level Trace::set_mask (const Module module, const Level levels) throw () { // Check module has valid value if ((size_t)module >= sizeof(Module)*8) return LEVEL_ERROR; Level old_mask = m_modules[module].levels; m_modules[module].levels = levels; return old_mask; } /* * FUNCTION: Trace::set_level_description * * DESCRIPTION: This function sets the description for one or more * specified levels * * IN: module: The affected module * levels: The affected levels * description: The description string * IN-OUT: * RETURN CODE: */ void Trace::set_level_description (const Module module, const Level levels, const string& description) throw() { // Check module has valid value if ((size_t)module >= sizeof(Module)*8) return; Level level = 1; // Find affected levels for (unsigned int i = 0; i < sizeof(Level)*8; ++i) { if (levels & level) { // Set the description if (description.size() != 0) { m_modules[module].levDescr[i] = description; m_modules[module].levDescrBits |= 0x1 << i; if (description.size() > m_levelMaxLength) m_levelMaxLength = description.size(); } else { // Unset description bit m_modules[module].levDescrBits &= ~(0x1 << i); m_levelMaxLength = 0; set_level_max_length(); } } level <<= 1; } } /* * FUNCTION: Trace::set_module_description * * DESCRIPTION: This function sets the decription for a module * * IN: module The module * description The description * IN-OUT: * RETURN CODE: */ void Trace::set_module_description (const Module module, const string& description) throw() { // Check module has valid value if ((size_t)module >= sizeof(Module)*8) return; if (description.size() != 0) { m_modules[module].description = description; m_modules[module].descriptionSet = true; if (description.size() > m_moduleMaxLength) m_moduleMaxLength = description.size(); } else { m_modules[module].descriptionSet = false; m_moduleMaxLength = 0; set_module_max_length(); } } /* * FUNCTION: Trace::enable * * DESCRIPTION: This function ORwises the specified options with the * flags already set in the class * * IN: flags The flags * IN-OUT: * RETURN CODE: The old flags value */ Trace::Flags Trace::enable (const Flags flags) throw () { Flags old_flags = m_flags; m_flags |= flags; return old_flags; } /* * FUNCTION: Trace::disable * * DESCRIPTION: This function disables the specified options from the class * flags * * IN: flags The flags * IN-OUT: * RETURN CODE: The old flags value */ Trace::Flags Trace::disable (const Flags flags) throw () { Flags old_flags = m_flags; m_flags &= ~flags; return old_flags; } /* * FUNCTION: Trace::set_flags * * DESCRIPTION: This function set the flags attribute. * * IN: flags The flags * IN-OUT: * RETURN CODE: The old flags value */ Trace::Flags Trace::set_flags (const Flags flags) throw () { Flags old_flags = m_flags; m_flags = flags; return old_flags; } /* * FUNCTION: Trace::close * * DESCRIPTION: This function closes one or more streams * * IN: streams The streams to close * IN-OUT: * RETURN CODE: The resulting opened streams */ Trace::Stream Trace::close (Stream streams) throw() { if ((m_streams & OSTREAM_FILE) && (streams & OSTREAM_FILE)) m_file.close(); m_streams &= ~streams; return m_streams; } /* * FUNCTION: Trace::open * * DESCRIPTION: Open a stream * * IN: streams The streams to open * IN-OUT: * RETURN CODE: The resulting opened streams */ Trace::Stream Trace::open (Stream streams) throw () { // Ignore file stream beacuse no file name specified if (streams & OSTREAM_FILE) streams &= ~OSTREAM_FILE; m_streams |= streams; return m_streams; } /* * FUNCTION: Trace::open * * DESCRIPTION: Open a stream * * IN: streams The streams to open * filename The name of a file to open * IN-OUT: * RETURN CODE: The resulting opened streams */ Trace::Stream Trace::open (const Stream streams, const string& filename) { if ((streams & OSTREAM_FILE) && ((m_streams & OSTREAM_FILE) == 0)) { m_file.open(filename.c_str(), ios::app); if (m_file == 0) return m_streams; } m_file.setf(ios::uppercase); m_streams |= streams; return m_streams; } /* * FUNCTION: Trace::create * * DESCRIPTION: This is the function that creates a Trace object * * IN: * IN-OUT: * RETURN CODE: true on success, false otherwise */ bool Trace::create () throw (bad_alloc) { assert(m_instance == 0); // An instance has already been created! try { m_instance = new Trace(); } catch (bad_alloc& ba) { // Propagate exception throw; return false; } return true; } /* * FUNCTION: Trace::time_stamp() * * DESCRIPTION: This function gets the local time. * * IN: * IN-OUT: buffer The buffer used to store the time stamp * RETURN CODE: The number of characters written in the buffer */ int Trace::time_stamp (char* buffer) throw () { /* * UNIX-LIKE PLATFORMS */ #if (!defined NO_GETTIMEOFDAY_AND_GETLOCALTIME && !defined HAVE_GETLOCALTIME) struct timeval t1; struct tm* t2; gettimeofday(&t1, NULL); if (m_flags & FLAGS_TIME_LOCAL) t2 = localtime((time_t*)&t1.tv_sec); else t2 = gmtime((time_t*)&t1.tv_sec); sprintf(buffer, "%.2d:%.2d:%.2d.%.2d", t2->tm_hour, t2->tm_min, t2->tm_sec, (int)t1.tv_usec/10000); return 11; /* * WINDOWS PLATOFORMS */ #elif (defined HAVE_GETLOCATIME) /* * OTHER PLATFORMS */ #else // HAVE_GETLOCALTIME // Get the time with a resolution of a second struct time_t t1; struct tm* t2; time(&t1); if (m_flags & FLAGS_TIME_LOCAL) t2 = localtime(&t1); else t2 = gmtime(&t1); sprintf(buffer, "%.2d:%.2d:%.2d", t2->tm_hour, t2->tm_min, t2->tm_sec); return 8; #endif // !NO_GETTIMEOFDAY_AND_GETLOCALTIME && !HAVE_GETLOCALTIME return 0; } /* * FUNCTION: Trace::do_header * * DESCRIPTION: This function outputs to the opened streams all the * header fields that have been enabled. * * IN: * IN-OUT: * RETURN CODE: */ void Trace::do_header () { // Use character buffer for efficiency reasons char header[80]; char* p = header; header[0] = '\0'; if ((m_flags & FLAGS_PROGRAM_NAME) && (m_programName.size() != 0)) { p += sprintf(p, "%s %c ", m_programName.c_str(), HEADER_DELIMITER); } if (m_flags & FLAGS_TIMESTAMP) { p += time_stamp(p); p += sprintf(p, " %c ", HEADER_DELIMITER); } if (m_flags & FLAGS_MODULE_DESCRIPTION) { if (m_modules[m_module].descriptionSet == true) { if (m_flags & FLAGS_ALIGNMENT) { p += sprintf(p, "%-*s %c ", m_moduleMaxLength, m_modules[m_module].description.c_str(), HEADER_DELIMITER); } else { p += sprintf(p, "%s %c ", m_modules[m_module].description.c_str(), HEADER_DELIMITER); } } } if (m_flags & FLAGS_LEVEL_DESCRIPTION) { int indexLevel; // Retrieve level index. for (indexLevel = 0; !(m_lookupLevel[indexLevel] & m_level); ++indexLevel); if (m_modules[m_module].levDescrBits & (0x1 << indexLevel)) { // A description has ben provided for this level if (m_flags & FLAGS_ALIGNMENT) { p += sprintf(p, "%-*s %c ", m_levelMaxLength, m_modules[m_module].levDescr[indexLevel].c_str(), HEADER_DELIMITER); } else { p += sprintf(p, "%s %c ", m_modules[m_module].levDescr[indexLevel].c_str(), HEADER_DELIMITER); } } else { // No description has been provided for this level. if (m_flags & FLAGS_ALIGNMENT) { p += sprintf(p, "0x%-*X %c ", m_levelMaxLength, m_level, HEADER_DELIMITER); } else { p += sprintf(p, "0x%X %c ", m_level, HEADER_DELIMITER); } } } if (m_flags & FLAGS_CALLER) { p += sprintf(p, "%s:%d %c ", m_locFile, m_locLine, HEADER_DELIMITER); } // Send the header to the opened streams if (m_streams & OSTREAM_STDOUT) cout << header; if (m_streams & OSTREAM_STDERR) cerr << header; if (m_streams & OSTREAM_FILE) m_file << header; // do not print the header until "endl" or "flush" manipulators m_start = false; } /* * FUNCTION: Trace::set_module_max_length * * DESCRIPTION: Retrieve and store the biggest length among all module * descriptions. * * IN: * IN-OUT: * RETURN CODE: */ void Trace::set_module_max_length () throw () { for (unsigned int i = 0; i < sizeof(Module)*8; ++i) { if ((m_modules[i].descriptionSet == true) && (m_modules[i].description.size() > m_moduleMaxLength)) { m_moduleMaxLength = m_modules[i].description.size(); } } } /* * FUNCTION: Trace::set_level_max_length * * DESCRIPTION: Retrieve and store the biggest length among all level * descriptions. * * IN: * IN-OUT: * RETURN CODE: */ void Trace::set_level_max_length () throw () { for (unsigned int i = 0; i < sizeof(Module)*8; ++i) { Level level = 0x1; // Iterate levels for (unsigned int j = 0; j < sizeof(Level)*8; ++j) { if ((m_modules[i].levDescrBits & level) && (m_modules[i].levDescr[j].size() > m_levelMaxLength)) { m_levelMaxLength = m_modules[i].levDescr[j].size(); } level <<= 1; } } } /* * OPERATOR: Trace::operator<< * * DESCRIPTION: Send a character to the streams * */ Trace& Trace::operator<< (char character) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; if (m_start == true) do_header(); if (m_streams & OSTREAM_STDOUT) cout << character; if (m_streams & OSTREAM_STDERR) cerr << character; if (m_streams & OSTREAM_FILE) m_file << character; return *this; } /* * OPERATOR: Trace::operator<< * * DESCRIPTION: Send a character to the streams * */ Trace& Trace::operator<< (unsigned char character) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; if (m_start == true) do_header(); if (m_streams & OSTREAM_STDOUT) cout << character; if (m_streams & OSTREAM_STDERR) cerr << character; if (m_streams & OSTREAM_FILE) m_file << character; return *this; } /* * OPERATOR: Trace::operator<< * * DESCRIPTION: Send a string to the streams * */ Trace& Trace::operator<< (char* str) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; if (m_start == true) do_header(); if (m_streams & OSTREAM_STDOUT) cout << str; if (m_streams & OSTREAM_STDERR) cerr << str; if (m_streams & OSTREAM_FILE) m_file << str; return *this; } /* * OPERATOR: Trace::operator<< * * DESCRIPTION: Send a string to the streams * */ Trace& Trace::operator<< (unsigned char* str) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; if (m_start == true) do_header(); if (m_streams & OSTREAM_STDOUT) cout << str; if (m_streams & OSTREAM_STDERR) cerr << str; if (m_streams & OSTREAM_FILE) m_file << str; return *this; } /* * OPERATOR: Trace::operator<< * * DESCRIPTION: Send a string to the streams * */ Trace& Trace::operator<< (const string& str) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; if (m_start == true) do_header(); if (m_streams & OSTREAM_STDOUT) cout << str.c_str(); if (m_streams & OSTREAM_STDERR) cerr << str.c_str(); if (m_streams & OSTREAM_FILE) m_file << str.c_str(); return *this; } /* * OPERATOR: Trace::operator<< * * DESCRIPTION: Send an int to the streams * */ Trace& Trace::operator<< (int nbr) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; if (m_start == true) do_header(); if (m_streams & OSTREAM_STDOUT) cout << nbr; if (m_streams & OSTREAM_STDERR) cerr << nbr; if (m_streams & OSTREAM_FILE) m_file << nbr; return *this; } /* * OPERATOR: Trace::operator<< * * DESCRIPTION: Send an unsigned int to the streams * */ Trace& Trace::operator<< (unsigned int nbr) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; if (m_start == true) do_header(); if (m_streams & OSTREAM_STDOUT) cout << nbr; if (m_streams & OSTREAM_STDERR) cerr << nbr; if (m_streams & OSTREAM_FILE) m_file << nbr; return *this; } /* * OPERATOR: Trace::operator<< * * DESCRIPTION: Send a long to the streams * */ Trace& Trace::operator<< (long nbr) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; if (m_start == true) do_header(); if (m_streams & OSTREAM_STDOUT) cout << nbr; if (m_streams & OSTREAM_STDERR) cerr << nbr; if (m_streams & OSTREAM_FILE) m_file << nbr; return *this; } /* * OPERATOR: Trace::operator<< * * DESCRIPTION: Send an unsigned long to the streams * */ Trace& Trace::operator<< (unsigned long nbr) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; if (m_start == true) do_header(); if (m_streams & OSTREAM_STDOUT) cout << nbr; if (m_streams & OSTREAM_STDERR) cerr << nbr; if (m_streams & OSTREAM_FILE) m_file << nbr; return *this; } /* * OPERATOR: Trace::operator<< * * DESCRIPTION: Send a short to the streams * */ Trace& Trace::operator<< (short nbr) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; if (m_start == true) do_header(); if (m_streams & OSTREAM_STDOUT) cout << nbr; if (m_streams & OSTREAM_STDERR) cerr << nbr; if (m_streams & OSTREAM_FILE) m_file << nbr; return *this; } /* * OPERATOR: Trace::operator<< * * DESCRIPTION: Send an unsigned short to the streams * */ Trace& Trace::operator<< (unsigned short nbr) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; if (m_start == true) do_header(); if (m_streams & OSTREAM_STDOUT) cout << nbr; if (m_streams & OSTREAM_STDERR) cerr << nbr; if (m_streams & OSTREAM_FILE) m_file << nbr; return *this; } /* * OPERATOR: Trace::operator<< * * DESCRIPTION: Send a float short to the streams * */ Trace& Trace::operator<< (float nbr) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; if (m_start == true) do_header(); if (m_streams & OSTREAM_STDOUT) cout << nbr; if (m_streams & OSTREAM_STDERR) cerr << nbr; if (m_streams & OSTREAM_FILE) m_file << nbr; return *this; } /* * OPERATOR: Trace::operator<< * * DESCRIPTION: Send a double short to the streams * */ Trace& Trace::operator<< (double nbr) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; if (m_start == true) do_header(); if (m_streams & OSTREAM_STDOUT) cout << nbr; if (m_streams & OSTREAM_STDERR) cerr << nbr; if (m_streams & OSTREAM_FILE) m_file << nbr; return *this; } /* * OPERATOR: operator<< * * DESCRIPTION: This operator is used for implementing the Hex effector. */ Trace& operator<< (Trace& trace, const Hex& h) { // Do nothing if module is invalid if ((size_t)trace.m_module >= sizeof(Trace::Module)*8) return trace; if ((trace.m_modules[trace.m_module].levels & trace.m_level) == 0) return trace; if (trace.m_start == true) trace.do_header(); if (trace.m_streams & Trace::OSTREAM_STDOUT) { cout.setf(ios::hex, ios::basefield); cout << "0x" << h.m_nbr; cout.setf(ios::dec, ios::basefield); } if (trace.m_streams & Trace::OSTREAM_STDERR) { cerr.setf(ios::hex, ios::basefield); cerr << "0x" << h.m_nbr; cerr.setf(ios::dec, ios::basefield); } if (trace.m_streams & Trace::OSTREAM_FILE) { trace.m_file.setf(ios::hex, ios::basefield); trace.m_file << "0x" << h.m_nbr; trace.m_file.setf(ios::dec, ios::basefield); } return trace; } Trace& Trace::operator<< (Trace_manip m) { // Do nothing if module is invalid if ((size_t)m_module >= sizeof(Module)*8) return *this; if ((m_modules[m_module].levels & m_level) == 0) return *this; m(*this); return *this; } Trace& operator<< (Trace& trace, const Width& w) { // Do nothing if module is invalid if ((size_t)trace.m_module >= sizeof(Trace::Module)*8) return trace; if ((trace.m_modules[trace.m_module].levels & trace.m_level) == 0) return trace; int justify; if (trace.m_start == true) trace.do_header(); switch (w.m_fmt) { case Width::LEFT: justify = ios::left; break; case Width::RIGHT: justify = ios::right; break; default: return trace; } if (trace.m_streams & Trace::OSTREAM_STDOUT) { cout.width(w.m_width); cout.fill(w.m_fill); cout.setf(justify, ios::adjustfield); } if (trace.m_streams & Trace::OSTREAM_STDERR) { cerr.width(w.m_width); cerr.fill(w.m_fill); cerr.setf(justify, ios::adjustfield); } if (trace.m_streams & Trace::OSTREAM_FILE) { trace.m_file.width(w.m_width); trace.m_file.fill(w.m_fill); trace.m_file.setf(justify, ios::adjustfield); } return trace; } /* * MANIPULATOR: endl * * DESCRIPTION: This manipulator adds a carriage return and flushes the * opened streams. */ Trace& endl (Trace& trace) { // Do nothing if module is invalid if ((size_t)trace.m_module >= sizeof(Trace::Module)*8) return trace; if ((trace.m_modules[trace.m_module].levels & trace.m_level) == 0) return trace; if (trace.m_start == true) trace.do_header(); if (trace.m_streams & Trace::OSTREAM_STDOUT) cout << endl; if (trace.m_streams & Trace::OSTREAM_STDERR) cerr << endl; if (trace.m_streams & Trace::OSTREAM_FILE) trace.m_file << endl; trace.m_start = true; return trace; } /* * MANIPULATOR: flush * * DESCRIPTION: This manipulator flushes the opened streams */ Trace& flush (Trace& trace) { // Do nothing if module is invalid if ((size_t)trace.m_module >= sizeof(Trace::Module)*8) return trace; if ((trace.m_modules[trace.m_module].levels & trace.m_level) == 0) return trace; if (trace.m_start == true) trace.do_header(); if (trace.m_streams & Trace::OSTREAM_STDOUT) cout << flush; if (trace.m_streams & Trace::OSTREAM_STDERR) cerr << flush; if (trace.m_streams & Trace::OSTREAM_FILE) trace.m_file << flush; trace.m_start = true; return trace; } /* * FUNCTION: Width::Width * * DESCRIPTION: Effector constructor * * IN: justify The type of justification * width The width of the next output * fill The filling character * IN-OUT: * RETURN CODE: */ Width::Width (Format justify, unsigned int width, char fill) : m_fmt(justify), m_width(width), m_fill(fill) { }