dbg.cpp

00001 /*
00002  * File:    dbg.cpp
00003  * Author:  Pete Goodliffe
00004  * Version: 1.10
00005  * Created: 7 June 2001
00006  *
00007  * Purpose: C++ debugging support library
00008  *
00009  * Copyright (c) Pete Goodliffe 2001-2002 (pete@cthree.org)
00010  *
00011  * This file is modifiable/redistributable under the terms of the GNU
00012  * Lesser General Public License.
00013  *
00014  * You should have recieved a copy of the GNU General Public License along
00015  * with this program; see the file COPYING. If not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 0211-1307, USA.
00017  */
00018 
00019 #ifndef DBG_ENABLED
00020 #define DBG_ENABLED
00021 #endif
00022 
00023 #include "dbg.h"
00024 
00025 #include <iostream>
00026 #include <cstdlib>
00027 #include <string>
00028 #include <vector>
00029 #include <map>
00030 #include <algorithm>
00031 #include <new>
00032 
00033     /**********************************************************************
00034      * Implementation notes
00035      **********************************************************************
00036      * Tested and found to work ok under
00037      *  - gcc 2.96
00038      *  - gcc 3.0
00039      *  - gcc 3.1
00040      *  - gcc 3.2
00041      *  - bcc32 5.5.1
00042      *  - MSVC 6.0
00043      *
00044      * MSVC v6.0
00045      *  - This platform makes me cry.
00046      *  - There are NUMEROUS hacks around it's deficient behaviour, just
00047      *    look for conditional complation based around _MSC_VER
00048      *  - The <ctime> header doesn't put all the definitions into the std
00049      *    namespace.
00050      *  - This means that we have to sacrifice our good namespace-based code
00051      *    for something more disgusting and primitve.
00052      *  - Where this has happened, and where in the future I'd really like to
00053      *    put the "std" namespace back in, I have instead used a STDCLK macro.
00054      *    See the implementation comment about this below for more grief.
00055      *  - A documented hack has been made in the dbg.h header file, of slightly
00056      *    less ghastly proportions. See dbgclock_t there.
00057      *  - Additionally, the dbg::array_size template utility could be (and was)
00058      *    more  elegantly be written:
00059      *         template <class T, int size>
00060      *         inline unsigned int array_size(T (&array)[size])
00061      *         {
00062      *             return size;
00063      *         }
00064      *    Of course, MSVC doesn't like that. Sigh. The version in dbg.h also
00065      *    works, its just not quite so nice.
00066      *  - The map implentation of MSVC doesn't provide data_type, so I have to
00067      *    hack around that.
00068      *  - The compiler doesn't like the dbg_ostream calling it's parent
00069      *    constructor by the name "ostream", it doesn't recognise the typedef.
00070      *    Ugh.
00071      *
00072      * Other thoughts:
00073      *  - Break out to debugger facility?
00074      *  - Only works for ostreams, not all basic_ostreams
00075      *  - Post-conditions are a bit limited, this is more of a C++
00076      *    language limitation, really.
00077      *********************************************************************/
00078 
00079 /******************************************************************************
00080  * Tedious compiler-specific issues
00081  *****************************************************************************/
00082 
00083 // Work around MSVC 6.0
00084 #ifdef _MSC_VER
00085 #define STDCLK
00086 #pragma warning(disable:4786)
00087 #else
00088 // In an ideal world, the following line would be
00089 //     namespace STDCLK = std;
00090 // However, gcc 2.96 doesn't seem to cope well with namespace aliases.
00091 // Sigh.
00092 #define STDCLK std
00093 #endif
00094 
00095 // Quieten tedius build warnings on Borland C++ compiler
00096 #ifdef __BCPLUSPLUS__
00097 #pragma warn -8066
00098 #pragma warn -8071
00099 #pragma warn -8070
00100 #endif
00101 
00102 /******************************************************************************
00103  * General dbg library private declarations
00104  *****************************************************************************/
00105 
00106 namespace
00107 {
00108     /**************************************************************************
00109      * Constants
00110      *************************************************************************/
00111 
00112     const char *LEVEL_NAMES[] =
00113     {
00114         "info",
00115         "warning",
00116         "error",
00117         "fatal",
00118         "tracing",
00119         "debug",
00120         "none",
00121         "all"
00122     };
00123     const char *BEHAVIOUR_NAMES[] =
00124     {
00125         "assertions_abort",
00126         "assertions_throw",
00127         "assertions_continue"
00128     };
00129     enum constraint_type
00130     {
00131         why_assertion,
00132         why_sentinel,
00133         why_unimplemented,
00134         why_check_ptr
00135     };
00136 
00137     const char         *TRACE_IN         = "->";
00138     const char         *TRACE_OUT        = "<-";
00139     const char         *INDENT           = "  ";
00140     const char         *PREFIX           = "*** ";
00141     const char         *TRUE_STRING      = "true";
00142     const char         *FALSE_STRING     = "false";
00143     const unsigned int  ALL_SOURCES_MASK = 0xff;
00144     const unsigned int  NUM_DBG_LEVELS   = dbg::all-1;
00145 
00146     /**************************************************************************
00147      * Internal types
00148      *************************************************************************/
00149 
00156     struct period_data
00157     {
00158         size_t          no_triggers;
00159         STDCLK::clock_t triggered_at;
00160 
00161         period_data();
00162     };
00163 
00169     struct lt_sp
00170     {
00171         bool operator()(const dbg::source_pos &a, const dbg::source_pos &b)
00172             const
00173         {
00174             if (a.file == b.file)
00175             {
00176                 if (a.func == b.func)
00177                 {
00178                     return a.line < b.line;
00179                 }
00180                 else
00181                 {
00182                     return a.func < b.func;
00183                 }
00184             }
00185             else
00186             {
00187                 return a.file < b.file;
00188             }
00189         }
00190     };
00191 
00203     class dbg_streambuf : public std::streambuf
00204     {
00205         public:
00206 
00207             dbg_streambuf(std::vector<std::ostream*> &ostreams, int bsize = 0);
00208             ~dbg_streambuf();
00209 
00210             int pubsync() { return sync(); }
00211 
00212         protected:
00213 
00214             int overflow(int);
00215             int sync();
00216 
00217         private:
00218 
00219             void put_buffer(void);
00220             void put_char(int);
00221 
00222             std::vector<std::ostream *> &ostreams;
00223     };
00224 
00235     class null_streambuf : public std::streambuf
00236     {
00237         public:
00238 
00239             null_streambuf()  {}
00240             ~null_streambuf() {}
00241 
00242         protected:
00243 
00244             int overflow(int) { return 0; }
00245             int sync()        { return 0; }
00246     };
00247 
00257     class dbg_ostream : public std::ostream
00258     {
00259         public:
00260 
00261 #ifndef _MSC_VER
00262             dbg_ostream() : std::ostream(&dbg_buf), dbg_buf(streams) {}
00263             dbg_ostream(const dbg_ostream &rhs)
00264                 : std::ostream(&dbg_buf), streams(rhs.streams),
00265                   dbg_buf(streams) {}
00266 #else
00267             // MSVC workaround. Sigh. It won't let us call the parent ctor as
00268             // "ostream" - it doesn't like the use of a typedef. On the other
00269             // hand gcc 2.96 doesn't provide basic_ostream, so I can't call the
00270             // base basic_ostream<> class there.
00271             dbg_ostream()
00272                 : std::basic_ostream<char>(&dbg_buf), dbg_buf(streams) {}
00273             dbg_ostream(const dbg_ostream &rhs)
00274                 : std::basic_ostream<char>(&dbg_buf), streams(rhs.streams),
00275                   dbg_buf(streams) {}
00276 #endif
00277             ~dbg_ostream() { dbg_buf.pubsync(); }
00278 
00279             void add(std::ostream &o);
00280             void remove(std::ostream &o);
00281             void clear();
00282 
00283         private:
00284 
00285             dbg_ostream &operator=(const dbg_ostream&);
00286 
00287             typedef std::vector<std::ostream*> stream_vec_type;
00288 
00289             stream_vec_type streams;
00290             dbg_streambuf   dbg_buf;
00291     };
00292 
00305     class source_info
00306     {
00307         public:
00308 
00314             enum ConstructionStyle
00315             {
00316                 ConstructTheDefaultSource    = 0,
00317                 ConstructCopyOfDefaultSource = 1
00318             };
00319 
00320             source_info(ConstructionStyle cs = ConstructCopyOfDefaultSource);
00321             source_info(const source_info &rhs);
00322             ~source_info();
00323 
00328             void enable(dbg::level lvl, bool enable);
00329 
00333             bool enabled(dbg::level lvl) const
00334             {
00335                 return (levels & dbg_source_mask(lvl)) != 0;
00336             }
00337 
00341             void add_ostream(dbg::level lvl, std::ostream &o);
00342 
00346             void remove_ostream(dbg::level lvl, std::ostream &o);
00347 
00351             void clear_ostream(dbg::level lvl);
00352 
00357             std::ostream &out(dbg::level lvl);
00358 
00359         private:
00360 
00365             static unsigned int dbg_source_mask(dbg::level lvl)
00366             {
00367                 return (lvl != dbg::all) ? 1 << lvl : ALL_SOURCES_MASK;
00368             }
00369 
00370             unsigned int levels;
00371 
00372             // We do a placement new of the dbg_streams array.
00373             // It looks somewhat tacky, but it allows us to have a single
00374             // constructor, which simplifies the client interface of this class.
00375             // It specifically avoids tonnes of grotesque unused dbg_ostream
00376             // constructions, as you'd create an array, and then copy the
00377             // default_source elements directly over these freshly constructed
00378             // elements. dbg_ostream is complex enough that this matters.
00379             // If we didn't have a clever cloning constructor, these lines
00380             // would just be "dbg_ostream dbg_streams[NUM_DBG_LEVELS];" and
00381             // we'd suffer a whole load of redundant dbg_ostream constructions.
00382             /*
00383             typedef        dbg_ostream array_type[NUM_DBG_LEVELS];
00384             dbg_ostream   *dbg_streams;
00385             unsigned char  raw_dbg_streams[sizeof(array_type)];
00386             */
00387             struct array_type
00388             {
00389                 // I wrap this up in an enclosing struct to make it obvious
00390                 // how to destroy the array "in place". To be honest I couldn't
00391                 // figure the syntax for the corresponding delete for a
00392                 // placement new array constrution.
00393                 dbg_ostream dbg_streams[NUM_DBG_LEVELS];
00394             };
00395             dbg_ostream   *dbg_streams;
00396             unsigned char  raw_dbg_streams[sizeof(array_type)];
00397 
00398             array_type &raw_cast()
00399             {
00400                 return *reinterpret_cast<array_type*>(raw_dbg_streams);
00401             }
00402             const array_type &raw_cast() const
00403             {
00404                 return *reinterpret_cast<const array_type*>(raw_dbg_streams);
00405             }
00406     };
00407 
00418     class source_map_type
00419     {
00420         public:
00421 
00422             typedef std::map<std::string, source_info> map_type;
00423             typedef map_type::iterator                 iterator;
00424             typedef map_type::key_type                 key_type;
00425 #ifndef _MSC_VER
00426             // Replaced data_type by mapped_type, since there is no
00427             // more data_type, data_type was remove in g++ 3.3. 
00428             typedef map_type::mapped_type                data_type;
00429 #else
00430             // MSVC. Just don't ask.
00431             typedef source_info                        data_type;
00432 #endif
00433             source_map_type()
00434             {
00435                 // Insert the default_source into the map
00436                 _map.insert(
00437                     std::make_pair(dbg::default_source,
00438                     source_info(source_info::ConstructTheDefaultSource)));
00439                 // Insert the unnamed source into the map too
00440                 _map.insert(
00441                     std::make_pair(dbg::dbg_source(""),
00442                     source_info(source_info::ConstructTheDefaultSource)));
00443             }
00444             iterator   begin()                  { return _map.begin(); }
00445             iterator   end()                    { return _map.end();   }
00446             data_type &operator[](key_type key) { return _map[key];    }
00447 
00448         private:
00449 
00450             map_type _map;
00451     };
00452 
00453     typedef std::map<dbg::source_pos, period_data, lt_sp> period_map_type;
00454 
00455     /**************************************************************************
00456      * Internal variables
00457      *************************************************************************/
00458 
00459     // The stream to write to when no output is required.
00460     std::ostream null_ostream(new null_streambuf());
00461 
00462     dbg::assertion_behaviour behaviour[dbg::all+1] =
00463     {
00464         dbg::assertions_abort,
00465         dbg::assertions_abort,
00466         dbg::assertions_abort,
00467         dbg::assertions_abort,
00468         dbg::assertions_abort,
00469         dbg::assertions_abort,
00470         dbg::assertions_abort,
00471         dbg::assertions_abort
00472     };
00473 
00474     unsigned int    indent_depth  = 0;
00475     std::string     indent_prefix = PREFIX;
00476     bool            level_prefix  = false;
00477     bool            time_prefix   = false;
00478     STDCLK::clock_t period        = 0;
00479     source_map_type source_map;
00480     period_map_type period_map;
00481 
00482     /**************************************************************************
00483      * Function declarations
00484      *************************************************************************/
00485 
00489     void print_pos(std::ostream &out, const dbg::source_pos &where);
00490 
00495     void print_pos_short(std::ostream &out, const dbg::source_pos &where);
00496 
00501     void print_period_info(std::ostream &out, const dbg::source_pos &where);
00502 
00507     void do_assertion_behaviour(dbg::level lvl, constraint_type why,
00508                                 const dbg::source_pos &pos);
00509 
00514     void do_prefix(dbg::level lvl, std::ostream &s);
00515 
00519     bool period_allows_impl(const dbg::source_pos &where);
00520 
00529     inline bool period_allows(const dbg::source_pos &where)
00530     {
00531         return !period || period_allows_impl(where);
00532     }
00533 
00539     void determine_source(dbg::dbg_source &src, const dbg::source_pos &here);
00540 }
00541 
00542 
00543 /******************************************************************************
00544  * Miscellaneous public bobbins
00545  *****************************************************************************/
00546 
00547 dbg::dbg_source dbg::default_source = "dbg::private::default_source";
00548 
00549 
00550 /******************************************************************************
00551  * Enable/disable dbg facilities
00552  *****************************************************************************/
00553 
00554 void dbg::enable(dbg::level lvl, bool enabled)
00555 {
00556     out(debug) << prefix(debug) << "dbg::enable(" << LEVEL_NAMES[lvl]
00557                << "," << (enabled ? TRUE_STRING : FALSE_STRING) << ")\n";
00558 
00559     source_map[""].enable(lvl, enabled);
00560 }
00561 
00562 
00563 void dbg::enable(dbg::level lvl, dbg::dbg_source src, bool enabled)
00564 {
00565     out(debug) << prefix(debug) << "dbg::enable(" << LEVEL_NAMES[lvl]
00566                << ",\"" << src << "\","
00567                << (enabled ? TRUE_STRING : FALSE_STRING) << ")\n";
00568 
00569     source_map[src].enable(lvl, enabled);
00570 }
00571 
00572 
00573 void dbg::enable_all(dbg::level lvl, bool enabled)
00574 {
00575     out(debug) << prefix(debug) << "dbg::enable_all("
00576                << LEVEL_NAMES[lvl] << ","
00577                << (enabled ? TRUE_STRING : FALSE_STRING) << ")\n";
00578 
00579     source_map_type::iterator i = source_map.begin();
00580     for ( ; i != source_map.end(); ++i)
00581     {
00582         (i->second).enable(lvl, enabled);
00583     }
00584 }
00585 
00586 
00587 /******************************************************************************
00588  * Logging
00589  *****************************************************************************/
00590 
00591 std::ostream &dbg::out(dbg::level lvl, dbg::dbg_source src)
00592 {
00593     return source_map[src ? src : ""].out(lvl);
00594 }
00595 
00596 
00597 void dbg::attach_ostream(dbg::level lvl, std::ostream &o)
00598 {
00599     out(debug) << prefix(debug) << "dbg::attach_ostream("
00600                << LEVEL_NAMES[lvl] << ",ostream)\n";
00601 
00602     source_map[""].add_ostream(lvl, o);
00603 }
00604 
00605 
00606 void dbg::attach_ostream(dbg::level lvl, dbg::dbg_source src, std::ostream &o)
00607 {
00608     out(debug) << prefix(debug) << "dbg::attach_ostream("
00609                << LEVEL_NAMES[lvl]
00610                << ", \"" << src
00611                << "\" ,ostream)\n";
00612 
00613     source_map[src].add_ostream(lvl, o);
00614 }
00615 
00616 
00617 void dbg::detach_ostream(dbg::level lvl, std::ostream &o)
00618 {
00619     out(debug) << prefix(debug) << "dbg::detach_ostream("
00620                << LEVEL_NAMES[lvl] << ")\n";
00621 
00622     source_map[""].remove_ostream(lvl, o);
00623 }
00624 
00625 
00626 void dbg::detach_ostream(dbg::level lvl, dbg::dbg_source src, std::ostream &o)
00627 {
00628     out(debug) << prefix(debug) << "dbg::detach_ostream("
00629                << LEVEL_NAMES[lvl]
00630                << ", \"" << src
00631                << "\" ,ostream)\n";
00632 
00633     source_map[src].remove_ostream(lvl, o);
00634 }
00635 
00636 
00637 void dbg::detach_all_ostreams(dbg::level lvl)
00638 {
00639     out(debug) << prefix(debug) << "dbg::detach_all_ostreams("
00640                << LEVEL_NAMES[lvl]
00641                << ")\n";
00642 
00643     source_map[""].clear_ostream(lvl);
00644 }
00645 
00646 
00647 void dbg::detach_all_ostreams(dbg::level lvl, dbg::dbg_source src)
00648 {
00649     out(debug) << prefix(debug) << "dbg::detach_all_ostreams("
00650                << LEVEL_NAMES[lvl]
00651                << ", \"" << src << "\")\n";
00652 
00653     source_map[src].clear_ostream(lvl);
00654 }
00655 
00656 
00657 /******************************************************************************
00658  * Output formatting
00659  *****************************************************************************/
00660 
00661 void dbg::set_prefix(const char *pfx)
00662 {
00663     out(debug) << prefix(debug) << "dbg::set_prefix(" << pfx << ")\n";
00664 
00665     indent_prefix = pfx;
00666 }
00667 
00668 
00669 void dbg::enable_level_prefix(bool enabled)
00670 {
00671     out(debug) << prefix(debug) << "dbg::enable_level_prefix("
00672                << (enabled ? TRUE_STRING : FALSE_STRING) << ")\n";
00673 
00674     level_prefix = enabled;
00675 }
00676 
00677 
00678 void dbg::enable_time_prefix(bool enabled)
00679 {
00680     out(debug) << prefix(debug) << "dbg::enable_time_prefix("
00681                << (enabled ? TRUE_STRING : FALSE_STRING) << ")\n";
00682 
00683     time_prefix = enabled;
00684 }
00685 
00686 
00687 std::ostream &dbg::operator<<(std::ostream &s, const prefix &p)
00688 {
00689     s << indent_prefix.c_str();
00690     do_prefix(p.l, s);
00691     return s;
00692 }
00693 
00694 
00695 std::ostream &dbg::operator<<(std::ostream &s, const indent &i)
00696 {
00697     s << indent_prefix.c_str();
00698     do_prefix(i.l, s);
00699     for (unsigned int n = 0; n < indent_depth; n++) s << INDENT;
00700     return s;
00701 }
00702 
00703 
00704 std::ostream &dbg::operator<<(std::ostream &s, const source_pos &pos)
00705 {
00706     print_pos(s, pos);
00707     return s;
00708 }
00709 
00710 
00711 /******************************************************************************
00712  * Behaviour
00713  *****************************************************************************/
00714 
00715 void dbg::set_assertion_behaviour(level lvl, dbg::assertion_behaviour b)
00716 {
00717     out(debug) << prefix(debug) << "dbg::set_assertion_behaviour("
00718                << LEVEL_NAMES[lvl] << "," << BEHAVIOUR_NAMES[b] << ")\n";
00719 
00720     if (lvl < dbg::all)
00721     {
00722         behaviour[lvl] = b;
00723     }
00724     else
00725     {
00726         for (int n = 0; n < dbg::all; n++)
00727         {
00728             behaviour[n] = b;
00729         }
00730     }
00731 }
00732 
00733 
00734 void dbg::set_assertion_period(dbgclock_t p)
00735 {
00736     out(debug) << prefix(debug) << "dbg::set_assertion_period("
00737                << p << ")\n";
00738 
00739     if (!p && period)
00740     {
00741         period_map.clear();
00742     }
00743 
00744     period = p;
00745 
00746     if (p && STDCLK::clock() == -1)
00747     {
00748         period = p;
00749         out(debug) << prefix(debug)
00750                    << "*** WARNING ***\n"
00751                    << "Platform does not support std::clock, and so\n"
00752                    << "dbg::set_assertion_period is not supported.\n";
00753     }
00754 }
00755 
00756 
00757 /******************************************************************************
00758  * Assertion
00759  *****************************************************************************/
00760 
00761 void dbg::assertion(dbg::level lvl, dbg::dbg_source src,
00762                     const assert_info &info)
00763 {
00764     determine_source(src, info);
00765 
00766     if (source_map[src].enabled(lvl) && !info.asserted && period_allows(info))
00767     {
00768         std::ostream &o = out(lvl, src);
00769 
00770         o << indent(lvl) << "assertion \"" << info.text << "\" failed ";
00771         if (strcmp(src, ""))
00772         {
00773             o << "for \"" << src << "\" ";
00774         }
00775         o << "at ";
00776         print_pos(o, info);
00777         print_period_info(o, info);
00778         o << "\n";
00779 
00780         do_assertion_behaviour(lvl, why_assertion, info);
00781     }
00782 }
00783 
00784 
00785 /******************************************************************************
00786  * Sentinel
00787  *****************************************************************************/
00788 
00789 void dbg::sentinel(dbg::level lvl, dbg::dbg_source src, const source_pos &here)
00790 {
00791     determine_source(src, here);
00792 
00793     if (source_map[src].enabled(lvl) && period_allows(here))
00794     {
00795         std::ostream &o = out(lvl, src);
00796         o << indent(lvl) << "sentinel reached at ";
00797         print_pos(o, here);
00798         print_period_info(o, here);
00799         o << "\n";
00800 
00801         do_assertion_behaviour(lvl, why_sentinel, here);
00802     }
00803 }
00804 
00805 
00806 /******************************************************************************
00807  * Unimplemented
00808  *****************************************************************************/
00809 
00810 void dbg::unimplemented(dbg::level lvl, dbg::dbg_source src,
00811                         const source_pos &here)
00812 {
00813     determine_source(src, here);
00814 
00815     if (source_map[src].enabled(lvl) && period_allows(here))
00816     {
00817         std::ostream &o = out(lvl, src);
00818         o << indent(lvl) << "behaviour not yet implemented at ";
00819         print_pos(o, here);
00820         print_period_info(o, here);
00821         o << "\n";
00822 
00823         do_assertion_behaviour(lvl, why_unimplemented, here);
00824     }
00825 }
00826 
00827 
00828 /******************************************************************************
00829  * Pointer checking
00830  *****************************************************************************/
00831 
00832 void dbg::check_ptr(dbg::level lvl, dbg::dbg_source src,
00833                     const void *p, const source_pos &here)
00834 {
00835     determine_source(src, here);
00836 
00837     if (source_map[src].enabled(lvl) && p == 0 && period_allows(here))
00838     {
00839         std::ostream &o = out(lvl, src);
00840         o << indent(lvl) << "pointer is zero at ";
00841         print_pos(o, here);
00842         print_period_info(o, here);
00843         o << "\n";
00844 
00845         do_assertion_behaviour(lvl, why_check_ptr, here);
00846     }
00847 }
00848 
00849 
00850 /******************************************************************************
00851  * Bounds checking
00852  *****************************************************************************/
00853 
00854 void dbg::check_bounds(dbg::level lvl, dbg::dbg_source src,
00855                        int index, int bound, const source_pos &here)
00856 {
00857     determine_source(src, here);
00858 
00859     if (source_map[src].enabled(lvl)
00860         && index >= 0 && index >= bound
00861         && period_allows(here))
00862     {
00863         std::ostream &o = out(lvl, src);
00864         o << indent(lvl) << "index " << index << " is out of bounds ("
00865           << bound << ") at ";
00866         print_pos(o, here);
00867         print_period_info(o, here);
00868         o << "\n";
00869 
00870         do_assertion_behaviour(lvl, why_check_ptr, here);
00871     }
00872 }
00873 
00874 
00875 /******************************************************************************
00876  * Tracing
00877  *****************************************************************************/
00878 
00879 dbg::trace::trace(func_name_t name)
00880 : m_src(0), m_name(name), m_pos(DBG_HERE), m_triggered(false)
00881 {
00882     determine_source(m_src, m_pos);
00883 
00884     if (source_map[m_src].enabled(dbg::tracing))
00885     {
00886         trace_begin();
00887     }
00888 }
00889 
00890 
00891 dbg::trace::trace(dbg_source src, func_name_t name)
00892 : m_src(src), m_name(name), m_pos(DBG_HERE), m_triggered(false)
00893 {
00894     determine_source(m_src, m_pos);
00895 
00896     if (source_map[m_src].enabled(dbg::tracing))
00897     {
00898         trace_begin();
00899     }
00900 }
00901 
00902 
00903 dbg::trace::trace(const source_pos &where)
00904 : m_src(0), m_name(0), m_pos(where), m_triggered(false)
00905 {
00906     determine_source(m_src, m_pos);
00907 
00908     if (source_map[m_src].enabled(dbg::tracing))
00909     {
00910         trace_begin();
00911     }
00912 }
00913 
00914 
00915 dbg::trace::trace(dbg_source src, const source_pos &where)
00916 : m_src(src), m_name(0), m_pos(where), m_triggered(false)
00917 {
00918     determine_source(m_src, m_pos);
00919 
00920     if (source_map[src].enabled(dbg::tracing))
00921     {
00922         trace_begin();
00923     }
00924 }
00925 
00926 
00927 dbg::trace::~trace()
00928 {
00929     if (m_triggered)
00930     {
00931         trace_end();
00932     }
00933 }
00934 
00935 
00936 void dbg::trace::trace_begin()
00937 {
00938     std::ostream &o = out(dbg::tracing, m_src);
00939     o << indent(tracing);
00940     indent_depth++;
00941     o << TRACE_IN;
00942     if (m_name)
00943     {
00944         o << m_name;
00945     }
00946     else
00947     {
00948         print_pos_short(o, m_pos);
00949     }
00950     if (m_src && strcmp(m_src, ""))
00951     {
00952         o << " (for \"" << m_src << "\")";
00953     }
00954     o << std::endl;
00955 
00956     m_triggered = true;
00957 }
00958 
00959 
00960 void dbg::trace::trace_end()
00961 {
00962     std::ostream &o = out(dbg::tracing, m_src);
00963     indent_depth--;
00964     o << indent(tracing);
00965     o << TRACE_OUT;
00966     if (m_name)
00967     {
00968         o << m_name;
00969     }
00970     else
00971     {
00972         print_pos_short(o, m_pos);
00973     }
00974     if (m_src && strcmp(m_src, ""))
00975     {
00976         o << " (for \"" << m_src << "\")";
00977     }
00978     o << std::endl;
00979 }
00980 
00981 
00982 /******************************************************************************
00983  * Internal implementation
00984  *****************************************************************************/
00985 
00986 namespace
00987 {
00988     /**************************************************************************
00989      * dbg_streambuf
00990      *************************************************************************/
00991 
00992     dbg_streambuf::dbg_streambuf(std::vector<std::ostream*> &o, int bsize)
00993     : ostreams(o)
00994     {
00995         if (bsize)
00996         {
00997             char *ptr = new char[bsize];
00998             setp(ptr, ptr + bsize);
00999         }
01000         else
01001         {
01002             setp(0, 0);
01003         }
01004         setg(0, 0, 0);
01005     }
01006 
01007     dbg_streambuf::~dbg_streambuf()
01008     {
01009         sync();
01010         delete [] pbase();
01011     }
01012 
01013     int dbg_streambuf::overflow(int c)
01014     {
01015         put_buffer();
01016         if (c != EOF)
01017         {
01018             if (pbase() == epptr())
01019             {
01020                 put_char(c);
01021             }
01022             else
01023             {
01024                 sputc(c);
01025             }
01026         }
01027         return 0;
01028     }
01029 
01030     int dbg_streambuf::sync()
01031     {
01032         put_buffer();
01033         return 0;
01034     }
01035 
01036     void dbg_streambuf::put_buffer(void)
01037     {
01038         if (pbase() != pptr())
01039         {
01040             std::vector<std::ostream *>::iterator i = ostreams.begin();
01041             while (i != ostreams.end())
01042             {
01043                 (*i)->write(pbase(), pptr() - pbase());
01044                 ++i;
01045             }
01046             setp(pbase(), epptr());
01047         }
01048     }
01049 
01050     void dbg_streambuf::put_char(int c)
01051     {
01052         std::vector<std::ostream *>::iterator i = ostreams.begin();
01053         while (i != ostreams.end())
01054         {
01055             (**i) << static_cast<char>(c);
01056             ++i;
01057         }
01058     }
01059 
01060 
01061     /**************************************************************************
01062      * dbg_ostream
01063      *************************************************************************/
01064 
01065     void dbg_ostream::add(std::ostream &o)
01066     {
01067         if (std::find(streams.begin(), streams.end(), &o) == streams.end())
01068         {
01069             streams.push_back(&o);
01070         }
01071     }
01072 
01073     void dbg_ostream::remove(std::ostream &o)
01074     {
01075         stream_vec_type::iterator i
01076             = std::find(streams.begin(), streams.end(), &o);
01077         if (i != streams.end())
01078         {
01079             streams.erase(i);
01080         }
01081     }
01082 
01083     void dbg_ostream::clear()
01084     {
01085         streams.clear();
01086     }
01087 
01088 
01089     /**************************************************************************
01090      * source_info
01091      *************************************************************************/
01092 
01093     source_info::source_info(ConstructionStyle cs)
01094     : levels(cs ? source_map[dbg::default_source].levels : 0),
01095       dbg_streams(raw_cast().dbg_streams)
01096     {
01097         if (cs)
01098         {
01099             new (raw_dbg_streams)
01100                 array_type(source_map[dbg::default_source].raw_cast());
01101         }
01102         else
01103         {
01104             new (raw_dbg_streams) array_type;
01105             // add cerr to the error and fatal levels.
01106             add_ostream(dbg::error, std::cerr);
01107             add_ostream(dbg::fatal, std::cerr);
01108         }
01109     }
01110 
01111     source_info::source_info(const source_info &rhs)
01112     : levels(rhs.levels), dbg_streams(raw_cast().dbg_streams)
01113     {
01114         new (raw_dbg_streams) array_type(rhs.raw_cast());
01115     }
01116 
01117     source_info::~source_info()
01118     {
01119         raw_cast().~array_type();
01120     }
01121 
01122     void source_info::enable(dbg::level lvl, bool status)
01123     {
01124         levels &= ~dbg_source_mask(lvl);
01125         if (status)
01126         {
01127             levels |= dbg_source_mask(lvl);
01128         }
01129     }
01130 
01131     void source_info::add_ostream(dbg::level lvl, std::ostream &o)
01132     {
01133         if (lvl == dbg::all)
01134         {
01135             for (unsigned int n = 0; n < NUM_DBG_LEVELS; ++n)
01136             {
01137                 dbg_streams[n].add(o);
01138             }
01139         }
01140         else
01141         {
01142             dbg_streams[lvl].add(o);
01143         }
01144     }
01145 
01146     void source_info::remove_ostream(dbg::level lvl, std::ostream &o)
01147     {
01148         if (lvl == dbg::all)
01149         {
01150             for (unsigned int n = 0; n < NUM_DBG_LEVELS; ++n)
01151             {
01152                 dbg_streams[n].remove(o);
01153             }
01154         }
01155         else
01156         {
01157             dbg_streams[lvl].remove(o);
01158         }
01159     }
01160 
01161     void source_info::clear_ostream(dbg::level lvl)
01162     {
01163         if (lvl == dbg::all)
01164         {
01165             for (unsigned int n = 0; n < NUM_DBG_LEVELS; ++n)
01166             {
01167                 dbg_streams[n].clear();
01168             }
01169         }
01170         else
01171         {
01172             dbg_streams[lvl].clear();
01173         }
01174     }
01175 
01176     std::ostream &source_info::out(dbg::level lvl)
01177     {
01178         if (lvl == dbg::none || !enabled(lvl))
01179         {
01180             return null_ostream;
01181         }
01182         else
01183         {
01184             return dbg_streams[lvl];
01185         }
01186     }
01187 
01188 
01189     /**************************************************************************
01190      * period_data
01191      *************************************************************************/
01192 
01193     period_data::period_data()
01194         : no_triggers(0), triggered_at(STDCLK::clock() - period*2)
01195     {
01196     }
01197 
01198 
01199     /**************************************************************************
01200      * Functions
01201      *************************************************************************/
01202 
01203     void print_pos(std::ostream &out, const dbg::source_pos &where)
01204     {
01205         if (where.file)
01206         {
01207            if (where.func)
01208            {
01209                out << "function: " << where.func << ", ";
01210            }
01211            out << "line: " << where.line << ", file: "    << where.file;
01212         }
01213     }
01214 
01215     void print_pos_short(std::ostream &out, const dbg::source_pos &where)
01216     {
01217         if (where.file)
01218         {
01219            if (where.func)
01220            {
01221                out << where.func << " (" << where.line
01222                    << " in " << where.file << ")";
01223            }
01224            else
01225            {
01226                out << "function at (" << where.line
01227                    << " in "    << where.file << ")";
01228            }
01229         }
01230     }
01231 
01232     void print_period_info(std::ostream &out, const dbg::source_pos &where)
01233     {
01234         if (period)
01235         {
01236             size_t no_triggers = period_map[where].no_triggers;
01237             out << " (triggered " << no_triggers << " time";
01238             if (no_triggers > 1)
01239             {
01240                 out << "s)";
01241             }
01242             else
01243             {
01244                 out << ")";
01245             }
01246         }
01247     }
01248 
01249     void do_assertion_behaviour(dbg::level lvl, constraint_type why,
01250                                 const dbg::source_pos &pos)
01251     {
01252         switch (lvl != dbg::fatal ? behaviour[lvl] : dbg::assertions_abort)
01253         {
01254             case dbg::assertions_abort:
01255             {
01256                 abort();
01257                 break;
01258             }
01259             case dbg::assertions_throw:
01260             {
01261                 switch (why)
01262                 {
01263                     default:
01264                     case why_assertion:
01265                     {
01266                         throw dbg::assertion_exception(pos);
01267                         break;
01268                     }
01269                     case why_sentinel:
01270                     {
01271                         throw dbg::sentinel_exception(pos);
01272                         break;
01273                     }
01274                     case why_unimplemented:
01275                     {
01276                         throw dbg::unimplemented_exception(pos);
01277                         break;
01278                     }
01279                     case why_check_ptr:
01280                     {
01281                         throw dbg::check_ptr_exception(pos);
01282                         break;
01283                     }
01284                 }
01285                 break;
01286             }
01287             case dbg::assertions_continue:
01288             default:
01289             {
01290                 break;
01291             }
01292         }
01293     }
01294 
01295     void do_prefix(dbg::level lvl, std::ostream &s)
01296     {
01297         if (time_prefix)
01298         {
01299             STDCLK::time_t t = STDCLK::time(0);
01300             if (t != -1)
01301             {
01302                 s << std::string(STDCLK::ctime(&t), 24) << ": ";
01303             }
01304         }
01305         if (level_prefix)
01306         {
01307             switch (lvl)
01308             {
01309                 case dbg::info:    { s << "   info: "; break; }
01310                 case dbg::warning: { s << "warning: "; break; }
01311                 case dbg::error:   { s << "  error: "; break; }
01312                 case dbg::fatal:   { s << "  fatal: "; break; }
01313                 case dbg::tracing: { s << "  trace: "; break; }
01314                 case dbg::debug:   { s << "  debug: "; break; }
01315                 case dbg::none:    {                   break; }
01316                 case dbg::all:     { s << "    all: "; break; }
01317             }
01318         }
01319     }
01320 
01321     bool period_allows_impl(const dbg::source_pos &where)
01322     {
01323         period_data &data = period_map[where];
01324         data.no_triggers++;
01325         if (data.triggered_at < STDCLK::clock() - period)
01326         {
01327             data.triggered_at = STDCLK::clock();
01328             return true;
01329         }
01330         else
01331         {
01332             return false;
01333         }
01334     }
01335 
01336     void determine_source(dbg::dbg_source &src, const dbg::source_pos &here)
01337     {
01338         if (!src) src = "";
01339         if (src == "" && here.src)
01340         {
01341            src = here.src;
01342         }
01343     }
01344 }

Generated on Tue Sep 18 04:17:35 2007 for libdbg by  doxygen 1.5.3