1 /*
2  *  Debugging macros, DUK_DPRINT() and its variants in particular.
3  *
4  *  DUK_DPRINT() allows formatted debug prints, and supports standard
5  *  and Duktape specific formatters.  See duk_debug_vsnprintf.c for details.
6  *
7  *  DUK_D(x), DUK_DD(x), and DUK_DDD(x) are used together with log macros
8  *  for technical reasons.  They are concretely used to hide 'x' from the
9  *  compiler when the corresponding log level is disabled.  This allows
10  *  clean builds on non-C99 compilers, at the cost of more verbose code.
11  *  Examples:
12  *
13  *    DUK_D(DUK_DPRINT("foo"));
14  *    DUK_DD(DUK_DDPRINT("foo"));
15  *    DUK_DDD(DUK_DDDPRINT("foo"));
16  *
17  *  This approach is preferable to the old "double parentheses" hack because
18  *  double parentheses make the C99 solution worse: __FILE__ and __LINE__ can
19  *  no longer be added transparently without going through globals, which
20  *  works poorly with threading.
21  */
22 
23 #if !defined(DUK_DEBUG_H_INCLUDED)
24 #define DUK_DEBUG_H_INCLUDED
25 
26 #if defined(DUK_USE_DEBUG)
27 
28 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
29 #define DUK_D(x) x
30 #else
31 #define DUK_D(x) do { } while (0) /* omit */
32 #endif
33 
34 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
35 #define DUK_DD(x) x
36 #else
37 #define DUK_DD(x) do { } while (0) /* omit */
38 #endif
39 
40 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
41 #define DUK_DDD(x) x
42 #else
43 #define DUK_DDD(x) do { } while (0) /* omit */
44 #endif
45 
46 /*
47  *  Exposed debug macros: debugging enabled
48  */
49 
50 #if defined(DUK_USE_VARIADIC_MACROS)
51 
52 /* Note: combining __FILE__, __LINE__, and __func__ into fmt would be
53  * possible compile time, but waste some space with shared function names.
54  */
55 #define DUK__DEBUG_LOG(lev,...)  duk_debug_log((duk_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__);
56 
57 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
58 #define DUK_DPRINT(...)          DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__)
59 #else
60 #define DUK_DPRINT(...)
61 #endif
62 
63 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
64 #define DUK_DDPRINT(...)         DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__)
65 #else
66 #define DUK_DDPRINT(...)
67 #endif
68 
69 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
70 #define DUK_DDDPRINT(...)        DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__)
71 #else
72 #define DUK_DDDPRINT(...)
73 #endif
74 
75 #else  /* DUK_USE_VARIADIC_MACROS */
76 
77 #define DUK__DEBUG_STASH(lev)    \
78 	(void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \
79 	(void) (duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
80 	(void) (duk_debug_line_stash = (duk_int_t) DUK_LINE_MACRO), \
81 	(void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \
82 	(void) (duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
83 	(void) (duk_debug_level_stash = (lev))
84 
85 /* Without variadic macros resort to comma expression trickery to handle debug
86  * prints.  This generates a lot of harmless warnings.  These hacks are not
87  * needed normally because DUK_D() and friends will hide the entire debug log
88  * statement from the compiler.
89  */
90 
91 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
92 #define DUK_DPRINT  DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log  /* args go here in parens */
93 #else
94 #define DUK_DPRINT  0 && /* args go here as a comma expression in parens */
95 #endif
96 
97 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
98 #define DUK_DDPRINT  DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log  /* args go here in parens */
99 #else
100 #define DUK_DDPRINT  0 && /* args */
101 #endif
102 
103 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
104 #define DUK_DDDPRINT  DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log  /* args go here in parens */
105 #else
106 #define DUK_DDDPRINT  0 && /* args */
107 #endif
108 
109 #endif  /* DUK_USE_VARIADIC_MACROS */
110 
111 #else  /* DUK_USE_DEBUG */
112 
113 /*
114  *  Exposed debug macros: debugging disabled
115  */
116 
117 #define DUK_D(x) do { } while (0) /* omit */
118 #define DUK_DD(x) do { } while (0) /* omit */
119 #define DUK_DDD(x) do { } while (0) /* omit */
120 
121 #if defined(DUK_USE_VARIADIC_MACROS)
122 
123 #define DUK_DPRINT(...)
124 #define DUK_DDPRINT(...)
125 #define DUK_DDDPRINT(...)
126 
127 #else  /* DUK_USE_VARIADIC_MACROS */
128 
129 #define DUK_DPRINT    0 && /* args go here as a comma expression in parens */
130 #define DUK_DDPRINT   0 && /* args */
131 #define DUK_DDDPRINT  0 && /* args */
132 
133 #endif  /* DUK_USE_VARIADIC_MACROS */
134 
135 #endif  /* DUK_USE_DEBUG */
136 
137 /*
138  *  Structs
139  */
140 
141 #if defined(DUK_USE_DEBUG)
142 struct duk_fixedbuffer {
143 	duk_uint8_t *buffer;
144 	duk_size_t length;
145 	duk_size_t offset;
146 	duk_bool_t truncated;
147 };
148 #endif
149 
150 /*
151  *  Prototypes
152  */
153 
154 #if defined(DUK_USE_DEBUG)
155 DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap);
156 #if 0  /*unused*/
157 DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...);
158 #endif
159 DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size);
160 
161 #if defined(DUK_USE_VARIADIC_MACROS)
162 DUK_INTERNAL_DECL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...);
163 #else  /* DUK_USE_VARIADIC_MACROS */
164 /* parameter passing, not thread safe */
165 #define DUK_DEBUG_STASH_SIZE  128
166 #if !defined(DUK_SINGLE_FILE)
167 DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
168 DUK_INTERNAL_DECL duk_int_t duk_debug_line_stash;
169 DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
170 DUK_INTERNAL_DECL duk_int_t duk_debug_level_stash;
171 #endif
172 DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...);
173 #endif  /* DUK_USE_VARIADIC_MACROS */
174 
175 DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length);
176 DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x);
177 DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x);
178 DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...);
179 DUK_INTERNAL_DECL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size);
180 DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
181 
182 #endif  /* DUK_USE_DEBUG */
183 
184 #endif  /* DUK_DEBUG_H_INCLUDED */
185