/* Principles Applications are using debug_printf to print various debugging information. A --debug option allows the user to turn the debugging on an off. This strategy has been used everywhere. Generally, as the number of debugging messages grows, developpers are adding some ways to filter them out. One way is the debug level. Less important debugging info are not shown. As the number of message grows, this is getting more and more difficult to select the appropriate debuging information. We are proposing a different scheme. Every debugging message is associated with some key. The key is either supplied to the debug_printf function (first argument) or the key is supplied using a DEBUG_CONTEXT object. When a DEBUG_CONTEXT exists, all debug_printf executed are associated with a given key. Using the --debugpath option, one can select which keys are enabled (producing debugging output). */ #include #include #include #include #include #include #include "tlmplib.h" #include "tlmplib.m" #include #include #include #include using namespace std; static DEBUG_KEY *first = NULL; int debug_keys () { DEBUG_KEY *pt = first; while (pt != NULL){ printf ("%-20s %s\n",pt->getkey(),pt->getdesc()); pt = pt->getnext(); } exit (1); return 0; } static set paths; /* Record a path to filter debugging messages. */ int debug_setpath(const char *val) { // fprintf (stderr,"setpath :%s:\n",val); paths.insert (val); return 0; } static FILE *fdebug = stderr; /* Record the debug file. By default debugging messages are going to stderr. */ int debug_setfdebug (const char *f) { if (fdebug != stderr) fclose (fdebug); fdebug = fopen64 (f,"a"); if (fdebug == NULL){ fprintf (stderr,"Can't open debug file %s (%s), using stderr\n",f,strerror(errno)); fdebug = stderr; } return 0; } static TLMP_OPTION opt ("debug",P_MSG_U(I_DEBUG,"Turn on debugging")); /* Turn on debugging */ void debug_seton() { opt.setval(NULL); } static SSTRINGS keys; static TLMP_OPTION showk ("debugkeys",P_MSG_U(I_DEBUGKEYS,"List debug keys") ,debug_keys); static TLMP_OPTION optk ("debugpath",P_MSG_U(I_DEBUGPATH,"Filter debugging") ,debug_setpath); static TLMP_OPTION optf ("debugfile",P_MSG_U(I_DEBUGFILE,"Send debugging to a file") ,debug_setfdebug); class DEBUG_KEY_private{ public: SSTRING key; SSTRING desc; DEBUG_KEY *next; DEBUG_KEY_private(const char *_key, const char *_desc, DEBUG_KEY *obj) { key = _key; desc = _desc; next = first; first = obj; } }; PUBLIC DEBUG_KEY::DEBUG_KEY(const char *key, const char *desc) { priv = new DEBUG_KEY_private (key,desc,this); } PUBLIC DEBUG_KEY::~DEBUG_KEY() { DEBUG_KEY **prev = &first; while (*prev != NULL){ if (*prev == this){ *prev = priv->next; break; } } delete priv; } PUBLIC const char *DEBUG_KEY::getkey() const { return priv->key.get(); } PUBLIC const char *DEBUG_KEY::getdesc() const { return priv->desc.get(); } PUBLIC DEBUG_KEY *DEBUG_KEY::getnext() const { return priv->next; } static stack ctxs; static bool context_match=false; class DEBUG_CONTEXT_private{ }; static void push_check (const char *name) { if (ctxs.size() > 0){ string n = ctxs.top() + "/" + name; ctxs.push (n); if (paths.count(n) > 0){ context_match = true; } }else{ ctxs.push(name); if (paths.count(name) > 0){ context_match = true; } } } PUBLIC DEBUG_CONTEXT::DEBUG_CONTEXT(const DEBUG_KEY &key) { priv = NULL; if (opt.ison()){ push_check(key.getkey()); } } PUBLIC DEBUG_CONTEXT::DEBUG_CONTEXT(const char *ctl, ...) { priv = NULL; if (opt.ison()){ va_list list; va_start (list,ctl); char buf[2000]; vsnprintf (buf,sizeof(buf)-1,ctl,list); va_end (list); push_check (buf); } } PUBLIC DEBUG_CONTEXT::~DEBUG_CONTEXT() { delete priv; if (opt.ison()){ ctxs.pop(); context_match = false; if (ctxs.size() > 0){ if (paths.count(ctxs.top())>0) context_match = true; } } } static void debug_printpath() { if (ctxs.size() > 0){ fprintf (fdebug,"%s: ",ctxs.top().c_str()); } } void debug_printf (const char *ctl, ...) { if (opt.ison()){ if (paths.size()== 0 || context_match){ debug_printpath(); va_list list; va_start (list,ctl); vfprintf (fdebug,ctl,list); va_end (list); } } } void debug_printf (const DEBUG_KEY &key, const char *ctl, ...) { if (opt.ison()){ DEBUG_CONTEXT c(key); if (paths.size()==0 || context_match){ debug_printpath(); va_list list; va_start (list,ctl); vfprintf (fdebug,ctl,list); va_end (list); } } }