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