Index: /trunk/createdoc.cmd
===================================================================
--- /trunk/createdoc.cmd	(revision 13)
+++ /trunk/createdoc.cmd	(revision 13)
@@ -0,0 +1,14 @@
+/* createdoc.cmd:
+    this calls xdoc\xdoc.exe on all the *.c files in \main and \helpers
+    to have HTML reference documentation created.
+    After this has been executed, open HTML\index.html to view the
+    documentation. */
+
+call RxFuncAdd 'SysLoadFuncs','RexxUtil','SysLoadFuncs'
+call SysLoadFuncs
+
+'@echo off'
+'call xdoc "-iinclude" src\helpers\*.c'
+
+rc = SysCreateObject("WPShadow", "index.html", directory(), "SHADOWID="directory()"\HTML\index.html", "R");
+
Index: /trunk/include/helpers/memdebug.h
===================================================================
--- /trunk/include/helpers/memdebug.h	(revision 12)
+++ /trunk/include/helpers/memdebug.h	(revision 13)
@@ -41,4 +41,61 @@
     extern PFNCBMEMDLOG    G_pMemdLogFunc;
 
+    /* ******************************************************************
+     *
+     *   Private declarations
+     *
+     ********************************************************************/
+
+    #ifdef MEMDEBUG_PRIVATE
+
+        BOOL memdLock(VOID);
+
+        VOID memdUnlock(VOID);
+
+        /*
+         *@@ HEAPITEM:
+         *      informational structure created for each
+         *      malloc() call by memdMalloc. These are stored
+         *      in a global linked list (G_pHeapItemsRoot).
+         *
+         *      We cannot use the linklist.c functions for
+         *      managing the linked list because these use
+         *      malloc in turn, which would lead to infinite
+         *      loops.
+         *
+         *@@added V0.9.3 (2000-04-11) [umoeller]
+         */
+
+        typedef struct _HEAPITEM
+        {
+            struct _HEAPITEM    *pNext;     // next item in linked list or NULL if last
+
+            void                *pAfterMagic; // memory pointer returned by memdMalloc;
+                                            // this points to after the magic string
+            unsigned long       ulSize;     // requested size (without magic head and tail)
+
+            const char          *pcszSourceFile;    // as passed to memdMalloc
+            unsigned long       ulLine;             // as passed to memdMalloc
+            const char          *pcszFunction;      // as passed to memdMalloc
+
+            DATETIME            dtAllocated;        // system date/time at time of memdMalloc call
+
+            ULONG               ulTID;      // thread ID that memdMalloc was running on
+
+            BOOL                fFreed;     // TRUE only after item has been freed by memdFree
+        } HEAPITEM, *PHEAPITEM;
+
+        extern PHEAPITEM    G_pHeapItemsRoot;
+        extern ULONG        G_ulItemsReleased;
+        extern ULONG        G_ulBytesReleased;
+
+    #endif // MEMDEBUG_PRIVATE
+
+    /* ******************************************************************
+     *
+     *   Publics
+     *
+     ********************************************************************/
+
     void* memdMalloc(size_t stSize,
                      const char *pcszSourceFile,
@@ -57,4 +114,10 @@
                   const char *pcszFunction);
 
+    void* memdRealloc(void *p,
+                      size_t stSize,
+                      const char *pcszSourceFile,
+                      unsigned long ulLine,
+                      const char *pcszFunction);
+
     unsigned long memdReleaseFreed(void);
 
@@ -64,4 +127,5 @@
             #define malloc(ul) memdMalloc(ul, __FILE__, __LINE__, __FUNCTION__)
             #define calloc(n, size) memdCalloc(n, size, __FILE__, __LINE__, __FUNCTION__)
+            #define realloc(p, ul) memdRealloc(p, ul, __FILE__, __LINE__, __FUNCTION__)
             #define free(p) memdFree(p, __FILE__, __LINE__, __FUNCTION__)
 
@@ -79,7 +143,7 @@
     #ifdef PM_INCLUDED
         /********************************************************************
-         *                                                                  *
-         *   XFolder debugging helpers                                      *
-         *                                                                  *
+         *
+         *   XFolder debugging helpers
+         *
          ********************************************************************/
 
@@ -94,7 +158,7 @@
 
         /* ******************************************************************
-         *                                                                  *
-         *   Heap debugging window                                          *
-         *                                                                  *
+         *
+         *   Heap debugging window
+         *
          ********************************************************************/
 
Index: /trunk/include/helpers/stringh.h
===================================================================
--- /trunk/include/helpers/stringh.h	(revision 12)
+++ /trunk/include/helpers/stringh.h	(revision 13)
@@ -64,8 +64,7 @@
 
     ULONG strhrpl(PSZ *ppszBuf,
-                  ULONG ulOfs,
+                  PULONG pulOfs,
                   const char *pcszSearch,
-                  const char *pcszReplace,
-                  PULONG pulAfterOfs);
+                  const char *pcszReplace);
 
     ULONG strhWords(PSZ psz);
@@ -74,4 +73,7 @@
 
     PSZ strhThousandsDouble(PSZ pszTarget, double dbl, CHAR cThousands);
+
+    PSZ strhVariableDouble(PSZ pszTarget, double dbl, PSZ pszUnits,
+                           CHAR cThousands);
 
     VOID strhFileDate(PSZ pszBuf,
@@ -102,4 +104,10 @@
                      PSZ *ppszEnd);
 
+    BOOL strhIsWord(const char *pcszBuf,
+                    const char *p,
+                    ULONG cbSearch,
+                    const char *pcszBeginChars,
+                    const char *pcszEndChars);
+
     PSZ strhFindWord(const char *pszBuf,
                      const char *pszSearch,
@@ -192,33 +200,10 @@
      ********************************************************************/
 
-    char* strhfind (const char *string,
-                    const char *pattern,
-                    BOOL repeat_find);
-
-    char* strhfind_r (const char *string,
-                      const char *pattern);
-
-    char* strhfind_rb (const char *string,
-                       const char *pattern,
-                       size_t     *shift,
-                       BOOL       *repeat_find);
-
-    void* strhmemfind (const void  *block,
-                       size_t       block_size,
-                       const void  *pattern,
-                       size_t       pattern_size,
-                       BOOL         repeat_find);
-
-    void* strhmemfind_r (const void  *block,
-                         size_t       block_size,
-                         const void  *pattern,
-                         size_t       pattern_size);
-
-    void* strhmemfind_rb (const void  *in_block,
-                          size_t       block_size,
-                          const void  *in_pattern,
-                          size_t       pattern_size,
-                          size_t      *shift,
-                          BOOL        *repeat_find);
+    void* strhmemfind(const void *in_block,
+                      size_t block_size,
+                      const void *in_pattern,
+                      size_t pattern_size,
+                      size_t *shift,
+                      BOOL *repeat_find);
 
     char* strhtxtfind (const char *string,
Index: /trunk/include/helpers/tree.h
===================================================================
--- /trunk/include/helpers/tree.h	(revision 12)
+++ /trunk/include/helpers/tree.h	(revision 13)
@@ -1,2 +1,27 @@
+
+/*
+ *@@sourcefile tree.h:
+ *      header file for tree.c (red-black balanced binary trees).
+ *      See remarks there.
+ */
+
+/*
+ *      Written:    97/11/18  Jonathan Schultz <jonathan@imatix.com>
+ *      Revised:    98/12/08  Jonathan Schultz <jonathan@imatix.com>
+ *
+ *      Copyright (C) 1991-99 iMatix Corporation.
+ *      Copyright (C) 2000 Ulrich Mller.
+ *      This file is part of the XWorkplace source package.
+ *      XWorkplace is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published
+ *      by the Free Software Foundation, in version 2 as it comes in the
+ *      "COPYING" file of the XWorkplace main distribution.
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ */
+
+
 /*  ----------------------------------------------------------------<Prolog>-
     Name:       sfltree.h
@@ -52,4 +77,17 @@
      *@@ TREE:
      *      tree node.
+     *
+     *      To use the tree functions, all your structures
+     *      must have a TREE structure as their first member.
+     *
+     *      Example:
+     *
+     +      typedef struct _MYTREENODE
+     +      {
+     +          TREE        tree;
+     +          char        acMyData[1000];
+     +      } MYTREENODE, *PMYTREENODE;
+     *
+     *      See tree.c for an introduction to the tree functions.
      */
 
@@ -61,5 +99,5 @@
         unsigned long   id;
         TREE_COLOUR     colour;
-    } TREE;
+    } TREE, *PTREE;
 
     // The tree algorithm needs to know how to sort the data.
Index: /trunk/include/helpers/xstring.h
===================================================================
--- /trunk/include/helpers/xstring.h	(revision 12)
+++ /trunk/include/helpers/xstring.h	(revision 13)
@@ -79,15 +79,23 @@
     #define xstrIsString(psz) ( (psz != 0) && (*(psz) != 0) )
 
+    PSZ xstrFindWord(const XSTRING *pxstr,
+                     ULONG ulOfs,
+                     const XSTRING *pstrFind,
+                     size_t *pShiftTable,
+                     PBOOL pfRepeatFind,
+                     const char *pcszBeginChars,
+                     const char *pcszEndChars);
+
     ULONG xstrrpl(PXSTRING pxstr,
-                  ULONG ulOfs,
+                  PULONG pulOfs,
                   const XSTRING *pstrSearch,
                   const XSTRING *pstrReplace,
-                  PULONG pulAfterOfs);
+                  size_t *pShiftTable,
+                  PBOOL pfRepeatFind);
 
     ULONG xstrcrpl(PXSTRING pxstr,
-                   ULONG ulOfs,
+                   PULONG pulOfs,
                    const char *pcszSearch,
-                   const char *pcszReplace,
-                   PULONG pulAfterOfs);
+                   const char *pcszReplace);
 #endif
 
Index: /trunk/readme.txt
===================================================================
--- /trunk/readme.txt	(revision 12)
+++ /trunk/readme.txt	(revision 13)
@@ -143,4 +143,12 @@
     headers.
 
+    Note that all the helpers C code includes their own include
+    files this way. As a result, the XWPHelpers "include"
+    directory must be in your include path, or this won't
+    compile.
+
+    Besides, the helpers C code expects a file called "setup.h"
+    in your include path somewhere. This is included by all
+    the C files so you can (re)define certain macros there.
 
 
Index: /trunk/src/helpers/cctl_progbar.c
===================================================================
--- /trunk/src/helpers/cctl_progbar.c	(revision 12)
+++ /trunk/src/helpers/cctl_progbar.c	(revision 13)
@@ -140,5 +140,5 @@
     {
         // make string
-        sprintf(szPercent, "%d %%", ((100 * pData->ulNow) / pData->ulMax) );
+        sprintf(szPercent, "%lu %%", ((100 * pData->ulNow) / pData->ulMax) );
 
         // calculate string space
Index: /trunk/src/helpers/debug.c
===================================================================
--- /trunk/src/helpers/debug.c	(revision 12)
+++ /trunk/src/helpers/debug.c	(revision 13)
@@ -700,9 +700,10 @@
                             NrPublic = pubfunc_ofs = pxdi->sspub32.offset;
                             read_types = TRUE;
-                            sprintf(pxdi->szNrPub, "%s %s (%s, seg %04X : ofs %08X\n",
+                            sprintf(pxdi->szNrPub,
+                                    "%s %s (%s, seg %04lX : ofs %08lX\n",
                                     (pxdi->sspub32.type == 1) ? " Abs" : " ",
                                     ename,
                                     ModName, // ()
-                                    pxdi->sspub32.segment,
+                                    (ULONG)pxdi->sspub32.segment,
                                     pxdi->sspub32.offset
                                 );
@@ -1177,5 +1178,5 @@
         sprintf(pszBuf, "%f", *(double*)varptr);
     else if (type == 10)
-        sprintf(pszBuf, "%f", *(long double*)varptr);
+        sprintf(pszBuf, "%f", (double)(*(long double*)varptr));
     else if (type == 16)
         sprintf(pszBuf, "%s", *(char*)varptr ? "TRUE" : "FALSE");
@@ -1187,12 +1188,12 @@
         sprintf(pszBuf, "%c", *(char*)varptr);
     else if (type == 21)
-        sprintf(pszBuf, "%lc", *(short*)varptr);
+        sprintf(pszBuf, "%hd", (*(short*)varptr));
     else if (type == 22)
-        sprintf(pszBuf, "%lc", *(long*)varptr);
+        sprintf(pszBuf, "%ld", *(long*)varptr);
     else if (type == 23)
         sprintf(pszBuf, "void");
     else if (type >= 32)
     {
-        sprintf(pszBuf, "0x%p", *(ULONG *) varptr);
+        sprintf(pszBuf, "0x%p", (void*)(*(ULONG*)varptr));
         if (Attr & PAG_FREE)
         {
@@ -1247,5 +1248,6 @@
                               one_userdef[pos].type_index - 0x80);
 
-                fprintf(LogFile, "     %- 6d %- 20.20s %- 33.33s %s (user)\n",
+                fprintf(LogFile,
+                        "     %- 6ld %- 20.20s %- 33.33s %s (user)\n",
                         autovar_def[var_no].stack_offset,       // stack offset
                         autovar_def[var_no].name,               // identifier
@@ -1295,5 +1297,5 @@
                       sszVar,
                       32);
-            fprintf(LogFile, "     %- 6d %- 20.20s %- 33.33s %s (ptr1)\n",
+            fprintf(LogFile, "     %- 6ld %- 20.20s %- 33.33s %s (ptr1)\n",
                     autovar_def[var_no].stack_offset,
                     autovar_def[var_no].name,
@@ -1319,5 +1321,5 @@
                           sszVar,
                           32);
-                fprintf(LogFile, "     %- 6d %- 20.20s %- 33.33s %s (ptr2)\n",
+                fprintf(LogFile, "     %- 6ld %- 20.20s %- 33.33s %s (ptr2)\n",
                         autovar_def[var_no].stack_offset,
                         autovar_def[var_no].name,
@@ -1335,5 +1337,5 @@
                           sszVar,
                           32);
-                fprintf(LogFile, "     %- 6d %- 20.20s %- 33.33s %s (ptr3)\n",
+                fprintf(LogFile, "     %- 6ld %- 20.20s %- 33.33s %s (ptr3)\n",
                         autovar_def[var_no].stack_offset,
                         autovar_def[var_no].name,
@@ -1372,5 +1374,7 @@
             {
                 AutoVarsFound = TRUE;
-                fprintf(LogFile, "     List of auto variables at EBP %p in %s:\n", stackofs, func_name);
+                fprintf(LogFile, "     List of auto variables at EBP %p in %s:\n",
+                        (PVOID)stackofs,
+                        func_name);
                 fprintf(LogFile, "     Offset Name                 Type                              Value            \n");
                 fprintf(LogFile, "     ÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n");
@@ -1388,5 +1392,5 @@
                           autovar_def[n].type_idx - 0x80);
 
-                fprintf(LogFile, "     %- 6d %- 20.20s %- 33.33s %s (simple)\n",
+                fprintf(LogFile, "     %- 6ld %- 20.20s %- 33.33s %s (simple)\n",
                         autovar_def[n].stack_offset,
                         autovar_def[n].name,
@@ -1400,5 +1404,5 @@
                     if (!search_pointers(LogFile, stackofs, n))
                     {
-                        fprintf(LogFile, "     %- 6d %-20.20s 0x%X (unknown)\n",
+                        fprintf(LogFile, "     %- 6ld %-20.20s 0x%X (unknown)\n",
                                 autovar_def[n].stack_offset,
                                 autovar_def[n].name,
@@ -1506,8 +1510,8 @@
                     {
                         // symbol found
-                        fprintf(LogFile, "between %s + 0x%X ", Buffer, TrapOffset - LastVal);
-                        fprintf(LogFile, "(ppLineDef: 0x%lX) ",
+                        fprintf(LogFile, "between %s + 0x%lX ", Buffer, TrapOffset - LastVal);
+                        /* fprintf(LogFile, "(ppLineDef: 0x%lX) ",
                                     LINEDEFOFFSET(SegDef)
-                                    );
+                                    ); */
                         fprintf(LogFile, "\n");
                     }
@@ -1522,5 +1526,5 @@
                         // symbol found, as above
                         fprintf(LogFile, "                                         "
-                                         "and %s - 0x%X ", Buffer, LastVal - TrapOffset);
+                                         "and %s - 0x%lX ", Buffer, LastVal - TrapOffset);
                         fprintf(LogFile, "\n");
                         break;
@@ -1534,5 +1538,5 @@
                     if (SymDef16.wSymVal > TrapOffset)
                     {
-                        fprintf(LogFile, "between %s + %X\n",
+                        fprintf(LogFile, "between %s + %lX\n",
                                          Buffer,
                                          TrapOffset - LastVal);
@@ -1545,5 +1549,5 @@
                     {
                         fprintf(LogFile, "                                         "
-                                         "and %s - %X\n",
+                                         "and %s - %lX\n",
                                          Buffer,
                                          LastVal - TrapOffset);
@@ -1681,5 +1685,5 @@
         else if (arc != 0)
             fprintf(LogFile,
-                    "Error %d reading symbol file %s\n",
+                    "Error %lu reading symbol file %s\n",
                     arc,
                     szSymName);
@@ -1743,15 +1747,15 @@
         if (rc != NO_ERROR)
         {
-            fprintf(LogFile, "Invalid EBP %8.8p (DosQueryMem returned %d)\n", Ebp, rc);
+            fprintf(LogFile, "Invalid EBP %8.8lX (DosQueryMem returned %lu)\n", (ULONG)Ebp, rc);
             break;
         }
         if (!(Attr & PAG_COMMIT))
         {
-            fprintf(LogFile, "Invalid EBP %8.8p (not committed)\n", Ebp);
+            fprintf(LogFile, "Invalid EBP %8.8lX (not committed)\n", (ULONG)Ebp);
             break;
         }
         if (Size < 10)
         {
-            fprintf(LogFile, "Invalid EBP %8.8p (mem block size < 10)\n", Ebp);
+            fprintf(LogFile, "Invalid EBP %8.8lX (mem block size < 10)\n", (ULONG)Ebp);
             break;
         }
@@ -1853,9 +1857,9 @@
             fprintf(LogFile, " Trap  ->  ");
         else
-            fprintf(LogFile, " %8.8p  ", Ebp);
+            fprintf(LogFile, " %8.8lX  ", (ULONG)Ebp);
 
         // "Address" column
         if (f32bit)
-            fprintf(LogFile, ":%8.8p  ", RetAddr);
+            fprintf(LogFile, ":%8.8lX  ", (ULONG)RetAddr);
         else
             fprintf(LogFile, "%04.04X:%04.04X  ", Cs, Ip);
@@ -1874,5 +1878,5 @@
             if (rc != NO_ERROR || !(Attr & PAG_COMMIT))
             {
-                fprintf(LogFile, "Invalid RetAddr: %8.8p\n", RetAddr);
+                fprintf(LogFile, "Invalid RetAddr: %8.8lX\n", (ULONG)RetAddr);
                 break;          // avoid infinite loops
             }
@@ -1895,5 +1899,5 @@
 
                     // print module and object
-                    fprintf(LogFile, "%-8s %04X  ", szName, ObjNum + 1);
+                    fprintf(LogFile, "%-8s %04lX  ", szName, ObjNum + 1);
 
                     if (strlen(Name) > 3)
@@ -1907,5 +1911,5 @@
                 else
                     fprintf(LogFile,
-                            "DosQueryModFromEIP failed, returned %d\n",
+                            "DosQueryModFromEIP failed, returned %lu\n",
                             rc);
             }
@@ -1949,5 +1953,5 @@
         if ((rc != NO_ERROR) || (Size < 4))
         {
-            fprintf(LogFile, "... lost stack chain - invalid EBP: %8.8p\n", Ebp);
+            fprintf(LogFile, "... lost stack chain - invalid EBP: %8.8lX\n", (ULONG)Ebp);
             break;
         }
Index: /trunk/src/helpers/dosh.c
===================================================================
--- /trunk/src/helpers/dosh.c	(revision 12)
+++ /trunk/src/helpers/dosh.c	(revision 13)
@@ -464,4 +464,6 @@
                          | OPEN_SHARE_DENYNONE,
                   NULL);
+
+    // _Pmpf((__FUNCTION__ ": DosOpen(OPEN_FLAGS_DASD) returned %d", arc));
 
     switch (arc)
@@ -1070,5 +1072,5 @@
     do
     {
-        sprintf(szCount, ".%03d", ulCount);
+        sprintf(szCount, ".%03lu", ulCount);
         strcpy(pszLastDot, szCount);
         ulCount++;
Index: /trunk/src/helpers/except.c
===================================================================
--- /trunk/src/helpers/except.c	(revision 12)
+++ /trunk/src/helpers/except.c	(revision 13)
@@ -299,5 +299,5 @@
             ulOffset = 0;
     fprintf(file,
-            "    %-8s: %08X ",
+            "    %-8s: %08lX ",
             pszDescription,
             ulAddress);
@@ -312,5 +312,5 @@
         // error:
         fprintf(file,
-                " %-8s:%d   Error: DosQueryModFromEIP returned %d\n",
+                " %-8s:%lu   Error: DosQueryModFromEIP returned %lu\n",
                 szMod1,
                 ulObject,
@@ -322,5 +322,5 @@
 
         fprintf(file,
-                " %-8s:%d   ",
+                " %-8s:%lu   ",
                 szMod1,
                 ulObject);
@@ -393,5 +393,5 @@
                )
             {
-                fprintf(file, "\n    %08X: ", pulStackWord);
+                fprintf(file, "\n    %08lX: ", (ULONG)pulStackWord);
                 fprintf(file, "Page inaccessible");
                 pulStackWord += 0x1000;
@@ -400,6 +400,6 @@
         }
 
-        sprintf(szAddress, "%08X",
-                pulStackWord);
+        sprintf(szAddress, "%08lX",
+                (ULONG)pulStackWord);
         excPrintStackFrame(file,
                            szAddress,
@@ -416,11 +416,9 @@
  *      This calls excPrintStackFrame for each stack frame.
  *
- *      If DEBUG_EXCPT_STACKDUMP is #define'd, this also dumps
- *      the stack completely, which isn't that useful.
- *
  *@@changed V0.9.0 [umoeller]: added support for application hook
  *@@changed V0.9.0 (99-11-02) [umoeller]: added TID to dump
  *@@changed V0.9.2 (2000-03-10) [umoeller]: now using excPrintStackFrame
  *@@changed V0.9.3 (2000-05-03) [umoeller]: fixed crashes
+ *@@changed V0.9.6 (2000-11-06) [umoeller]: added more register dumps
  */
 
@@ -475,11 +473,11 @@
     // generic exception info
     fprintf(file,
-            "\n%s:\n    Exception type: %08X\n    Address:        %08X\n    Params:         ",
+            "\n%s:\n    Exception type: %08lX\n    Address:        %08lX\n    Params:         ",
             pszHandlerName,
             pReportRec->ExceptionNum,
-            pReportRec->ExceptionAddress);
+            (ULONG)pReportRec->ExceptionAddress);
     for (ul = 0;  ul < pReportRec->cParameters;  ul++)
     {
-        fprintf(file, "%08X  ",
+        fprintf(file, "%08lX  ",
                 pReportRec->ExceptionInfo[ul]);
     }
@@ -494,16 +492,16 @@
             fprintf(file, "\nAccess violation: ");
             if (pReportRec->ExceptionInfo[0] & XCPT_READ_ACCESS)
-                fprintf(file, "Invalid read access from 0x%04X:%08X.\n",
+                fprintf(file, "Invalid read access from 0x%04lX:%08lX.\n",
                         pContextRec->ctx_SegDs, pReportRec->ExceptionInfo[1]);
             else if (pReportRec->ExceptionInfo[0] & XCPT_WRITE_ACCESS)
-                fprintf(file, "Invalid write access to 0x%04X:%08X.\n",
+                fprintf(file, "Invalid write access to 0x%04lX:%08lX.\n",
                         pContextRec->ctx_SegDs, pReportRec->ExceptionInfo[1]);
             else if (pReportRec->ExceptionInfo[0] & XCPT_SPACE_ACCESS)
-                fprintf(file, "Invalid space access at 0x%04X.\n",
+                fprintf(file, "Invalid space access at 0x%04lX.\n",
                         pReportRec->ExceptionInfo[1]);
             else if (pReportRec->ExceptionInfo[0] & XCPT_LIMIT_ACCESS)
                 fprintf(file, "Invalid limit access occurred.\n");
             else if (pReportRec->ExceptionInfo[0] == XCPT_UNKNOWN_ACCESS)
-                fprintf(file, "unknown at 0x%04X:%08X\n",
+                fprintf(file, "unknown at 0x%04lX:%08lX\n",
                             pContextRec->ctx_SegDs, pReportRec->ExceptionInfo[1]);
             fprintf(file,
@@ -586,5 +584,5 @@
                     "\n    Process module:  0x%lX (%s)"
                     "\n    Trapping module: 0x%lX (%s)"
-                    "\n    Object: %d\n",
+                    "\n    Object: %lu\n",
                     ppib->pib_ulpid,
                     hMod1, szMod1,
@@ -594,5 +592,5 @@
             fprintf(file,
                     "\nTrapping thread information:"
-                    "\n    Thread ID:       0x%lX (%d)"
+                    "\n    Thread ID:       0x%lX (%lu)"
                     "\n    Priority:        0x%lX\n",
                     ptib->tib_ptib2->tib2_ultid, ptib->tib_ptib2->tib2_ultid,
@@ -618,21 +616,34 @@
         if (pContextRec->ContextFlags & CONTEXT_INTEGER)
         {
+            // DS the following 4 added V0.9.6 (2000-11-06) [umoeller]
+            fprintf(file, "\n    DS  = %08lX  ", pContextRec->ctx_SegDs);
+            excDescribePage(file, pContextRec->ctx_SegDs);
+            // ES
+            fprintf(file, "\n    ES  = %08lX  ", pContextRec->ctx_SegEs);
+            excDescribePage(file, pContextRec->ctx_SegEs);
+            // FS
+            fprintf(file, "\n    FS  = %08lX  ", pContextRec->ctx_SegFs);
+            excDescribePage(file, pContextRec->ctx_SegFs);
+            // GS
+            fprintf(file, "\n    GS  = %08lX  ", pContextRec->ctx_SegGs);
+            excDescribePage(file, pContextRec->ctx_SegGs);
+
             // EAX
-            fprintf(file, "\n    EAX = %08X  ", pContextRec->ctx_RegEax);
+            fprintf(file, "\n    EAX = %08lX  ", pContextRec->ctx_RegEax);
             excDescribePage(file, pContextRec->ctx_RegEax);
             // EBX
-            fprintf(file, "\n    EBX = %08X  ", pContextRec->ctx_RegEbx);
+            fprintf(file, "\n    EBX = %08lX  ", pContextRec->ctx_RegEbx);
             excDescribePage(file, pContextRec->ctx_RegEbx);
             // ECX
-            fprintf(file, "\n    ECX = %08X  ", pContextRec->ctx_RegEcx);
+            fprintf(file, "\n    ECX = %08lX  ", pContextRec->ctx_RegEcx);
             excDescribePage(file, pContextRec->ctx_RegEcx);
             // EDX
-            fprintf(file, "\n    EDX = %08X  ", pContextRec->ctx_RegEdx);
+            fprintf(file, "\n    EDX = %08lX  ", pContextRec->ctx_RegEdx);
             excDescribePage(file, pContextRec->ctx_RegEdx);
             // ESI
-            fprintf(file, "\n    ESI = %08X  ", pContextRec->ctx_RegEsi);
+            fprintf(file, "\n    ESI = %08lX  ", pContextRec->ctx_RegEsi);
             excDescribePage(file, pContextRec->ctx_RegEsi);
             // EDI
-            fprintf(file, "\n    EDI = %08X  ", pContextRec->ctx_RegEdi);
+            fprintf(file, "\n    EDI = %08lX  ", pContextRec->ctx_RegEdi);
             excDescribePage(file, pContextRec->ctx_RegEdi);
             fprintf(file, "\n");
@@ -646,5 +657,5 @@
             // *** instruction
 
-            fprintf(file, "Instruction pointer (where exception occured):\n    CS:EIP = %04X:%08X  ",
+            fprintf(file, "Instruction pointer (where exception occured):\n    CS:EIP = %04lX:%08lX  ",
                     pContextRec->ctx_SegCs,
                     pContextRec->ctx_RegEip);
@@ -653,5 +664,5 @@
             // *** CPU flags
 
-            fprintf(file, "\n    FLG    = %08X", pContextRec->ctx_EFlags);
+            fprintf(file, "\n    EFLAGS = %08lX", pContextRec->ctx_EFlags);
 
             /*
@@ -660,12 +671,13 @@
              */
 
-            fprintf(file, "\nStack:\n    Base:         %08X\n    Limit:        %08X",
-                   (ptib ? ptib->tib_pstack : 0),
-                   (ptib ? ptib->tib_pstacklimit :0));
-            fprintf(file, "\n    SS:ESP = %04X:%08X  ",
-                    pContextRec->ctx_SegSs, pContextRec->ctx_RegEsp);
+            fprintf(file, "\nStack:\n    Base:         %08lX\n    Limit:        %08lX",
+                   (ULONG)(ptib ? ptib->tib_pstack : 0),
+                   (ULONG)(ptib ? ptib->tib_pstacklimit : 0));
+            fprintf(file, "\n    SS:ESP = %04lX:%08lX  ",
+                    pContextRec->ctx_SegSs,
+                    pContextRec->ctx_RegEsp);
             excDescribePage(file, pContextRec->ctx_RegEsp);
 
-            fprintf(file, "\n    EBP    =      %08X  ", pContextRec->ctx_RegEbp);
+            fprintf(file, "\n    EBP    =      %08lX  ", pContextRec->ctx_RegEbp);
             excDescribePage(file, pContextRec->ctx_RegEbp);
 
Index: /trunk/src/helpers/gpih.c
===================================================================
--- /trunk/src/helpers/gpih.c	(revision 12)
+++ /trunk/src/helpers/gpih.c	(revision 13)
@@ -384,5 +384,5 @@
         {
             // _Pmpf(("Found font PP: %s", pszFontFound));
-            sscanf(pszFontNameSize, "%d", pulSize);
+            sscanf(pszFontNameSize, "%lu", pulSize);
             *ppszFaceName = pcDot + 1;
             brc = TRUE;
@@ -932,5 +932,5 @@
         {
             // _Pmpf(("Found font PP: %s", pszFontFound));
-            sscanf(pszFontFound, "%d", &ulFontSize);
+            sscanf(pszFontFound, "%lu", &ulFontSize);
             if (plSize)
                 *plSize = ulFontSize;
Index: /trunk/src/helpers/helpers_post.in
===================================================================
--- /trunk/src/helpers/helpers_post.in	(revision 12)
+++ /trunk/src/helpers/helpers_post.in	(revision 13)
@@ -114,4 +114,8 @@
 $(OUTPUTDIR)\memdebug.obj:  $(@B).c $(HLPINC)\$(@B).h \
                $(PROJECTINC)\setup.h \
+               $(HLPINC)\except.h $(HLPINC)\stringh.h
+
+$(OUTPUTDIR)\memdebug_win.obj:  $(@B).c $(HLPINC)\memdebug.h \
+               $(PROJECTINC)\setup.h \
                $(HLPINC)\cnrh.h $(HLPINC)\except.h $(HLPINC)\stringh.h $(HLPINC)\winh.h
 
Index: /trunk/src/helpers/helpers_pre.in
===================================================================
--- /trunk/src/helpers/helpers_pre.in	(revision 12)
+++ /trunk/src/helpers/helpers_pre.in	(revision 13)
@@ -40,44 +40,45 @@
 
 PLAINCOBJS = \
-       $(OUTPUTDIR)\linklist.obj \
-       $(OUTPUTDIR)\tree.obj \
-       $(OUTPUTDIR)\xml.obj \
+$(OUTPUTDIR)\linklist.obj \
+$(OUTPUTDIR)\tree.obj \
+$(OUTPUTDIR)\xml.obj \
 
 CPOBJS = $(PLAINCOBJS) \
-       $(OUTPUTDIR)\datetime.obj \
-       $(OUTPUTDIR)\debug.obj \
-       $(OUTPUTDIR)\dosh.obj \
-       $(OUTPUTDIR)\dosh2.obj \
-       $(OUTPUTDIR)\eah.obj \
-       $(OUTPUTDIR)\except.obj \
-       $(OUTPUTDIR)\level.obj \
-       $(OUTPUTDIR)\procstat.obj \
-       $(OUTPUTDIR)\prfh.obj \
-       $(OUTPUTDIR)\prfh2.obj \
-       $(OUTPUTDIR)\resh.obj \
-       $(OUTPUTDIR)\stringh.obj \
-       $(OUTPUTDIR)\syssound.obj \
-       $(OUTPUTDIR)\threads.obj \
-       $(OUTPUTDIR)\tmsgfile.obj \
-       $(OUTPUTDIR)\wphandle.obj \
-       $(OUTPUTDIR)\xprf.obj \
-       $(OUTPUTDIR)\xprf2.obj \
-       $(OUTPUTDIR)\xstring.obj
+$(OUTPUTDIR)\datetime.obj \
+$(OUTPUTDIR)\debug.obj \
+$(OUTPUTDIR)\dosh.obj \
+$(OUTPUTDIR)\dosh2.obj \
+$(OUTPUTDIR)\eah.obj \
+$(OUTPUTDIR)\except.obj \
+$(OUTPUTDIR)\level.obj \
+$(OUTPUTDIR)\procstat.obj \
+$(OUTPUTDIR)\prfh.obj \
+$(OUTPUTDIR)\prfh2.obj \
+$(OUTPUTDIR)\resh.obj \
+$(OUTPUTDIR)\stringh.obj \
+$(OUTPUTDIR)\syssound.obj \
+$(OUTPUTDIR)\tmsgfile.obj \
+$(OUTPUTDIR)\wphandle.obj \
+$(OUTPUTDIR)\xprf.obj \
+$(OUTPUTDIR)\xprf2.obj \
+$(OUTPUTDIR)\xstring.obj
 
 OBJS = $(CPOBJS) \
-       $(OUTPUTDIR)\animate.obj \
-       $(OUTPUTDIR)\cctl_chart.obj \
-       $(OUTPUTDIR)\cctl_checkcnr.obj \
-       $(OUTPUTDIR)\cctl_progbar.obj \
-       $(OUTPUTDIR)\cctl_splitwin.obj \
-       $(OUTPUTDIR)\cctl_tooltip.obj \
-       $(OUTPUTDIR)\comctl.obj \
-       $(OUTPUTDIR)\cnrh.obj \
-       $(OUTPUTDIR)\gpih.obj \
-       $(OUTPUTDIR)\memdebug.obj \
-       $(OUTPUTDIR)\shapewin.obj \
-       $(OUTPUTDIR)\textview.obj \
-       $(OUTPUTDIR)\textv_html.obj \
-       $(OUTPUTDIR)\winh.obj
+$(OUTPUTDIR)\animate.obj \
+$(OUTPUTDIR)\cctl_chart.obj \
+$(OUTPUTDIR)\cctl_checkcnr.obj \
+$(OUTPUTDIR)\cctl_progbar.obj \
+$(OUTPUTDIR)\cctl_splitwin.obj \
+$(OUTPUTDIR)\cctl_tooltip.obj \
+$(OUTPUTDIR)\comctl.obj \
+$(OUTPUTDIR)\cnrh.obj \
+$(OUTPUTDIR)\gpih.obj \
+$(OUTPUTDIR)\memdebug.obj \
+$(OUTPUTDIR)\memdebug_win.obj \
+$(OUTPUTDIR)\shapewin.obj \
+$(OUTPUTDIR)\threads.obj \
+$(OUTPUTDIR)\textview.obj \
+$(OUTPUTDIR)\textv_html.obj \
+$(OUTPUTDIR)\winh.obj
 
 # helpers include path
Index: /trunk/src/helpers/makefile
===================================================================
--- /trunk/src/helpers/makefile	(revision 12)
+++ /trunk/src/helpers/makefile	(revision 13)
@@ -136,9 +136,26 @@
 # The exclamation point ( ! ) preceding the LIB command causes NMAKE
 # to execute the LIB command once for each dependent file in the list.
+
 $(OUTPUTDIR)\helpers.lib: $(OBJS)
 !ifdef EMX
-    !emxomfar cr $(OUTPUTDIR)\helpers.lib $?
+    !emxomfar cr $* $?
 !else
-    !ilib /nol /nob $(OUTPUTDIR)\helpers.lib -+$?;
+    !ilib /nol /nob $* -+$?;
+!endif
+
+# same thing for cp.lib
+$(OUTPUTDIR)\cp.lib: $(CPOBJS)
+!ifdef EMX
+    !emxomfar cr $* $?
+!else
+    !ilib /nol /nob $* -+$?;
+!endif
+
+# same thing for plainc.lib
+$(OUTPUTDIR)\plainc.lib: $(PLAINCOBJS)
+!ifdef EMX
+    !emxomfar cr $* $?
+!else
+    !ilib /nol /nob $* -+$?;
 !endif
 
Index: /trunk/src/helpers/memdebug.c
===================================================================
--- /trunk/src/helpers/memdebug.c	(revision 12)
+++ /trunk/src/helpers/memdebug.c	(revision 13)
@@ -1,7 +1,6 @@
 
 /*
- * memdebug.c:
- *      memory debugging helpers. Memory debugging is enabled
- *      if the __XWPMEMDEBUG__ #define is set in setup.h.
+ *@@sourcefile memdebug.c:
+ *      memory debugging helpers.
  *
  *      Several things are in here which might turn out to
@@ -12,5 +11,12 @@
  *      -- Sophisticated heap debugging functions, which
  *         automatically replace malloc() and free() etc.
- *         when XWorkplace is compiled with debug code.
+ *         If the __XWPMEMDEBUG__ #define is set before including
+ *         memdebug.h, all those standard library calls
+ *         are remapped to use the functions in this file
+ *         instead.
+ *
+ *         At present, malloc(), calloc(), realloc(), strdup()
+ *         and free() are supported.
+ *
  *         These log every memory allocation made and log
  *         much more data compared to the VAC++ memory
@@ -28,17 +34,15 @@
  *         function.
  *
- *         At present, malloc(), calloc(), strdup() and free()
- *         are supported. If you invoke free() on a memory block
- *         allocated by a function other than the above, you'll
- *         get a runtime error.
- *
  *         These debug functions have been added with V0.9.3
  *         and should now be compiler-independent.
  *
- *      -- A PM heap debugging window which shows the statuzs
+ *         V0.9.6 added realloc() support and fixed a few bugs.
+ *
+ *      -- A PM heap debugging window which shows the status
  *         of the heap logging list. See memdCreateMemDebugWindow
- *         for details.
- *
- *      To enable memory debugging, do the following:
+ *         (memdebug_win.c) for details.
+ *
+ *      To enable memory debugging, do the following in each (!)
+ *      of your code modules:
  *
  *      1) Include at least <stdlib.h> and <string.h>.
@@ -53,4 +57,33 @@
  *      That's all. XWorkplace's setup.h does this automatically
  *      if XWorkplace is compiled with debug code.
+ *
+ *      A couple of WARNINGS:
+ *
+ *      1)  Memory debugging can greatly slow down the system
+ *          after a while. When free() is invoked, the memory
+ *          that was allocated is freed, but not the memory
+ *          log entry (the HEAPITEM) to allow tracing what was
+ *          freed. As a result, the linked list of memory items
+ *          keeps growing longer, and free() becomes terribly
+ *          slow after a while because it must traverse the
+ *          entire list for each free() call. Use memdReleaseFreed
+ *          from time to time.
+ *
+ *      2)  The replacement functions in this file allocate
+ *          extra memory for the magic strings. For example, if
+ *          you call malloc(100), more than 100 bytes get allocated
+ *          to allow for storing the magic strings to detect
+ *          memory overwrites. Two magic strings are allocated,
+ *          one before the actual buffer, and one behind it.
+ *
+ *          As a result, YOU MUST NOT confuse the replacement
+ *          memory functions with the original ones. If you
+ *          use malloc() in one source file and free() the
+ *          buffer in another one where debug memory has not
+ *          been enabled, you'll get crashes.
+ *
+ *          As a rule of thumb, enable memory debugging for all
+ *          your source files or for none. And make sure everything
+ *          is recompiled when you change your mind.
  *
  *@@added V0.9.1 (2000-02-12) [umoeller]
@@ -80,27 +113,19 @@
 #define INCL_DOSERRORS
 
-#define INCL_WINWINDOWMGR
-#define INCL_WINFRAMEMGR
-#define INCL_WINCOUNTRY
-#define INCL_WINSYS
-#define INCL_WINMENUS
-#define INCL_WINSTDCNR
 #include <os2.h>
 
 #include <stdio.h>
 #include <string.h>
-// #include <malloc.h>
 #include <setjmp.h>
 
-#define DONT_REPLACE_MALLOC             // we need the "real" malloc in this file
+#define DONT_REPLACE_MALLOC             // never do debug memory for this
+#define MEMDEBUG_PRIVATE
 #include "setup.h"
 
 #ifdef __XWPMEMDEBUG__
 
-#include "helpers\cnrh.h"
 #include "helpers\except.h"
-// #include "helpers\memdebug.h"        // included by setup.h already
+#include "helpers\memdebug.h"        // included by setup.h already
 #include "helpers\stringh.h"
-#include "helpers\winh.h"
 
 /*
@@ -120,48 +145,13 @@
 #define MEMBLOCKMAGIC_TAIL     "\250\210&%/dfjsk%#,dlhf\223"
 
-/*
- *@@ HEAPITEM:
- *      informational structure created for each
- *      malloc() call by memdMalloc. These are stored
- *      in a global linked list (G_pHeapItemsRoot).
- *
- *      We cannot use the linklist.c functions for
- *      managing the linked list because these use
- *      malloc in turn, which would lead to infinite
- *      loops.
- *
- *@@added V0.9.3 (2000-04-11) [umoeller]
- */
-
-typedef struct _HEAPITEM
-{
-    struct _HEAPITEM    *pNext;     // next item in linked list or NULL if last
-
-    void                *pAfterMagic; // memory pointer returned by memdMalloc;
-                                    // this points to after the magic string
-    unsigned long       ulSize;     // size of *pData
-
-    const char          *pcszSourceFile;    // as passed to memdMalloc
-    unsigned long       ulLine;             // as passed to memdMalloc
-    const char          *pcszFunction;      // as passed to memdMalloc
-
-    DATETIME            dtAllocated;        // system date/time at time of memdMalloc call
-
-    ULONG               ulTID;      // thread ID that memdMalloc was running on
-
-    BOOL                fFreed;     // TRUE only after item has been freed by memdFree
-} HEAPITEM, *PHEAPITEM;
-
 HMTX            G_hmtxMallocList = NULLHANDLE;
 
-PHEAPITEM       G_pHeapItemsRoot = NULL,
-                G_pHeapItemsLast = NULL;
-
-PSZ             G_pszMemCnrTitle = NULL;
+extern PHEAPITEM G_pHeapItemsRoot = NULL;
+PHEAPITEM       G_pHeapItemsLast = NULL;
 
 PFNCBMEMDLOG    G_pMemdLogFunc = NULL;
 
-ULONG           G_ulItemsReleased = 0,
-                G_ulBytesReleased = 0;
+extern ULONG    G_ulItemsReleased = 0;
+extern ULONG    G_ulBytesReleased = 0;
 
 /* ******************************************************************
@@ -189,9 +179,9 @@
         arc = DosCreateMutexSem(NULL,
                                 &G_hmtxMallocList,
-                                0,
-                                FALSE);
-
-    arc = DosRequestMutexSem(G_hmtxMallocList,
-                             SEM_INDEFINITE_WAIT);
+                                0,          // unshared
+                                TRUE);      // request now!
+    else
+        arc = DosRequestMutexSem(G_hmtxMallocList,
+                                 SEM_INDEFINITE_WAIT);
 
     return (arc == NO_ERROR);
@@ -435,9 +425,7 @@
                     pHeapItem->fFreed = TRUE;
 
-                    /* lstRemoveNode(&G_llHeapItems,
-                                  pNode); */
                     fFound = TRUE;
                     break;
-                }
+                } // if (!pHeapItem->fFreed)
 
             pHeapItem = pHeapItem->pNext;
@@ -452,5 +440,5 @@
             CHAR szMsg[1000];
             sprintf(szMsg,
-                    "free() failed. Called from %s (%s, line %d) for object 0x%lX.",
+                    "free() called with invalid object from %s (%s, line %d) for object 0x%lX.",
                     pcszFunction,
                         pcszSourceFile,
@@ -459,4 +447,151 @@
             G_pMemdLogFunc(szMsg);
         }
+}
+
+/*
+ *@@ memdRealloc:
+ *      wrapper function for realloc(). See memdMalloc for
+ *      details.
+ *
+ *@@added V0.9.6 (2000-11-12) [umoeller]
+ */
+
+void* memdRealloc(void *p,
+                  size_t stSize,
+                  const char *pcszSourceFile, // in: source file name
+                  unsigned long ulLine,       // in: source line
+                  const char *pcszFunction)   // in: function name
+{
+    void *prc = NULL;
+    BOOL fFound = FALSE;
+
+    if (memdLock())
+    {
+        PHEAPITEM pHeapItem = G_pHeapItemsRoot;
+
+        // search the list with the pointer which was
+        // really returned by the original malloc(),
+        // that is, the byte before the magic string
+        void *pBeforeMagic = ((PBYTE)p) - sizeof(MEMBLOCKMAGIC_HEAD);
+
+        while (pHeapItem)
+        {
+            if (pHeapItem->pAfterMagic == p)
+                // the same address may be allocated and freed
+                // several times, so if this address has been
+                // freed, search on
+                if (!pHeapItem->fFreed)
+                {
+                    // found:
+                    PVOID   pObjNew = 0;
+                    ULONG   ulError = 0;
+                    ULONG   cbCopy = 0;
+                    PTIB    ptib;
+                    PPIB    ppib;
+
+                    // check magic string
+                    if (memcmp(pBeforeMagic,
+                               MEMBLOCKMAGIC_HEAD,
+                               sizeof(MEMBLOCKMAGIC_HEAD))
+                            != 0)
+                        ulError = 1;
+                    else if (memcmp(((PBYTE)pHeapItem->pAfterMagic) + pHeapItem->ulSize,
+                                    MEMBLOCKMAGIC_TAIL,
+                                    sizeof(MEMBLOCKMAGIC_TAIL))
+                            != 0)
+                        ulError = 2;
+
+                    if (ulError)
+                    {
+                        // magic block has been overwritten:
+                        if (G_pMemdLogFunc)
+                        {
+                            CHAR szMsg[1000];
+                            sprintf(szMsg,
+                                    "Magic string %s memory block at 0x%lX has been overwritten.\n"
+                                    "This was detected by the realloc() call at %s (%s, line %d).\n"
+                                    "The block was allocated by %s (%s, line %d).",
+                                    (ulError == 1) ? "before" : "after",
+                                    p,
+                                    pcszFunction,
+                                        pcszSourceFile,
+                                        ulLine, // free
+                                    pHeapItem->pcszFunction,
+                                        pHeapItem->pcszSourceFile,
+                                        pHeapItem->ulLine);
+                            G_pMemdLogFunc(szMsg);
+                        }
+                    }
+
+                    // now reallocate!
+                    pObjNew = malloc(stSize   // new size
+                                     + sizeof(MEMBLOCKMAGIC_HEAD)
+                                     + sizeof(MEMBLOCKMAGIC_TAIL));
+
+                    // store "front" magic string
+                    memcpy(pObjNew,
+                           MEMBLOCKMAGIC_HEAD,
+                           sizeof(MEMBLOCKMAGIC_HEAD));
+                    // return address: first byte after "front" magic string
+                    prc = ((PBYTE)pObjNew) + sizeof(MEMBLOCKMAGIC_HEAD);
+
+                    // bytes to copy: the smaller of the old and the new size
+                    cbCopy = pHeapItem->ulSize;
+                    if (stSize < pHeapItem->ulSize)
+                        cbCopy = stSize;
+
+                    // copy buffer from old memory object
+                    memcpy(prc,         // after "front" magic
+                           pHeapItem->pAfterMagic,
+                           cbCopy);
+
+                    // store "tail" magic string to block which
+                    // will be returned plus the size which was requested
+                    memcpy(((PBYTE)prc) + stSize,
+                           MEMBLOCKMAGIC_TAIL,
+                           sizeof(MEMBLOCKMAGIC_TAIL));
+
+                    // free the old buffer
+                    free(pBeforeMagic);
+
+                    // update the HEAPITEM
+                    pHeapItem->pAfterMagic = prc;       // new pointer!
+                    pHeapItem->ulSize = stSize;         // new size!
+                    pHeapItem->pcszSourceFile = pcszSourceFile;
+                    pHeapItem->ulLine = ulLine;
+                    pHeapItem->pcszFunction = pcszFunction;
+
+                    // update date, time, TID
+                    DosGetDateTime(&pHeapItem->dtAllocated);
+                    pHeapItem->ulTID = 0;
+                    if (DosGetInfoBlocks(&ptib, &ppib) == NO_ERROR)
+                        if (ptib)
+                            if (ptib->tib_ptib2)
+                                pHeapItem->ulTID = ptib->tib_ptib2->tib2_ultid;
+
+                    fFound = TRUE;
+                    break;
+                } // if (!pHeapItem->fFreed)
+
+            pHeapItem = pHeapItem->pNext;
+        }
+
+        memdUnlock();
+    }
+
+    if (!fFound)
+        if (G_pMemdLogFunc)
+        {
+            CHAR szMsg[1000];
+            sprintf(szMsg,
+                    "realloc() called with invalid object from %s (%s, line %d) for object 0x%lX.",
+                    pcszFunction,
+                        pcszSourceFile,
+                        ulLine,
+                    p);
+            G_pMemdLogFunc(szMsg);
+        }
+
+    return (prc);
 }
 
@@ -485,8 +620,10 @@
         while (pHeapItem)
         {
+            // store next first, because we can change the "next" pointer
             PHEAPITEM   pNext = pHeapItem->pNext;       // can be NULL
+
             if (pHeapItem->fFreed)
             {
-                // item freed:
+                // item was freed:
                 if (pPrevious == NULL)
                     // head of list:
@@ -499,4 +636,8 @@
                 ulItemsReleased++;
                 ulBytesReleased += pHeapItem->ulSize;
+
+                if (pHeapItem == G_pHeapItemsLast)
+                    // reset "last item" cache
+                    G_pHeapItemsLast = NULL;
 
                 free(pHeapItem);
@@ -550,681 +691,4 @@
 #endif
 
-/* ******************************************************************
- *                                                                  *
- *   Heap debugging window                                          *
- *                                                                  *
- ********************************************************************/
-
-/*
- *@@ MEMRECORD:
- *
- *@@added V0.9.1 (99-12-04) [umoeller]
- */
-
-typedef struct _MEMRECORD
-{
-    RECORDCORE  recc;
-
-    ULONG       ulIndex;
-
-    CDATE       cdateAllocated;
-    CTIME       ctimeAllocated;
-
-    PSZ         pszFreed;
-
-    ULONG       ulTID;
-
-    PSZ         pszFunction;    // points to szFunction
-    CHAR        szFunction[400];
-
-    PSZ         pszSource;      // points to szSource
-    CHAR        szSource[CCHMAXPATH];
-
-    ULONG       ulLine;
-
-    PSZ         pszAddress;     // points to szAddress
-    CHAR        szAddress[20];
-
-    ULONG       ulSize;
-
-} MEMRECORD, *PMEMRECORD;
-
-/* ULONG       ulHeapItemsCount1,
-            ulHeapItemsCount2;
-ULONG       ulTotalAllocated,
-            ulTotalFreed;
-PMEMRECORD  pMemRecordThis = NULL;
-PSZ         pszMemCnrTitle = NULL; */
-
-#if 0
-    /*
-     *@@ fncbMemHeapWalkCount:
-     *      callback func for _heap_walk function used for
-     *      fnwpMemDebug.
-     *
-     *@@added V0.9.1 (99-12-04) [umoeller]
-     */
-
-    int fncbMemHeapWalkCount(const void *pObject,
-                             size_t Size,
-                             int useflag,
-                             int status,
-                             const char *filename,
-                             size_t line)
-    {
-        // skip all the items which seem to be
-        // internal to the runtime
-        if ((filename) || (useflag == _FREEENTRY))
-        {
-            ulHeapItemsCount1++;
-            if (useflag == _FREEENTRY)
-                ulTotalFreed += Size;
-            else
-                ulTotalAllocated += Size;
-        }
-        return (0);
-    }
-
-    /*
-     *@@ fncbMemHeapWalkFill:
-     *      callback func for _heap_walk function used for
-     *      fnwpMemDebug.
-     *
-     *@@added V0.9.1 (99-12-04) [umoeller]
-     */
-
-    int fncbMemHeapWalkFill(const void *pObject,
-                            size_t Size,
-                            int useflag,
-                            int status,
-                            const char *filename,
-                            size_t line)
-    {
-        // skip all the items which seem to be
-        // internal to the runtime
-        if ((filename) || (useflag == _FREEENTRY))
-        {
-            ulHeapItemsCount2++;
-            if ((pMemRecordThis) && (ulHeapItemsCount2 < ulHeapItemsCount1))
-            {
-                pMemRecordThis->ulIndex = ulHeapItemsCount2 - 1;
-
-                pMemRecordThis->pObject = pObject;
-                pMemRecordThis->useflag = useflag;
-                pMemRecordThis->status = status;
-                pMemRecordThis->filename = filename;
-
-                pMemRecordThis->pszAddress = pMemRecordThis->szAddress;
-
-                pMemRecordThis->ulSize = Size;
-
-                pMemRecordThis->pszSource = pMemRecordThis->szSource;
-
-                pMemRecordThis->ulLine = line;
-
-                pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
-            }
-            else
-                return (1);     // stop
-        }
-
-        return (0);
-    }
-
-    /*
-     *@@ memdCreateRecordsVAC:
-     *
-     *@@added V0.9.3 (2000-04-10) [umoeller]
-     */
-
-    VOID memdCreateRecordsVAC(HWND hwndCnr)
-    {
-        // count heap items
-        ulHeapItemsCount1 = 0;
-        ulTotalFreed = 0;
-        ulTotalAllocated = 0;
-        _heap_walk(fncbMemHeapWalkCount);
-
-        pMemRecordFirst = (PMEMRECORD)cnrhAllocRecords(hwndCnr,
-                                                       sizeof(MEMRECORD),
-                                                       ulHeapItemsCount1);
-        if (pMemRecordFirst)
-        {
-            ulHeapItemsCount2 = 0;
-            pMemRecordThis = pMemRecordFirst;
-            _heap_walk(fncbMemHeapWalkFill);
-
-            // the following doesn't work while _heap_walk is running
-            pMemRecordThis = pMemRecordFirst;
-            while (pMemRecordThis)
-            {
-                switch (pMemRecordThis->useflag)
-                {
-                    case _USEDENTRY: pMemRecordThis->pszUseFlag = "Used"; break;
-                    case _FREEENTRY: pMemRecordThis->pszUseFlag = "Freed"; break;
-                }
-
-                switch (pMemRecordThis->status)
-                {
-                    case _HEAPBADBEGIN: pMemRecordThis->pszStatus = "heap bad begin"; break;
-                    case _HEAPBADNODE: pMemRecordThis->pszStatus = "heap bad node"; break;
-                    case _HEAPEMPTY: pMemRecordThis->pszStatus = "heap empty"; break;
-                    case _HEAPOK: pMemRecordThis->pszStatus = "OK"; break;
-                }
-
-                sprintf(pMemRecordThis->szAddress, "0x%lX", pMemRecordThis->pObject);
-                strcpy(pMemRecordThis->szSource,
-                        (pMemRecordThis->filename)
-                            ? pMemRecordThis->filename
-                            : "?");
-
-                pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
-            }
-
-            cnrhInsertRecords(hwndCnr,
-                              NULL,         // parent
-                              (PRECORDCORE)pMemRecordFirst,
-                              TRUE,
-                              NULL,
-                              CRA_RECORDREADONLY,
-                              ulHeapItemsCount2);
-        }
-    }
-
-#endif
-
-/*
- *@@ memdCreateRecords:
- *
- *@@added V0.9.3 (2000-04-10) [umoeller]
- */
-
-VOID memdCreateRecords(HWND hwndCnr,
-                       PULONG pulTotalItems,
-                       PULONG pulAllocatedItems,
-                       PULONG pulFreedItems,
-                       PULONG pulTotalBytes,
-                       PULONG pulAllocatedBytes,
-                       PULONG pulFreedBytes)
-{
-    // count heap items
-    ULONG       ulHeapItemsCount1 = 0;
-    PMEMRECORD  pMemRecordFirst;
-
-    if (memdLock())
-    {
-        // PLISTNODE   pNode = lstQueryFirstNode(&G_llHeapItems);
-        PHEAPITEM pHeapItem = G_pHeapItemsRoot;
-
-        *pulTotalItems = 0;
-        *pulAllocatedItems = 0;
-        *pulFreedItems = 0;
-
-        *pulTotalBytes = 0;
-        *pulAllocatedBytes = 0;
-        *pulFreedBytes = 0;
-
-        while (pHeapItem)
-        {
-            ulHeapItemsCount1++;
-            if (pHeapItem->fFreed)
-            {
-                (*pulFreedItems)++;
-                (*pulFreedBytes) += pHeapItem->ulSize;
-            }
-            else
-            {
-                (*pulAllocatedItems)++;
-                (*pulAllocatedBytes) += pHeapItem->ulSize;
-            }
-
-            (*pulTotalBytes) += pHeapItem->ulSize;
-
-            pHeapItem = pHeapItem->pNext;
-        }
-
-        *pulTotalItems = ulHeapItemsCount1;
-
-        pMemRecordFirst = (PMEMRECORD)cnrhAllocRecords(hwndCnr,
-                                                       sizeof(MEMRECORD),
-                                                       ulHeapItemsCount1);
-        if (pMemRecordFirst)
-        {
-            ULONG       ulHeapItemsCount2 = 0;
-            PMEMRECORD  pMemRecordThis = pMemRecordFirst;
-            pHeapItem = G_pHeapItemsRoot;
-            // PLISTNODE   pMemNode = lstQueryFirstNode(&G_llHeapItems);
-
-            while ((pMemRecordThis) && (pHeapItem))
-            {
-                // PHEAPITEM pHeapItem = (PHEAPITEM)pMemNode->pItemData;
-
-                pMemRecordThis->ulIndex = ulHeapItemsCount2++;
-
-                cnrhDateTimeDos2Win(&pHeapItem->dtAllocated,
-                                    &pMemRecordThis->cdateAllocated,
-                                    &pMemRecordThis->ctimeAllocated);
-
-                if (pHeapItem->fFreed)
-                    pMemRecordThis->pszFreed = "yes";
-
-                pMemRecordThis->ulTID = pHeapItem->ulTID;
-
-                strcpy(pMemRecordThis->szSource, pHeapItem->pcszSourceFile);
-                pMemRecordThis->pszSource = pMemRecordThis->szSource;
-
-                pMemRecordThis->ulLine = pHeapItem->ulLine;
-
-                strcpy(pMemRecordThis->szFunction, pHeapItem->pcszFunction);
-                pMemRecordThis->pszFunction = pMemRecordThis->szFunction;
-
-                sprintf(pMemRecordThis->szAddress, "0x%lX", pHeapItem->pAfterMagic);
-                pMemRecordThis->pszAddress = pMemRecordThis->szAddress;
-
-                pMemRecordThis->ulSize = pHeapItem->ulSize;
-
-
-                /* switch (pMemRecordThis->useflag)
-                {
-                    case _USEDENTRY: pMemRecordThis->pszUseFlag = "Used"; break;
-                    case _FREEENTRY: pMemRecordThis->pszUseFlag = "Freed"; break;
-                }
-
-                switch (pMemRecordThis->status)
-                {
-                    case _HEAPBADBEGIN: pMemRecordThis->pszStatus = "heap bad begin"; break;
-                    case _HEAPBADNODE: pMemRecordThis->pszStatus = "heap bad node"; break;
-                    case _HEAPEMPTY: pMemRecordThis->pszStatus = "heap empty"; break;
-                    case _HEAPOK: pMemRecordThis->pszStatus = "OK"; break;
-                }
-
-                sprintf(pMemRecordThis->szAddress, "0x%lX", pMemRecordThis->pObject);
-                strcpy(pMemRecordThis->szSource,
-                        (pMemRecordThis->filename)
-                            ? pMemRecordThis->filename
-                            : "?"); */
-
-                pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
-                pHeapItem = pHeapItem->pNext;
-            }
-
-            cnrhInsertRecords(hwndCnr,
-                              NULL,         // parent
-                              (PRECORDCORE)pMemRecordFirst,
-                              TRUE,
-                              NULL,
-                              CRA_RECORDREADONLY,
-                              ulHeapItemsCount2);
-        }
-
-        memdUnlock();
-    }
-}
-
-/*
- *@@ mnu_fnCompareIndex:
- *
- *@@added V0.9.1 (99-12-03) [umoeller]
- */
-
-SHORT EXPENTRY mnu_fnCompareIndex(PMEMRECORD pmrc1, PMEMRECORD  pmrc2, PVOID pStorage)
-{
-    // HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
-    pStorage = pStorage; // to keep the compiler happy
-    if ((pmrc1) && (pmrc2))
-        if (pmrc1->ulIndex < pmrc2->ulIndex)
-            return (-1);
-        else if (pmrc1->ulIndex > pmrc2->ulIndex)
-            return (1);
-
-    return (0);
-}
-
-/*
- *@@ mnu_fnCompareSourceFile:
- *
- *@@added V0.9.1 (99-12-03) [umoeller]
- */
-
-SHORT EXPENTRY mnu_fnCompareSourceFile(PMEMRECORD pmrc1, PMEMRECORD  pmrc2, PVOID pStorage)
-{
-    HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
-    pStorage = pStorage; // to keep the compiler happy
-    if ((pmrc1) && (pmrc2))
-            switch (WinCompareStrings(habDesktop, 0, 0,
-                                      pmrc1->szSource,
-                                      pmrc2->szSource,
-                                      0))
-            {
-                case WCS_LT: return (-1);
-                case WCS_GT: return (1);
-                default:    // equal
-                    if (pmrc1->ulLine < pmrc2->ulLine)
-                        return (-1);
-                    else if (pmrc1->ulLine > pmrc2->ulLine)
-                        return (1);
-
-            }
-
-    return (0);
-}
-
-#define ID_MEMCNR   1000
-
-/*
- *@@ memd_fnwpMemDebug:
- *      client window proc for the heap debugger window
- *      accessible from the Desktop context menu if
- *      __XWPMEMDEBUG__ is defined. Otherwise, this is not
- *      compiled.
- *
- *      Usage: this is a regular PM client window procedure
- *      to be used with WinRegisterClass and WinCreateStdWindow.
- *      See dtpMenuItemSelected, which uses this.
- *
- *      This creates a container with all the memory objects
- *      with the size of the client area in turn.
- *
- *@@added V0.9.1 (99-12-04) [umoeller]
- */
-
-
-MRESULT EXPENTRY memd_fnwpMemDebug(HWND hwndClient, ULONG msg, MPARAM mp1, MPARAM mp2)
-{
-    MRESULT mrc = 0;
-
-    switch (msg)
-    {
-        case WM_CREATE:
-        {
-            TRY_LOUD(excpt1, NULL)
-            {
-                // PCREATESTRUCT pcs = (PCREATESTRUCT)mp2;
-                HWND hwndCnr;
-                hwndCnr = WinCreateWindow(hwndClient,        // parent
-                                          WC_CONTAINER,
-                                          "",
-                                          WS_VISIBLE | CCS_MINIICONS | CCS_READONLY | CCS_SINGLESEL,
-                                          0, 0, 0, 0,
-                                          hwndClient,        // owner
-                                          HWND_TOP,
-                                          ID_MEMCNR,
-                                          NULL, NULL);
-                if (hwndCnr)
-                {
-                    XFIELDINFO      xfi[11];
-                    PFIELDINFO      pfi = NULL;
-                    PMEMRECORD      pMemRecordFirst;
-                    int             i = 0;
-
-                    ULONG           ulTotalItems = 0,
-                                    ulAllocatedItems = 0,
-                                    ulFreedItems = 0;
-                    ULONG           ulTotalBytes = 0,
-                                    ulAllocatedBytes = 0,
-                                    ulFreedBytes = 0;
-
-                    // set up cnr details view
-                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulIndex);
-                    xfi[i].pszColumnTitle = "No.";
-                    xfi[i].ulDataType = CFA_ULONG;
-                    xfi[i++].ulOrientation = CFA_RIGHT;
-
-                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, cdateAllocated);
-                    xfi[i].pszColumnTitle = "Date";
-                    xfi[i].ulDataType = CFA_DATE;
-                    xfi[i++].ulOrientation = CFA_LEFT;
-
-                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ctimeAllocated);
-                    xfi[i].pszColumnTitle = "Time";
-                    xfi[i].ulDataType = CFA_TIME;
-                    xfi[i++].ulOrientation = CFA_LEFT;
-
-                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszFreed);
-                    xfi[i].pszColumnTitle = "Freed";
-                    xfi[i].ulDataType = CFA_STRING;
-                    xfi[i++].ulOrientation = CFA_CENTER;
-
-                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulTID);
-                    xfi[i].pszColumnTitle = "TID";
-                    xfi[i].ulDataType = CFA_ULONG;
-                    xfi[i++].ulOrientation = CFA_RIGHT;
-
-                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszFunction);
-                    xfi[i].pszColumnTitle = "Function";
-                    xfi[i].ulDataType = CFA_STRING;
-                    xfi[i++].ulOrientation = CFA_LEFT;
-
-                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszSource);
-                    xfi[i].pszColumnTitle = "Source";
-                    xfi[i].ulDataType = CFA_STRING;
-                    xfi[i++].ulOrientation = CFA_LEFT;
-
-                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulLine);
-                    xfi[i].pszColumnTitle = "Line";
-                    xfi[i].ulDataType = CFA_ULONG;
-                    xfi[i++].ulOrientation = CFA_RIGHT;
-
-                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulSize);
-                    xfi[i].pszColumnTitle = "Size";
-                    xfi[i].ulDataType = CFA_ULONG;
-                    xfi[i++].ulOrientation = CFA_RIGHT;
-
-                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszAddress);
-                    xfi[i].pszColumnTitle = "Address";
-                    xfi[i].ulDataType = CFA_STRING;
-                    xfi[i++].ulOrientation = CFA_LEFT;
-
-                    pfi = cnrhSetFieldInfos(hwndCnr,
-                                            &xfi[0],
-                                            i,             // array item count
-                                            TRUE,          // no draw lines
-                                            3);            // return column
-
-                    {
-                        PSZ pszFont = "9.WarpSans";
-                        WinSetPresParam(hwndCnr,
-                                        PP_FONTNAMESIZE,
-                                        strlen(pszFont),
-                                        pszFont);
-                    }
-
-                    memdCreateRecords(hwndCnr,
-                                      &ulTotalItems,
-                                      &ulAllocatedItems,
-                                      &ulFreedItems,
-                                      &ulTotalBytes,
-                                      &ulAllocatedBytes,
-                                      &ulFreedBytes);
-
-                    BEGIN_CNRINFO()
-                    {
-                        CHAR    szCnrTitle[1000];
-                        CHAR    szTotalItems[100],
-                                szAllocatedItems[100],
-                                szFreedItems[100],
-                                szReleasedItems[100];
-                        CHAR    szTotalBytes[100],
-                                szAllocatedBytes[100],
-                                szFreedBytes[100],
-                                szReleasedBytes[100];
-                        sprintf(szCnrTitle,
-                                "Total logs in use: %s items = %s bytes\n"
-                                "    Total in use: %s items = %s bytes\n"
-                                "    Total freed: %s items = %s bytes\n"
-                                "Total logs released: %s items = %s bytes",
-                                strhThousandsDouble(szTotalItems,
-                                                    ulTotalItems,
-                                                    '.'),
-                                strhThousandsDouble(szTotalBytes,
-                                                    ulTotalBytes,
-                                                    '.'),
-                                strhThousandsDouble(szAllocatedItems,
-                                                    ulAllocatedItems,
-                                                    '.'),
-                                strhThousandsDouble(szAllocatedBytes,
-                                                    ulAllocatedBytes,
-                                                    '.'),
-                                strhThousandsDouble(szFreedItems,
-                                                    ulFreedItems,
-                                                    '.'),
-                                strhThousandsDouble(szFreedBytes,
-                                                    ulFreedBytes,
-                                                    '.'),
-                                strhThousandsDouble(szReleasedItems,
-                                                    G_ulItemsReleased,
-                                                    '.'),
-                                strhThousandsDouble(szReleasedBytes,
-                                                    G_ulBytesReleased,
-                                                    '.'));
-                        G_pszMemCnrTitle = strdup(szCnrTitle);
-                        cnrhSetTitle(G_pszMemCnrTitle);
-                        cnrhSetView(CV_DETAIL | CV_MINI | CA_DETAILSVIEWTITLES
-                                        | CA_DRAWICON
-                                    | CA_CONTAINERTITLE | CA_TITLEREADONLY
-                                        | CA_TITLESEPARATOR | CA_TITLELEFT);
-                        cnrhSetSplitBarAfter(pfi);
-                        cnrhSetSplitBarPos(250);
-                    } END_CNRINFO(hwndCnr);
-
-                    WinSetFocus(HWND_DESKTOP, hwndCnr);
-                }
-            }
-            CATCH(excpt1) {} END_CATCH();
-
-            mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
-        break; }
-
-        case WM_WINDOWPOSCHANGED:
-        {
-            PSWP pswp = (PSWP)mp1;
-            mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
-            if (pswp->fl & SWP_SIZE)
-            {
-                WinSetWindowPos(WinWindowFromID(hwndClient, ID_MEMCNR), // cnr
-                                HWND_TOP,
-                                0, 0, pswp->cx, pswp->cy,
-                                SWP_SIZE | SWP_MOVE | SWP_SHOW);
-            }
-        break; }
-
-        case WM_CONTROL:
-        {
-            USHORT usItemID = SHORT1FROMMP(mp1),
-                   usNotifyCode = SHORT2FROMMP(mp1);
-            if (usItemID == ID_MEMCNR)       // cnr
-            {
-                switch (usNotifyCode)
-                {
-                    case CN_CONTEXTMENU:
-                    {
-                        PMEMRECORD precc = (PMEMRECORD)mp2;
-                        if (precc == NULL)
-                        {
-                            // whitespace
-                            HWND hwndMenu = WinCreateMenu(HWND_DESKTOP,
-                                                          NULL); // no menu template
-                            winhInsertMenuItem(hwndMenu,
-                                               MIT_END,
-                                               1001,
-                                               "Sort by index",
-                                               MIS_TEXT, 0);
-                            winhInsertMenuItem(hwndMenu,
-                                               MIT_END,
-                                               1002,
-                                               "Sort by source file",
-                                               MIS_TEXT, 0);
-                            cnrhShowContextMenu(WinWindowFromID(hwndClient, ID_MEMCNR),
-                                                NULL,       // record
-                                                hwndMenu,
-                                                hwndClient);
-                        }
-                    }
-                }
-            }
-        break; }
-
-        case WM_COMMAND:
-            switch (SHORT1FROMMP(mp1))
-            {
-                case 1001:  // sort by index
-                    WinSendMsg(WinWindowFromID(hwndClient, ID_MEMCNR),
-                               CM_SORTRECORD,
-                               (MPARAM)mnu_fnCompareIndex,
-                               0);
-                break;
-
-                case 1002:  // sort by source file
-                    WinSendMsg(WinWindowFromID(hwndClient, ID_MEMCNR),
-                               CM_SORTRECORD,
-                               (MPARAM)mnu_fnCompareSourceFile,
-                               0);
-                break;
-            }
-        break;
-
-        case WM_CLOSE:
-            WinDestroyWindow(WinWindowFromID(hwndClient, ID_MEMCNR));
-            WinDestroyWindow(WinQueryWindow(hwndClient, QW_PARENT));
-            free(G_pszMemCnrTitle);
-            G_pszMemCnrTitle = NULL;
-        break;
-
-        default:
-            mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
-    }
-
-    return (mrc);
-}
-
-/*
- *@@ memdCreateMemDebugWindow:
- *      creates a heap debugging window which
- *      is a standard frame with a container,
- *      listing all heap objects ever allocated.
- *
- *      The client of this standard frame is in
- *      memd_fnwpMemDebug.
- *
- *      This thing lists all calls to malloc()
- *      which were ever made, including the
- *      source file and source line number which
- *      made the call. Extreeeemely useful for
- *      detecting memory leaks.
- *
- *      This only works if the memory functions
- *      have been replaced with the debug versions
- *      in this file.
- */
-
-VOID memdCreateMemDebugWindow(VOID)
-{
-    ULONG flStyle = FCF_TITLEBAR | FCF_SYSMENU | FCF_HIDEMAX
-                    | FCF_SIZEBORDER | FCF_SHELLPOSITION
-                    | FCF_NOBYTEALIGN | FCF_TASKLIST;
-    if (WinRegisterClass(WinQueryAnchorBlock(HWND_DESKTOP),
-                         "XWPMemDebug",
-                         memd_fnwpMemDebug, 0L, 0))
-    {
-        HWND hwndClient;
-        HWND hwndMemFrame = WinCreateStdWindow(HWND_DESKTOP,
-                                               0L,
-                                               &flStyle,
-                                               "XWPMemDebug",
-                                               "Allocated XWorkplace Memory Objects",
-                                               0L,
-                                               NULLHANDLE,     // resource
-                                               0,
-                                               &hwndClient);
-        if (hwndMemFrame)
-        {
-            WinSetWindowPos(hwndMemFrame,
-                            HWND_TOP,
-                            0, 0, 0, 0,
-                            SWP_ZORDER | SWP_SHOW | SWP_ACTIVATE);
-        }
-    }
-}
-
 #else
 void memdDummy(void)
Index: /trunk/src/helpers/memdebug_win.c
===================================================================
--- /trunk/src/helpers/memdebug_win.c	(revision 13)
+++ /trunk/src/helpers/memdebug_win.c	(revision 13)
@@ -0,0 +1,792 @@
+
+/*
+ *@@sourcefile memdebug_win.c:
+ *      implementation of the PM heap debugging window,
+ *      if the __XWPMEMDEBUG__ #define is set in setup.h.
+ *
+ *      This has been extracted from memdebug.c to allow
+ *      linking with non-PM programs.
+ *
+ *@@added V0.9.6 (2000-11-12) [umoeller]
+ */
+
+/*
+ *      Copyright (C) 2000 Ulrich Mller.
+ *      This program is part of the XWorkplace package.
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation, in version 2 as it comes in the COPYING
+ *      file of the XWorkplace main distribution.
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ */
+
+#define OS2EMX_PLAIN_CHAR
+    // this is needed for "os2emx.h"; if this is defined,
+    // emx will define PSZ as _signed_ char, otherwise
+    // as unsigned char
+
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSEXCEPTIONS
+#define INCL_DOSPROCESS
+#define INCL_DOSERRORS
+
+#define INCL_WINWINDOWMGR
+#define INCL_WINFRAMEMGR
+#define INCL_WINCOUNTRY
+#define INCL_WINSYS
+#define INCL_WINMENUS
+#define INCL_WINSTDCNR
+#include <os2.h>
+
+#include <stdio.h>
+#include <string.h>
+// #include <malloc.h>
+#include <setjmp.h>
+
+#define DONT_REPLACE_MALLOC             // never do debug memory for this
+#define MEMDEBUG_PRIVATE
+#include "setup.h"
+
+#ifdef __XWPMEMDEBUG__
+
+#include "helpers\cnrh.h"
+#include "helpers\except.h"
+// #include "helpers\memdebug.h"        // included by setup.h already
+#include "helpers\stringh.h"
+#include "helpers\winh.h"
+
+/*
+ *@@category: Helpers\C helpers\Heap debugging
+ */
+
+/* ******************************************************************
+ *
+ *   Global variables
+ *
+ ********************************************************************/
+
+PSZ             G_pszMemCnrTitle = NULL;
+HWND            G_hwndMemDebugMenu = NULLHANDLE;
+
+/* ******************************************************************
+ *
+ *   Heap debugging window
+ *
+ ********************************************************************/
+
+/*
+ *@@ MEMRECORD:
+ *
+ *@@added V0.9.1 (99-12-04) [umoeller]
+ */
+
+typedef struct _MEMRECORD
+{
+    RECORDCORE  recc;
+
+    ULONG       ulIndex;
+
+    CDATE       cdateAllocated;
+    CTIME       ctimeAllocated;
+
+    PSZ         pszFreed;
+
+    ULONG       ulTID;
+
+    PSZ         pszFunction;    // points to szFunction
+    CHAR        szFunction[400];
+
+    PSZ         pszSource;      // points to szSource
+    CHAR        szSource[CCHMAXPATH];
+
+    ULONG       ulLine;
+
+    PSZ         pszAddress;     // points to szAddress
+    CHAR        szAddress[20];
+
+    ULONG       ulSize;
+
+} MEMRECORD, *PMEMRECORD;
+
+/* ULONG       ulHeapItemsCount1,
+            ulHeapItemsCount2;
+ULONG       ulTotalAllocated,
+            ulTotalFreed;
+PMEMRECORD  pMemRecordThis = NULL;
+PSZ         pszMemCnrTitle = NULL; */
+
+#if 0
+    /*
+     *@@ fncbMemHeapWalkCount:
+     *      callback func for _heap_walk function used for
+     *      fnwpMemDebug.
+     *
+     *@@added V0.9.1 (99-12-04) [umoeller]
+     */
+
+    int fncbMemHeapWalkCount(const void *pObject,
+                             size_t Size,
+                             int useflag,
+                             int status,
+                             const char *filename,
+                             size_t line)
+    {
+        // skip all the items which seem to be
+        // internal to the runtime
+        if ((filename) || (useflag == _FREEENTRY))
+        {
+            ulHeapItemsCount1++;
+            if (useflag == _FREEENTRY)
+                ulTotalFreed += Size;
+            else
+                ulTotalAllocated += Size;
+        }
+        return (0);
+    }
+
+    /*
+     *@@ fncbMemHeapWalkFill:
+     *      callback func for _heap_walk function used for
+     *      fnwpMemDebug.
+     *
+     *@@added V0.9.1 (99-12-04) [umoeller]
+     */
+
+    int fncbMemHeapWalkFill(const void *pObject,
+                            size_t Size,
+                            int useflag,
+                            int status,
+                            const char *filename,
+                            size_t line)
+    {
+        // skip all the items which seem to be
+        // internal to the runtime
+        if ((filename) || (useflag == _FREEENTRY))
+        {
+            ulHeapItemsCount2++;
+            if ((pMemRecordThis) && (ulHeapItemsCount2 < ulHeapItemsCount1))
+            {
+                pMemRecordThis->ulIndex = ulHeapItemsCount2 - 1;
+
+                pMemRecordThis->pObject = pObject;
+                pMemRecordThis->useflag = useflag;
+                pMemRecordThis->status = status;
+                pMemRecordThis->filename = filename;
+
+                pMemRecordThis->pszAddress = pMemRecordThis->szAddress;
+
+                pMemRecordThis->ulSize = Size;
+
+                pMemRecordThis->pszSource = pMemRecordThis->szSource;
+
+                pMemRecordThis->ulLine = line;
+
+                pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
+            }
+            else
+                return (1);     // stop
+        }
+
+        return (0);
+    }
+
+    /*
+     *@@ memdCreateRecordsVAC:
+     *
+     *@@added V0.9.3 (2000-04-10) [umoeller]
+     */
+
+    VOID memdCreateRecordsVAC(HWND hwndCnr)
+    {
+        // count heap items
+        ulHeapItemsCount1 = 0;
+        ulTotalFreed = 0;
+        ulTotalAllocated = 0;
+        _heap_walk(fncbMemHeapWalkCount);
+
+        pMemRecordFirst = (PMEMRECORD)cnrhAllocRecords(hwndCnr,
+                                                       sizeof(MEMRECORD),
+                                                       ulHeapItemsCount1);
+        if (pMemRecordFirst)
+        {
+            ulHeapItemsCount2 = 0;
+            pMemRecordThis = pMemRecordFirst;
+            _heap_walk(fncbMemHeapWalkFill);
+
+            // the following doesn't work while _heap_walk is running
+            pMemRecordThis = pMemRecordFirst;
+            while (pMemRecordThis)
+            {
+                switch (pMemRecordThis->useflag)
+                {
+                    case _USEDENTRY: pMemRecordThis->pszUseFlag = "Used"; break;
+                    case _FREEENTRY: pMemRecordThis->pszUseFlag = "Freed"; break;
+                }
+
+                switch (pMemRecordThis->status)
+                {
+                    case _HEAPBADBEGIN: pMemRecordThis->pszStatus = "heap bad begin"; break;
+                    case _HEAPBADNODE: pMemRecordThis->pszStatus = "heap bad node"; break;
+                    case _HEAPEMPTY: pMemRecordThis->pszStatus = "heap empty"; break;
+                    case _HEAPOK: pMemRecordThis->pszStatus = "OK"; break;
+                }
+
+                sprintf(pMemRecordThis->szAddress, "0x%lX", pMemRecordThis->pObject);
+                strcpy(pMemRecordThis->szSource,
+                        (pMemRecordThis->filename)
+                            ? pMemRecordThis->filename
+                            : "?");
+
+                pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
+            }
+
+            cnrhInsertRecords(hwndCnr,
+                              NULL,         // parent
+                              (PRECORDCORE)pMemRecordFirst,
+                              TRUE,
+                              NULL,
+                              CRA_RECORDREADONLY,
+                              ulHeapItemsCount2);
+        }
+    }
+
+#endif
+
+/*
+ *@@ memdCreateRecords:
+ *
+ *@@added V0.9.3 (2000-04-10) [umoeller]
+ */
+
+VOID memdCreateRecords(HWND hwndCnr,
+                       PULONG pulTotalItems,
+                       PULONG pulAllocatedItems,
+                       PULONG pulFreedItems,
+                       PULONG pulTotalBytes,
+                       PULONG pulAllocatedBytes,
+                       PULONG pulFreedBytes)
+{
+    // count heap items
+    ULONG       ulHeapItemsCount1 = 0;
+    PMEMRECORD  pMemRecordFirst;
+
+    if (memdLock())
+    {
+        PHEAPITEM pHeapItem = G_pHeapItemsRoot;
+
+        *pulTotalItems = 0;
+        *pulAllocatedItems = 0;
+        *pulFreedItems = 0;
+
+        *pulTotalBytes = 0;
+        *pulAllocatedBytes = 0;
+        *pulFreedBytes = 0;
+
+        while (pHeapItem)
+        {
+            ulHeapItemsCount1++;
+            if (pHeapItem->fFreed)
+            {
+                (*pulFreedItems)++;
+                (*pulFreedBytes) += pHeapItem->ulSize;
+            }
+            else
+            {
+                (*pulAllocatedItems)++;
+                (*pulAllocatedBytes) += pHeapItem->ulSize;
+            }
+
+            (*pulTotalBytes) += pHeapItem->ulSize;
+
+            pHeapItem = pHeapItem->pNext;
+        }
+
+        *pulTotalItems = ulHeapItemsCount1;
+
+        pMemRecordFirst = (PMEMRECORD)cnrhAllocRecords(hwndCnr,
+                                                       sizeof(MEMRECORD),
+                                                       ulHeapItemsCount1);
+        if (pMemRecordFirst)
+        {
+            ULONG       ulHeapItemsCount2 = 0;
+            PMEMRECORD  pMemRecordThis = pMemRecordFirst;
+            pHeapItem = G_pHeapItemsRoot;
+            // PLISTNODE   pMemNode = lstQueryFirstNode(&G_llHeapItems);
+
+            while ((pMemRecordThis) && (pHeapItem))
+            {
+                // PHEAPITEM pHeapItem = (PHEAPITEM)pMemNode->pItemData;
+
+                pMemRecordThis->ulIndex = ulHeapItemsCount2++;
+
+                cnrhDateTimeDos2Win(&pHeapItem->dtAllocated,
+                                    &pMemRecordThis->cdateAllocated,
+                                    &pMemRecordThis->ctimeAllocated);
+
+                if (pHeapItem->fFreed)
+                    pMemRecordThis->pszFreed = "yes";
+
+                pMemRecordThis->ulTID = pHeapItem->ulTID;
+
+                strcpy(pMemRecordThis->szSource, pHeapItem->pcszSourceFile);
+                pMemRecordThis->pszSource = pMemRecordThis->szSource;
+
+                pMemRecordThis->ulLine = pHeapItem->ulLine;
+
+                strcpy(pMemRecordThis->szFunction, pHeapItem->pcszFunction);
+                pMemRecordThis->pszFunction = pMemRecordThis->szFunction;
+
+                sprintf(pMemRecordThis->szAddress, "0x%lX", pHeapItem->pAfterMagic);
+                pMemRecordThis->pszAddress = pMemRecordThis->szAddress;
+
+                pMemRecordThis->ulSize = pHeapItem->ulSize;
+
+
+                /* switch (pMemRecordThis->useflag)
+                {
+                    case _USEDENTRY: pMemRecordThis->pszUseFlag = "Used"; break;
+                    case _FREEENTRY: pMemRecordThis->pszUseFlag = "Freed"; break;
+                }
+
+                switch (pMemRecordThis->status)
+                {
+                    case _HEAPBADBEGIN: pMemRecordThis->pszStatus = "heap bad begin"; break;
+                    case _HEAPBADNODE: pMemRecordThis->pszStatus = "heap bad node"; break;
+                    case _HEAPEMPTY: pMemRecordThis->pszStatus = "heap empty"; break;
+                    case _HEAPOK: pMemRecordThis->pszStatus = "OK"; break;
+                }
+
+                sprintf(pMemRecordThis->szAddress, "0x%lX", pMemRecordThis->pObject);
+                strcpy(pMemRecordThis->szSource,
+                        (pMemRecordThis->filename)
+                            ? pMemRecordThis->filename
+                            : "?"); */
+
+                pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
+                pHeapItem = pHeapItem->pNext;
+            }
+
+            cnrhInsertRecords(hwndCnr,
+                              NULL,         // parent
+                              (PRECORDCORE)pMemRecordFirst,
+                              TRUE,
+                              NULL,
+                              CRA_RECORDREADONLY,
+                              ulHeapItemsCount2);
+        }
+
+        memdUnlock();
+    }
+}
+
+/*
+ *@@ mnu_fnCompareIndex:
+ *
+ *@@added V0.9.1 (99-12-03) [umoeller]
+ */
+
+SHORT EXPENTRY mnu_fnCompareIndex(PMEMRECORD pmrc1, PMEMRECORD  pmrc2, PVOID pStorage)
+{
+    // HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
+    pStorage = pStorage; // to keep the compiler happy
+    if ((pmrc1) && (pmrc2))
+        if (pmrc1->ulIndex < pmrc2->ulIndex)
+            return (-1);
+        else if (pmrc1->ulIndex > pmrc2->ulIndex)
+            return (1);
+
+    return (0);
+}
+
+/*
+ *@@ mnu_fnCompareSourceFile:
+ *
+ *@@added V0.9.1 (99-12-03) [umoeller]
+ */
+
+SHORT EXPENTRY mnu_fnCompareSourceFile(PMEMRECORD pmrc1, PMEMRECORD  pmrc2, PVOID pStorage)
+{
+    HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
+    pStorage = pStorage; // to keep the compiler happy
+    if ((pmrc1) && (pmrc2))
+            switch (WinCompareStrings(habDesktop, 0, 0,
+                                      pmrc1->szSource,
+                                      pmrc2->szSource,
+                                      0))
+            {
+                case WCS_LT: return (-1);
+                case WCS_GT: return (1);
+                default:    // equal
+                    if (pmrc1->ulLine < pmrc2->ulLine)
+                        return (-1);
+                    else if (pmrc1->ulLine > pmrc2->ulLine)
+                        return (1);
+
+            }
+
+    return (0);
+}
+
+/*
+ *@@ mnu_fnCompareSourceFile:
+ *
+ *V0.9.6 (2000-11-12) [umoeller]
+ */
+
+SHORT EXPENTRY mnu_fnCompareSize(PMEMRECORD pmrc1, PMEMRECORD  pmrc2, PVOID pStorage)
+{
+    HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
+    pStorage = pStorage; // to keep the compiler happy
+    if ((pmrc1) && (pmrc2))
+    {
+        if (pmrc1->ulSize > pmrc2->ulSize)
+            return (1);
+        else if (pmrc1->ulSize < pmrc2->ulSize)
+            return (-1);
+    }
+
+    return (0);
+}
+
+#define ID_MEMCNR   1000
+
+/*
+ *@@ memd_fnwpMemDebug:
+ *      client window proc for the heap debugger window
+ *      accessible from the Desktop context menu if
+ *      __XWPMEMDEBUG__ is defined. Otherwise, this is not
+ *      compiled.
+ *
+ *      Usage: this is a regular PM client window procedure
+ *      to be used with WinRegisterClass and WinCreateStdWindow.
+ *      See dtpMenuItemSelected, which uses this.
+ *
+ *      This creates a container with all the memory objects
+ *      with the size of the client area in turn.
+ *
+ *@@added V0.9.1 (99-12-04) [umoeller]
+ */
+
+MRESULT EXPENTRY memd_fnwpMemDebug(HWND hwndClient, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+    MRESULT mrc = 0;
+
+    switch (msg)
+    {
+        case WM_CREATE:
+        {
+            TRY_LOUD(excpt1, NULL)
+            {
+                // PCREATESTRUCT pcs = (PCREATESTRUCT)mp2;
+                HWND hwndCnr;
+                hwndCnr = WinCreateWindow(hwndClient,        // parent
+                                          WC_CONTAINER,
+                                          "",
+                                          WS_VISIBLE | CCS_MINIICONS | CCS_READONLY | CCS_SINGLESEL,
+                                          0, 0, 0, 0,
+                                          hwndClient,        // owner
+                                          HWND_TOP,
+                                          ID_MEMCNR,
+                                          NULL, NULL);
+                if (hwndCnr)
+                {
+                    XFIELDINFO      xfi[11];
+                    PFIELDINFO      pfi = NULL;
+                    PMEMRECORD      pMemRecordFirst;
+                    int             i = 0;
+
+                    ULONG           ulTotalItems = 0,
+                                    ulAllocatedItems = 0,
+                                    ulFreedItems = 0;
+                    ULONG           ulTotalBytes = 0,
+                                    ulAllocatedBytes = 0,
+                                    ulFreedBytes = 0;
+
+                    // set up cnr details view
+                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulIndex);
+                    xfi[i].pszColumnTitle = "No.";
+                    xfi[i].ulDataType = CFA_ULONG;
+                    xfi[i++].ulOrientation = CFA_RIGHT;
+
+                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, cdateAllocated);
+                    xfi[i].pszColumnTitle = "Date";
+                    xfi[i].ulDataType = CFA_DATE;
+                    xfi[i++].ulOrientation = CFA_LEFT;
+
+                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ctimeAllocated);
+                    xfi[i].pszColumnTitle = "Time";
+                    xfi[i].ulDataType = CFA_TIME;
+                    xfi[i++].ulOrientation = CFA_LEFT;
+
+                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszFreed);
+                    xfi[i].pszColumnTitle = "Freed";
+                    xfi[i].ulDataType = CFA_STRING;
+                    xfi[i++].ulOrientation = CFA_CENTER;
+
+                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulTID);
+                    xfi[i].pszColumnTitle = "TID";
+                    xfi[i].ulDataType = CFA_ULONG;
+                    xfi[i++].ulOrientation = CFA_RIGHT;
+
+                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszFunction);
+                    xfi[i].pszColumnTitle = "Function";
+                    xfi[i].ulDataType = CFA_STRING;
+                    xfi[i++].ulOrientation = CFA_LEFT;
+
+                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszSource);
+                    xfi[i].pszColumnTitle = "Source";
+                    xfi[i].ulDataType = CFA_STRING;
+                    xfi[i++].ulOrientation = CFA_LEFT;
+
+                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulLine);
+                    xfi[i].pszColumnTitle = "Line";
+                    xfi[i].ulDataType = CFA_ULONG;
+                    xfi[i++].ulOrientation = CFA_RIGHT;
+
+                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulSize);
+                    xfi[i].pszColumnTitle = "Size";
+                    xfi[i].ulDataType = CFA_ULONG;
+                    xfi[i++].ulOrientation = CFA_RIGHT;
+
+                    xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszAddress);
+                    xfi[i].pszColumnTitle = "Address";
+                    xfi[i].ulDataType = CFA_STRING;
+                    xfi[i++].ulOrientation = CFA_LEFT;
+
+                    pfi = cnrhSetFieldInfos(hwndCnr,
+                                            &xfi[0],
+                                            i,             // array item count
+                                            TRUE,          // no draw lines
+                                            3);            // return column
+
+                    {
+                        PSZ pszFont = "9.WarpSans";
+                        WinSetPresParam(hwndCnr,
+                                        PP_FONTNAMESIZE,
+                                        strlen(pszFont),
+                                        pszFont);
+                    }
+
+                    memdCreateRecords(hwndCnr,
+                                      &ulTotalItems,
+                                      &ulAllocatedItems,
+                                      &ulFreedItems,
+                                      &ulTotalBytes,
+                                      &ulAllocatedBytes,
+                                      &ulFreedBytes);
+
+                    BEGIN_CNRINFO()
+                    {
+                        CHAR    szCnrTitle[1000];
+                        CHAR    szTotalItems[100],
+                                szAllocatedItems[100],
+                                szFreedItems[100],
+                                szReleasedItems[100];
+                        CHAR    szTotalBytes[100],
+                                szAllocatedBytes[100],
+                                szFreedBytes[100],
+                                szReleasedBytes[100];
+                        sprintf(szCnrTitle,
+                                "Total memory log entries in use: %s items = %s bytes\n"
+                                "    Total memory logs allocated: %s items = %s bytes\n"
+                                "    Total memory logs freed: %s items = %s bytes\n"
+                                "Total memory logs freed and discarded: %s items = %s bytes",
+                                strhThousandsDouble(szTotalItems,
+                                                    ulTotalItems,
+                                                    '.'),
+                                strhThousandsDouble(szTotalBytes,
+                                                    ulTotalBytes,
+                                                    '.'),
+                                strhThousandsDouble(szAllocatedItems,
+                                                    ulAllocatedItems,
+                                                    '.'),
+                                strhThousandsDouble(szAllocatedBytes,
+                                                    ulAllocatedBytes,
+                                                    '.'),
+                                strhThousandsDouble(szFreedItems,
+                                                    ulFreedItems,
+                                                    '.'),
+                                strhThousandsDouble(szFreedBytes,
+                                                    ulFreedBytes,
+                                                    '.'),
+                                strhThousandsDouble(szReleasedItems,
+                                                    G_ulItemsReleased,
+                                                    '.'),
+                                strhThousandsDouble(szReleasedBytes,
+                                                    G_ulBytesReleased,
+                                                    '.'));
+                        G_pszMemCnrTitle = strdup(szCnrTitle);
+                        cnrhSetTitle(G_pszMemCnrTitle);
+                        cnrhSetView(CV_DETAIL | CV_MINI | CA_DETAILSVIEWTITLES
+                                        | CA_DRAWICON
+                                    | CA_CONTAINERTITLE | CA_TITLEREADONLY
+                                        | CA_TITLESEPARATOR | CA_TITLELEFT);
+                        cnrhSetSplitBarAfter(pfi);
+                        cnrhSetSplitBarPos(250);
+                    } END_CNRINFO(hwndCnr);
+
+                    // create menu
+                    G_hwndMemDebugMenu = WinCreateMenu(HWND_DESKTOP,
+                                                       NULL); // no menu template
+
+                    winhInsertMenuItem(G_hwndMemDebugMenu,
+                                       MIT_END,
+                                       1001,
+                                       "Sort by index",
+                                       MIS_TEXT, 0);
+                    winhInsertMenuItem(G_hwndMemDebugMenu,
+                                       MIT_END,
+                                       1002,
+                                       "Sort by source file",
+                                       MIS_TEXT, 0);
+                    winhInsertMenuItem(G_hwndMemDebugMenu,
+                                       MIT_END,
+                                       1003,
+                                       "Sort by object size",
+                                       MIS_TEXT, 0);
+
+                    WinSetFocus(HWND_DESKTOP, hwndCnr);
+                }
+            }
+            CATCH(excpt1) {} END_CATCH();
+
+            mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
+        break; }
+
+        case WM_WINDOWPOSCHANGED:
+        {
+            PSWP pswp = (PSWP)mp1;
+            mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
+            if (pswp->fl & SWP_SIZE)
+            {
+                WinSetWindowPos(WinWindowFromID(hwndClient, ID_MEMCNR), // cnr
+                                HWND_TOP,
+                                0, 0, pswp->cx, pswp->cy,
+                                SWP_SIZE | SWP_MOVE | SWP_SHOW);
+            }
+        break; }
+
+        case WM_CONTROL:
+        {
+            USHORT usItemID = SHORT1FROMMP(mp1),
+                   usNotifyCode = SHORT2FROMMP(mp1);
+            if (usItemID == ID_MEMCNR)       // cnr
+            {
+                switch (usNotifyCode)
+                {
+                    case CN_CONTEXTMENU:
+                    {
+                        PMEMRECORD precc = (PMEMRECORD)mp2;
+                        if (precc == NULL)
+                        {
+                            // whitespace:
+                            cnrhShowContextMenu(WinWindowFromID(hwndClient, ID_MEMCNR),
+                                                NULL,       // record
+                                                G_hwndMemDebugMenu,
+                                                hwndClient);
+                        }
+                    }
+                }
+            }
+        break; }
+
+        case WM_COMMAND:
+            switch (SHORT1FROMMP(mp1))
+            {
+                case 1001:  // sort by index
+                    WinSendMsg(WinWindowFromID(hwndClient, ID_MEMCNR),
+                               CM_SORTRECORD,
+                               (MPARAM)mnu_fnCompareIndex,
+                               0);
+                break;
+
+                case 1002:  // sort by source file
+                    WinSendMsg(WinWindowFromID(hwndClient, ID_MEMCNR),
+                               CM_SORTRECORD,
+                               (MPARAM)mnu_fnCompareSourceFile,
+                               0);
+                break;
+
+                case 1003: // sort by object size
+                    WinSendMsg(WinWindowFromID(hwndClient, ID_MEMCNR),
+                               CM_SORTRECORD,
+                               (MPARAM)mnu_fnCompareSize,
+                               0);
+                break;
+            }
+        break;
+
+        case WM_CLOSE:
+            WinDestroyWindow(WinWindowFromID(hwndClient, ID_MEMCNR));
+            WinDestroyWindow(WinQueryWindow(hwndClient, QW_PARENT));
+            free(G_pszMemCnrTitle);
+            WinDestroyWindow(G_hwndMemDebugMenu);
+            G_pszMemCnrTitle = NULL;
+        break;
+
+        default:
+            mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
+    }
+
+    return (mrc);
+}
+
+/*
+ *@@ memdCreateMemDebugWindow:
+ *      creates a heap debugging window which
+ *      is a standard frame with a container,
+ *      listing all heap objects ever allocated.
+ *
+ *      The client of this standard frame is in
+ *      memd_fnwpMemDebug.
+ *
+ *      This thing lists all calls to malloc()
+ *      which were ever made, including the
+ *      source file and source line number which
+ *      made the call. Extreeeemely useful for
+ *      detecting memory leaks.
+ *
+ *      This only works if the memory functions
+ *      have been replaced with the debug versions
+ *      in this file.
+ */
+
+VOID memdCreateMemDebugWindow(VOID)
+{
+    ULONG flStyle = FCF_TITLEBAR | FCF_SYSMENU | FCF_HIDEMAX
+                    | FCF_SIZEBORDER | FCF_SHELLPOSITION
+                    | FCF_NOBYTEALIGN | FCF_TASKLIST;
+    if (WinRegisterClass(WinQueryAnchorBlock(HWND_DESKTOP),
+                         "XWPMemDebug",
+                         memd_fnwpMemDebug, 0L, 0))
+    {
+        HWND hwndClient;
+        HWND hwndMemFrame = WinCreateStdWindow(HWND_DESKTOP,
+                                               0L,
+                                               &flStyle,
+                                               "XWPMemDebug",
+                                               "Allocated XWorkplace Memory Objects",
+                                               0L,
+                                               NULLHANDLE,     // resource
+                                               0,
+                                               &hwndClient);
+        if (hwndMemFrame)
+        {
+            WinSetWindowPos(hwndMemFrame,
+                            HWND_TOP,
+                            0, 0, 0, 0,
+                            SWP_ZORDER | SWP_SHOW | SWP_ACTIVATE);
+        }
+    }
+}
+
+#else
+void memdDummy2(void)
+{
+    int i = 0;
+}
+#endif
+
Index: /trunk/src/helpers/prfh.c
===================================================================
--- /trunk/src/helpers/prfh.c	(revision 12)
+++ /trunk/src/helpers/prfh.c	(revision 13)
@@ -263,5 +263,5 @@
 {
     CHAR szColor[30];
-    LONG r, g, b;
+    ULONG r, g, b;
     PrfQueryProfileString(
                 HINI_USER,
@@ -271,6 +271,6 @@
                 szColor,
                 sizeof(szColor)-1);
-    sscanf(szColor, "%d %d %d ", &r, &g, &b);
-    return (r*0x10000 + g*0x100 + b);
+    sscanf(szColor, "%lu %lu %lu ", &r, &g, &b);
+    return (LONG)(r*0x10000 + g*0x100 + b);
 }
 
@@ -468,5 +468,5 @@
             if (PrfQueryProfile(hab, &Profiles))
             {
-                _Pmpf(("Old user profile: %s", Profiles.pszUserName));
+                // _Pmpf(("Old user profile: %s", Profiles.pszUserName));
 
                 // change INIs
Index: /trunk/src/helpers/prfh2.c
===================================================================
--- /trunk/src/helpers/prfh2.c	(revision 12)
+++ /trunk/src/helpers/prfh2.c	(revision 13)
@@ -98,5 +98,5 @@
     if (fLog)
     {
-        fprintf(fLog, "    Error occured: %s\n    Return code: %s (%d)\n",
+        fprintf(fLog, "    Error occured: %s\n    Return code: %s (%lu)\n",
                 pszErrorString,
                     (ulrc == MBID_ABORT) ? "MBID_ABORT"
@@ -179,5 +179,11 @@
                       "hiniOld 0x%lX, pszOld %s, pfnwpCallback 0x%lX, "
                       "hwnd 0x%lX, msg 0x%lX, ulCount 0x%lX, ulMax 0x%lX\n",
-                hOld, pszOld, fncbUpdate, hwnd, msg, ulCount, ulMax);
+                hOld,
+                pszOld,
+                (ULONG)fncbUpdate,
+                hwnd,
+                msg,
+                ulCount,
+                ulMax);
         fflush(fLog);
     }
@@ -500,5 +506,5 @@
                 arc2 = doshSetPathAttr(szSysBackup, FILE_NORMAL);
                 if (fLog)
-                    fprintf(fLog, "    rc2: %d\n", arc2);
+                    fprintf(fLog, "    rc2: %lu\n", arc2);
 
                 // delete OS2SYS.BAK
@@ -509,5 +515,5 @@
                 arc2 = DosDelete(szSysBackup);
                 if (fLog)
-                    fprintf(fLog, "    rc2: %d\n", arc2);
+                    fprintf(fLog, "    rc2: %lu\n", arc2);
 
                 // attrib -r -s -h -a OS2SYS.INI
@@ -518,5 +524,5 @@
                 arc2 = doshSetPathAttr(Profiles.pszSysName, FILE_NORMAL);
                 if (fLog)
-                    fprintf(fLog, "    rc2: %d\n", arc2);
+                    fprintf(fLog, "    rc2: %lu\n", arc2);
 
                 // move OS2SYS.INI OS2SYS.BAK
@@ -526,5 +532,5 @@
                 arc = DosMove(Profiles.pszSysName, szSysBackup);
                 if (fLog)
-                    fprintf(fLog, "    rc: %d\n", arc);
+                    fprintf(fLog, "    rc: %lu\n", arc);
 
                 if (arc)
@@ -539,5 +545,5 @@
                 arc = DosMove(szSysNew, Profiles.pszSysName);
                 if (fLog)
-                    fprintf(fLog, "    rc: %d\n", arc);
+                    fprintf(fLog, "    rc: %lu\n", arc);
                 if (arc)
                     ulErrorOccured = prfhINIError(MB_ABORTRETRYIGNORE, fLog, fncbError, "Error moving newly created profile to system profile.");
@@ -566,5 +572,5 @@
                 arc2 = doshSetPathAttr(szUserBackup, FILE_NORMAL);
                 if (fLog)
-                    fprintf(fLog, "    rc2: %d\n", arc2);
+                    fprintf(fLog, "    rc2: %lu\n", arc2);
 
                 // delete OS2.BAK
@@ -575,5 +581,5 @@
                 arc2 = DosDelete(szUserBackup);
                 if (fLog)
-                    fprintf(fLog, "    rc2: %d\n", arc2);
+                    fprintf(fLog, "    rc2: %lu\n", arc2);
 
                 // attrib -r -s -h -a OS2.INI
@@ -583,5 +589,5 @@
                 arc2 = doshSetPathAttr(Profiles.pszUserName, FILE_NORMAL);
                 if (fLog)
-                    fprintf(fLog, "    rc2: %d\n", arc2);
+                    fprintf(fLog, "    rc2: %lu\n", arc2);
 
                 // move OS2.INI OS2.BAK
@@ -591,5 +597,5 @@
                 arc = DosMove(Profiles.pszUserName, szUserBackup);
                 if (fLog)
-                    fprintf(fLog, "    rc: %d\n", arc);
+                    fprintf(fLog, "    rc: %lu\n", arc);
 
                 if (arc)
@@ -606,5 +612,5 @@
                 arc = DosMove(szUserNew, Profiles.pszUserName);
                 if (fLog)
-                    fprintf(fLog, "    rc: %d\n", arc);
+                    fprintf(fLog, "    rc: %lu\n", arc);
 
                 if (arc)
Index: /trunk/src/helpers/procstat.c
===================================================================
--- /trunk/src/helpers/procstat.c	(revision 12)
+++ /trunk/src/helpers/procstat.c	(revision 13)
@@ -593,5 +593,5 @@
                               USHORT usSemID)         // in: as in QPROCESS32.pausSem16
 {
-    PQSEM32STRUC32  pSemThis = pInfo->pSem32Data;
+    // PQSEM32STRUC32  pSemThis = pInfo->pSem32Data;
 
     /* while (pSemThis)
Index: /trunk/src/helpers/stringh.c
===================================================================
--- /trunk/src/helpers/stringh.c	(revision 12)
+++ /trunk/src/helpers/stringh.c	(revision 13)
@@ -3,5 +3,11 @@
  *@@sourcefile stringh.c:
  *      contains string/text helper functions. These are good for
- *      parsing/splitting strings and other stuff used throughout XWorkplace.
+ *      parsing/splitting strings and other stuff used throughout
+ *      XWorkplace.
+ *
+ *      Note that these functions are really a bunch of very mixed
+ *      up string helpers, which you may or may not find helpful.
+ *      If you're looking for string functions with memory
+ *      management, look at xstring.c instead.
  *
  *      Usage: All OS/2 programs.
@@ -180,5 +186,6 @@
  *      this creates a new PSZ containing the string
  *      from pBegin to pEnd, excluding the pEnd character.
- *      The new string is null-terminated.
+ *      The new string is null-terminated. The caller
+ *      must free() the new string after use.
  *
  *      Example:
@@ -424,6 +431,6 @@
  *      be free()'able.
  *
- *      Use of this wrapper is not recommended because
- *      it is considerably slower than xstrrpl.
+ *      Repetitive use of this wrapper is not recommended
+ *      because it is considerably slower than xstrrpl.
  *
  *@@added V0.9.6 (2000-11-01) [umoeller]
@@ -431,8 +438,8 @@
 
 ULONG strhrpl(PSZ *ppszBuf,                // in/out: string
-              ULONG ulOfs,                  // in: where to begin search (0 = start)
-              const char *pcszSearch,    // in: search string; cannot be NULL
-              const char *pcszReplace,   // in: replacement string; cannot be NULL
-              PULONG pulAfterOfs)           // out: offset where found (ptr can be NULL)
+              PULONG pulOfs,               // in: where to begin search (0 = start);
+                                           // out: ofs of first char after replacement string
+              const char *pcszSearch,      // in: search string; cannot be NULL
+              const char *pcszReplace)     // in: replacement string; cannot be NULL
 {
     ULONG   ulrc = 0;
@@ -440,4 +447,6 @@
             xstrFind,
             xstrReplace;
+    size_t  ShiftTable[256];
+    BOOL    fRepeat = FALSE;
     xstrInit(&xstrBuf, 0);
     xstrset(&xstrBuf, *ppszBuf);
@@ -447,5 +456,10 @@
     xstrset(&xstrReplace, (PSZ)pcszReplace);
 
-    if (ulrc = xstrrpl(&xstrBuf, ulOfs, &xstrFind, &xstrReplace, pulAfterOfs))
+    if ((ulrc = xstrrpl(&xstrBuf,
+                        pulOfs,
+                        &xstrFind,
+                        &xstrReplace,
+                        ShiftTable,
+                        &fRepeat)))
         // replaced:
         *ppszBuf = xstrBuf.psz;
@@ -482,10 +496,15 @@
  *      converts a ULONG into a decimal string, while
  *      inserting thousands separators into it. Specify
- *      the separator char in cThousands.
+ *      the separator character in cThousands.
+ *
  *      Returns pszTarget so you can use it directly
  *      with sprintf and the "%s" flag.
+ *
  *      For cThousands, you should use the data in
  *      OS2.INI ("PM_National" application), which is
  *      always set according to the "Country" object.
+ *      You can use prfhQueryCountrySettings to
+ *      retrieve this setting.
+ *
  *      Use strhThousandsDouble for "double" values.
  */
@@ -497,5 +516,5 @@
     USHORT ust, uss, usc;
     CHAR   szTemp[40];
-    sprintf(szTemp, "%d", ul);
+    sprintf(szTemp, "%lu", ul);
 
     ust = 0;
@@ -548,4 +567,30 @@
 
 /*
+ *@@ strhVariableDouble:
+ *      like strhThousandsULong, but for a "double" value, and
+ *      with a variable number of decimal places depending on the
+ *      size of the quantity.
+ *
+ *@@added V0.9.6 (2000-11-12) [pr]
+ */
+
+PSZ strhVariableDouble(PSZ pszTarget,
+                       double dbl,
+                       PSZ pszUnits,
+                       CHAR cThousands)
+{
+    if (dbl < 100.0)
+        sprintf(pszTarget, "%.2f%s", dbl, pszUnits);
+    else
+        if (dbl < 1000.0)
+            sprintf(pszTarget, "%.1f%s", dbl, pszUnits);
+        else
+            strcat(strhThousandsDouble(pszTarget, dbl, cThousands),
+                   pszUnits);
+
+    return(pszTarget);
+}
+
+/*
  *@@ strhFileDate:
  *      converts file date data to a string (to pszBuf).
@@ -566,8 +611,8 @@
  *      cDateSep is used as a date separator (e.g. '.').
  *      This can be queried using:
- +              prfhQueryProfileChar(HINI_USER, "PM_National", "sDate", '/');
+ +          prfhQueryProfileChar(HINI_USER, "PM_National", "sDate", '/');
  *
  *      Alternatively, you can query all the country settings
- *      at once using prfhQueryCountrySettings (prfh.c, new with V0.9.0).
+ *      at once using prfhQueryCountrySettings (prfh.c).
  *
  *@@changed (99-11-07) [umoeller]: now calling strhDateTime
@@ -611,5 +656,5 @@
  *
  *      Alternatively, you can query all the country settings
- *      at once using prfhQueryCountrySettings (prfh.c, new with V0.9.0).
+ *      at once using prfhQueryCountrySettings (prfh.c).
  *
  *@@changed 99-03-15 fixed 12-hour crash
@@ -637,6 +682,6 @@
 /*
  *@@ strhDateTime:
- *      converts Control Programe DATETIME info
- *      to two strings. See strhFileDate and strhFileTime
+ *      converts Control Program DATETIME info
+ *      into two strings. See strhFileDate and strhFileTime
  *      for more detailed parameter descriptions.
  *
@@ -821,4 +866,51 @@
 
 /*
+ *@@ strhIsWord:
+ *      returns TRUE if p points to a "word"
+ *      in pcszBuf.
+ *
+ *      p is considered a word if the character _before_
+ *      it is in pcszBeginChars and the char _after_
+ *      it (i.e. *(p+cbSearch)) is in pcszEndChars.
+ *
+ *@@added V0.9.6 (2000-11-12) [umoeller]
+ */
+
+BOOL strhIsWord(const char *pcszBuf,
+                const char *p,                 // in: start of word
+                ULONG cbSearch,                // in: length of word
+                const char *pcszBeginChars,    // suggestion: "\x0d\x0a ()/\\-,."
+                const char *pcszEndChars)      // suggestion: "\x0d\x0a ()/\\-,.:;"
+{
+    BOOL    fEndOK = FALSE;
+
+    // check previous char
+    if (    (p == pcszBuf)
+         || (strchr(pcszBeginChars, *(p-1)))
+       )
+    {
+        // OK, valid begin char:
+        // check end char
+        CHAR    cNextChar = *(p + cbSearch);
+        if (cNextChar == 0)
+            fEndOK = TRUE;
+        else
+        {
+            char *pc = strchr(pcszEndChars, cNextChar);
+            if (pc)
+                // OK, is end char: avoid doubles of that char,
+                // but allow spaces
+                if (    (cNextChar+1 != *pc)
+                     || (cNextChar+1 == ' ')
+                     || (cNextChar+1 == 0)
+                   )
+                    fEndOK = TRUE;
+        }
+    }
+
+    return (fEndOK);
+}
+
+/*
  *@@ strhFindWord:
  *      searches for pszSearch in pszBuf, which is
@@ -836,10 +928,8 @@
  *
  *      The algorithm here uses strstr to find pszSearch in pszBuf
- *      and performs additional "is-word" checks for each item found.
- *      With VAC++ 3.0, this is still much faster than searching
- *      words first and then comparing each word with pszSearch.
- *      I've tried it that way too, and that took nearly double as
- *      long. Apparently, the VAC++ runtime library uses some
- *      optimized search algorithm here, so we better use that one.
+ *      and performs additional "is-word" checks for each item found
+ *      (by calling strhIsWord).
+ *
+ *      Note that this function is fairly slow compared to xstrFindWord.
  *
  *@@added V0.9.0 (99-11-08) [umoeller]
@@ -859,61 +949,4 @@
     {
         const char *p = pszBuf;
-
-        /*  // go thru all characters
-        while (*p)
-        {
-            // check if current character is either the
-            // very first or a "begin word" character
-            if (    (p == pszBuf)
-                 || (strchr(pcszBeginChars, *p) == 0)
-               )
-            {
-                // yes: go for next
-                if (*(++p))
-                {
-                    // compare with search string
-                    if (strcmp(p, pszSearch) == 0)
-                    {
-                        // is the same:
-                        // check if still in buffer
-                        if (p < pszBuf + cbBuf)
-                        {
-                            CHAR    cAfterEndOfWord = *(p + cbSearch);
-                            if (cAfterEndOfWord == 0)
-                            {
-                                // end of string:
-                                // that's ok
-                                pszReturn = (PSZ)p;
-                                break;
-                            }
-                            else
-                            {
-                                // check if in "end of word" list
-                                char *pc2 = strchr(pcszEndChars, cAfterEndOfWord);
-                                if (pc2)
-                                    // OK, is end char: avoid doubles of that char,
-                                    // but allow spaces
-                                    if (    (cAfterEndOfWord+1 != *pc2)
-                                         || (cAfterEndOfWord+1 == ' ')
-                                         || (cAfterEndOfWord+1 == 0)
-                                       )
-                                    {
-                                        // end of string:
-                                        // that's ok
-                                        pszReturn = (PSZ)p;
-                                        break;
-                                    }
-                            }
-                        }
-                    }
-                }
-                else
-                    // end of string:
-                    break;
-            }
-
-            ++p;
-        } // end while
-        */
 
         do  // while p
@@ -925,35 +958,15 @@
                 // check if that's a word
 
-                // check previous char
-                if (    (p == pszBuf)
-                     || (strchr(pcszBeginChars, *(p-1)))
-                   )
+                if (strhIsWord(pszBuf,
+                               p,
+                               cbSearch,
+                               pcszBeginChars,
+                               pcszEndChars))
                 {
-                    // OK, valid begin char:
-                    BOOL    fEndOK = FALSE;
-                    // check end char
-                    CHAR    cNextChar = *(p + cbSearch);
-                    if (cNextChar == 0)
-                        fEndOK = TRUE;
-                    else
-                    {
-                        char *pc = strchr(pcszEndChars, cNextChar);
-                        if (pc)
-                            // OK, is end char: avoid doubles of that char,
-                            // but allow spaces
-                            if (    (cNextChar+1 != *pc)
-                                 || (cNextChar+1 == ' ')
-                                 || (cNextChar+1 == 0)
-                               )
-                                fEndOK = TRUE;
-                    }
-
-                    if (fEndOK)
-                    {
-                        // valid end char:
-                        pszReturn = (PSZ)p;
-                        break;
-                    }
+                    // valid end char:
+                    pszReturn = (PSZ)p;
+                    break;
                 }
+
                 p += cbSearch;
             }
@@ -1186,7 +1199,6 @@
             if (pEOL)
             {
-                XSTRING strBuf,
-                        strFind,
-                        strReplace;
+                XSTRING strBuf;
+                ULONG   ulOfs = 0;
 
                 PSZ pszOldCopy = (PSZ)malloc(cbOldParam+1);
@@ -1196,8 +1208,9 @@
                 xstrInit(&strBuf, 0);
                 xstrset(&strBuf, *ppszBuf);         // this must not be freed!
-                xstrInit(&strFind, 0);
+                /* xstrInit(&strFind, 0);
                 xstrset(&strFind, pszOldCopy);      // this must not be freed!
                 xstrInit(&strReplace, 0);
                 xstrset(&strReplace, pszNewParam);  // this must not be freed!
+                   */
 
                 // check for upper case desired?
@@ -1206,5 +1219,5 @@
                         strupr(pszNewParam);
 
-                xstrrpl(&strBuf, 0, &strFind, &strReplace, NULL);
+                xstrcrpl(&strBuf, &ulOfs, pszOldCopy, pszNewParam);
 
                 free(pszOldCopy);
@@ -1373,5 +1386,5 @@
     PSZ pParam;
     if ((pParam = strhFindAttribValue(pszSearchIn, pszTag)))
-        sscanf(pParam, "%d", pl);
+        sscanf(pParam, "%ld", pl);
 
     return (pParam);
@@ -1799,5 +1812,5 @@
             pszLine += ulIndent;
         }
-        pszLine += sprintf(pszLine, "%02lX ", *pbCurrent);
+        pszLine += sprintf(pszLine, "%02lX ", (ULONG)*pbCurrent);
 
         if ( (*pbCurrent > 31) && (*pbCurrent < 127) )
@@ -1869,5 +1882,5 @@
 
 /*
- *@@ skip_comp_os2:
+ * skip_comp_os2:
  *      Return a pointer to the next component of the path SRC, for OS/2
  *      and DOS styles.  When the end of the string is reached, a pointer
@@ -2467,255 +2480,73 @@
 
 /*
- *@@ strhfind:
- *      searches for a pattern in a string using the Boyer-Moore-
- *      Horspool-Sunday algorithm.  The string and pattern are null-terminated
- *      strings.  Returns a pointer to the pattern if found within the string,
- *      or NULL if the pattern was not found.  If you repeatedly scan for the
- *      same pattern, use the repeat_find argument.  If this is TRUE, the
- *      function does not re-parse the pattern.  You must of course call the
- *      function with repeat_find equal to FALSE the first time.  This function
- *      is meant to handle  character data, and is most effective when you work
- *      with large strings.  To search binary data use strhmemfind().  Will not work
- *      on multibyte characters.
- *
- *      Examples:
- +      char *result;
+ *@@ strhmemfind:
+ *      searches for a pattern in a block of memory using the
+ *      Boyer-Moore-Horspool-Sunday algorithm.
+ *
+ *      The block and pattern may contain any values; you must
+ *      explicitly provide their lengths. If you search for strings,
+ *      use strlen() on the buffers.
+ *
+ *      Returns a pointer to the pattern if found within the block,
+ *      or NULL if the pattern was not found.
+ *
+ *      This algorithm needs a "shift table" to cache data for the
+ *      search pattern. This table can be reused when performing
+ *      several searches with the same pattern.
+ *
+ *      "shift" must point to an array big enough to hold 256 (8**2)
+ *      "size_t" values.
+ *
+ *      If (*repeat_find == FALSE), the shift table is initialized.
+ *      So on the first search with a given pattern, *repeat_find
+ *      should be FALSE. This function sets it to TRUE after the
+ *      shift table is initialised, allowing the initialisation
+ *      phase to be skipped on subsequent searches.
+ *
+ *      This function is most effective when repeated searches are
+ *      made for the same pattern in one or more large buffers.
+ *
+ *      Example:
+ *
+ +          PSZ     pszHaystack = "This is a sample string.",
+ +                  pszNeedle = "string";
+ +          size_t  shift[256];
+ +          BOOL    fRepeat = FALSE;
  +
- +      result = strhfind ("abracadabra", "cad", FALSE);
- +      if (result)
- +          puts (result);
- +
+ +          PSZ     pFound = strhmemfind(pszHaystack,
+ +                                       strlen(pszHaystack),   // block size
+ +                                       pszNeedle,
+ +                                       strlen(pszNeedle),     // pattern size
+ +                                       shift,
+ +                                       &fRepeat);
+ *
  *      Taken from the "Standard Function Library", file sflfind.c.
  *      Copyright:  Copyright (c) 1991-99 iMatix Corporation.
- *      Slightly modified.
+ *      Slightly modified by umoeller.
  *
  *@@added V0.9.3 (2000-05-08) [umoeller]
  */
 
-char* strhfind (const char *string,            //  String containing data
-                const char *pattern,           //  Pattern to search for
-                BOOL repeat_find)              //  Same pattern as last time
-{
-    static size_t
-        searchbuf [256];                //  Fixed search buffer
-
-    ASSERT (string);                    //  Expect non-NULL pointers, but
-    ASSERT (pattern);                   //  fall through if not debugging
-
-    return (char *) strhmemfind_rb (string,    strlen (string),
-                                pattern,   strlen (pattern),
-                                searchbuf, &repeat_find);
-}
-
-/*
- *@@ strhfind_r:
- *      searches for a pattern in a string using the Boyer-Moore-
- *      Horspool-Sunday algorithm.  The string and pattern are null-terminated
- *      strings.  Returns a pointer to the pattern if found within the string,
- *      or NULL if the pattern was not found.  This function is meant to handle
- *      character data, and is most effective when you work with large strings.
- *      To search binary data use strhmemfind().  Will not work on multibyte
- *      characters.  Reentrant.
- *
- *      Examples:
- +      char *result;
- +
- +      result = strhfind_r ("abracadabra", "cad");
- +      if (result)
- +          puts (result);
- *
- *      Taken from the "Standard Function Library", file sflfind.c.
- *      Copyright:  Copyright (c) 1991-99 iMatix Corporation.
- *      Slightly modified.
- *
- *@@added V0.9.3 (2000-05-08) [umoeller]
- */
-
-char* strhfind_r (const char *string,          //  String containing data
-                  const char *pattern)         //  Pattern to search for
-{
-    size_t
-        searchbuf [256];                //  One-time search buffer
-    BOOL
-        secondtime = FALSE;             //  Search buffer init needed
-
-    ASSERT (string);                    //  Expect non-NULL pointers, but
-    ASSERT (pattern);                   //  fall through if not debugging
-
-    return (char *) strhmemfind_rb (string,    strlen (string),
-                                    pattern,   strlen (pattern),
-                                    searchbuf, &secondtime);
-}
-
-/*
- *@@ strhfind_rb:
- *      searches for a pattern in a string using the Boyer-Moore-
- *      Horspool-Sunday algorithm.  The string and pattern are null-terminated
- *      strings.  Returns a pointer to the pattern if found within the string,
- *      or NULL if the pattern was not found.  Supports more efficient repeat
- *      searches (for the same pattern), through a supplied search buffer.  The
- *      search buffer must be long enough to contain 256 (2**8) size_t entries.
- *      On the first call repeat_find must be set to FALSE.  After the search
- *      buffer has been initialised, repeat_find will be set to TRUE by the
- *      function, avoiding the search buffer initialisation on later calls.
- *
- *      This function is most effective when repeated searches are made for
- *      the same pattern in one or more strings.  This function is meant to
- *      handle  character data, and is most effective when you work with
- *      large strings.  To search binary data use strhmemfind().  Will not work
- *      on multibyte characters.  Reentrant.
- *
- *      Examples:
- +      char   *result;
- +      BOOL   repeat_search = FALSE;
- +      size_t searchbuf[256];
- +
- +      result = strhfind_rb ("abracadabra", "cad", searchbuf, &repeat_search);
- +      if (result)
- +        {
- +          puts (result);
- +          result = strhfind_rb ("cad/cam", "cad", searchbuf, &repeat_search);
- +          if (result)
- +              puts (result);
- +        }
- *
- *      Taken from the "Standard Function Library", file sflfind.c.
- *      Copyright:  Copyright (c) 1991-99 iMatix Corporation.
- *      Slightly modified.
- *
- *@@added V0.9.3 (2000-05-08) [umoeller]
- */
-
-char* strhfind_rb (const char *string,         //  String containing data
-                   const char *pattern,        //  Pattern to search for
-                   size_t     *shift,          //  Working buffer between searches
-                   BOOL       *repeat_find)    //  Flag for first/later search
-{
-    ASSERT (string);                    //  Expect non-NULL pointers, but
-    ASSERT (pattern);                   //  fall through if not debugging
-    ASSERT (shift);
-    ASSERT (repeat_find);
-
-    return (char *) strhmemfind_rb (string,    strlen (string),
-                                    pattern,   strlen (pattern),
-                                    shift,     repeat_find);
-}
-
-/*
- *@@ strhmemfind:
- *      searches for a pattern in a block of memory using the Boyer-
- *      Moore-Horspool-Sunday algorithm.  The block and pattern may contain any
- *      values; you must explicitly provide their lengths.  Returns a pointer to
- *      the pattern if found within the block, or NULL if the pattern was not
- *      found.  If you repeatedly scan for the same pattern, use the repeat_find
- *      argument.  If this is TRUE, the function does not re-parse the pattern.
- *      This function is meant to handle binary data.  If you need to search
- *      strings, use the strhfind_r or strhfind_rb() functions.  Non-Reentrant.
- *
- *      Taken from the "Standard Function Library", file sflfind.c.
- *      Copyright:  Copyright (c) 1991-99 iMatix Corporation.
- *      Slightly modified.
- *
- *@@added V0.9.3 (2000-05-08) [umoeller]
- */
-
-void* strhmemfind (const void  *block,            //  Block containing data
-                   size_t       block_size,       //  Size of block in bytes
-                   const void  *pattern,          //  Pattern to search for
-                   size_t       pattern_size,     //  Size of pattern block
-                   BOOL         repeat_find)      //  Same pattern as last time
-{
-    static size_t
-        searchbuf [256];                //  Static shared search buffer
-
-    ASSERT (block);                     //  Expect non-NULL pointers, but
-    ASSERT (pattern);                   //  full through if not debugging
-
-    return strhmemfind_rb (block, block_size, pattern, pattern_size,
-                       searchbuf, &repeat_find);
-}
-
-/*
- *@@ strhmemfind_r:
- *      searches for a pattern in a block of memory using the Boyer-
- *      Moore-Horspool-Sunday algorithm.  The block and pattern may contain any
- *      values; you must explicitly provide their lengths.  Returns a pointer to
- *      the pattern if found within the block, or NULL if the pattern was not
- *      found.
- *
- *      This function is meant to handle binary data, for a single search for
- *      a given pattern.  If you need to search strings, use the strhfind_r()
- *      or strhfind_rb() functions.  If you want to do efficient repeated searches
- *      for one pattern, use strhmemfind_rb().  Reentrant.
- *
- *      Taken from the "Standard Function Library", file sflfind.c.
- *      Copyright:  Copyright (c) 1991-99 iMatix Corporation.
- *      Slightly modified.
- *
- *@@added V0.9.3 (2000-05-08) [umoeller]
- */
-
-void* strhmemfind_r (const void  *block,          //  Block containing data
-                     size_t       block_size,     //  Size of block in bytes
-                     const void  *pattern,        //  Pattern to search for
-                     size_t       pattern_size)   //  Size of pattern block
-{
-    size_t
-        searchbuf [256];                //  One-time search buffer
-    BOOL
-        secondtime  = FALSE;
-
-    ASSERT (block);                     //  Expect non-NULL pointers, but
-    ASSERT (pattern);                   //  full through if not debugging
-
-    return strhmemfind_rb (block, block_size, pattern, pattern_size,
-                           searchbuf, &secondtime);
-}
-
-/*
- *@@ strhmemfind_rb:
- *      searches for a pattern in a block of memory using the Boyer-
- *      Moore-Horspool-Sunday algorithm.  The block and pattern may contain any
- *      values; you must explicitly provide their lengths.  Returns a pointer to
- *      the pattern if found within the block, or NULL if the pattern was not
- *      found.  On the first search with a given pattern, *repeat_find should
- *      be FALSE.  It will be set to TRUE after the shift table is initialised,
- *      allowing the initialisation phase to be skipped on subsequent searches.
- *      shift must point to an array big enough to hold 256 (8**2) size_t values.
- *
- *      This function is meant to handle binary data, for repeated searches
- *      for the same pattern.  If you need to search strings, use the
- *      strhfind_r() or strhfind_rb() functions.  If you wish to search for a
- *      pattern only once consider using strhmemfind_r(). Reentrant.
- *
- *      Taken from the "Standard Function Library", file sflfind.c.
- *      Copyright:  Copyright (c) 1991-99 iMatix Corporation.
- *      Slightly modified.
- *
- *@@added V0.9.3 (2000-05-08) [umoeller]
- */
-
-void* strhmemfind_rb (const void  *in_block,      //  Block containing data
-                      size_t       block_size,    //  Size of block in bytes
-                      const void  *in_pattern,    //  Pattern to search for
-                      size_t       pattern_size,  //  Size of pattern block
-                      size_t      *shift,         //  Shift table (search buffer)
-                      BOOL        *repeat_find)   //  TRUE: search buffer already init
-{
-    size_t
-        byte_nbr,                       //  Distance through block
-        match_size;                     //  Size of matched part
+void* strhmemfind(const void *in_block,     // in: block containing data
+                  size_t block_size,        // in: size of block in bytes
+                  const void *in_pattern,   // in: pattern to search for
+                  size_t pattern_size,      // in: size of pattern block
+                  size_t *shift,            // in/out: shift table (search buffer)
+                  BOOL *repeat_find)        // in/out: if TRUE, *shift is already initialized
+{
+    size_t      byte_nbr,                       //  Distance through block
+                match_size;                     //  Size of matched part
     const unsigned char
-        *match_base = NULL,             //  Base of match of pattern
-        *match_ptr  = NULL,             //  Point within current match
-        *limit      = NULL;             //  Last potiental match point
+                *match_base = NULL,             //  Base of match of pattern
+                *match_ptr  = NULL,             //  Point within current match
+                *limit      = NULL;             //  Last potiental match point
     const unsigned char
-        *block   = (unsigned char *) in_block,   //  Concrete pointer to block data
-        *pattern = (unsigned char *) in_pattern; //  Concrete pointer to search value
-
-    ASSERT (block);                     //  Expect non-NULL pointers, but
-    ASSERT (pattern);                   //  fail gracefully if not debugging
-    ASSERT (shift);                     //  NULL repeat_find => is false
-    if (block == NULL || pattern == NULL || shift == NULL)
+                *block   = (unsigned char *) in_block,   //  Concrete pointer to block data
+                *pattern = (unsigned char *) in_pattern; //  Concrete pointer to search value
+
+    if (    (block == NULL)
+         || (pattern == NULL)
+         || (shift == NULL)
+       )
         return (NULL);
 
@@ -2736,13 +2567,17 @@
 
     if (!repeat_find || !*repeat_find)
-      {
-        for (byte_nbr = 0; byte_nbr < 256; byte_nbr++)
-            shift [byte_nbr] = pattern_size + 1;
-        for (byte_nbr = 0; byte_nbr < pattern_size; byte_nbr++)
-            shift [(unsigned char) pattern [byte_nbr]] = pattern_size - byte_nbr;
+    {
+        for (byte_nbr = 0;
+             byte_nbr < 256;
+             byte_nbr++)
+            shift[byte_nbr] = pattern_size + 1;
+        for (byte_nbr = 0;
+             byte_nbr < pattern_size;
+             byte_nbr++)
+            shift[(unsigned char)pattern[byte_nbr]] = pattern_size - byte_nbr;
 
         if (repeat_find)
             *repeat_find = TRUE;
-      }
+    }
 
     //  Search for the block, each time jumping up by the amount
@@ -2754,21 +2589,21 @@
     for (match_base = block;
          match_base < limit;
-         match_base += shift [*(match_base + pattern_size)])
-      {
+         match_base += shift[*(match_base + pattern_size)])
+    {
         match_ptr  = match_base;
         match_size = 0;
 
         //  Compare pattern until it all matches, or we find a difference
-        while (*match_ptr++ == pattern [match_size++])
-          {
+        while (*match_ptr++ == pattern[match_size++])
+        {
             ASSERT (match_size <= pattern_size &&
                     match_ptr == (match_base + match_size));
 
-            //  If we found a match, return the start address
+            // If we found a match, return the start address
             if (match_size >= pattern_size)
-              return ((void*)(match_base));
-
-          }
-      }
+                return ((void*)(match_base));
+
+        }
+    }
     return (NULL);                      //  Found nothing
 }
Index: /trunk/src/helpers/syssound.c
===================================================================
--- /trunk/src/helpers/syssound.c	(revision 12)
+++ /trunk/src/helpers/syssound.c	(revision 13)
@@ -153,5 +153,5 @@
             {
                 // individual volume settings per sound
-                sscanf(p1, "%d", pulVolume);
+                sscanf(p1, "%lu", pulVolume);
                 ulrc++;
             }
@@ -290,5 +290,5 @@
                                           "100",
                                           szData2, sizeof(szData2));
-                    sscanf(szData2, "%d", pulVolume);
+                    sscanf(szData2, "%lu", pulVolume);
                 }
 
@@ -332,5 +332,5 @@
         CHAR szData[1000];
         // format: soundfile#description#volume
-        sprintf(szData, "%s#%s#%d", pszFile, pszDescr, ulVolume);
+        sprintf(szData, "%s#%s#%lu", pszFile, pszDescr, ulVolume);
         brc = PrfWriteProfileString(hiniMMPM,
                                     MMINIKEY_SYSSOUNDS, szKey,
@@ -475,5 +475,5 @@
                     ulKeyLen = strlen(szFile)+1;    // go beyond null byte
                     ulKeyLen += sprintf(szFile+ulKeyLen,
-                                "%d",
+                                "%lu",
                                 ulVolume) + 1;
                     // and write to OS2SYS.INI
@@ -608,10 +608,10 @@
                             // copy it
                             sscanf(pSchemeSoundData + cbSchemeSoundFile,
-                                   "%d",
+                                   "%lu",
                                    &ulVolume);
 
                         // and write data to MMPM.INI
                         // format: soundfile#description#volume
-                        sprintf(szData, "%s#%s#%d", szFile, szDescription, ulVolume);
+                        sprintf(szData, "%s#%s#%lu", szFile, szDescription, ulVolume);
                         if (PrfWriteProfileString(hiniMMPM,
                                                   MMINIKEY_SYSSOUNDS, // "MMPM2_AlarmSounds"
Index: /trunk/src/helpers/textv_html.c
===================================================================
--- /trunk/src/helpers/textv_html.c	(revision 12)
+++ /trunk/src/helpers/textv_html.c	(revision 13)
@@ -175,5 +175,5 @@
 
 VOID AppendChar(PCOPYTARGET pct,  // in/out: formatting buffer
-                CHAR c)
+                unsigned char c)
 {
     // calculate ofs where to store next char
@@ -685,11 +685,13 @@
                                                 pct->ulListLevel - 1);
         if (pListDesc)
+        {
             if (pListDesc->ulListType == 1)
                 // is ordered list:
-                sprintf(szMarker, "%d.", (pListDesc->ulItem)++);
+                sprintf(szMarker, "%lu.", (pListDesc->ulItem)++);
             else if (pListDesc->ulListType == 0)
                 // is unordered list:
                 // set bullet type according to unordered nesting
                 szMarker[2] = pct->ulUnorderedListLevel;
+        }
     }
 
@@ -864,5 +866,5 @@
     if (pct->fInLink)
     {
-        sprintf(szAnchor, "%04lX", pct->usAnchorIndex);
+        sprintf(szAnchor, "%04hX", pct->usAnchorIndex);
         AppendString(pct,
                      TXVESC_LINK);
@@ -933,8 +935,10 @@
                 case 'd': // ADDRESS
                     if (stricmp(p2, "DRESS") == 0)
+                    {
                         if (!fEndOfTag)
                             return TagI;
                         else
                             return TagXI;
+                    }
             }
         break;
@@ -976,8 +980,10 @@
                 case 'o':
                     if (stricmp(p2, "DE") == 0)
+                    {
                         if (!fEndOfTag)
                             return TagCODE;
                         else
                             return TagXCODE;
+                    }
                 break;
             }
@@ -998,8 +1004,10 @@
                     if (*p2 == 'R')
                         if (*(pCheck + 3) == 0)
+                        {
                             if (!fEndOfTag)
                                 return TagUL;
                             else
                                 return TagXUL;
+                        }
                 break;
 
@@ -1007,8 +1015,10 @@
                 case 'l': // DL
                     if (*p2 == 0)
+                    {
                         if (!fEndOfTag)
                             return TagDL;
                         else
                             return TagXDL;
+                    }
                 break;
 
@@ -1025,8 +1035,10 @@
             if ( (c1 == 'M') || (c1 == 'm') )  // EM
                 if (*p2 == 0)
+                {
                     if (!fEndOfTag)
                         return TagI;
                     else
                         return TagXI;
+                }
         break;
 
@@ -1073,8 +1085,10 @@
         case 'i':
             if (c1 == 0)
+            {
                 if (!fEndOfTag)
                     return TagI;
                 else
                     return TagXI;
+            }
         break;
 
@@ -1089,8 +1103,10 @@
         case 'm':
             if (stricmp(p2, "NU") == 0)
+            {
                 if (!fEndOfTag)
                     return TagUL;
                 else
                     return TagXUL;
+            }
         break;
 
@@ -1099,8 +1115,10 @@
             if ((c1 == 'L') || (c1 == 'l'))
                 if (*p2 == 0)
+                {
                     if (!fEndOfTag)
                         return TagOL;
                     else
                         return TagXOL;
+                }
         break;
 
@@ -1118,8 +1136,10 @@
                     if ((*p2 == 'E') || (*p2 == 'e'))
                         if (*(pCheck + 3) == 0)
+                        {
                             if (!fEndOfTag)
                                 return TagPRE;
                             else
                                 return TagXPRE;
+                        }
                 break;
             }
@@ -1133,13 +1153,17 @@
                 case 't': // STRONG
                     if (stricmp(p2, "RONG") == 0)
+                    {
                         if (!fEndOfTag)
                             return TagB;
                         else
                             return TagXB;
+                    }
                     else if (stricmp(p2, "RIKE") == 0)
+                    {
                         if (!fEndOfTag)
                             return TagSTRIKE;
                         else
                             return TagXSTRIKE;
+                    }
                 break;
 
@@ -1147,8 +1171,10 @@
                 case 'a':
                     if (stricmp(p2, "MP") == 0)
+                    {
                         if (!fEndOfTag)
                             return TagCODE;
                         else
                             return TagXCODE;
+                    }
                 break;
             }
@@ -1174,8 +1200,10 @@
                 case 't':
                     if (*p2 == 0)
+                    {
                         if (!fEndOfTag)
                             return TagCODE;
                         else
                             return TagXCODE;
+                    }
                 break;
             }
@@ -1195,8 +1223,10 @@
                 case 'l':
                     if (*p2 == 0)
+                    {
                         if (!fEndOfTag)
                             return TagUL;
                         else
                             return TagXUL;
+                    }
                 break;
             }
@@ -1393,5 +1423,5 @@
  */
 
-CHAR ConvertEscape(PSZ pszTag)
+unsigned char ConvertEscape(PSZ pszTag)
 {
     CHAR c0, c1;
Index: /trunk/src/helpers/textview.c
===================================================================
--- /trunk/src/helpers/textview.c	(revision 12)
+++ /trunk/src/helpers/textview.c	(revision 13)
@@ -1311,4 +1311,5 @@
                                 pWordThis->pvRectangle = (PVOID)pRect;
                                 lstAppendItem(&pRect->llWords, pWordThis);
+                                            // ### memory leak right here!!!
                                 ulWordsInThisRect++;
 
Index: /trunk/src/helpers/tmsgfile.c
===================================================================
--- /trunk/src/helpers/tmsgfile.c	(revision 12)
+++ /trunk/src/helpers/tmsgfile.c	(revision 13)
@@ -724,5 +724,5 @@
 
             // determine entry
-            sprintf(szEntry, "%s %u %u" NEWLINE,
+            sprintf(szEntry, "%s %lu %lu" NEWLINE,
                     pCurrentNameStart,
                     ulCurrentMessagePos,
Index: /trunk/src/helpers/tree.c
===================================================================
--- /trunk/src/helpers/tree.c	(revision 12)
+++ /trunk/src/helpers/tree.c	(revision 13)
@@ -15,7 +15,19 @@
  *      This has been taken from the Standard Function Library (SFL)
  *      by iMatix Corporation and changed to user the "id" member for
- *      tree sorting/comparison.
+ *      tree sorting/comparison. This implementation is released
+ *      under the GPL.
  *
  *      <B>Using binary trees</B>
+ *
+ *      You can use any structure as elements in a tree, provided
+ *      that the first member in the structure is a TREE structure
+ *      (i.e. it has the left, right, parent, id, and colour members).
+ *      The tree functions don't care what follows.
+ *
+ *      So the implementation here is slightly different from the
+ *      linked lists in linklist.c, because the LISTNODE structs
+ *      only have pointers to the data. By contrast, the TREE structs
+ *      are expected to contain the data themselves. See treeInsertID()
+ *      for a sample.
  *
  *      Each TREE node does not only contain data, but also an
@@ -55,14 +67,15 @@
  *      Differences compared to linklist.c:
  *
+ *      -- Trees are considerably slower when inserting and removing
+ *         nodes because the tree has to be rebalanced every time
+ *         a node changes. By contrast, trees are much faster finding
+ *         nodes because the tree is always sorted.
+ *
+ *      -- You must always supply a comparison function to allow the
+ *         tree functions to sort the tree.
+ *
  *      -- As opposed to a LISTNODE, the TREE structure (which
- *         represents a tree node) does not contain a data pointer.
- *         Instead, all tree nodes are assumed to contain the
- *         data themselves. As a result, you must define your
- *         own structures which start with a TREE structure.
- *
- *         See treeInsertID() for samples.
- *
- *      -- You must supply a comparison function to allow the
- *         tree functions to sort the tree.
+ *         represents a tree node) does not contain a data pointer,
+ *         as said above.
  *
  *@@added V0.9.5 (2000-09-29) [umoeller]
@@ -838,10 +851,17 @@
  *      and will receive the "pUser" parameter, which you can use
  *      as a data pointer to some structure for whatever you like.
- */
-
-void treeTraverse(TREE *tree,
-                  TREE_PROCESS *process,
-                  void *pUser,
-                  int method)
+ *
+ *      "method" specifies in which order the nodes are traversed.
+ *      This can be:
+ *
+ *      -- 1: current node first, then left node, then right node.
+ *      -- 2: left node first, then right node, then current node.
+ *      -- other: left node first, then current node, then right node.
+ */
+
+void treeTraverse(TREE *tree,               // in: root of tree
+                  TREE_PROCESS *process,    // in: callback for each node
+                  void *pUser,              // in: user param for callback
+                  int method)               // in: traversal mode
 {
     if ((!tree)
Index: /trunk/src/helpers/winh.c
===================================================================
--- /trunk/src/helpers/winh.c	(revision 12)
+++ /trunk/src/helpers/winh.c	(revision 13)
@@ -2979,5 +2979,6 @@
     if (pszText)
     {
-        if (strhrpl(&pszText, 0, pszSearch, pszReplaceWith, 0) > 0)
+        ULONG ulOfs = 0;
+        if (strhrpl(&pszText, &ulOfs, pszSearch, pszReplaceWith) > 0)
         {
             WinSetWindowText(hwnd, pszText);
Index: /trunk/src/helpers/xml.c
===================================================================
--- /trunk/src/helpers/xml.c	(revision 12)
+++ /trunk/src/helpers/xml.c	(revision 13)
@@ -240,4 +240,5 @@
 PSZ xmlTokenize(const char *pcszXML)
 {
+    return (0);
 }
 
Index: /trunk/src/helpers/xstring.c
===================================================================
--- /trunk/src/helpers/xstring.c	(revision 12)
+++ /trunk/src/helpers/xstring.c	(revision 13)
@@ -51,11 +51,16 @@
  *      3) If you need the char* pointer (e.g. for a call
  *         to another function), use XSTRING.psz. However,
- *         you should NEVER modify the psz pointer yourself
- *         because then these functions will get into trouble.
+ *         you should ONLY modify the psz pointer yourself
+ *         if the other XSTRING members are updated accordingly.
+ *         You may, for example, change single characters
+ *         in the psz buffer. By contrast, if you change the
+ *         length of the string, you must update XSTRING.ulLength.
+ *         Otherwise these functions will get into trouble.
  *
  *         Also, you should never assume that the "psz"
  *         pointer has not changed after you have called
  *         one of the xstr* functions because these can
- *         always reallocate the buffer if needed.
+ *         always reallocate the buffer if more memory
+ *         was needed.
  *
  *      4) If (and only if) you have a char* buffer which
@@ -68,5 +73,6 @@
  *      The functions in this file used to be in stringh.c
  *      before V0.9.3 (2000-04-01). These have been largely
- *      rewritten with V0.9.6 (2000-11-01).
+ *      rewritten with V0.9.6 (2000-11-01) and are now much
+ *      more efficient.
  *
  *      Note: Version numbering in this file relates to XWorkplace
@@ -145,6 +151,15 @@
  *      the XSTRING with.
  *
+ *      This does not create a copy of pszNew. Instead,
+ *      pszNew is used as the member string in pxstr
+ *      directly.
+ *
  *      Do not use this on an XSTRING which is already
  *      initialized. Use xstrset instead.
+ *
+ *      Example:
+ *
+ +          XSTRING str;
+ +          xstrInitSet(&str, strdup("blah"));
  *
  *@@added V0.9.6 (2000-11-01) [umoeller]
@@ -173,6 +188,14 @@
  *      of an existing string.
  *
+ *      As opposed to xstrInitSet, this does create
+ *      a copy of pcszSource.
+ *
  *      Do not use this on an XSTRING which is already
  *      initialized. Use xstrcpy instead.
+ *
+ *      Example:
+ *
+ +          XSTRING str;
+ +          xstrInitCopy(&str, "blah");
  *
  *@@added V0.9.6 (2000-11-01) [umoeller]
@@ -301,4 +324,6 @@
  +          xstrInit(&str, 0);
  +          xstrcpy(&str, "blah");
+ *
+ *      This sequence can be abbreviated using xstrInitCopy.
  *
  *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxcpy
@@ -351,6 +376,6 @@
 /*
  *@@ xstrcat:
- *      appends pcszSource to pxstr, for which memory is allocated
- *      as necessary.
+ *      appends pcszSource to pxstr, for which memory is
+ *      reallocated if necessary.
  *
  *      If pxstr is empty, this behaves just like xstrcpy.
@@ -366,9 +391,6 @@
  +          xstrcat(&str, "blup");
  *
- *      would do the following:
- *      a)  free the old value of str ("blah");
- *      b)  reallocate str;
- *      c)  so that psz afterwards points to a new string containing
- *          "blahblup".
+ *      After this, psz points to a new string containing
+ *      "blahblup".
  *
  *@@changed V0.9.1 (99-12-20) [umoeller]: fixed memory leak
@@ -424,11 +446,13 @@
 
             // 2) append source string:
-            strcpy(pxstr->psz + pxstr->ulLength,
-                   pcszSource);
+            memcpy(pxstr->psz + pxstr->ulLength,
+                   pcszSource,
+                   ulSourceLength + 1);     // null terminator
 
             // in all cases, set new length
             pxstr->ulLength += ulSourceLength;
             ulrc = ulSourceLength;
-        }
+
+        } // end if (ulSourceLength)
         // else no source specified or source is empty:
         // do nothing
@@ -439,11 +463,80 @@
 
 /*
+ *@@ xstrFindWord:
+ *      searches for pstrFind in pxstr, starting at ulOfs.
+ *      However, this only finds pstrFind if it's a "word",
+ *      i.e. surrounded by one of the characters in the
+ *      pcszBeginChars and pcszEndChars array.
+ *
+ *      This is similar to strhFindWord, but this uses
+ *      strhmemfind for fast searching, and it doesn't
+ *      have to calculate the string lengths because these
+ *      already in XSTRING.
+ *
+ *      Returns 0 if no "word" was found, or the offset
+ *      of the "word" in pxstr if found.
+ *
+ *@@added V0.9.6 (2000-11-12) [umoeller]
+ */
+
+PSZ xstrFindWord(const XSTRING *pxstr,        // in: buffer to search ("haystack")
+                 ULONG ulOfs,                 // in: where to begin search (0 = start)
+                 const XSTRING *pstrFind,     // in: word to find ("needle")
+                 size_t *pShiftTable,         // in: shift table (see strhmemfind)
+                 PBOOL pfRepeatFind,          // in: repeat find? (see strhmemfind)
+                 const char *pcszBeginChars,  // suggestion: "\x0d\x0a ()/\\-,."
+                 const char *pcszEndChars)    // suggestion: "\x0d\x0a ()/\\-,.:;"
+{
+    PSZ     pReturn = 0;
+    ULONG   ulFoundLen = pstrFind->ulLength;
+
+    if ((pxstr->ulLength) && (ulFoundLen))
+    {
+        const char *p = pxstr->psz + ulOfs;
+
+        do  // while p
+        {
+            // p = strstr(p, pstrFind->psz);
+            p = (PSZ)strhmemfind(p,         // in: haystack
+                                 pxstr->ulLength - (p - pxstr->psz),
+                                            // remaining length of haystack
+                                 pstrFind->psz,
+                                 ulFoundLen,
+                                 pShiftTable,
+                                 pfRepeatFind);
+            if (p)
+            {
+                // string found:
+                // check if that's a word
+
+                if (strhIsWord(pxstr->psz,
+                               p,
+                               ulFoundLen,
+                               pcszBeginChars,
+                               pcszEndChars))
+                {
+                    // valid end char:
+                    pReturn = (PSZ)p;
+                    break;
+                }
+
+                p += ulFoundLen;
+            }
+        } while (p);
+
+    }
+    return (pReturn);
+}
+
+/*
  *@@ xstrrpl:
- *      replaces pstrSearch with pstrReplace in pxstr.
+ *      replaces the first occurence of pstrSearch with
+ *      pstrReplace in pxstr.
  *
  *      Starting with V0.9.6, this operates entirely on
  *      XSTRING's for speed because we then know the string
  *      lengths already and can use memcpy instead of strcpy.
- *      This new version should be magnitudes faster.
+ *      This new version should be magnitudes faster,
+ *      especially with large string bufffers.
  *
  *      None of the pointers can be NULL, but if pstrReplace
@@ -454,13 +547,11 @@
  *      (and pxstr was therefore not changed).
  *
- *      If the string was found and (pulAfterOfs != NULL),
- *      *pulAfterOfs will be set to the first character
- *      after the new replacement string. This allows you
- *      to call this func again with the same strings to
- *      have several occurences replaced.
- *
- *      Only the first occurence is replaced. To replace
- *      all occurences in a buffer, repeat calling this
- *      function until it returns 0.
+ *      This starts the search at *pulOffset. If
+ *      (*pulOffset == 0), this starts from the beginning
+ *      of pxstr.
+ *      If the string was found, *pulOffset will be set to the
+ *      first character after the new replacement string. This
+ *      allows you to call this func again with the same strings
+ *      to have several occurences replaced (see the example below).
  *
  *      There are two wrappers around this function which
@@ -476,12 +567,11 @@
  *
  +          XSTRING str;
- +          ULONG ulPos = 0;
+ +          ULONG ulOffset = 0;
  +          xstrInit(&str, 0);
  +          xstrcpy(&str, "Test phrase 1. Test phrase 2.");
  +          while (xstrrpl(&str,
- +                         ulPos,
+ +                         &ulPos,      // in/out: offset
  +                         "Test",      // search
- +                         "Dummy",     // replace
- +                         &ulPos))
+ +                         "Dummy")     // replace
  +              ;
  *
@@ -493,13 +583,16 @@
  *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxrpl
  *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
+ *@@changed V0.9.6 (2000-11-12) [umoeller]: now using strhmemfind
  */
 
 ULONG xstrrpl(PXSTRING pxstr,               // in/out: string
-              ULONG ulOfs,                  // in: where to begin search (0 = start)
+              PULONG pulOfs,                // in: where to begin search (0 = start);
+                                            // out: ofs of first char after replacement string
               const XSTRING *pstrSearch,    // in: search string; cannot be NULL
               const XSTRING *pstrReplace,   // in: replacement string; cannot be NULL
-              PULONG pulAfterOfs)           // out: offset where found (ptr can be NULL)
-{
-    ULONG    ulrc = 0;
+              size_t *pShiftTable,          // in: shift table (see strhmemfind)
+              PBOOL pfRepeatFind)           // in: repeat find? (see strhmemfind)
+{
+    ULONG    ulrc = 0;      // default: not found
 
     if ((pxstr) && (pstrSearch) && (pstrReplace))
@@ -508,12 +601,17 @@
 
         // can we search this?
-        if (    (ulOfs < pxstr->ulLength)
+        if (    (*pulOfs < pxstr->ulLength)
              && (cSearchLen)
            )
         {
             // yes:
-            PSZ     pFound = strstr(pxstr->psz + ulOfs,
-                                    pstrSearch->psz);
-
+            /* PSZ     pFound = strstr(pxstr->psz + *pulOfs,
+                                    pstrSearch->psz);        */
+            PSZ pFound = (PSZ)strhmemfind(pxstr->psz + *pulOfs, // in: haystack
+                                          pxstr->ulLength - *pulOfs,
+                                          pstrSearch->psz,
+                                          cSearchLen,
+                                          pShiftTable,
+                                          pfRepeatFind);
             if (pFound)
             {
@@ -569,4 +667,5 @@
                                 + 1); // null terminator
 
+                    // replace old buffer with new one
                     free(pxstr->psz);
                     pxstr->psz = pszNew;
@@ -627,9 +726,8 @@
                 // return new length
                 ulrc = cbNeeded - 1;
-                if (pulAfterOfs)
-                    *pulAfterOfs = ulFoundOfs + cReplaceLen;
-            }
-        }
-    }
+                *pulOfs = ulFoundOfs + cReplaceLen;
+            } // end if (pFound)
+        } // end if (    (*pulOfs < pxstr->ulLength) ...
+    } // end if ((pxstr) && (pstrSearch) && (pstrReplace))
 
     return (ulrc);
@@ -638,25 +736,33 @@
 /*
  *@@ xstrcrpl:
- *      wrapper around xstrrpl which allows using C strings
+ *      wrapper around xstrrpl() which allows using C strings
  *      for the find and replace parameters.
  *
+ *      This creates two temporary XSTRING's for pcszSearch
+ *      pcszReplace. As a result, this is slower than xstrrpl.
+ *      If you search with the same strings several times,
+ *      you'll be better off using xstrrpl() directly.
+ *
  *@@added V0.9.6 (2000-11-01) [umoeller]
  */
 
 ULONG xstrcrpl(PXSTRING pxstr,              // in/out: string
-               ULONG ulOfs,                 // in: where to begin search (0 = start)
+               PULONG pulOfs,               // in: where to begin search (0 = start);
+                                            // out: ofs of first char after replacement string
                const char *pcszSearch,      // in: search string; cannot be NULL
-               const char *pcszReplace,     // in: replacement string; cannot be NULL
-               PULONG pulAfterOfs)          // out: offset where found (ptr can be NULL)
-{
-    ULONG   ulrc = 0;
+               const char *pcszReplace)     // in: replacement string; cannot be NULL
+{
+    // ULONG   ulrc = 0;
     XSTRING xstrFind,
             xstrReplace;
-    xstrInit(&xstrFind, 0);
-    xstrset(&xstrFind, (PSZ)pcszSearch);
-    xstrInit(&xstrReplace, 0);
-    xstrset(&xstrReplace, (PSZ)pcszReplace);
-
-    return (xstrrpl(pxstr, ulOfs, &xstrFind, &xstrReplace, pulAfterOfs));
+    size_t  ShiftTable[256];
+    BOOL    fRepeat = FALSE;
+    // initialize find/replace strings... note that the
+    // C strings are not free()'able, so we MUST NOT use xstrClear
+    // before leaving
+    xstrInitSet(&xstrFind, (PSZ)pcszSearch);
+    xstrInitSet(&xstrReplace, (PSZ)pcszReplace);
+
+    return (xstrrpl(pxstr, pulOfs, &xstrFind, &xstrReplace, ShiftTable, &fRepeat));
 }
 
