| /* |
| * Debugging macros, DUK_DPRINT() and its variants in particular. |
| * |
| * DUK_DPRINT() allows formatted debug prints, and supports standard |
| * and Duktape specific formatters. See duk_debug_vsnprintf.c for details. |
| * |
| * DUK_D(x), DUK_DD(x), and DUK_DDD(x) are used together with log macros |
| * for technical reasons. They are concretely used to hide 'x' from the |
| * compiler when the corresponding log level is disabled. This allows |
| * clean builds on non-C99 compilers, at the cost of more verbose code. |
| * Examples: |
| * |
| * DUK_D(DUK_DPRINT("foo")); |
| * DUK_DD(DUK_DDPRINT("foo")); |
| * DUK_DDD(DUK_DDDPRINT("foo")); |
| * |
| * This approach is preferable to the old "double parentheses" hack because |
| * double parentheses make the C99 solution worse: __FILE__ and __LINE__ can |
| * no longer be added transparently without going through globals, which |
| * works poorly with threading. |
| */ |
| |
| #ifndef DUK_DEBUG_H_INCLUDED |
| #define DUK_DEBUG_H_INCLUDED |
| |
| #ifdef DUK_USE_DEBUG |
| |
| #if defined(DUK_USE_DPRINT) |
| #define DUK_D(x) x |
| #else |
| #define DUK_D(x) do { } while (0) /* omit */ |
| #endif |
| |
| #if defined(DUK_USE_DDPRINT) |
| #define DUK_DD(x) x |
| #else |
| #define DUK_DD(x) do { } while (0) /* omit */ |
| #endif |
| |
| #if defined(DUK_USE_DDDPRINT) |
| #define DUK_DDD(x) x |
| #else |
| #define DUK_DDD(x) do { } while (0) /* omit */ |
| #endif |
| |
| /* |
| * Exposed debug macros: debugging enabled |
| */ |
| |
| #define DUK_LEVEL_DEBUG 1 |
| #define DUK_LEVEL_DDEBUG 2 |
| #define DUK_LEVEL_DDDEBUG 3 |
| |
| #ifdef DUK_USE_VARIADIC_MACROS |
| |
| /* Note: combining __FILE__, __LINE__, and __func__ into fmt would be |
| * possible compile time, but waste some space with shared function names. |
| */ |
| #define DUK__DEBUG_LOG(lev,...) duk_debug_log((duk_small_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__); |
| |
| #define DUK_DPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__) |
| |
| #ifdef DUK_USE_DDPRINT |
| #define DUK_DDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__) |
| #else |
| #define DUK_DDPRINT(...) |
| #endif |
| |
| #ifdef DUK_USE_DDDPRINT |
| #define DUK_DDDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__) |
| #else |
| #define DUK_DDDPRINT(...) |
| #endif |
| |
| #else /* DUK_USE_VARIADIC_MACROS */ |
| |
| #define DUK__DEBUG_STASH(lev) \ |
| (void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \ |
| duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \ |
| (void) DUK_SNPRINTF(duk_debug_line_stash, DUK_DEBUG_STASH_SIZE, "%ld", (long) DUK_LINE_MACRO), \ |
| duk_debug_line_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \ |
| (void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \ |
| duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \ |
| (void) (duk_debug_level_stash = (lev)) |
| |
| /* Without variadic macros resort to comma expression trickery to handle debug |
| * prints. This generates a lot of harmless warnings. These hacks are not |
| * needed normally because DUK_D() and friends will hide the entire debug log |
| * statement from the compiler. |
| */ |
| |
| #ifdef DUK_USE_DPRINT |
| #define DUK_DPRINT DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log /* args go here in parens */ |
| #else |
| #define DUK_DPRINT 0 && /* args go here as a comma expression in parens */ |
| #endif |
| |
| #ifdef DUK_USE_DDPRINT |
| #define DUK_DDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log /* args go here in parens */ |
| #else |
| #define DUK_DDPRINT 0 && /* args */ |
| #endif |
| |
| #ifdef DUK_USE_DDDPRINT |
| #define DUK_DDDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log /* args go here in parens */ |
| #else |
| #define DUK_DDDPRINT 0 && /* args */ |
| #endif |
| |
| #endif /* DUK_USE_VARIADIC_MACROS */ |
| |
| #else /* DUK_USE_DEBUG */ |
| |
| /* |
| * Exposed debug macros: debugging disabled |
| */ |
| |
| #define DUK_D(x) do { } while (0) /* omit */ |
| #define DUK_DD(x) do { } while (0) /* omit */ |
| #define DUK_DDD(x) do { } while (0) /* omit */ |
| |
| #ifdef DUK_USE_VARIADIC_MACROS |
| |
| #define DUK_DPRINT(...) |
| #define DUK_DDPRINT(...) |
| #define DUK_DDDPRINT(...) |
| |
| #else /* DUK_USE_VARIADIC_MACROS */ |
| |
| #define DUK_DPRINT 0 && /* args go here as a comma expression in parens */ |
| #define DUK_DDPRINT 0 && /* args */ |
| #define DUK_DDDPRINT 0 && /* args */ |
| |
| #endif /* DUK_USE_VARIADIC_MACROS */ |
| |
| #endif /* DUK_USE_DEBUG */ |
| |
| /* |
| * Structs |
| */ |
| |
| #ifdef DUK_USE_DEBUG |
| struct duk_fixedbuffer { |
| duk_uint8_t *buffer; |
| duk_size_t length; |
| duk_size_t offset; |
| duk_bool_t truncated; |
| }; |
| #endif |
| |
| /* |
| * Prototypes |
| */ |
| |
| #ifdef DUK_USE_DEBUG |
| DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap); |
| #if 0 /*unused*/ |
| DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...); |
| #endif |
| DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size); |
| |
| #ifdef DUK_USE_VARIADIC_MACROS |
| DUK_INTERNAL_DECL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...); |
| #else /* DUK_USE_VARIADIC_MACROS */ |
| /* parameter passing, not thread safe */ |
| #define DUK_DEBUG_STASH_SIZE 128 |
| #if !defined(DUK_SINGLE_FILE) |
| DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE]; |
| DUK_INTERNAL_DECL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE]; |
| DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE]; |
| DUK_INTERNAL_DECL duk_small_int_t duk_debug_level_stash; |
| #endif |
| DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...); |
| #endif /* DUK_USE_VARIADIC_MACROS */ |
| |
| DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length); |
| DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x); |
| DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x); |
| DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...); |
| DUK_INTERNAL_DECL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size); |
| DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb); |
| |
| #endif /* DUK_USE_DEBUG */ |
| |
| #endif /* DUK_DEBUG_H_INCLUDED */ |