summaryrefslogtreecommitdiff
path: root/debug.h
blob: 7fb97c7f466eaca5929a27855c94de2a593b922e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#ifndef _DEBUG_H
#define _DEBUG_H

#define DEVELOPER   4
#define ALPHA       3
#define BETA        2
#define RELEASE     1
#define NO_SEATBELT 0

#ifndef RELEASE_LEVEL
#define RELEASE_LEVEL RELEASE
#endif

#if RELEASE_LEVEL >= ALPHA
#include <cstdlib>              // for `getenv'
#include <cstring>              // for `strcmp'
#endif

#if RELEASE_LEVEL >= BETA
#include <cassert>
#endif

#if RELEASE_LEVEL >= RELEASE
#include <iostream>
#endif

#include <sstream>              // used for constructing exceptions

namespace ledger {

//////////////////////////////////////////////////////////////////////
//
// Debugging facilities for Ledger
//
// - In developer level, all checking and debugging facilities are
//   active.
//
// - Alpha level does not include performance degrading
//   VALIDATE calls.
//
// - Beta level is like Alpha, but does not include debugging
//   facilities.
//
// - Release level does not include CONFIRM checks, but does include
//   assert calls.
//
// - Running with no seatbelt disables all checking except for normal
//   syntax and semantic error checking.

#define WARN(x)							\
  if (ledger::warning_stream)					\
    *ledger::warning_stream << "Warning: "<< x << std::endl

#define ERR(exc, x) {				\
    std::ostringstream s;                       \
    s << x;                                     \
    throw exc(s.str().c_str());                 \
  }

#if RELEASE_LEVEL >= ALPHA

#include <pcre.h>
#include <cstring>

#define DEBUG_ENABLED

extern std::ostream * warning_stream;
extern std::ostream * debug_stream;
extern bool           free_debug_stream;

inline bool _debug_active(const char * const cls) {
  if (char * debug = std::getenv("DEBUG_CLASS")) {
    static const char * error;
    static int	  erroffset;
    static int	  ovec[30];
    static pcre * class_regexp = pcre_compile(debug, PCRE_CASELESS,
					      &error, &erroffset, NULL);
    return pcre_exec(class_regexp, NULL, cls, std::strlen(cls),
		     0, 0, ovec, 30) >= 0;
  }
  return false;
}

#define DEBUG_CLASS(cls) static const char * const _debug_cls = (cls)

#define DEBUG(cls) (ledger::_debug_active(cls))
#define DEBUG_() DEBUG(_debug_cls)

#define DEBUG_PRINT(cls, x)					\
  if (ledger::debug_stream && ledger::_debug_active(cls)) {	\
    *ledger::debug_stream << x << std::endl;			\
  }
#define DEBUG_PRINT_(x) DEBUG_PRINT(_debug_cls, x)

#define DEBUG_PRINT_TIME(cls, x) {			\
  char buf[256];					\
  std::strftime(buf, 255, "%Y/%m/%d", std::gmtime(&x));	\
  DEBUG_PRINT(cls, #x << " is " << buf);		\
}

#define DEBUG_PRINT_TIME_(x) DEBUG_PRINT_TIME(_debug_cls, x)

#define CONFIRM(x) assert(x)

#if RELEASE_LEVEL == DEVELOPER
#define VALIDATE(x) assert(x)
#else
#define VALIDATE(x)
#endif

#else // RELEASE_LEVEL

#define DEBUG_CLASS(cls)
#define DEBUG(cls) 0
#define DEBUG_() 0
#define DEBUG_PRINT(cls, x)
#define DEBUG_PRINT_(x)

#define VALIDATE(x)

#if RELEASE_LEVEL == NO_SEATBELT

#undef assert
#define assert(x)
#define CONFIRM(x)

#elif RELEASE_LEVEL >= RELEASE

extern std::ostream * warning_stream;
#define CONFIRM(x)

#elif RELEASE_LEVEL >= BETA

#define CONFIRM(x) assert(x)

#endif

#endif // RELEASE_LEVEL

} // namespace ledger

#endif // _DEBUG_H