Main Page   Namespace List   Alphabetical List   Compound List   File List   Compound Members   File Members  

debug.cpp

Go to the documentation of this file.
00001 /* Reference : A Handy Debugger Class by Maurice Fox, C/C++ Users Journal Apr 2001
00002    Copyright (C) Maurice J. Fox 2000 - 2003
00003    Copyright (C) Kwee Heong Tan 2002 - 2003
00004    Permission is granted to use this code without restriction as
00005    long as this copyright notice appears in all source files.
00006 */
00007 // $Id: Debug.cpp,v 1.16 2002/11/21 17:52:42 khtan Exp khtan $
00008 #include "Debug.h"
00009 #include <algorithm>
00010 // Added enhancements turned on with preprocessor defines
00011 
00012 #ifdef STL96
00013    #define CLEAR(name) name.erase(name.begin(),name.end());
00014    extern "C" {
00015       int ftime(struct timeb *timeptr);
00016    }
00017 #else
00018    using namespace std;
00019    #define CLEAR(name) name.clear()
00020 #endif
00021 
00022 #ifdef TESTING
00023 static void f1(void);
00024 static void f2(void);
00025 int main( int argc, char * argv[] ) {
00026     Debug D("main");
00027     float pi = (float)3.14;
00028     int   i = 1999;
00029     char String[] = "This is a testing string ";
00030 
00031     for(int j = 1; j < argc; j++) {
00032       Debug::specify(argv[j]);
00033       D.Dbg("argv[j]",argv[j]);
00034       D.Dbg("float", pi);
00035       D.Dbg("integer", i);
00036       D.Dbg("string", String, i);
00037       f1();
00038     }
00039     return 0;
00040 }
00041 
00042 static void f1() {
00043     Debug D("f1");
00044     D.Dbg("string","f1's string");
00045     D.Sync();
00046     D.Dbg("string","string one ", "string two");
00047     f2();
00048 }
00049 
00050 static void f2() {
00051     Debug D("f2");
00052     D.Dbg("string","f2's string");
00053     D.Dbg("integer","This is an unsigned hex one ", static_cast<unsigned long>(0XDEADBEEF));
00054     D.Dbg("integer","This is a regular integer ", static_cast<int>(0XDEADBEEF));
00055     //    D.TimeEnd("bogus,once","This has no preceding TimeStart call");
00056     //    D.TimeEnd("once","This is in f2");
00057     D.Dbg("bogus,fred,fork,a,string,integer","a string");
00058     Debug::Sync();
00059     //sleep(1);
00060 }
00061 #endif // TESTING
00062 
00063 #ifndef DEBUG_OFF
00064     // Static members
00065 int Debug::level = 0;
00066 bool Debug::Debugging = false;
00067 bool Debug::Tracing = false;
00068 bool Debug::Timing = false;
00069 STD ofstream* Debug::pFile=NULL;
00070 STD ostream* Debug::pDebugStream=&clog; // default on startup, use clog
00071 
00072 char Debug::separator = '?';
00073 
00074 char Debug::mybuff[200];
00075 string Debug::filename;
00076 
00077 vector<string> Debug::keywords;
00078 vector<string> Debug::functions;
00079 vector<string> Debug::timekeys;
00080 vector<pair<string, struct timeb> > Debug::timers;
00081 
00082 Debug::Debug(const char* f,bool rawtimeMode,bool bEndLine) :
00083 function_name(f), timing(rawtimeMode),raw_time(rawtimeMode),going_in(rawtimeMode)
00084 {
00085     level++;
00086     if(tracing(function_name)) 
00087         Enter(bEndLine);
00088     going_in=false;
00089 }
00090 Debug::~Debug() {
00091         if(tracing(function_name)) Exit();
00092         level--;
00093 }
00094 
00095 bool Debug::tracing(const string & f) {
00096     if(!Tracing) return false;
00097     
00098     return (functions.empty() || 
00099     find(functions.begin(),functions.end(),f) != functions.end());
00100 }
00101 
00102 bool Debug::debugging(const string & k) {
00103     if(!Debugging) return false;
00104 
00105 #if defined DEBUG_MULT_KWDS
00106     if( keywords.empty()) return true;
00107     string::size_type start, end;
00108     string kw;
00109     start = 0;
00110     do {// This is the beginning of a do-while loop
00111         // Look for a comma delimiting an internal keyword
00112         // We are assuming well-formed multiple keywords - 
00113         // no leading, trailing, or multiple commas.
00114         end = k.find(',', start);
00115         if( end == string::npos ) {
00116             // Assign the rest of k to kw.  This could be all of k
00117             // when start is still 0.
00118             kw = k.substr(start);
00119         } else {
00120             // Assign the substring just found to kw, adjust start point 
00121             kw = k.substr(start,end-start);
00122             start = end + 1;
00123         }
00124         if(find(keywords.begin(),keywords.end(),kw) != keywords.end()) {
00125             return true;
00126         }
00127     } while( end != string::npos );
00128     return false;
00129 #else
00130     return (keywords.empty() || 
00131     find(keywords.begin(),keywords.end(),k) != keywords.end());
00132 #endif
00133 }
00134 
00135 bool Debug::IntTiming(const string & t) {
00136     if(!Timing) return false;
00137 
00138 #if defined DEBUG_MULT_KWDS
00139     if( timekeys.empty()) return true;
00140     string::size_type start, end;
00141     string kw;
00142     start = 0;
00143     do {// This is the beginning of a do-while loop
00144         // Look for a comma delimiting an internal keyword
00145         // We are assuming well-formed multiple keywords - 
00146         // no leading, trailing, or multiple commas.
00147         end = t.find(',', start);
00148         if( end == string::npos ) {
00149             // Assign the rest of t to kw.  This could be all of t
00150             // when start is still 0.
00151             kw = t.substr(start);
00152         } else {
00153             // Assign the substring just found to kw, adjust start point 
00154             kw = t.substr(start,end-start);
00155             start = end + 1;
00156         }
00157         if(find(timekeys.begin(),timekeys.end(),kw) != timekeys.end()) {
00158             return true;
00159         }
00160     } while( end != string::npos );
00161     return false;
00162 #else
00163     return(timekeys.empty() ||
00164     find(timekeys.begin(),timekeys.end(),t) != timekeys.end());
00165 #endif
00166 }
00167 void Debug::Enter(bool bEndLine){
00168   string sBuffer;
00169   for(int i = 1; i < (level < limit ? level : limit) ; i++ ){
00170     sBuffer+="  ";
00171   }
00172 #if defined(EMACS_OUTLINE) // not handling level > limit case
00173   sBuffer.replace(0,level-1,level-1,'*');
00174 #endif//EMACS_OUTLINE
00175 
00176   (*pDebugStream) << sBuffer;
00177   (*pDebugStream) << "=> " << function_name << time_stuff();
00178   if(bEndLine) (*pDebugStream) << "\n";
00179 }
00180 void Debug::Exit(){
00181     for(int i = 1; i < (level < limit ? level : limit) ; i++ )
00182     (*pDebugStream) << "  ";
00183 
00184     (*pDebugStream) << "<= " << function_name << time_stuff() << "\n";
00185 }
00186 char * Debug::time_stuff() {
00187     if(!timing) return "";
00188 
00189     if(raw_time) {
00190         struct timeb Tb;
00191         ftime(&Tb);
00192         if(going_in) {
00193             sprintf(mybuff, " %ld.%03d",Tb.time, Tb.millitm);
00194             Start = Tb;
00195         } else {
00196             long int secs, millis;
00197             millis = Tb.millitm - Start.millitm;
00198             secs = Tb.time - Start.time;
00199             if(millis < 0) {
00200                 millis += 1000;
00201                 -- secs;
00202             }
00203             sprintf(mybuff, "         %ld.%03ld", secs, millis);
00204         }
00205 
00206     } else { // Cooked time
00207         time_t Clock;
00208         time(&Clock);
00209         sprintf(mybuff," %s", asctime(localtime(&Clock)));
00210         mybuff[strlen(mybuff)-1] = '\0';
00211     }
00212     return mybuff;
00213 }
00214 
00215 void Debug::indent() {
00216     if( Tracing ) {
00217         for( int i = 0; i <= (level < (limit + 1) ? level : (limit + 1)); i++ ) 
00218         (*pDebugStream) << "  ";
00219     }
00220 }
00221 void Debug::Dbg(const std::string& keyword, const std::string& description, char* pC){
00222   // cout << "-print char*\n";
00223   if(!debugging(keyword)) return;
00224   indent();
00225   if(NULL==pC){
00226     (*pDebugStream) << keyword << ": "<< description << " = NULL\n";
00227   }else{
00228     (*pDebugStream) << keyword << ": "<< description << " = " << pC << "\n";
00229   }
00230 };
00231 void Debug::Dbg(const std::string& keyword, char* pC){
00232   // cout << "-print char*\n";
00233   if(!debugging(keyword)) return;
00234   indent();
00235   if(NULL==pC){
00236     (*pDebugStream) << keyword << ": NULL\n";
00237   }else{
00238     (*pDebugStream) << keyword << ": "<< pC << "\n";
00239   }
00240 };
00241 
00242 void Debug::TimeStart(const string &t, const char *s) {
00243     if(!IntTiming(t)) return;
00244     
00245     unsigned int i = 0;
00246     for(i = 0; i < timers.size(); i++) {
00247         if(timers[i].first == t) break;
00248     }
00249     timeb tb;
00250     ftime(&tb);
00251     if( i == timers.size()) {  // Not found, so put one in.
00252         timers.push_back(make_pair(t,tb));
00253     } else {
00254         timers[i].second = tb;
00255     }
00256     sprintf(mybuff," %ld.%03d", tb.time, tb.millitm);
00257 
00258     indent();
00259     (*pDebugStream) << t << ": " << s << mybuff << "\n";
00260 }
00261     
00262 void Debug::TimeEnd(const string &t, const char *s) {
00263     if(!IntTiming(t)) return;
00264     
00265     unsigned int i = 0;
00266     for(i = 0; i < timers.size(); i++) {
00267         if(timers[i].first == t) break;
00268     }
00269     timeb tb;
00270     ftime(&tb);
00271     if( i == timers.size()) { // Not found!
00272         // This puts an entry in the timers vector
00273         // it won't be very informative, but it keeps
00274         // things going OK.
00275         timers.push_back(make_pair(t,tb));
00276     }
00277     // i now has the index of our timer in the vector
00278 
00279     int secs, millis;
00280     millis = tb.millitm - timers[i].second.millitm;
00281     secs = tb.time - timers[i].second.time;
00282     if(millis < 0) {
00283         millis += 1000;
00284         --secs;
00285     }
00286     sprintf(mybuff, " %d.%03d", secs, millis);
00287 
00288     indent();
00289     (*pDebugStream) << t << ": " << s << mybuff << "\n";
00290 }
00291 
00292 void Debug::Sync() {
00293     pDebugStream->flush();
00294 }
00295     
00296 /***********************************
00297 * Debug::specify()
00298 * Extracts options and keywords from a Debug specification string
00299 * and deals with them "appropriately."
00300 * 
00301 * PSEUDOCODE:
00302 * look for an option
00303 * while(there is an option)
00304 *   look for next option or end of string
00305 *   look for a keyword in the substring thus found
00306 *   while(where is a keyword)
00307 *       depending upon the option found
00308 *       save the keyword OR
00309 *       extract and save some value OR
00310 *       ignore the keyword
00311 *       look for a keyword
00312 *   end while
00313 * end while
00314 *
00315 * Option strings have the form
00316 * L:keyword,keyword,L:keyword,keyword,
00317 * L:L:keyword,keyword
00318 * L:L:,keyword
00319 * etc.  Terminating commas are optional
00320 * Leading commas are harmless.
00321 **************************************/
00322 void Debug::specify(const char * opt) {
00323   string s = opt;
00324 
00325   // Find options
00326   unsigned int j = s.find_first_of(separator,0);
00327   while(j < s.length()) {  // Option found
00328     // j points to the separator at the end of this option
00329 
00330     unsigned int k = s.find_first_of(separator,j+1);
00331     // k now points to the separator at the end of the next option
00332     // or to outer space
00333         
00334     string Option;
00335     if(j == 0) {
00336       Option = "0";
00337       Option += s[0];
00338     } else {
00339       Option = string(s,j-1,2);
00340     }
00341         
00342     // Find keywords
00343     unsigned int l = s.find_first_of(',',j+1);
00344 
00345     // Deal with the case of no comma, like F:keywordD: or
00346     // F:keyword
00347     if((l >= k) && (j < k-2)) {
00348       if( k > s.length() ) // No trailing option
00349         l = s.length();
00350       else l = k-1;    // Trailing option is found
00351     }
00352     while(l < k) {  // keyword found
00353       string kw;
00354       if(j+1 < l ) {
00355         kw = string(s,j+1,l-j-1);
00356       } else {
00357         kw = "";
00358       }
00359 
00360       if( l < s.length() ) {
00361             
00362         j = l;  // Advance to virtual ( or real ) comma.
00363         unsigned int m = s.find_first_of(',',l+1);
00364 
00365         // Again, what if there's no trailing comma in a
00366         // sequence of keywords like F:abcd,efgh,ijklD:
00367         // or F:a,b,c,d
00368         if((m >= k) && (j < k-1)) {
00369           if( (m > s.length()) && ( k > s.length()))
00370             m = s.length();
00371           else m = k-1;
00372         }
00373         l = m;
00374       } else l = k;  // Bail out of the loop
00375 
00376       // This is where we deal with the keywords and options
00377       switch(Option[0]) {
00378       case 'D':    // Turn debugging on
00379         if(kw.length()) keywords.push_back(kw);
00380         break;
00381 
00382       case 'O':   // Changing output, maybe
00383 #ifdef STL96
00384           if(!( (! kw.length()) || kw==filename)) {
00385 #else
00386           if(kw.length() && kw != filename) {
00387 #endif
00388             filename = kw;
00389             if( kw == "-"){
00390               pDebugStream=&cout;
00391             }else{ 
00392               if(kw == "--") {
00393                 pDebugStream=&clog;
00394               }else{
00395                 if(NULL!=pFile){
00396                   delete pFile;
00397                   pFile=NULL;
00398                 }
00399                 pFile=new(ofstream);
00400                 pFile->open(filename.c_str(),ios::app);
00401                 pDebugStream=pFile;
00402               }
00403             }
00404           }
00405           break;
00406 
00407         case 'T':    // Turn tracing on
00408           if(kw.length()) functions.push_back(kw);
00409           break;
00410 
00411         case 'M':    // Turn interval timing on
00412           if(kw.length()) timekeys.push_back(kw);
00413           break;
00414 
00415         default:       // Ignore other options silently
00416           break;
00417         }
00418       } // end of loop on finding keywords
00419       // This is where we complete dealing with options
00420       switch(Option[0]) {
00421       case 'D':    // Turn debugging on
00422         Debugging = true;
00423         break;
00424 
00425       case 'd':       // Turn debugging off
00426         CLEAR(keywords);
00427         Debugging = false;
00428         break;
00429 
00430       case 'O':   // Changing output, maybe - khtan : no longer needed
00431         break;
00432 
00433       case 'T':    // Turn tracing on
00434         Tracing = true;
00435         break;
00436 
00437       case 't':       // Turn tracing off
00438             CLEAR(functions);
00439         Tracing = false;
00440         break;
00441             
00442       case 'M':       // Turn interval timing on
00443         Timing = true;
00444         break;
00445 
00446       case 'm':       // Turn interval timing off
00447             CLEAR(timekeys);
00448         CLEAR(timers);
00449         Timing = false;
00450         break;
00451 
00452       default:       // Ignore other options silently
00453         break;
00454       }
00455       j = k; // Advance to next option
00456     } // end of loop on finding options
00457 }
00458 #endif // ndef DEBUG_OFF

Generated on Mon Jan 20 11:54:25 2003 for ATPG by doxygen1.3-rc1