wietse@porcupine.org writes:
Below is my "least painful" patch for both parties. What do you think?
That's roughly what I wrote was thinking, yes.
We haven't heard if it will go in at all, though:-) If this ITS is a reaction to ITS#7774, then the motivation is not catching an lmdb bug, but letting the user band-aid a user error. Still makes sense to me, lmdb lets the user screw up in many ways.
Anyway:
Why drop the info parameter? If you don't need it after all, that's fine. But then it won't be coming back later. It doesn't fit in the varargs, they're reserved for the message.
I ended up declaring a type for it in ldmb.h, to make future expansion a bit friendlier: /** Dummy definition for future extension of #mdb_assert_cb(). */ typedef struct MDB_assertion MDB_assertion;
I dislike when a feature makes me #include <stdarg.h>, so I'd not make one myself. I'd build the message in a buffer. Also the code needs fleshing out a bit: Obey NDEBUG, and omit all this if something already #defined assert. See below.
Finally, __func__ needs a wrapper. It can go in a renamed "compat" section:
--- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -151,3 +150,3 @@ */ -/** @defgroup compat Windows Compatibility Macros +/** @defgroup compat Compatibility Macros * A bunch of macros to minimize the amount of platform-specific ifdefs @@ -158,2 +157,13 @@ */ + + /** Wrapper around __func__, which is a C99 feature */ +#if __STDC_VERSION__ >= 199901L +# define mdb_func_ __func__ +#elif __GNUC__ >= 2 || _MSC_VER >= 1300 +# define mdb_func_ __FUNCTION__ +#else +/* If a debug message says <mdb_unknown>(), update the #if statements above */ +# define mdb_func_ "<mdb_unknown>" +#endif + #ifdef _WIN32 @@ -329,3 +339,3 @@ static txnid_t mdb_debug_start; # define DPRINTF0(fmt, ...) \ - fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, __VA_ARGS__) + fprintf(stderr, "%s:%d " fmt "\n", mdb_func_, __LINE__, __VA_ARGS__) #else
Google found more compiler #ifdefs, but I'm not sure which of these are still relevant as non-C99 compilers. Could add them later at need: __func__: (defined(__SUNPRO_C) && defined(__C99FEATURES__)) __FUNC__: __BORLANDC__ >= 0x550 __FUNCTION__: __MWERKS__ >= 0x3000 || defined(__ghs__) || __DMC__ >= 0x810 || __IBMCPP__ >= 500
And the assert() itself:
/** assert(3) replacement. * Omitted in programs that #include mdb.c and already define assert(). */ #ifndef assert # ifdef NDEBUG # define assert(expr) ((void) 0) # else # define assert(expr) ((expr) ? (void)0 : \ mdb_assert_fail(#expr, mdb_func_, __FILE__, __LINE__)) static void mdb_assert_fail(const char *expr, const char *func, const char *file, int line) { char buf[400]; sprintf(buf, "%.100s:%d: Assertion '%.200s' failed in %.40s()", file, line, expr, func); if (mdb_assert_cb) mdb_assert_cb(buf, NULL); fprintf(stderr, "%s\n", buf); abort(); } # endif /* NDEBUG */ #endif /* assert */