homework-jianmu/2.0/deps/MsvcLibX/include/msvcDebugm.h

207 lines
11 KiB
C

/*****************************************************************************\
* *
* Filename: debugm.h *
* *
* Description: Debug macros *
* *
* Notes: Macros inspired by my Tcl/Bash/Batch debugging libraries. *
* The idea is to output the function call stack, indenting *
* subroutines proportionally to the call depth. *
* To ease reading the output, it must look like real C code.*
* *
* DEBUG_GLOBALS Define global variables used by macros below: *
* int iDebug = FALSE; Global variable enabling debug output if TRUE.*
* int iIndent = 0; Global variable controlling debug indentation.*
* *
* DEBUG_PRINTF((format, ...)) Print a debug string if debug is on. *
* The double parenthesis are necessary *
* because C90 does not support macros *
* with variable list of arguments. *
* DEBUG_ENTER((format, ...)) Print a function name and arguments. *
* Increase indentation of further calls.*
* It's the caller's responsibility to *
* format the routine name and arguments.*
* DEBUG_LEAVE((format, ...)) Print a function return value. *
* Decrease indentation of further calls.*
* It's the caller's responsibility to *
* format the return instruction & value.*
* *
* Any call to DEBUG_ENTER MUST be matched by one call to *
* DEBUG_LEAVE or RETURN_... when the function returns. * *
* *
* History: *
* 2012-01-16 JFL jf.larvoire@hp.com created this file. *
* 2012-02-03 JFL Renamed DEBUG_IF_IS_ON DEBUG_CODE_IF_ON. *
* Renamed file from debug.h to debugm.h because of a file *
* name collision with another library on my PC. *
* 2014-02-10 JFL Added macros for an extra debug mode. *
* 2014-07-02 JFL renamed macro RETURN() as RETURN_CONST(), and defined *
* new macro RETURN() to return nothing. *
* Idem for RETURN_COMMENT() as RETURN_CONST_COMMENT(). *
* 2016-09-09 JFL Flush every DEBUG_PRINTF output, to make sure to see *
* every debug string printed before a program crash. *
* 2016-09-13 JFL Added macros DEBUG_WSTR2NEWUTF8() and DEBUG_FREEUTF8(). *
* 2016-10-04 JFL Added macros DEBUG_OFF(), DEBUG_MORE(), DEBUG_LESS(). *
* Allow using DEBUG_ON()/MORE()/LESS()/OFF() in release mode.
* *
* Copyright 2016 Hewlett Packard Enterprise Development LP *
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
\*****************************************************************************/
#ifndef _DEBUGM_H
#define _DEBUGM_H 1
#include <stdio.h> /* Macros use printf */
#ifdef _MSC_VER
#pragma warning(disable:4127) /* Avoid warnings on while(0) below */
#endif
#define DEBUG_DO(code) do {code} while (0)
#define DEBUG_DO_NOTHING() do {} while (0)
/* Conditional compilation based on Microsoft's standard _DEBUG definition */
#if defined(_DEBUG)
#define DEBUG_VERSION " Debug"
#define DEBUG_GLOBALS \
int iDebug = 0; /* Global variable enabling debug output if TRUE. */ \
int iIndent = 0; /* Global variable controlling debug indentation. */
extern int iDebug; /* Global variable enabling of disabling debug messages */
#define DEBUG_ON() iDebug = 1 /* Turn debug mode on */
#define DEBUG_MORE() iDebug += 1 /* Increase the debug level */
#define DEBUG_LESS() iDebug -= 1 /* Decrease the debug level */
#define DEBUG_OFF() iDebug = 0 /* Turn debug mode off */
#define DEBUG_IS_ON() (iDebug > 0) /* Check if the debug mode is enabled */
#define XDEBUG_ON() iDebug = 2 /* Turn extra debug mode on. Same as calling DEBUG_MORE() twice. */
#define XDEBUG_IS_ON() (iDebug > 1) /* Check if the extra debug mode is enabled */
#define DEBUG_CODE(code) code /* Code included in the _DEBUG version only */
#define DEBUG_CODE_IF_ON(code) DEBUG_CODE(if (DEBUG_IS_ON()) {code}) /*
Debug code executed if debug mode is on */
#define XDEBUG_CODE_IF_ON(code) DEBUG_CODE(if (XDEBUG_IS_ON()) {code}) /*
Debug code executed if extra debug mode is on */
extern int iIndent; /* Debug messages indentation */
#define DEBUG_INDENT_STEP 2 /* How many spaces to add for each indentation level */
#define DEBUG_PRINT_INDENT() printf("%*s", iIndent, "")
/* Debug code, conditionally printing a string based on global variable 'debug' */
/* The enter and leave variants print, then respectively increase or decrease indentation,
to make recursive calls easier to review. */
#define DEBUG_FPRINTF(args) DEBUG_DO(if (DEBUG_IS_ON()) {DEBUG_PRINT_INDENT(); fprintf args;})
#define DEBUG_PRINTF(args) DEBUG_DO(if (DEBUG_IS_ON()) {DEBUG_PRINT_INDENT(); printf args; fflush(stdout);})
#define XDEBUG_PRINTF(args) DEBUG_DO(if (XDEBUG_IS_ON()) {DEBUG_PRINT_INDENT(); printf args; fflush(stdout);})
#define DEBUG_ENTER(args) DEBUG_DO(DEBUG_PRINTF(args); iIndent += DEBUG_INDENT_STEP;)
#define DEBUG_LEAVE(args) DEBUG_DO(DEBUG_PRINTF(args); iIndent -= DEBUG_INDENT_STEP;)
#define DEBUG_RETURN_INT(i, comment) DEBUG_DO(int DEBUG_i = (i); \
DEBUG_LEAVE(("return %d; // " comment "\n", DEBUG_i)); return DEBUG_i;)
/* print return instruction and decrease indent */
#define RETURN() DEBUG_DO(DEBUG_LEAVE(("return;\n")); return;)
#define RETURN_CONST(value) DEBUG_DO(DEBUG_LEAVE(("return %s;\n", #value)); return value;)
#define RETURN_INT(i) DEBUG_DO(int DEBUG_i = (i); \
DEBUG_LEAVE(("return %d;\n", DEBUG_i)); return DEBUG_i;)
#define RETURN_STRING(s) DEBUG_DO(char *DEBUG_s = (s); \
DEBUG_LEAVE(("return \"%s\";\n", DEBUG_s)); return DEBUG_s;)
#define RETURN_CHAR(c) DEBUG_DO(char DEBUG_c = (c); \
DEBUG_LEAVE(("return '%c';\n", DEBUG_c)); return DEBUG_c;)
#define RETURN_BOOL(b) DEBUG_DO(int DEBUG_b = (b); \
DEBUG_LEAVE(("return %s;\n", DEBUG_b ? "TRUE" : "FALSE")); return DEBUG_b;)
#define RETURN_COMMENT(args) DEBUG_DO(DEBUG_LEAVE(("return; // ")); \
if (DEBUG_IS_ON()) printf args; return;)
#define RETURN_CONST_COMMENT(value, args) DEBUG_DO(DEBUG_LEAVE(("return %s; // ", #value)); \
if (DEBUG_IS_ON()) printf args; return value;)
#define RETURN_INT_COMMENT(i, args) DEBUG_DO(int DEBUG_i = (i); \
DEBUG_LEAVE(("return %d; // ", DEBUG_i)); if (DEBUG_IS_ON()) printf args; return DEBUG_i;)
#define RETURN_BOOL_COMMENT(b, args) DEBUG_DO(int DEBUG_b = (b); \
DEBUG_LEAVE(("return %s; // ", DEBUG_b ? "TRUE" : "FALSE")); if (DEBUG_IS_ON()) printf args; return DEBUG_b;)
#else /* !defined(_DEBUG) */
#define DEBUG_VERSION "" /* Non debug version: Simply don't say it */
#define DEBUG_GLOBALS
#define DEBUG_ON() (void)0
#define DEBUG_MORE() (void)0
#define DEBUG_LESS() (void)0
#define DEBUG_OFF() (void)0
#define DEBUG_IS_ON() 0
#define XDEBUG_IS_ON() 0
#define DEBUG_CODE(code) /* Code included in _DEBUG version only */
#define DEBUG_CODE_IF_ON(code) /* Code included in _DEBUG version only */
#define XDEBUG_CODE_IF_ON(code) /* Code included in _DEBUG version only */
#define DEBUG_PRINT_INDENT() DEBUG_DO_NOTHING() /* Print call-depth spaces */
#define DEBUG_FPRINTF(args) DEBUG_DO_NOTHING() /* Print a debug string to a stream */
#define DEBUG_PRINTF(args) DEBUG_DO_NOTHING() /* Print a debug string to stdout */
#define XDEBUG_PRINTF(args) DEBUG_DO_NOTHING() /* Print an extra debug string to stdout */
#define DEBUG_ENTER(args) DEBUG_DO_NOTHING() /* Print and increase indent */
#define DEBUG_LEAVE(args) DEBUG_DO_NOTHING() /* Print and decrease indent */
#define DEBUG_RETURN_INT(i, comment) return(i)
/* print return instruction and decrease indent */
#define RETURN() return
#define RETURN_CONST(value) return(value)
#define RETURN_INT(i) return(i)
#define RETURN_STRING(s) return(s)
#define RETURN_CHAR(c) return(c)
#define RETURN_BOOL(b) return(b)
#define RETURN_COMMENT(args) return
#define RETURN_CONST_COMMENT(value, args) return(value)
#define RETURN_INT_COMMENT(i, args) return(i)
#define RETURN_BOOL_COMMENT(b, args) return(b)
#endif /* defined(_DEBUG) */
#define STRINGIZE(s) #s /* Convert a macro name to a string */
#define VALUEIZE(s) STRINGIZE(s) /* Convert a macro value to a string */
#define MACRODEF(s) "#define " #s " " STRINGIZE(s)
/* Display a macro name and value. */
#define DEBUG_PRINT_MACRO(name) DEBUG_DO( \
const char *pszName = #name; /* Don't use STRINGIZE because we're already inside a macro */ \
const char *pszValue = STRINGIZE(name); /* Don't use VALUEIZE because we're already inside a macro */ \
DEBUG_PRINT_INDENT(); \
if (strcmp(pszName, pszValue)) { \
printf("#define %s %s\n", pszName, pszValue); \
} else { /* Not 100% certain, but most likely. */ \
printf("#undef %s\n", pszName); \
} \
)
#ifdef _WIN32
/* Helper macros for displaying Unicode strings */
#define DEBUG_WSTR2UTF8(from, to, toSize) DEBUG_CODE( \
WideCharToMultiByte(CP_UTF8, 0, from, lstrlenW(from)+1, to, toSize, NULL, NULL); \
)
/* Dynamically allocate a new buffer, then convert a Unicode string to UTF-8 */
/* The dynamic allocation is useful in modules using lots of UTF-16 pathnames.
This avoids having many local buffers of length UTF8_PATH_MAX, which may
make the stack grow too large and overflow. */
#define DEBUG_WSTR2NEWUTF8(pwStr, pUtf8) \
DEBUG_CODE( \
do { \
int nUtf8 = (int)lstrlenW(pwStr) * 2 + 1; \
pUtf8 = malloc(nUtf8); \
DEBUG_WSTR2UTF8(pwStr, pUtf8, nUtf8); \
} while (0); \
) /* DEBUG_FREE(pUtf8) MUST be used to free the UTF-8 string after use, else there will be a memory leak */
#define DEBUG_FREEUTF8(pUtf8) DEBUG_CODE(free(pUtf8))
#endif /* defined(_WIN32) */
#endif /* !defined(_DEBUGM_H) */