Index: trunk/src/emx/include/InnoTekLIBC/log.h
===================================================================
--- trunk/src/emx/include/InnoTekLIBC/log.h	(revision 1287)
+++ trunk/src/emx/include/InnoTekLIBC/log.h	(revision 1288)
@@ -2,5 +2,5 @@
 /** @file
  *
- * Debug Logging Features - internal libc use only.
+ * InnoTek LIBC - Debug Logging and Strict Checking Features.
  *
  * InnoTek Systemberatung GmbH confidential
@@ -16,9 +16,331 @@
 #define __InnoTekLIBC_LOG_H__
 
-
-#ifdef DEBUG_LOGGING
-/*
- * Logging is enabled.
- */
+/** @defgroup   __libc_log      Debug Logging and Strict Checking Features
+ *
+ * The logging feature is not accessible unless DEBUG_LOGGING is #defined.
+ *
+ * The user of this feature must #define __LIBC_LOG_GROUP to a valid group
+ * number before including this file.
+ *
+ * The user may also #define __LIBC_LOG_INSTANCE if it doesn't want to use
+ * the default logging device.
+ *
+ * Note that all everything but the main logger macros are using the default
+ * prefix to avoid namespace pollution. The main logger macros are not
+ * prefixed with the double underscore because that would make the code less
+ * readable (and it's more to type which for me means more pain).
+ *
+ * @{
+ */
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/**
+ * The user may also #define __LIBC_LOG_INSTANCE if it doesn't want to use
+ * the default logging device.
+ */
+#ifdef DEBUG_LOGGING
+#ifndef __LIBC_LOG_INSTANCE
+#define __LIBC_LOG_INSTANCE NULL
+#endif
+#endif
+
+/**
+ * The user of this feature must #define __LIBC_LOG_GROUP to a valid group
+ * number before including this file.
+ */
+#ifdef DEBUG_LOGGING
+#ifndef __LIBC_LOG_GROUP
+#define __LIBC_LOG_GROUP    0
+#error "__LIBC_LOG_GROUP must be defined before including InnoTekLIBC/log.h"
+#endif
+#endif
+
+/** Macro to log a function entry. */
+#ifdef DEBUG_LOGGING
+#define LIBCLOG_ENTER(...) \
+    unsigned __libclog_uEnterTS__ = __libc_LogEnter(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __VA_ARGS__)
+#else
+#define LIBCLOG_ENTER(...)  //hmm
+#endif
+
+/** Macro to log a generic message within a function entered by LIBCLOG_ENTER(). */
+#ifdef DEBUG_LOGGING
+#define LIBCLOG_MSG(...) \
+    __libc_LogMsg(__libclog_uEnterTS__, __LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __VA_ARGS__)
+#else
+#define LIBCLOG_MSG(...)    do {} while (0)
+#endif
+
+/** Macro to log a generic message within a functionw. */
+#ifdef DEBUG_LOGGING
+#define LIBCLOG_MSG2(...) \
+    __libc_LogMsg(~0, __LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __VA_ARGS__)
+#else
+#define LIBCLOG_MSG2(...)   do {} while (0)
+#endif
+
+/** Macro to log a raw message. */
+#ifdef DEBUG_LOGGING
+#define LIBCLOG_RAW(string, maxlen) \
+    __libc_LogRaw(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, string, maxlen)
+#else
+#define LIBCLOG_RAW(...)    do {} while (0)
+#endif
+
+/** Macro to log a function exit. */
+#ifdef DEBUG_LOGGING
+#define LIBCLOG_LEAVE(...) \
+    __libc_LogLeave(__libclog_uEnterTS__, __LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __VA_ARGS__)
+#else
+#define LIBCLOG_LEAVE(...)  do {} while (0)
+#endif
+/** Macro to log a void return and do the return. */
+#define LIBCLOG_RETURN_VOID()    do { LIBCLOG_LEAVE("ret void\n");                      return;      } while (0)
+/** Macro to log an int return and do the return. */
+#define LIBCLOG_RETURN_INT(rc)   do { LIBCLOG_LEAVE("ret %d (%#x)\n", (rc), (rc));      return (rc); } while (0)
+/** Macro to log an unsigned int return and do the return. */
+#define LIBCLOG_RETURN_UINT(rc)  do { LIBCLOG_LEAVE("ret %u (%#x)\n", (rc), (rc));      return (rc); } while (0)
+/** Macro to log an long int return and do the return. */
+#define LIBCLOG_RETURN_LONG(rc)  do { LIBCLOG_LEAVE("ret %ld (%#lx)\n", (rc), (rc));    return (rc); } while (0)
+/** Macro to log an unsigned long int return and do the return. */
+#define LIBCLOG_RETURN_ULONG(rc) do { LIBCLOG_LEAVE("ret %lu (%#lx)\n", (rc), (rc));    return (rc); } while (0)
+/** Macro to log a pointer return and do the return. */
+#define LIBCLOG_RETURN_P(rc)     do { LIBCLOG_LEAVE("ret %p\n", (rc));                  return (rc); } while (0)
+
+
+/** @defgroup   __libc_log_groups   Default Logging Groups
+ * @{ */
+/** whatever. */
+#define __LIBCLOG_GRP_NOGROUP       0
+
+/*-- LIBC --*/
+/** Process APIs. */
+#define __LIBCLOG_GRP_PROCESS       1
+/** Heap APIs. */
+#define __LIBCLOG_GRP_HEAP          2
+/** File stream APIs. */
+#define __LIBCLOG_GRP_STREAM        3
+/** Other I/O APIs. */
+#define __LIBCLOG_GRP_IO            4
+/** String APIs. */
+#define __LIBCLOG_GRP_STRING        5
+/** Locale APIs. */
+#define __LIBCLOG_GRP_LOCALE        6
+/** Regular expression APIs. */
+#define __LIBCLOG_GRP_REGEX         7
+/** Math APIs. */
+#define __LIBCLOG_GRP_MATH          8
+/** Time APIs. */
+#define __LIBCLOG_GRP_TIME          9
+/** BSD DB APIs. */
+#define __LIBCLOG_GRP_BSD_DB        10
+/** GLIBC POSIX APIs. */
+#define __LIBCLOG_GRP_GLIBC_POSIX   11
+
+/** Backend APIs. */
+#define __LIBCLOG_GRP_BACKEND       28
+/** Misc APIs. */
+#define __LIBCLOG_GRP_MISC          29
+/** BSD Gen APIs. */
+#define __LIBCLOG_GRP_BSD_GEN       30
+/** GLIBC Misc APIs. */
+#define __LIBCLOG_GRP_GLIBC_MISC    31
+
+/*-- other libraries/APIs --*/
+/** Socket APIs. */
+#define __LIBCLOG_GRP_SOCKET        32
+/** Other TCP/IP APIs. */
+#define __LIBCLOG_GRP_TCPIP         33
+/** iconv APIs. */
+#define __LIBCLOG_GRP_ICONV         34
+/** Dynamic Library (libdl) APIs. */
+#define __LIBCLOG_GRP_DLFCN         35
+/** Posix thread APIs. */
+#define __LIBCLOG_GRP_PTHREAD       36
+
+/** @todo complete this */
+#define __LIBCLOG_GRP_MAX           36
+/** @} */
+
+
+/** @defgroup   __libc_log_strict   Strict Assertions
+ * @{ */
+
+/** Generic assertion.
+ * @param expr  Boolean expression,
+ */
+#ifdef DEBUG_STRICT
+#define LIBC_ASSERT(expr) ((expr) ? (void)0 \
+    : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #expr, \
+                       NULL))
+#else
+#define LIBC_ASSERT(expr) ((void)0)
+#endif
+
+/** Assert that a memory buffer is readable.
+ * @param pv    Pointer to buffer.
+ * @param cb    Size of buffer.
+ */
+#ifdef DEBUG_STRICT
+#define LIBC_ASSERT_MEM_R(pv, cb) (__libc_StrictMemoryR((pv), (cb)) ? (void)0 \
+    : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #pv "; " #cb, \
+                       "Memory buffer at %p of %d bytes isn't readable!\n", (pv), (cb)))
+#else
+#define LIBC_ASSERT_MEM_R(pv, cb) ((void)0)
+#endif
+
+/** Assert that a memory buffer is readable and writable.
+ * @param pv    Pointer to buffer.
+ * @param cb    Size of buffer.
+ */
+#ifdef DEBUG_STRICT
+#define LIBC_ASSERT_MEM_RW(pv, cb) (__libc_StrictMemoryRW((pv), (cb)) ? (void)0 \
+    : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #pv "; " #cb, \
+                       "Memory buffer at %p of %d bytes isn't readable and writable!\n", (pv), (cb)))
+#else
+#define LIBC_ASSERT_MEM_RW(pv, cb) ((void)0)
+#endif
+
+/** Assert that a zero terminated string is readable.
+ * @param psz    Pointer to buffer.
+ */
+#ifdef DEBUG_STRICT
+#define LIBC_ASSERT_STR(psz) (__libc_StrictStringR((psz), ~0) ? (void)0 \
+    : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #psz, \
+                       "String at %p isn't readable!\n", (psz)))
+#else
+#define LIBC_ASSERT_STR(psz) ((void)0)
+#endif
+
+/** Assert that a zero terminated string with a maximum lenght is readable.
+ * @param psz       Pointer to buffer.
+ * @param cchMax    Max string length.
+ */
+#ifdef DEBUG_STRICT
+#define LIBC_ASSERT_NSTR(psz, cchMax) (__libc_StrictStringR((psz), cchMax) ? (void)0 \
+    : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #psz " " #cchMax, \
+                       "String at %p of maximum %d bytes isn't readable!\n", (psz), (cchMax)))
+#else
+#define LIBC_ASSERT_NSTR(psz, cchMax) ((void)0)
+#endif
+
+
+/** Generic assertion, custom message.
+ * @param expr  Boolean expression,
+ * @param ...   Custom error message.
+ */
+#ifdef DEBUG_STRICT
+#define LIBC_ASSERTM(expr, ...) ((expr) ? (void)0 \
+    : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #expr, \
+                       __VA_ARGS__))
+#else
+#define LIBC_ASSERTM(expr, ...) ((void)0)
+#endif
+
+/** Assert that a memory buffer is readable, custom message
+ * @param pv    Pointer to buffer.
+ * @param cb    Size of buffer.
+ */
+#ifdef DEBUG_STRICT
+#define LIBC_ASSERTM_MEM_R(pv, cb, ...) (__libc_StrictMemoryR((pv), (cb)) ? (void)0 \
+    : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #pv "; " #cb, \
+                       __VA_ARGS__))
+#else
+#define LIBC_ASSERTM_MEM_R(pv, cb, ...) ((void)0)
+#endif
+
+/** Assert that a memory buffer is readable and writable, custom message
+ * @param pv    Pointer to buffer.
+ * @param cb    Size of buffer.
+ */
+#ifdef DEBUG_STRICT
+#define LIBC_ASSERTM_MEM_RW(pv, cb, ...) (__libc_StrictMemoryRW((pv), (cb)) ? (void)0 \
+    : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #pv "; " #cb, \
+                       __VA_ARGS__))
+#else
+#define LIBC_ASSERTM_MEM_RW(pv, cb, ...) ((void)0)
+#endif
+
+/** Assert that a zero terminated string is readable, custom message
+ * @param psz    Pointer to buffer.
+ */
+#ifdef DEBUG_STRICT
+#define LIBC_ASSERTM_STR(psz, ...) (__libc_StrictStringR((psz), ~0) ? (void)0 \
+    : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #psz, \
+                       __VA_ARGS__))
+#else
+#define LIBC_ASSERTM_STR(psz, ...) ((void)0)
+#endif
+
+/** Assert that a zero terminated string with a maximum lenght is readable, custom message
+ * @param psz       Pointer to buffer.
+ * @param cchMax    Max string length.
+ */
+#ifdef DEBUG_STRICT
+#define LIBC_ASSERTM_NSTR(psz, cchMax, ...) (__libc_StrictStringR((psz), cchMax) ? (void)0 \
+    : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #psz " " #cchMax, \
+                       __VA_ARGS__))
+#else
+#define LIBC_ASSERTM_NSTR(psz, cchMax, ...) ((void)0)
+#endif
+
+/** @} */
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/** Logging group. */
+typedef struct __libc_log_group
+{
+    /** Set if logging for the group is enabled, clear if it's disabled. */
+    int             fEnabled;
+    /** Group name */
+    const char *    pszGroupName;
+} __LIBC_LOGGROUP, *__LIBC_PLOGGROUP;
+
+/** Ordered collection of logging groups. */
+typedef struct __libc_log_groups
+{
+    /** Group index base. This value is subtracted from the group part of the
+     * fFlagsAndGroups arguments to make an index into paGroups. */
+    unsigned            uBase;
+    /** Number of groups in the array. */
+    unsigned            cGroups;
+    /** Array of log groups. */
+    __LIBC_PLOGGROUP    paGroups;
+} __LIBC_LOGGROUPS, __LIBC_PLOGGROUPS;
+
+
+/*******************************************************************************
+*   External Functions                                                         *
+*******************************************************************************/
+/**
+ * Create a logger.
+ *
+ * @returns Pointer to a logger instance on success.
+ * @returns NULL on failure. errno is set.
+ * @param   fFlags              Flags reserved for future use. Set to zero.
+ * @param   pGroups             Pointer to a table of logging groups used for this
+ *                              logger instance.
+ * @param   pszFilenameFormat   Format string for making up the log filename.
+ * @param   ...                 Arguments to the format string.
+ */
+extern void *__libc_logInit(unsigned fFlags, __LIBC_PLOGGROUPS pGroups, const char *pszFilenameFormat, ...) __printflike(3, 4);
+
+/**
+ * Terminate (or close if you like) a logger instance.
+ * This means flushing any buffered messages and writing a termination
+ * message before closing the log file.
+ *
+ * @returns 0 on succes.
+ * @returns -1 on failure, error is set.
+ * @param   pvInstance      Logger instance.
+ */
+extern int   __libc_logTerm(void *pvInstance);
+
 /**
  * Output an enter function log message.
@@ -27,9 +349,13 @@
  *
  * @returns Current timestamp.
+ * @param   pvInstance      Logger instance. If NULL the message goes to the
+ *                          default log instance.
+ * @param   fGroupAndFlags  Logging group and logging flags.
  * @param   pszFunction     Name of the function which was entered.
  * @param   pszFormat       Format string to display arguments.
  * @param   ...             Arguments to the format string.
  */
-extern unsigned __libc_LogEnter(const char *pszFunction, const char *pszFormat, ...) __printflike(2, 3);
+extern unsigned __libc_LogEnter(void *pvInstance, unsigned fGroupAndFlags, const char *pszFunction, const char *pszFormat, ...) __printflike(4, 5);
+
 /**
  * Output a leave function log message.
@@ -38,9 +364,12 @@
  *
  * @param   uEnterTS        The timestamp returned by LogEnter.
+ * @param   pvInstance      Logger instance. If NULL the message goes to the
+ *                          default log instance.
+ * @param   fGroupAndFlags  Logging group and logging flags.
  * @param   pszFunction     Name of the function which was entered.
  * @param   pszFormat       Format string to display the result.
  * @param   ...             Arguments to the format string.
  */
-extern void     __libc_LogLeave(unsigned uEnterTS, const char *pszFunction, const char *pszFormat, ...) __printflike(3, 4);
+extern void     __libc_LogLeave(unsigned uEnterTS, void *pvInstance, unsigned fGroupAndFlags, const char *pszFunction, const char *pszFormat, ...) __printflike(5, 6);
 
 /**
@@ -50,38 +379,74 @@
  *
  * @param   uEnterTS        The timestamp returned by LogEnter.
+ * @param   pvInstance      Logger instance. If NULL the message goes to the
+ *                          default log instance.
+ * @param   fGroupAndFlags  Logging group and logging flags.
  * @param   pszFunction     Name of the function which was entered.
  * @param   pszFormat       Format string for the message to log.
  * @param   ...             Arguments to the format string.
  */
-extern void     __libc_LogMsg(unsigned uEnterTS, const char *pszFunction, const char *pszFormat, ...) __printflike(3, 4);
-
-/** Macro to log a function entry. */
-#define LIBCLOG_ENTER(...) \
-    unsigned __libclog_uEnterTS__ = __libc_LogEnter(__PRETTY_FUNCTION__, __VA_ARGS__)
-#define LIBCLOG_LEAVE(...) \
-    __libc_LogLeave(__libclog_uEnterTS__, __PRETTY_FUNCTION__, __VA_ARGS__)
-#define LIBCLOG_MSG(...) \
-    __libc_LogLeave(__libclog_uEnterTS__, __PRETTY_FUNCTION__, __VA_ARGS__)
-#define LIBCLOG_MSG2(...) \
-    __libc_LogLeave(~0, __PRETTY_FUNCTION__, __VA_ARGS__)
-
-#else
-/*
- * Logging is disabled.
- */
-#define LIBCLOG_ENTER(...) //hmm
-#define LIBCLOG_LEAVE(...)  do {} while (0)
-#define LIBCLOG_MSG(...)    do {} while (0)
-#define LIBCLOG_MSG2(...)    do {} while (0)
-
-#endif
-
-/* helpers */
-#define LIBCLOG_RETURN_VOID()    do { LIBCLOG_LEAVE("ret void\n");                      return;      } while (0)
-#define LIBCLOG_RETURN_INT(rc)   do { LIBCLOG_LEAVE("ret %d (%#x)\n", (rc), (rc));      return (rc); } while (0)
-#define LIBCLOG_RETURN_UINT(rc)  do { LIBCLOG_LEAVE("ret %u (%#x)\n", (rc), (rc));      return (rc); } while (0)
-#define LIBCLOG_RETURN_LONG(rc)  do { LIBCLOG_LEAVE("ret %ld (%#lx)\n", (rc), (rc));    return (rc); } while (0)
-#define LIBCLOG_RETURN_ULONG(rc) do { LIBCLOG_LEAVE("ret %lu (%#lx)\n", (rc), (rc));    return (rc); } while (0)
-#define LIBCLOG_RETURN_P(rc)     do { LIBCLOG_LEAVE("ret %p\n", (rc));                  return (rc); } while (0)
-
-#endif
+extern void     __libc_LogMsg(unsigned uEnterTS, void *pvInstance, unsigned fGroupAndFlags, const char *pszFunction, const char *pszFormat, ...) __printflike(5, 6);
+
+/**
+ * Output a raw log message.
+ * Nothing is prepended. No newline is appended.
+ *
+ * @param   uEnterTS        The timestamp returned by LogEnter.
+ * @param   pvInstance      Logger instance. If NULL the message goes to the
+ *                          default log instance.
+ * @param   fGroupAndFlags  Logging group and logging flags.
+ * @param   pszFunction     Name of the function which was entered.
+ * @param   pszString       Pointer to raw log message.
+ * @param   cchMax          Maximum number of bytes to write.
+ */
+extern void     __libc_LogRaw(void *pvInstance, unsigned fGroupAndFlags, const char *pszString, unsigned cchMax);
+
+/**
+ * Assertion helper.
+ * Logs and displays (stderr) an assertion failed message.
+ *
+ * @param   pvInstance      Logger instance. If NULL the message goes to the
+ *                          default log instance.
+ * @param   pszFunction     Name of the function which was entered.
+ * @param   pszFile         Source filename.
+ * @param   uLine           Line number.
+ * @param   pszExpression   Expression.
+ * @param   pszFormat       Format string for the message to log.
+ * @param   ...             Arguments to the format string.
+ */
+extern void     __libc_LogAssert(void *pvInstance, unsigned fGroupAndFlags,
+                                 const char *pszFunction, const char *pszFile, unsigned uLine, const char *pszExpression,
+                                 const char *pszFormat, ...) __printflike(7, 8);
+
+/**
+ * Validate a memory area for read access.
+ * @returns 1 if readable.
+ * @returns 0 if not entirely readable.
+ * @param   pv      Pointer to memory area.
+ * @param   cb      Size of memory area.
+ */
+extern int      __libc_StrictMemoryR(const void *pv, size_t cb);
+
+/**
+ * Validate a memory area for read & write access.
+ * @returns 1 if readable and writable.
+ * @returns 0 if not entirely readable and writable.
+ * @param   pv      Pointer to memory area.
+ * @param   cb      Size of memory area.
+ */
+extern int      __libc_StrictMemoryRW(void *pv, size_t cb);
+
+/**
+ * Validate a zero terminated string for read access.
+ * @returns 1 if readable.
+ * @returns 0 if not entirely readable.
+ * @param   psz         Pointer to string.
+ * @param   cchMax      Max string length. Use ~0 if to very all the
+ *                      way to the terminator.
+ */
+extern int      __libc_StrictStringR(const void *psz, size_t cchMax);
+
+
+/** @} */
+
+#endif
