/* debug.h -- declarations for debugging
   $Id: debug.h,v 1.12 2002/08/22 22:13:58 awm Exp $

   Dan Pelleg
*/

#ifndef DEBUG_H
#define DEBUG_H

#include <stdio.h>

#define BUFLEN (512)
#define MSG_SIZE (512)
#define DBG_COUNTER_NUM (10)

extern int debug_level;
extern int dbg_counter[DBG_COUNTER_NUM];

void get_debug_flags_from_names(const char *const flag_names[], int argc, char *argv[]);

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void panic(const char *function_name, const char *format, ...);
void dbg_printf(const char *format, ...);
#ifdef __cplusplus
}

#endif /* __cplusplus */

#ifdef NINSTR

#define INSTR_COUNTER_INC(i)      /* nothing */
#define INSTR_RESET_COUNTER(i)    /* nothing */
#define INSTR_COUNTER_VAL(i)      /* nothing */
#define INSTR_FLAG(lvl) (0)
#define INSTR_PRINTF(level, x)    /* nothing */

#else							/* NINSTR */

#define INSTR_COUNTER_INC(i)     dbg_counter[i]++
#define INSTR_RESET_COUNTER(i)   dbg_counter[i] = 0
#define INSTR_COUNTER_VAL(i)     dbg_counter[i]
#define INSTR_FLAG(lvl) (debug_level & (1 << lvl))
#define INSTR_PRINTF(level, x) \
    if (INSTR_FLAG(level))     \
	  dbg_printf x;

#endif                          /* NINSTR */

#ifdef AMFAST
#define NDEBUG
#endif   /* AMFAST */

#ifdef NDEBUG 
#define DEBUG_FLAG(lvl) (0)
#define DEBUG_SET(lvl)			/* nothing */
#define DEBUG_CLEAR(lvl)		/* nothing */
#define DBG_PRINTF(level, x)    /* nothing */
#ifdef __cplusplus

#include <fstream.h>
class omanip_dbg {
public:
  omanip_dbg(ostream & (*ff)(ostream &, int), int lvl):
	f(ff), level(lvl) {}
  friend ostream &operator<<(ostream &os, omanip_dbg d)
  { return d.f(os, d.level); }
  friend ostream &filtermask(ostream &, int);
  static int debug_level;
private:
  ostream & (*f)(ostream &, int);
  int level;
  static ofstream cnull;				/* a stream which ignores all sent to it */
};

inline ostream &filtermask(ostream &os, int lvl)
{
  if(DEBUG_FLAG(lvl))
	return os;
  else
	return omanip_dbg::cnull;
}

inline omanip_dbg mask(int lvl) {
  return omanip_dbg(&filtermask, lvl);
}
#endif /* __cplusplus */

#else							/* NDEBUG */
#define DEBUG_FLAG(lvl) (debug_level & (1 << lvl))
#define DEBUG_SET(lvl) (debug_level |= (1 << lvl))
#define DEBUG_CLEAR(lvl) (debug_level &= (-1 ^ (1 << lvl)))
#define DBG_PRINTF(level, x) \
    if (DEBUG_FLAG(level))     \
	  dbg_printf x;

#ifdef __cplusplus
#include <fstream.h>
class omanip_dbg {
public:
  omanip_dbg(ostream & (*ff)(ostream &, int), int lvl):
	f(ff), level(lvl) {}
  friend ostream &operator<<(ostream &os, omanip_dbg d)
  { return d.f(os, d.level); }
  friend ostream &filtermask(ostream &, int);
  static int debug_level;
private:
  ostream & (*f)(ostream &, int);
  int level;
  static ofstream cnull;				/* a stream which ignores all sent to it */
};

inline ostream &filtermask(ostream &os, int lvl)
{
  if(DEBUG_FLAG(lvl))
	return os;
  else
	return omanip_dbg::cnull;
}

inline omanip_dbg mask(int lvl) {
  return omanip_dbg(&filtermask, lvl);
}
#endif /* __cplusplus */

#endif /* NDEBUG */

#endif /* DEBUG_H */
