[Forensics-changes] [SCM] debian-forensics/guymager branch, upstream, updated. upstream/0.5.7beta1-2-ga43d74e

Michael Prokop mika at debian.org
Sun Jul 10 15:35:15 UTC 2011


The following commit has been merged in the upstream branch:
commit a43d74ee8c9f20814198505bda23d653409455b6
Author: Michael Prokop <mika at debian.org>
Date:   Sun Jul 10 17:14:14 2011 +0200

    Adding new upstream release 0.5.9.

diff --git a/CREDITS b/CREDITS
index f9ed512..d5510ac 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1,7 +1,15 @@
 
-Joachim Metz <joachim.metz at gmail.com>
+Joachim Metz <jbmetz at users.sourceforge.net>
    Guymager uses Joachim's libewf for writing EWF image files. Without
    Joachim's work on the EWF format, the Guymager project would probably
    never have been started. Special thanks to Joachim as well for
    believing in the idea of parallelised compression and adding the
    necessary extra functions to libewf for Guymager.
+
+Michael Prokop <mika at debian.org>
+   Mika took care of correctly packaging Guymager and making it available in 
+   the main repositories. Without him, the Guymager installation would have 
+   remained the nightmare it was before. As well, many thanks to Mika for his 
+   patience while answering my numerous questions about copyright and his 
+   suggestions for giving the sources a GPL compliant shape.
+
diff --git a/compileinfo.cpp b/compileinfo.cpp
deleted file mode 100644
index d6678a4..0000000
--- a/compileinfo.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-// Automatically generated file. See project file and compileinfo.sh for further information.
-const char *pCompileInfoTimestamp = "2011-07-01-12.11.49";
-const char *pCompileInfoVersion   = "0.5.8beta9-1";
diff --git a/guymager.desktop b/guymager.desktop
index d7b6e8e..b9e2688 100644
--- a/guymager.desktop
+++ b/guymager.desktop
@@ -6,7 +6,6 @@
 Type=Application
 Version=1.0
 Name=Guymager
-Name[vi]=Wireshark
 GenericName=Imager
 Comment=Fast forensic imager
 Icon=guymager_128.png
diff --git a/hash.cpp b/hash.cpp
old mode 100755
new mode 100644
diff --git a/hash.h b/hash.h
old mode 100755
new mode 100644
diff --git a/local.cfg b/local.cfg
deleted file mode 100644
index 45ce147..0000000
--- a/local.cfg
+++ /dev/null
@@ -1,42 +0,0 @@
-
-StartupSizeManualX  = 150
-StartupSizeManualY  = 250
-StartupSizeManualDx = 1500
-StartupSizeManualDy = 700
-
-TABLE DlgAcquireField NoName
-   REM Field                Entry mode   Entry mode  Default
-   REM name                 image        clone       value
-   REM --------------------------------------------------------------------------------------------------------
-       'SplitFileSize'      ShowLast     Hide         '4'
-       'SplitFileUnit'      ShowLast     Hide         'EiB'
-       'EwfCaseNumber'      ShowLast     Hide         '1'
-       'EwfEvidenceNumber'  ShowDefault  Hide         '--'
-       'EwfExaminer'        ShowLast     Hide         'VOGU / PGD-SPJ-SNT'
-       'EwfDescription'     Hide  Hide         'Acquisition of "%model%" started on %dd%.%MM%.%yyyy% at %hh%:%mm%'
-       'EwfNotes'           ShowLast     Hide         '%serial%'
-       'DestImageDirectory' ShowLast     Hide         '/data/xxx/yyy'
-       'DestInfoDirectory'  Hide         ShowLast     '/data/xxx/yyy'
-       'DestImageFilename'  ShowDefault  Hide         '%serial%_%size%'
-       'DestInfoFilename'   ShowDefault  ShowDefault  '%serial%_%size%'
-ENDTABLE
-
-TABLE DlgAcquireRule NoName
-   REM Trigger              Destination         Value
-   REM field name           field name
-   REM ----------------------------------------------------------------------------------------
-REM    'EwfExaminer'        'EwfNotes'          'Acquired by %EwfExaminer% for case %EwfCaseNumber% on %d%.%MM%.%yyyy%'
-REM    'EwfCaseNumber'      'EwfNotes'          'Acquired by %EwfExaminer% for case %EwfCaseNumber% on %d%.%MM%.%yyyy%'
-       'EwfDescription'     'DestImageFilename' '%EwfDescription%'
-       'EwfDescription'     'DestInfoFilename'  '%EwfDescription%'
-       'DestImageDirectory' 'DestInfoDirectory' '%DestImageDirectory%'
-       'DestImageFilename'  'DestInfoFilename'  '%DestImageFilename%'
-ENDTABLE
-
-
-SECTION MACADDR_000FEACE580D
-
-ENDSECTION
-
-
-
diff --git a/manuals/guymager.1 b/manuals/guymager.1
deleted file mode 100644
index c5c0c78..0000000
--- a/manuals/guymager.1
+++ /dev/null
@@ -1,58 +0,0 @@
-.TH guymager 1 "2011-07-01" "version 0.5.8beta9-1" "guymager manual pages"
-.SH NAME
-guymager \- a forensic acquisition program
-.SH SYNOPSIS
-.B guymager
-[\fBlog=\fIlog_file\fR]
-[\fBcfg=\fIconfiguration_file\fR]
-[options]
-.SH DESCRIPTION
-Guymager is a Qt-based forensic imager. It is capable of producing image files in EWF, AFF 
-and dd format. Its main strenghs are the easy user interface, the high imaging speed and the
-extended acquisition info file.
-.PP
-The internal structure is based on separate threads for reading, hash calculation (MD5 and 
-SHA256), writing and includes a parallelised compression engine, thus making full usage of 
-multi\-processor and hyper\-threading machines.
-.PP
-Guymager should be run with root privileges, as other users do not have access to physical
-devices normally.
-.SH OPTIONS
-.TP
-.BI log= "log_file"
-By default, guymager uses /var/log/guymager.log as its log file. This option allows for
-specifying a different file.
-.TP
-.BI cfg= "configuration_file"
-The default configuration file is /etc/guymager/guymager.cfg. This option allows for
-specifying a different file. Guymager creates a template configuration file when the
-option
-.B \-cfg=template.cfg
-is given.
-.P
-All other configuration options may be specified on the command line and/or in the
-configuration file. See /etc/guymager/guymager.cfg for a description of all possible
-options. In case an option is specified in the configuration file and on the command
-line, the command line dominates.
-.SH EXIT CODES
-.TP
-Guymager normally returns an exit code of 0. Exit code 1 means that Guymager terminated because the AutoExit function became active. All other exit codes are related to internal Guymager or Qt errors.
-.SH EXAMPLES
-.TP
-Write all log entries to ./my.log:
-.B guymager
-log=my.log
-.TP
-Create a template configuration file
-.B guymager
-cfg=template.cfg
-.TP
-Read the configuration from my.cfg and use 4 threads for parallelised compression:
-.B guymager
-cfg=my.cfg CompressionThreads=4
-.P
-See /etc/guymager/guymager.cfg for details about option CompressionThreads and all
-other options as well.
-.SH AUTHOR
-Guy Voncken (vogu00 (at) gmail.com)
-
diff --git a/memwatch.c b/memwatch.c
new file mode 100644
index 0000000..08c5f39
--- /dev/null
+++ b/memwatch.c
@@ -0,0 +1,2664 @@
+/*
+** MEMWATCH.C
+** Nonintrusive ANSI C memory leak / overwrite detection
+** Copyright (C) 1992-2003 Johan Lindh
+** All rights reserved.
+** Version 2.71
+
+	This file is part of MEMWATCH.
+
+    MEMWATCH 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; either version 2 of the License, or
+    (at your option) any later version.
+
+    MEMWATCH 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.
+
+    You should have received a copy of the GNU General Public License
+    along with MEMWATCH; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+**
+** 920810 JLI   [1.00]
+** 920830 JLI   [1.10 double-free detection]
+** 920912 JLI   [1.15 mwPuts, mwGrab/Drop, mwLimit]
+** 921022 JLI   [1.20 ASSERT and VERIFY]
+** 921105 JLI   [1.30 C++ support and TRACE]
+** 921116 JLI   [1.40 mwSetOutFunc]
+** 930215 JLI   [1.50 modified ASSERT/VERIFY]
+** 930327 JLI   [1.51 better auto-init & PC-lint support]
+** 930506 JLI   [1.55 MemWatch class, improved C++ support]
+** 930507 JLI   [1.60 mwTest & CHECK()]
+** 930809 JLI   [1.65 Abort/Retry/Ignore]
+** 930820 JLI   [1.70 data dump when unfreed]
+** 931016 JLI   [1.72 modified C++ new/delete handling]
+** 931108 JLI   [1.77 mwSetAssertAction() & some small changes]
+** 940110 JLI   [1.80 no-mans-land alloc/checking]
+** 940328 JLI   [2.00 version 2.0 rewrite]
+**              Improved NML (no-mans-land) support.
+**              Improved performance (especially for free()ing!).
+**              Support for 'read-only' buffers (checksums)
+**              ^^ NOTE: I never did this... maybe I should?
+**              FBI (free'd block info) tagged before freed blocks
+**              Exporting of the mwCounter variable
+**              mwBreakOut() localizes debugger support
+**              Allocation statistics (global, per-module, per-line)
+**              Self-repair ability with relinking
+** 950913 JLI   [2.10 improved garbage handling]
+** 951201 JLI   [2.11 improved auto-free in emergencies]
+** 960125 JLI   [X.01 implemented auto-checking using mwAutoCheck()]
+** 960514 JLI   [2.12 undefining of existing macros]
+** 960515 JLI   [2.13 possibility to use default new() & delete()]
+** 960516 JLI   [2.20 suppression of file flushing on unfreed msgs]
+** 960516 JLI   [2.21 better support for using MEMWATCH with DLL's]
+** 960710 JLI   [X.02 multiple logs and mwFlushNow()]
+** 960801 JLI   [2.22 merged X.01 version with current]
+** 960805 JLI   [2.30 mwIsXXXXAddr() to avoid unneeded GP's]
+** 960805 JLI   [2.31 merged X.02 version with current]
+** 961002 JLI   [2.32 support for realloc() + fixed STDERR bug]
+** 961222 JLI   [2.40 added mwMark() & mwUnmark()]
+** 970101 JLI   [2.41 added over/underflow checking after failed ASSERT/VERIFY]
+** 970113 JLI   [2.42 added support for PC-Lint 7.00g]
+** 970207 JLI   [2.43 added support for strdup()]
+** 970209 JLI   [2.44 changed default filename to lowercase]
+** 970405 JLI   [2.45 fixed bug related with atexit() and some C++ compilers]
+** 970723 JLI   [2.46 added MW_ARI_NULLREAD flag]
+** 970813 JLI   [2.47 stabilized marker handling]
+** 980317 JLI   [2.48 ripped out C++ support; wasn't working good anyway]
+** 980318 JLI   [2.50 improved self-repair facilities & SIGSEGV support]
+** 980417 JLI	[2.51 more checks for invalid addresses]
+** 980512 JLI	[2.52 moved MW_ARI_NULLREAD to occur before aborting]
+** 990112 JLI	[2.53 added check for empty heap to mwIsOwned]
+** 990217 JLI	[2.55 improved the emergency repairs diagnostics and NML]
+** 990224 JLI	[2.56 changed ordering of members in structures]
+** 990303 JLI	[2.57 first maybe-fixit-for-hpux test]
+** 990516 JLI	[2.58 added 'static' to the definition of mwAutoInit]
+** 990517 JLI	[2.59 fixed some high-sensitivity warnings]
+** 990610 JLI	[2.60 fixed some more high-sensitivity warnings]
+** 990715 JLI	[2.61 changed TRACE/ASSERT/VERIFY macro names]
+** 991001 JLI	[2.62 added CHECK_BUFFER() and mwTestBuffer()]
+** 991007 JLI	[2.63 first shot at a 64-bit compatible version]
+** 991009 JLI	[2.64 undef's strdup() if defined, mwStrdup made const]
+** 000704 JLI	[2.65 added some more detection for 64-bits]
+** 010502 JLI   [2.66 incorporated some user fixes]
+**              [mwRelink() could print out garbage pointer (thanks mac at phobos.ca)]
+**				[added array destructor for C++ (thanks rdasilva at connecttel.com)]
+**				[added mutex support (thanks rdasilva at connecttel.com)]
+** 010531 JLI	[2.67 fix: mwMutexXXX() was declared even if MW_HAVE_MUTEX was not defined]
+** 010619 JLI	[2.68 fix: mwRealloc() could leave the mutex locked]
+** 020918 JLI	[2.69 changed to GPL, added C++ array allocation by Howard Cohen]
+** 030212 JLI	[2.70 mwMalloc() bug for very large allocations (4GB on 32bits)]
+** 030520 JLI	[2.71 added ULONG_LONG_MAX as a 64-bit detector (thanks Sami Salonen)]
+*/
+
+#define __MEMWATCH_C 1
+
+#ifdef MW_NOCPP
+#define MEMWATCH_NOCPP
+#endif
+#ifdef MW_STDIO
+#define MEMWATCH_STDIO
+#endif
+
+/***********************************************************************
+** Include files
+***********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <time.h>
+#include <limits.h>
+#include "memwatch.h"
+
+#ifndef toupper
+#include <ctype.h>
+#endif
+
+#if defined(WIN32) || defined(__WIN32__)
+#define MW_HAVE_MUTEX 1
+#include <windows.h>
+#endif
+
+#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
+#define MW_HAVE_MUTEX 1
+#include <pthread.h>
+#endif
+
+/***********************************************************************
+** Defines & other weird stuff
+***********************************************************************/
+
+/*lint -save -e767 */
+#define VERSION     "2.71"         /* the current version number */
+#define CHKVAL(mw)  (0xFE0180L^(long)mw->count^(long)mw->size^(long)mw->line)
+#define FLUSH()     mwFlush()
+#define TESTS(f,l)  if(mwTestAlways) (void)mwTestNow(f,l,1)
+#define PRECHK      0x01234567L
+#define POSTCHK     0x76543210L
+#define mwBUFFER_TO_MW(p) ( (mwData*) (void*) ( ((char*)p)-mwDataSize-mwOverflowZoneSize ) )
+/*lint -restore */
+
+#define MW_NML      0x0001
+
+#ifdef _MSC_VER
+#define COMMIT "c"  /* Microsoft C requires the 'c' to perform as desired */
+#else
+#define COMMIT ""   /* Normal ANSI */
+#endif /* _MSC_VER */
+
+#ifdef __cplusplus
+#define CPPTEXT "++"
+#else
+#define CPPTEXT ""
+#endif /* __cplusplus */
+
+#ifdef MEMWATCH_STDIO
+#define mwSTDERR stderr
+#else
+#define mwSTDERR mwLog
+#endif
+
+#ifdef MW_HAVE_MUTEX
+#define MW_MUTEX_INIT()		mwMutexInit()
+#define MW_MUTEX_TERM()		mwMutexTerm()
+#define MW_MUTEX_LOCK()		mwMutexLock()
+#define MW_MUTEX_UNLOCK()	mwMutexUnlock()
+#else
+#define MW_MUTEX_INIT()
+#define MW_MUTEX_TERM()
+#define MW_MUTEX_LOCK()
+#define MW_MUTEX_UNLOCK()
+#endif
+
+/***********************************************************************
+** If you really, really know what you're doing,
+** you can predefine these things yourself.
+***********************************************************************/
+
+#ifndef mwBYTE_DEFINED
+# if CHAR_BIT != 8
+#  error need CHAR_BIT to be 8!
+# else
+typedef unsigned char mwBYTE;
+#  define mwBYTE_DEFINED 1
+# endif
+#endif
+
+#if defined(ULONGLONG_MAX) || defined(ULLONG_MAX) || defined(_UI64_MAX) || defined(ULONG_LONG_MAX)
+# define mw64BIT 1
+# define mwROUNDALLOC_DEFAULT 8
+#else
+# if UINT_MAX <= 0xFFFFUL
+#  define mw16BIT 1
+#  define mwROUNDALLOC_DEFAULT	2
+# else
+#  if ULONG_MAX > 0xFFFFFFFFUL
+#   define mw64BIT 1
+#   define mwROUNDALLOC_DEFAULT	8
+#  else
+#   define mw32BIT 1
+#   define mwROUNDALLOC_DEFAULT	4
+#  endif
+# endif
+#endif
+
+/* mwROUNDALLOC is the number of bytes to */
+/* round up to, to ensure that the end of */
+/* the buffer is suitable for storage of */
+/* any kind of object */
+#ifndef mwROUNDALLOC
+# define mwROUNDALLOC mwROUNDALLOC_DEFAULT
+#endif
+
+#ifndef mwDWORD_DEFINED
+#if ULONG_MAX == 0xFFFFFFFFUL
+typedef unsigned long mwDWORD;
+#define mwDWORD_DEFINED "unsigned long"
+#endif
+#endif
+
+#ifndef mwDWORD_DEFINED
+#if UINT_MAX == 0xFFFFFFFFUL
+typedef unsigned int mwDWORD;
+#define mwDWORD_DEFINED "unsigned int"
+#endif
+#endif
+
+#ifndef mwDWORD_DEFINED
+#if USHRT_MAX == 0xFFFFFFFFUL
+typedef unsigned short mwDWORD;
+#define mwDWORD_DEFINED "unsigned short"
+#endif
+#endif
+
+#ifndef mwBYTE_DEFINED
+#error "can't find out the correct type for a 8 bit scalar"
+#endif
+
+#ifndef mwDWORD_DEFINED
+#error "can't find out the correct type for a 32 bit scalar"
+#endif
+
+/***********************************************************************
+** Typedefs & structures
+***********************************************************************/
+
+/* main data holding area, precedes actual allocation */
+typedef struct mwData_ mwData;
+struct mwData_ {
+    mwData*     prev;   /* previous allocation in chain */
+    mwData*     next;   /* next allocation in chain */
+    const char* file;   /* file name where allocated */
+    long        count;  /* action count */
+    long        check;  /* integrity check value */
+#if 0
+    long        crc;    /* data crc value */
+#endif
+    size_t      size;   /* size of allocation */
+    int         line;   /* line number where allocated */
+    unsigned    flag;   /* flag word */
+    };
+
+/* statistics structure */
+typedef struct mwStat_ mwStat;
+struct mwStat_ {
+    mwStat*     next;   /* next statistic buffer */
+    const char* file;
+    long        total;  /* total bytes allocated */
+    long        num;    /* total number of allocations */
+    long        max;    /* max allocated at one time */
+    long        curr;   /* current allocations */
+    int         line;
+    };
+
+/* grabbing structure, 1K in size */
+typedef struct mwGrabData_ mwGrabData;
+struct mwGrabData_ {
+    mwGrabData* next;
+    int         type;
+    char        blob[ 1024 - sizeof(mwGrabData*) - sizeof(int) ];
+    };
+
+typedef struct mwMarker_ mwMarker;
+struct mwMarker_ {
+    void *host;
+    char *text;
+    mwMarker *next;
+    int level;
+    };
+
+#if defined(WIN32) || defined(__WIN32__)
+typedef HANDLE          mwMutex;
+#endif
+
+#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
+typedef pthread_mutex_t mwMutex;
+#endif
+
+/***********************************************************************
+** Static variables
+***********************************************************************/
+
+static int      mwInited =      0;
+static int      mwInfoWritten = 0;
+static int      mwUseAtexit =   0;
+static FILE*    mwLog =         NULL;
+static int      mwFlushing =    0;
+static int      mwStatLevel =   MW_STAT_DEFAULT;
+static int      mwNML =         MW_NML_DEFAULT;
+static int      mwFBI =         0;
+static long     mwAllocLimit =  0L;
+static int      mwUseLimit =    0;
+
+static long     mwNumCurAlloc = 0L;
+static mwData*  mwHead = 		NULL;
+static mwData*  mwTail = 		NULL;
+static int		mwDataSize =	0;
+static unsigned char mwOverflowZoneTemplate[] = "mEmwAtch";
+static int		mwOverflowZoneSize = mwROUNDALLOC;
+
+static void     (*mwOutFunction)(int) = NULL;
+static int      (*mwAriFunction)(const char*) = NULL;
+static int      mwAriAction = MW_ARI_ABORT;
+
+static char     mwPrintBuf[MW_TRACE_BUFFER+8];
+
+static unsigned long mwCounter = 0L;
+static long     mwErrors =      0L;
+
+static int      mwTestFlags =   0;
+static int      mwTestAlways =  0;
+
+static FILE*    mwLogB1 =       NULL;
+static int      mwFlushingB1 =  0;
+
+static mwStat*  mwStatList = NULL;
+static long     mwStatTotAlloc = 0L;
+static long     mwStatMaxAlloc = 0L;
+static long     mwStatNumAlloc = 0L;
+static long     mwStatCurAlloc = 0L;
+static long     mwNmlNumAlloc = 0L;
+static long     mwNmlCurAlloc = 0L;
+
+static mwGrabData* mwGrabList = NULL;
+static long     mwGrabSize = 0L;
+
+static void *   mwLastFree[MW_FREE_LIST];
+static const char *mwLFfile[MW_FREE_LIST];
+static int      mwLFline[MW_FREE_LIST];
+static int      mwLFcur = 0;
+
+static mwMarker* mwFirstMark = NULL;
+
+static FILE*    mwLogB2 =       NULL;
+static int      mwFlushingB2 =  0;
+
+#ifdef MW_HAVE_MUTEX
+static mwMutex	mwGlobalMutex;
+#endif
+
+/***********************************************************************
+** Static function declarations
+***********************************************************************/
+
+static void     mwAutoInit( void );
+static FILE*    mwLogR( void );
+static void     mwLogW( FILE* );
+static int      mwFlushR( void );
+static void     mwFlushW( int );
+static void     mwFlush( void );
+static void     mwIncErr( void );
+static void     mwUnlink( mwData*, const char* file, int line );
+static int      mwRelink( mwData*, const char* file, int line );
+static int      mwIsHeapOK( mwData *mw );
+static int      mwIsOwned( mwData* mw, const char* file, int line );
+static int      mwTestBuf( mwData* mw, const char* file, int line );
+static void     mwDefaultOutFunc( int );
+static void     mwWrite( const char* format, ... );
+static void     mwLogFile( const char* name );
+static size_t   mwFreeUp( size_t, int );
+static const void *mwTestMem( const void *, unsigned, int );
+static int      mwStrCmpI( const char *s1, const char *s2 );
+static int      mwTestNow( const char *file, int line, int always_invoked );
+static void     mwDropAll( void );
+static const char *mwGrabType( int type );
+static unsigned mwGrab_( unsigned kb, int type, int silent );
+static unsigned mwDrop_( unsigned kb, int type, int silent );
+static int      mwARI( const char* text );
+static void     mwStatReport( void );
+static mwStat*  mwStatGet( const char*, int, int );
+static void     mwStatAlloc( size_t, const char*, int );
+static void     mwStatFree( size_t, const char*, int );
+static int		mwCheckOF( const void * p );
+static void		mwWriteOF( void * p );
+static char		mwDummy( char c );
+#ifdef MW_HAVE_MUTEX
+static void		mwMutexInit( void );
+static void		mwMutexTerm( void );
+static void		mwMutexLock( void );
+static void		mwMutexUnlock( void );
+#endif
+
+/***********************************************************************
+** System functions
+***********************************************************************/
+
+void mwInit( void ) {
+    time_t tid;
+
+    if( mwInited++ > 0 ) return;
+
+	MW_MUTEX_INIT();
+
+    /* start a log if none is running */
+    if( mwLogR() == NULL ) mwLogFile( "memwatch.log" );
+    if( mwLogR() == NULL ) {
+        int i;
+        char buf[32];
+        /* oops, could not open it! */
+        /* probably because it's already open */
+        /* so we try some other names */
+        for( i=1; i<100; i++ ) {
+            sprintf( buf, "memwat%02d.log", i );
+            mwLogFile( buf );
+            if( mwLogR() != NULL ) break;
+            }
+        }
+
+    /* initialize the statistics */
+    mwStatList = NULL;
+    mwStatTotAlloc = 0L;
+    mwStatCurAlloc = 0L;
+    mwStatMaxAlloc = 0L;
+    mwStatNumAlloc = 0L;
+	mwNmlCurAlloc = 0L;
+	mwNmlNumAlloc = 0L;
+
+	/* calculate the buffer size to use for a mwData */
+	mwDataSize = sizeof(mwData);
+	while( mwDataSize % mwROUNDALLOC ) mwDataSize ++;
+
+    /* write informational header if needed */
+    if( !mwInfoWritten ) {
+        mwInfoWritten = 1;
+        (void) time( &tid );
+        mwWrite(
+            "\n============="
+            " MEMWATCH " VERSION " Copyright (C) 1992-1999 Johan Lindh "
+            "=============\n");
+        mwWrite( "\nStarted at %s\n", ctime( &tid ) );
+
+/**************************************************************** Generic */
+		mwWrite( "Modes: " );
+#ifdef mwNew
+        mwWrite( "C++ " );
+#endif /* mwNew */
+#ifdef __STDC__
+        mwWrite( "__STDC__ " );
+#endif /* __STDC__ */
+#ifdef mw16BIT
+		mwWrite( "16-bit " );
+#endif
+#ifdef mw32BIT
+		mwWrite( "32-bit " );
+#endif
+#ifdef mw64BIT
+		mwWrite( "64-bit " );
+#endif
+		mwWrite( "mwDWORD==(" mwDWORD_DEFINED ")\n" );
+		mwWrite( "mwROUNDALLOC==%d sizeof(mwData)==%d mwDataSize==%d\n",
+			mwROUNDALLOC, sizeof(mwData), mwDataSize );
+/**************************************************************** Generic */
+
+/************************************************************ Microsoft C */
+#ifdef _MSC_VER
+        mwWrite( "Compiled using Microsoft C" CPPTEXT
+            " %d.%02d\n", _MSC_VER / 100, _MSC_VER % 100 );
+#endif /* _MSC_VER */
+/************************************************************ Microsoft C */
+
+/************************************************************** Borland C */
+#ifdef __BORLANDC__
+        mwWrite( "Compiled using Borland C"
+#ifdef __cplusplus
+            "++ %d.%01d\n", __BCPLUSPLUS__/0x100, (__BCPLUSPLUS__%0x100)/0x10 );
+#else
+            " %d.%01d\n", __BORLANDC__/0x100, (__BORLANDC__%0x100)/0x10 );
+#endif /* __cplusplus */
+#endif /* __BORLANDC__ */
+/************************************************************** Borland C */
+
+/************************************************************** Watcom C */
+#ifdef __WATCOMC__
+        mwWrite( "Compiled using Watcom C %d.%02d ",
+            __WATCOMC__/100, __WATCOMC__%100 );
+#ifdef __FLAT__
+        mwWrite( "(32-bit flat model)" );
+#endif /* __FLAT__ */
+        mwWrite( "\n" );
+#endif /* __WATCOMC__ */
+/************************************************************** Watcom C */
+
+        mwWrite( "\n" );
+        FLUSH();
+        }
+
+    if( mwUseAtexit ) (void) atexit( mwAbort );
+    return;
+    }
+
+void mwAbort( void ) {
+    mwData *mw;
+    mwMarker *mrk;
+    char *data;
+    time_t tid;
+    int c, i, j;
+	int errors;
+
+    tid = time( NULL );
+    mwWrite( "\nStopped at %s\n", ctime( &tid) );
+
+    if( !mwInited )
+        mwWrite( "internal: mwAbort(): MEMWATCH not initialized!\n" );
+
+    /* release the grab list */
+    mwDropAll();
+
+    /* report mwMarked items */
+    while( mwFirstMark ) {
+        mrk = mwFirstMark->next;
+        mwWrite( "mark: %p: %s\n", mwFirstMark->host, mwFirstMark->text );
+        free( mwFirstMark->text );
+        free( mwFirstMark );
+        mwFirstMark = mrk;
+        mwErrors ++;
+        }
+
+    /* release all still allocated memory */
+	errors = 0;
+    while( mwHead != NULL && errors < 3 ) {
+		if( !mwIsOwned(mwHead, __FILE__, __LINE__ ) ) {
+			if( errors < 3 )
+			{
+				errors ++;
+				mwWrite( "internal: NML/unfreed scan restarting\n" );
+				FLUSH();
+				mwHead = mwHead;
+				continue;
+			}
+			mwWrite( "internal: NML/unfreed scan aborted, heap too damaged\n" );
+			FLUSH();
+			break;
+			}
+        mwFlushW(0);
+        if( !(mwHead->flag & MW_NML) ) {
+            mwErrors++;
+            data = ((char*)mwHead)+mwDataSize;
+            mwWrite( "unfreed: <%ld> %s(%d), %ld bytes at %p ",
+                mwHead->count, mwHead->file, mwHead->line, (long)mwHead->size, data+mwOverflowZoneSize );
+            if( mwCheckOF( data ) ) {
+                mwWrite( "[underflowed] ");
+                FLUSH();
+                }
+            if( mwCheckOF( (data+mwOverflowZoneSize+mwHead->size) ) ) {
+                mwWrite( "[overflowed] ");
+                FLUSH();
+                }
+            mwWrite( " \t{" );
+            j = 16; if( mwHead->size < 16 ) j = (int) mwHead->size;
+            for( i=0;i<16;i++ ) {
+                if( i<j ) mwWrite( "%02X ",
+                    (unsigned char) *(data+mwOverflowZoneSize+i) );
+                else mwWrite( ".. " );
+                }
+            for( i=0;i<j;i++ ) {
+                c = *(data+mwOverflowZoneSize+i);
+                if( c < 32 || c > 126 ) c = '.';
+                mwWrite( "%c", c );
+                }
+            mwWrite( "}\n" );
+			mw = mwHead;
+			mwUnlink( mw, __FILE__, __LINE__ );
+            free( mw );
+            }
+        else {
+            data = ((char*)mwHead) + mwDataSize + mwOverflowZoneSize;
+            if( mwTestMem( data, mwHead->size, MW_VAL_NML ) ) {
+                mwErrors++;
+                mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
+                    mwHead->count, data + mwOverflowZoneSize, mwHead->file, mwHead->line );
+                FLUSH();
+                }
+			mwNmlNumAlloc --;
+			mwNmlCurAlloc -= mwHead->size;
+			mw = mwHead;
+			mwUnlink( mw, __FILE__, __LINE__ );
+            free( mw );
+            }
+        }
+
+	if( mwNmlNumAlloc ) mwWrite("internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc );
+	if( mwNmlCurAlloc ) mwWrite("internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc );
+
+    /* report statistics */
+    mwStatReport();
+    FLUSH();
+
+    mwInited = 0;
+    mwHead = mwTail = NULL;
+    if( mwErrors )
+        fprintf(mwSTDERR,"MEMWATCH detected %ld anomalies\n",mwErrors);
+    mwLogFile( NULL );
+    mwErrors = 0;
+
+    MW_MUTEX_TERM();
+
+    }
+
+void mwTerm( void ) {
+    if( mwInited == 1 )
+    {
+        mwAbort();
+        return;
+    }
+    if( !mwInited )
+        mwWrite("internal: mwTerm(): MEMWATCH has not been started!\n");
+    else
+        mwInited --;
+    }
+
+void mwStatistics( int level )
+{
+    mwAutoInit();
+    if( level<0 ) level=0;
+    if( mwStatLevel != level )
+    {
+		mwWrite( "statistics: now collecting on a %s basis\n",
+			level<1?"global":(level<2?"module":"line") );
+	    mwStatLevel = level;
+	}
+}
+
+void mwAutoCheck( int onoff ) {
+    mwAutoInit();
+    mwTestAlways = onoff;
+    if( onoff ) mwTestFlags = MW_TEST_ALL;
+    }
+
+void mwSetOutFunc( void (*func)(int) ) {
+    mwAutoInit();
+    mwOutFunction = func;
+    }
+
+static void mwWriteOF( void *p )
+{
+	int i;
+	unsigned char *ptr;
+	ptr = (unsigned char*) p;
+	for( i=0; i<mwOverflowZoneSize; i++ )
+	{
+		*(ptr+i) = mwOverflowZoneTemplate[i%8];
+	}
+	return;
+}
+
+static int mwCheckOF( const void *p )
+{
+	int i;
+	const unsigned char *ptr;
+	ptr = (const unsigned char *) p;
+	for( i=0; i<mwOverflowZoneSize; i++ )
+	{
+		if( *(ptr+i) != mwOverflowZoneTemplate[i%8] )
+			return 1; /* errors found */
+	}
+	return 0; /* no errors */
+}
+
+int mwTest( const char *file, int line, int items ) {
+    mwAutoInit();
+    mwTestFlags = items;
+    return mwTestNow( file, line, 0 );
+    }
+
+/*
+** Returns zero if there are no errors.
+** Returns nonzero if there are errors.
+*/
+int mwTestBuffer( const char *file, int line, void *p ) {
+    mwData* mw;
+
+    mwAutoInit();
+
+    /* do the quick ownership test */
+    mw = (mwData*) mwBUFFER_TO_MW( p );
+
+    if( mwIsOwned( mw, file, line ) ) {
+        return mwTestBuf( mw, file, line );
+		}
+	return 1;
+	}
+
+void mwBreakOut( const char* cause ) {
+    fprintf(mwSTDERR, "breakout: %s\n", cause);
+    mwWrite("breakout: %s\n", cause );
+    return;
+    }
+
+/*
+** 981217 JLI: is it possible that ->next is not always set?
+*/
+void * mwMark( void *p, const char *desc, const char *file, unsigned line ) {
+    mwMarker *mrk;
+    unsigned n, isnew;
+    char *buf;
+    int tot, oflow = 0;
+    char wherebuf[128];
+
+    mwAutoInit();
+    TESTS(NULL,0);
+
+    if( desc == NULL ) desc = "unknown";
+    if( file == NULL ) file = "unknown";
+
+    tot = sprintf( wherebuf, "%.48s called from %s(%d)", desc, file, line );
+    if( tot >= (int)sizeof(wherebuf) ) { wherebuf[sizeof(wherebuf)-1] = 0; oflow = 1; }
+
+    if( p == NULL ) {
+        mwWrite("mark: %s(%d), no mark for NULL:'%s' may be set\n", file, line, desc );
+        return p;
+        }
+
+	if( mwFirstMark != NULL && !mwIsReadAddr( mwFirstMark, sizeof( mwMarker ) ) )
+	{
+		mwWrite("mark: %s(%d), mwFirstMark (%p) is trashed, can't mark for %s\n",
+			file, line, mwFirstMark, desc );
+		return p;
+	}
+
+    for( mrk=mwFirstMark; mrk; mrk=mrk->next )
+	{
+		if( mrk->next != NULL && !mwIsReadAddr( mrk->next, sizeof( mwMarker ) ) )
+		{
+			mwWrite("mark: %s(%d), mark(%p)->next(%p) is trashed, can't mark for %s\n",
+				file, line, mrk, mrk->next, desc );
+			return p;
+		}
+		if( mrk->host == p ) break;
+	}
+
+    if( mrk == NULL ) {
+        isnew = 1;
+        mrk = (mwMarker*) malloc( sizeof( mwMarker ) );
+        if( mrk == NULL ) {
+            mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc );
+            return p;
+            }
+		mrk->next = NULL;
+        n = 0;
+        }
+    else {
+        isnew = 0;
+        n = strlen( mrk->text );
+        }
+
+    n += strlen( wherebuf );
+    buf = (char*) malloc( n+3 );
+    if( buf == NULL ) {
+        if( isnew ) free( mrk );
+        mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc );
+        return p;
+        }
+
+    if( isnew ) {
+        memcpy( buf, wherebuf, n+1 );
+        mrk->next = mwFirstMark;
+        mrk->host = p;
+        mrk->text = buf;
+        mrk->level = 1;
+        mwFirstMark = mrk;
+        }
+    else {
+        strcpy( buf, mrk->text );
+        strcat( buf, ", " );
+        strcat( buf, wherebuf );
+        free( mrk->text );
+        mrk->text = buf;
+        mrk->level ++;
+        }
+
+    if( oflow ) {
+        mwIncErr();
+        mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
+        }
+    return p;
+    }
+
+void* mwUnmark( void *p, const char *file, unsigned line ) {
+    mwMarker *mrk, *prv;
+    mrk = mwFirstMark;
+    prv = NULL;
+    while( mrk ) {
+        if( mrk->host == p ) {
+            if( mrk->level < 2 ) {
+                if( prv ) prv->next = mrk->next;
+                else mwFirstMark = mrk->next;
+                free( mrk->text );
+                free( mrk );
+                return p;
+                }
+            mrk->level --;
+            return p;
+            }
+        prv = mrk;
+        mrk = mrk->next;
+        }
+    mwWrite("mark: %s(%d), no mark found for %p\n", file, line, p );
+    return p;
+    }
+
+
+/***********************************************************************
+** Abort/Retry/Ignore handlers
+***********************************************************************/
+
+static int mwARI( const char *estr ) {
+    char inbuf[81];
+    int c;
+    fprintf(mwSTDERR, "\n%s\nMEMWATCH: Abort, Retry or Ignore? ", estr);
+    (void) fgets(inbuf,sizeof(inbuf),stdin);
+	for( c=0; inbuf[c] && inbuf[c] <= ' '; c++ ) ;
+    c = inbuf[c];
+    if( c == 'R' || c == 'r' ) {
+        mwBreakOut( estr );
+        return MW_ARI_RETRY;
+        }
+    if( c == 'I' || c == 'i' ) return MW_ARI_IGNORE;
+    return MW_ARI_ABORT;
+    }
+
+/* standard ARI handler (exported) */
+int mwAriHandler( const char *estr ) {
+    mwAutoInit();
+    return mwARI( estr );
+    }
+
+/* used to set the ARI function */
+void mwSetAriFunc( int (*func)(const char *) ) {
+    mwAutoInit();
+    mwAriFunction = func;
+    }
+
+/***********************************************************************
+** Allocation handlers
+***********************************************************************/
+
+void* mwMalloc( size_t size, const char* file, int line) {
+    size_t needed;
+    mwData *mw;
+    char *ptr;
+    void *p;
+
+    mwAutoInit();
+
+	MW_MUTEX_LOCK();
+
+    TESTS(file,line);
+
+    mwCounter ++;
+    needed = mwDataSize + mwOverflowZoneSize*2 + size;
+    if( needed < size )
+    {
+    	/* theoretical case: req size + mw overhead exceeded size_t limits */
+    	return NULL;
+    }
+
+    /* if this allocation would violate the limit, fail it */
+    if( mwUseLimit && ((long)size + mwStatCurAlloc > mwAllocLimit) ) {
+        mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n",
+            mwCounter, file, line, (long)size, mwAllocLimit - mwStatCurAlloc );
+        mwIncErr();
+        FLUSH();
+		MW_MUTEX_UNLOCK();
+        return NULL;
+        }
+
+    mw = (mwData*) malloc( needed );
+    if( mw == NULL ) {
+        if( mwFreeUp(needed,0) >= needed ) {
+            mw = (mwData*) malloc(needed);
+            if( mw == NULL ) {
+                mwWrite( "internal: mwFreeUp(%u) reported success, but malloc() fails\n", needed );
+                mwIncErr();
+                FLUSH();
+                }
+            }
+        if( mw == NULL ) {
+            mwWrite( "fail: <%ld> %s(%d), %ld wanted %ld allocated\n",
+                mwCounter, file, line, (long)size, mwStatCurAlloc );
+            mwIncErr();
+            FLUSH();
+			MW_MUTEX_UNLOCK();
+            return NULL;
+            }
+        }
+
+    mw->count = mwCounter;
+    mw->prev = NULL;
+    mw->next = mwHead;
+    mw->file = file;
+    mw->size = size;
+    mw->line = line;
+    mw->flag = 0;
+    mw->check = CHKVAL(mw);
+
+    if( mwHead ) mwHead->prev = mw;
+    mwHead = mw;
+    if( mwTail == NULL ) mwTail = mw;
+
+    ptr = ((char*)mw) + mwDataSize;
+	mwWriteOF( ptr ); /* '*(long*)ptr = PRECHK;' */
+    ptr += mwOverflowZoneSize;
+    p = ptr;
+    memset( ptr, MW_VAL_NEW, size );
+    ptr += size;
+    mwWriteOF( ptr ); /* '*(long*)ptr = POSTCHK;' */
+
+    mwNumCurAlloc ++;
+    mwStatCurAlloc += (long) size;
+    mwStatTotAlloc += (long) size;
+    if( mwStatCurAlloc > mwStatMaxAlloc )
+        mwStatMaxAlloc = mwStatCurAlloc;
+    mwStatNumAlloc ++;
+
+    if( mwStatLevel ) mwStatAlloc( size, file, line );
+
+	MW_MUTEX_UNLOCK();
+    return p;
+    }
+
+void* mwRealloc( void *p, size_t size, const char* file, int line) {
+    int oldUseLimit, i;
+    mwData *mw;
+    char *ptr;
+
+    mwAutoInit();
+
+    if( p == NULL ) return mwMalloc( size, file, line );
+    if( size == 0 ) { mwFree( p, file, line ); return NULL; }
+
+	MW_MUTEX_LOCK();
+
+    /* do the quick ownership test */
+    mw = (mwData*) mwBUFFER_TO_MW( p );
+    if( mwIsOwned( mw, file, line ) ) {
+
+		/* if the buffer is an NML, treat this as a double-free */
+		if( mw->flag & MW_NML )
+		{
+            mwIncErr();
+			if( *((unsigned char*)(mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML )
+			{
+				mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n",
+					mwCounter, file, line, mw );
+			}
+			goto check_dbl_free;
+		}
+
+        /* if this allocation would violate the limit, fail it */
+        if( mwUseLimit && ((long)size + mwStatCurAlloc - (long)mw->size > mwAllocLimit) ) {
+            TESTS(file,line);
+            mwCounter ++;
+            mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n",
+                mwCounter, file, line, (unsigned long)size - mw->size, mwAllocLimit - mwStatCurAlloc );
+            mwIncErr();
+            FLUSH();
+			MW_MUTEX_UNLOCK();
+            return NULL;
+            }
+
+        /* fake realloc operation */
+        oldUseLimit = mwUseLimit;
+        mwUseLimit = 0;
+        ptr = (char*) mwMalloc( size, file, line );
+        if( ptr != NULL ) {
+            if( size < mw->size )
+                memcpy( ptr, p, size );
+            else
+                memcpy( ptr, p, mw->size );
+            mwFree( p, file, line );
+            }
+        mwUseLimit = oldUseLimit;
+		MW_MUTEX_UNLOCK();
+        return (void*) ptr;
+        }
+
+    /* Unknown pointer! */
+
+    /* using free'd pointer? */
+check_dbl_free:
+    for(i=0;i<MW_FREE_LIST;i++) {
+        if( mwLastFree[i] == p ) {
+            mwIncErr();
+            mwWrite( "realloc: <%ld> %s(%d), %p was"
+                " freed from %s(%d)\n",
+                mwCounter, file, line, p,
+                mwLFfile[i], mwLFline[i] );
+            FLUSH();
+			MW_MUTEX_UNLOCK();
+            return NULL;
+            }
+        }
+
+    /* some weird pointer */
+    mwIncErr();
+    mwWrite( "realloc: <%ld> %s(%d), unknown pointer %p\n",
+        mwCounter, file, line, p );
+    FLUSH();
+	MW_MUTEX_UNLOCK();
+    return NULL;
+    }
+
+char *mwStrdup( const char* str, const char* file, int line ) {
+    size_t len;
+    char *newstring;
+
+	MW_MUTEX_LOCK();
+
+    if( str == NULL ) {
+        mwIncErr();
+        mwWrite( "strdup: <%ld> %s(%d), strdup(NULL) called\n",
+            mwCounter, file, line );
+        FLUSH();
+		MW_MUTEX_UNLOCK();
+        return NULL;
+        }
+
+    len = strlen( str ) + 1;
+    newstring = (char*) mwMalloc( len, file, line );
+    if( newstring != NULL ) memcpy( newstring, str, len );
+	MW_MUTEX_UNLOCK();
+    return newstring;
+    }
+
+void mwFree( void* p, const char* file, int line ) {
+    int i;
+    mwData* mw;
+    char buffer[ sizeof(mwData) + (mwROUNDALLOC*3) + 64 ];
+
+    /* this code is in support of C++ delete */
+    if( file == NULL ) {
+        mwFree_( p );
+		MW_MUTEX_UNLOCK();
+        return;
+        }
+
+    mwAutoInit();
+
+	MW_MUTEX_LOCK();
+    TESTS(file,line);
+    mwCounter ++;
+
+    /* on NULL free, write a warning and return */
+    if( p == NULL ) {
+        mwWrite( "NULL free: <%ld> %s(%d), NULL pointer free'd\n",
+            mwCounter, file, line );
+        FLUSH();
+		MW_MUTEX_UNLOCK();
+        return;
+        }
+
+    /* do the quick ownership test */
+    mw = (mwData*) mwBUFFER_TO_MW( p );
+
+    if( mwIsOwned( mw, file, line ) ) {
+        (void) mwTestBuf( mw, file, line );
+
+		/* if the buffer is an NML, treat this as a double-free */
+		if( mw->flag & MW_NML )
+		{
+			if( *(((unsigned char*)mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML )
+			{
+				mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n",
+					mwCounter, file, line, mw );
+			}
+			goto check_dbl_free;
+		}
+
+        /* update the statistics */
+        mwNumCurAlloc --;
+        mwStatCurAlloc -= (long) mw->size;
+        if( mwStatLevel ) mwStatFree( mw->size, mw->file, mw->line );
+
+        /* we should either free the allocation or keep it as NML */
+        if( mwNML ) {
+            mw->flag |= MW_NML;
+			mwNmlNumAlloc ++;
+			mwNmlCurAlloc += (long) mw->size;
+            memset( ((char*)mw)+mwDataSize+mwOverflowZoneSize, MW_VAL_NML, mw->size );
+            }
+        else {
+            /* unlink the allocation, and enter the post-free data */
+            mwUnlink( mw, file, line );
+            memset( mw, MW_VAL_DEL,
+                mw->size + mwDataSize+mwOverflowZoneSize+mwOverflowZoneSize );
+            if( mwFBI ) {
+                memset( mw, '.', mwDataSize + mwOverflowZoneSize );
+                sprintf( buffer, "FBI<%ld>%s(%d)", mwCounter, file, line );
+                strncpy( (char*)(void*)mw, buffer, mwDataSize + mwOverflowZoneSize );
+                }
+            free( mw );
+            }
+
+        /* add the pointer to the last-free track */
+        mwLFfile[ mwLFcur ] = file;
+        mwLFline[ mwLFcur ] = line;
+        mwLastFree[ mwLFcur++ ] = p;
+        if( mwLFcur == MW_FREE_LIST ) mwLFcur = 0;
+
+		MW_MUTEX_UNLOCK();
+        return;
+        }
+
+    /* check for double-freeing */
+check_dbl_free:
+    for(i=0;i<MW_FREE_LIST;i++) {
+        if( mwLastFree[i] == p ) {
+            mwIncErr();
+            mwWrite( "double-free: <%ld> %s(%d), %p was"
+                " freed from %s(%d)\n",
+                mwCounter, file, line, p,
+                mwLFfile[i], mwLFline[i] );
+            FLUSH();
+			MW_MUTEX_UNLOCK();
+            return;
+            }
+        }
+
+    /* some weird pointer... block the free */
+    mwIncErr();
+    mwWrite( "WILD free: <%ld> %s(%d), unknown pointer %p\n",
+        mwCounter, file, line, p );
+    FLUSH();
+	MW_MUTEX_UNLOCK();
+    return;
+    }
+
+void* mwCalloc( size_t a, size_t b, const char *file, int line ) {
+    void *p;
+    size_t size = a * b;
+    p = mwMalloc( size, file, line );
+    if( p == NULL ) return NULL;
+    memset( p, 0, size );
+    return p;
+    }
+
+void mwFree_( void *p ) {
+	MW_MUTEX_LOCK();
+    TESTS(NULL,0);
+	MW_MUTEX_UNLOCK();
+    free(p);
+    }
+
+void* mwMalloc_( size_t size ) {
+	MW_MUTEX_LOCK();
+    TESTS(NULL,0);
+	MW_MUTEX_UNLOCK();
+    return malloc( size );
+    }
+
+void* mwRealloc_( void *p, size_t size ) {
+	MW_MUTEX_LOCK();
+    TESTS(NULL,0);
+	MW_MUTEX_UNLOCK();
+    return realloc( p, size );
+    }
+
+void* mwCalloc_( size_t a, size_t b ) {
+	MW_MUTEX_LOCK();
+    TESTS(NULL,0);
+	MW_MUTEX_UNLOCK();
+    return calloc( a, b );
+    }
+
+void mwFlushNow( void ) {
+    if( mwLogR() ) fflush( mwLogR() );
+    return;
+    }
+
+void mwDoFlush( int onoff ) {
+    mwFlushW( onoff<1?0:onoff );
+    if( onoff ) if( mwLogR() ) fflush( mwLogR() );
+    return;
+    }
+
+void mwLimit( long lim ) {
+    TESTS(NULL,0);
+    mwWrite("limit: old limit = ");
+    if( !mwAllocLimit ) mwWrite( "none" );
+    else mwWrite( "%ld bytes", mwAllocLimit );
+    mwWrite( ", new limit = ");
+    if( !lim ) {
+        mwWrite( "none\n" );
+        mwUseLimit = 0;
+        }
+    else {
+        mwWrite( "%ld bytes\n", lim );
+        mwUseLimit = 1;
+        }
+    mwAllocLimit = lim;
+    FLUSH();
+    }
+
+void mwSetAriAction( int action ) {
+	MW_MUTEX_LOCK();
+    TESTS(NULL,0);
+    mwAriAction = action;
+	MW_MUTEX_UNLOCK();
+    return;
+    }
+
+int mwAssert( int exp, const char *exps, const char *fn, int ln ) {
+    int i;
+    char buffer[MW_TRACE_BUFFER+8];
+    if( exp ) {
+    	return 0;
+    	}
+    mwAutoInit();
+	MW_MUTEX_LOCK();
+    TESTS(fn,ln);
+    mwIncErr();
+    mwCounter++;
+    mwWrite( "assert trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps );
+    if( mwAriFunction != NULL ) {
+        sprintf( buffer, "MEMWATCH: assert trap: %s(%d), %s", fn, ln, exps );
+        i = (*mwAriFunction)(buffer);
+		switch( i ) {
+			case MW_ARI_IGNORE:
+	           	mwWrite( "assert trap: <%ld> IGNORED - execution continues\n", mwCounter );
+				MW_MUTEX_UNLOCK();
+    	        return 0;
+			case MW_ARI_RETRY:
+            	mwWrite( "assert trap: <%ld> RETRY - executing again\n", mwCounter );
+				MW_MUTEX_UNLOCK();
+            	return 1;
+			}
+        }
+    else {
+        if( mwAriAction & MW_ARI_IGNORE ) {
+            mwWrite( "assert trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter );
+			MW_MUTEX_UNLOCK();
+            return 0;
+            }
+        fprintf(mwSTDERR,"\nMEMWATCH: assert trap: %s(%d), %s\n", fn, ln, exps );
+        }
+
+    FLUSH();
+    (void) mwTestNow( fn, ln, 1 );
+    FLUSH();
+
+	if( mwAriAction & MW_ARI_NULLREAD ) {
+		/* This is made in an attempt to kick in */
+		/* any debuggers or OS stack traces */
+	    FLUSH();
+		/*lint -save -e413 */
+		i = *((int*)NULL);
+		mwDummy( (char)i );
+		/*lint -restore */
+		}
+
+	MW_MUTEX_UNLOCK();
+    exit(255);
+    /* NOT REACHED - the return statement is in to keep */
+    /* stupid compilers from squeaking about differing return modes. */
+    /* Smart compilers instead say 'code unreachable...' */
+    /*lint -save -e527 */
+    return 0;
+    /*lint -restore */
+    }
+
+int mwVerify( int exp, const char *exps, const char *fn, int ln ) {
+    int i;
+    char buffer[MW_TRACE_BUFFER+8];
+    if( exp ) {
+    	return 0;
+    	}
+    mwAutoInit();
+	MW_MUTEX_LOCK();
+    TESTS(fn,ln);
+    mwIncErr();
+    mwCounter++;
+    mwWrite( "verify trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps );
+    if( mwAriFunction != NULL ) {
+        sprintf( buffer, "MEMWATCH: verify trap: %s(%d), %s", fn, ln, exps );
+        i = (*mwAriFunction)(buffer);
+        if( i == 0 ) {
+            mwWrite( "verify trap: <%ld> IGNORED - execution continues\n", mwCounter );
+			MW_MUTEX_UNLOCK();
+            return 0;
+            }
+        if( i == 1 ) {
+            mwWrite( "verify trap: <%ld> RETRY - executing again\n", mwCounter );
+			MW_MUTEX_UNLOCK();
+            return 1;
+            }
+        }
+    else {
+        if( mwAriAction & MW_ARI_NULLREAD ) {
+            /* This is made in an attempt to kick in */
+            /* any debuggers or OS stack traces */
+		    FLUSH();
+            /*lint -save -e413 */
+            i = *((int*)NULL);
+			mwDummy( (char)i );
+            /*lint -restore */
+            }
+        if( mwAriAction & MW_ARI_IGNORE ) {
+            mwWrite( "verify trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter );
+			MW_MUTEX_UNLOCK();
+            return 0;
+            }
+        fprintf(mwSTDERR,"\nMEMWATCH: verify trap: %s(%d), %s\n", fn, ln, exps );
+        }
+    FLUSH();
+    (void) mwTestNow( fn, ln, 1 );
+    FLUSH();
+	MW_MUTEX_UNLOCK();
+	exit(255);
+    /* NOT REACHED - the return statement is in to keep */
+    /* stupid compilers from squeaking about differing return modes. */
+    /* Smart compilers instead say 'code unreachable...' */
+    /*lint -save -e527 */
+    return 0;
+    /*lint -restore */
+    }
+
+void mwTrace( const char *format, ... ) {
+    int tot, oflow = 0;
+    va_list mark;
+
+    mwAutoInit();
+	MW_MUTEX_LOCK();
+    TESTS(NULL,0);
+    if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
+
+    va_start( mark, format );
+    tot = vsprintf( mwPrintBuf, format, mark );
+    va_end( mark );
+    if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; }
+    for(tot=0;mwPrintBuf[tot];tot++)
+        (*mwOutFunction)( mwPrintBuf[tot] );
+    if( oflow ) {
+        mwIncErr();
+        mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
+        }
+
+    FLUSH();
+	MW_MUTEX_UNLOCK();
+    }
+
+
+/***********************************************************************
+** Grab & Drop
+***********************************************************************/
+
+unsigned mwGrab( unsigned kb ) {
+    TESTS(NULL,0);
+    return mwGrab_( kb, MW_VAL_GRB, 0 );
+    }
+
+unsigned mwDrop( unsigned kb ) {
+    TESTS(NULL,0);
+    return mwDrop_( kb, MW_VAL_GRB, 0 );
+    }
+
+static void mwDropAll() {
+    TESTS(NULL,0);
+    (void) mwDrop_( 0, MW_VAL_GRB, 0 );
+    (void) mwDrop_( 0, MW_VAL_NML, 0 );
+    if( mwGrabList != NULL )
+        mwWrite( "internal: the grab list is not empty after mwDropAll()\n");
+    }
+
+static const char *mwGrabType( int type ) {
+    switch( type ) {
+        case MW_VAL_GRB:
+            return "grabbed";
+        case MW_VAL_NML:
+            return "no-mans-land";
+        default:
+            /* do nothing */
+            ;
+        }
+    return "<unknown type>";
+    }
+
+static unsigned mwGrab_( unsigned kb, int type, int silent ) {
+    unsigned i = kb;
+    mwGrabData *gd;
+    if( !kb ) i = kb = 65000U;
+
+    for(;kb;kb--) {
+        if( mwUseLimit &&
+            (mwStatCurAlloc + mwGrabSize + (long)sizeof(mwGrabData) > mwAllocLimit) ) {
+            if( !silent ) {
+                mwWrite("grabbed: all allowed memory to %s (%u kb)\n",
+                    mwGrabType(type), i-kb);
+                FLUSH();
+                }
+            return i-kb;
+            }
+        gd = (mwGrabData*) malloc( sizeof(mwGrabData) );
+        if( gd == NULL ) {
+            if( !silent ) {
+                mwWrite("grabbed: all available memory to %s (%u kb)\n",
+                    mwGrabType(type), i-kb);
+                FLUSH();
+                }
+            return i-kb;
+            }
+        mwGrabSize += (long) sizeof(mwGrabData);
+        gd->next = mwGrabList;
+        memset( gd->blob, type, sizeof(gd->blob) );
+        gd->type = type;
+        mwGrabList = gd;
+        }
+    if( !silent ) {
+        mwWrite("grabbed: %u kilobytes of %s memory\n", i, mwGrabType(type) );
+        FLUSH();
+        }
+    return i;
+    }
+
+static unsigned mwDrop_( unsigned kb, int type, int silent ) {
+    unsigned i = kb;
+    mwGrabData *gd,*tmp,*pr;
+    const void *p;
+
+    if( mwGrabList == NULL && kb == 0 ) return 0;
+    if( !kb ) i = kb = 60000U;
+
+    pr = NULL;
+    gd = mwGrabList;
+    for(;kb;) {
+        if( gd == NULL ) {
+            if( i-kb > 0 && !silent ) {
+                mwWrite("dropped: all %s memory (%u kb)\n", mwGrabType(type), i-kb);
+                FLUSH();
+                }
+            return i-kb;
+            }
+        if( gd->type == type ) {
+            if( pr ) pr->next = gd->next;
+            kb --;
+            tmp = gd;
+            if( mwGrabList == gd ) mwGrabList = gd->next;
+            gd = gd->next;
+            p = mwTestMem( tmp->blob, sizeof( tmp->blob ), type );
+            if( p != NULL ) {
+                mwWrite( "wild pointer: <%ld> %s memory hit at %p\n",
+                    mwCounter, mwGrabType(type), p );
+                FLUSH();
+                }
+            mwGrabSize -= (long) sizeof(mwGrabData);
+            free( tmp );
+            }
+        else {
+            pr = gd;
+            gd = gd->next;
+            }
+        }
+    if( !silent ) {
+        mwWrite("dropped: %u kilobytes of %s memory\n", i, mwGrabType(type) );
+        FLUSH();
+        }
+    return i;
+    }
+
+/***********************************************************************
+** No-Mans-Land
+***********************************************************************/
+
+void mwNoMansLand( int level ) {
+    mwAutoInit();
+    TESTS(NULL,0);
+    switch( level ) {
+        case MW_NML_NONE:
+            (void) mwDrop_( 0, MW_VAL_NML, 0 );
+            break;
+        case MW_NML_FREE:
+            break;
+        case MW_NML_ALL:
+            (void) mwGrab_( 0, MW_VAL_NML, 0 );
+            break;
+        default:
+            return;
+        }
+    mwNML = level;
+    }
+
+/***********************************************************************
+** Static functions
+***********************************************************************/
+
+static void mwAutoInit( void )
+{
+    if( mwInited ) return;
+    mwUseAtexit = 1;
+    mwInit();
+    return;
+}
+
+static FILE *mwLogR() {
+    if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) return mwLog;
+    if( mwLog == mwLogB1 ) mwLogB2 = mwLog;
+    if( mwLog == mwLogB2 ) mwLogB1 = mwLog;
+    if( mwLogB1 == mwLogB2 ) mwLog = mwLogB1;
+    if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) {
+        mwWrite("internal: log file handle damaged and recovered\n");
+        FLUSH();
+        return mwLog;
+        }
+    fprintf(mwSTDERR,"\nMEMWATCH: log file handle destroyed, using mwSTDERR\n" );
+    mwLog = mwLogB1 = mwLogB2 = mwSTDERR;
+    return mwSTDERR;
+    }
+
+static void mwLogW( FILE *p ) {
+    mwLog = mwLogB1 = mwLogB2 = p;
+    }
+
+static int mwFlushR() {
+    if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) return mwFlushing;
+    if( mwFlushing == mwFlushingB1 ) mwFlushingB2 = mwFlushing;
+    if( mwFlushing == mwFlushingB2 ) mwFlushingB1 = mwFlushing;
+    if( mwFlushingB1 == mwFlushingB2 ) mwFlushing = mwFlushingB1;
+    if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) {
+        mwWrite("internal: flushing flag damaged and recovered\n");
+        FLUSH();
+        return mwFlushing;
+        }
+    mwWrite("internal: flushing flag destroyed, so set to true\n");
+    mwFlushing = mwFlushingB1 = mwFlushingB2 = 1;
+    return 1;
+    }
+
+static void mwFlushW( int n ) {
+    mwFlushing = mwFlushingB1 = mwFlushingB2 = n;
+    }
+
+static void mwIncErr() {
+    mwErrors++;
+    mwFlushW( mwFlushR()+1 );
+    FLUSH();
+    }
+
+static void mwFlush() {
+    if( mwLogR() == NULL ) return;
+#ifdef MW_FLUSH
+    fflush( mwLogR() );
+#else
+    if( mwFlushR() ) fflush( mwLogR() );
+#endif
+    return;
+    }
+
+static void mwUnlink( mwData* mw, const char* file, int line ) {
+    if( mw->prev == NULL ) {
+        if( mwHead != mw )
+            mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 NULL, but not head\n",
+                mwCounter, file, line, mw );
+        mwHead = mw->next;
+        }
+    else {
+        if( mw->prev->next != mw )
+            mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 failure\n",
+                mwCounter, file, line, mw );
+        else mw->prev->next = mw->next;
+        }
+    if( mw->next == NULL ) {
+        if( mwTail != mw )
+            mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 NULL, but not tail\n",
+                mwCounter, file, line, mw );
+        mwTail = mw->prev;
+        }
+    else {
+        if( mw->next->prev != mw )
+            mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 failure\n",
+                mwCounter, file, line, mw );
+        else mw->next->prev = mw->prev;
+        }
+    }
+
+/*
+** Relinking tries to repair a damaged mw block.
+** Returns nonzero if it thinks it successfully
+** repaired the heap chain.
+*/
+static int mwRelink( mwData* mw, const char* file, int line ) {
+    int fails;
+    mwData *mw1, *mw2;
+    long count, size;
+    mwStat *ms;
+
+	if( file == NULL ) file = "unknown";
+
+    if( mw == NULL ) {
+        mwWrite("relink: cannot repair MW at NULL\n");
+        FLUSH();
+        goto emergency;
+        }
+
+    if( !mwIsSafeAddr(mw, mwDataSize) ) {
+        mwWrite("relink: MW-%p is a garbage pointer\n", mw);
+        FLUSH();
+        goto emergency;
+        }
+
+    mwWrite("relink: <%ld> %s(%d) attempting to repair MW-%p...\n", mwCounter, file, line, mw );
+    FLUSH();
+    fails = 0;
+
+    /* Repair from head */
+    if( mwHead != mw ) {
+        if( !mwIsSafeAddr( mwHead, mwDataSize ) ) {
+            mwWrite("relink: failed for MW-%p; head pointer destroyed\n", mw );
+            FLUSH();
+            goto emergency;
+            }
+        for( mw1=mwHead; mw1; mw1=mw1->next ) {
+            if( mw1->next == mw ) {
+                mw->prev = mw1;
+                break;
+                }
+            if( mw1->next &&
+                ( !mwIsSafeAddr(mw1->next, mwDataSize ) || mw1->next->prev != mw1) ) {
+                mwWrite("relink: failed for MW-%p; forward chain fragmented at MW-%p: 'next' is %p\n", mw, mw1, mw1->next );
+                FLUSH();
+                goto emergency;
+                }
+            }
+        if( mw1 == NULL ) {
+            mwWrite("relink: MW-%p not found in forward chain search\n", mw );
+            FLUSH();
+            fails ++;
+            }
+        }
+	else
+	{
+		mwWrite( "relink: MW-%p is the head (first) allocation\n", mw );
+		if( mw->prev != NULL )
+		{
+			mwWrite( "relink: MW-%p prev pointer is non-NULL, you have a wild pointer\n", mw );
+			mw->prev = NULL;
+		}
+	}
+
+    /* Repair from tail */
+    if( mwTail != mw ) {
+        if( !mwIsSafeAddr( mwTail, mwDataSize ) ) {
+            mwWrite("relink: failed for MW-%p; tail pointer destroyed\n", mw );
+            FLUSH();
+            goto emergency;
+            }
+        for( mw1=mwTail; mw1; mw1=mw1->prev ) {
+            if( mw1->prev == mw ) {
+                mw->next = mw1;
+                break;
+                }
+            if( mw1->prev && (!mwIsSafeAddr(mw1->prev, mwDataSize ) || mw1->prev->next != mw1) ) {
+                mwWrite("relink: failed for MW-%p; reverse chain fragmented at MW-%p, 'prev' is %p\n", mw, mw1, mw1->prev );
+                FLUSH();
+                goto emergency;
+                }
+            }
+        if( mw1 == NULL ) {
+            mwWrite("relink: MW-%p not found in reverse chain search\n", mw );
+            FLUSH();
+            fails ++;
+            }
+        }
+	else
+	{
+		mwWrite( "relink: MW-%p is the tail (last) allocation\n", mw );
+		if( mw->next != NULL )
+		{
+			mwWrite( "relink: MW-%p next pointer is non-NULL, you have a wild pointer\n", mw );
+			mw->next = NULL;
+		}
+	}
+
+    if( fails > 1 ) {
+        mwWrite("relink: heap appears intact, MW-%p probably garbage pointer\n", mw );
+        FLUSH();
+        goto verifyok;
+        }
+
+    /* restore MW info where possible */
+    if( mwIsReadAddr( mw->file, 1 ) ) {
+        ms = mwStatGet( mw->file, -1, 0 );
+        if( ms == NULL ) mw->file = "<relinked>";
+        }
+    mw->check = CHKVAL(mw);
+    goto verifyok;
+
+    /* Emergency repair */
+    emergency:
+
+    if( mwHead == NULL && mwTail == NULL )
+    {
+        if( mwStatCurAlloc == 0 )
+            mwWrite("relink: <%ld> %s(%d) heap is empty, nothing to repair\n", mwCounter, file, line );
+        else
+            mwWrite("relink: <%ld> %s(%d) heap damaged beyond repair\n", mwCounter, file, line );
+        FLUSH();
+        return 0;
+    }
+
+    mwWrite("relink: <%ld> %s(%d) attempting emergency repairs...\n", mwCounter, file, line );
+    FLUSH();
+
+	if( mwHead == NULL || mwTail == NULL )
+	{
+		if( mwHead == NULL ) mwWrite("relink: mwHead is NULL, but mwTail is %p\n", mwTail );
+		else mwWrite("relink: mwTail is NULL, but mwHead is %p\n", mwHead );
+	}
+
+    mw1=NULL;
+    if( mwHead != NULL )
+	{
+		if( !mwIsReadAddr( mwHead, mwDataSize ) || mwHead->check != CHKVAL(mwHead) )
+		{
+			mwWrite("relink: mwHead (MW-%p) is damaged, skipping forward scan\n", mwHead );
+			mwHead = NULL;
+			goto scan_reverse;
+		}
+		if( mwHead->prev != NULL )
+		{
+			mwWrite("relink: the mwHead pointer's 'prev' member is %p, not NULL\n", mwHead->prev );
+		}
+        for( mw1=mwHead; mw1; mw1=mw1->next )
+		{
+			if( mw1->next )
+			{
+				if( !mwIsReadAddr(mw1->next,mwDataSize) ||
+					!mw1->next->check != CHKVAL(mw1) ||
+					mw1->next->prev != mw1 )
+				{
+					mwWrite("relink: forward chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
+						mw1, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw1->file, mw1->line );
+					if( mwIsReadAddr(mw1->next,mwDataSize ) )
+					{
+						mwWrite("relink: forward chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
+							mw1->next, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"",
+							mwIsReadAddr(mw1->file,16)?mw1->file:"<garbage-pointer>", mw1->line );
+					}
+					else
+					{
+						mwWrite("relink: the 'next' pointer of this MW points to %p, which is out-of-legal-access\n",
+							mw1->next );
+					}
+					break;
+				}
+			}
+        }
+	}
+
+
+scan_reverse:
+    mw2=NULL;
+    if( mwTail != NULL )
+	{
+		if( !mwIsReadAddr(mwTail,mwDataSize) || mwTail->check != CHKVAL(mwTail) )
+		{
+			mwWrite("relink: mwTail (%p) is damaged, skipping reverse scan\n", mwTail );
+			mwTail = NULL;
+			goto analyze;
+		}
+		if( mwTail->next != NULL )
+		{
+			mwWrite("relink: the mwTail pointer's 'next' member is %p, not NULL\n", mwTail->next );
+		}
+        for( mw2=mwTail; mw2; mw2=mw2->prev )
+		{
+            if( mw2->prev )
+			{
+				if( !mwIsReadAddr(mw2->prev,mwDataSize) ||
+					!mw2->prev->check != CHKVAL(mw2) ||
+					mw2->prev->next != mw2 )
+				{
+					mwWrite("relink: reverse chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
+						mw2, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw2->file, mw2->line );
+					if( mwIsReadAddr(mw2->prev,mwDataSize ) )
+					{
+						mwWrite("relink: reverse chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
+							mw2->prev, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"",
+							mwIsReadAddr(mw2->file,16)?mw2->file:"<garbage-pointer>", mw2->line );
+					}
+					else
+					{
+						mwWrite("relink: the 'prev' pointer of this MW points to %p, which is out-of-legal-access\n",
+							mw2->prev );
+					}
+					break;
+				}
+			}
+        }
+	}
+
+analyze:
+	if( mwHead == NULL && mwTail == NULL )
+	{
+        mwWrite("relink: both head and tail pointers damaged, aborting program\n");
+        mwFlushW(1);
+        FLUSH();
+        abort();
+	}
+	if( mwHead == NULL )
+	{
+		mwHead = mw2;
+		mwWrite("relink: heap truncated, MW-%p designated as new mwHead\n", mw2 );
+		mw2->prev = NULL;
+		mw1 = mw2 = NULL;
+	}
+	if( mwTail == NULL )
+	{
+		mwTail = mw1;
+		mwWrite("relink: heap truncated, MW-%p designated as new mwTail\n", mw1 );
+		mw1->next = NULL;
+		mw1 = mw2 = NULL;
+	}
+    if( mw1 == NULL && mw2 == NULL &&
+        mwHead->prev == NULL && mwTail->next == NULL ) {
+        mwWrite("relink: verifying heap integrity...\n" );
+        FLUSH();
+        goto verifyok;
+        }
+    if( mw1 && mw2 && mw1 != mw2 ) {
+        mw1->next = mw2;
+        mw2->prev = mw1;
+        mwWrite("relink: emergency repairs successful, assessing damage...\n");
+        FLUSH();
+        }
+    else {
+        mwWrite("relink: heap totally destroyed, aborting program\n");
+        mwFlushW(1);
+        FLUSH();
+        abort();
+        }
+
+    /* Verify by checking that the number of active allocations */
+    /* match the number of entries in the chain */
+verifyok:
+    if( !mwIsHeapOK( NULL ) ) {
+        mwWrite("relink: heap verification FAILS - aborting program\n");
+        mwFlushW(1);
+        FLUSH();
+        abort();
+        }
+    for( size=count=0, mw1=mwHead; mw1; mw1=mw1->next ) {
+        count ++;
+        size += (long) mw1->size;
+        }
+    if( count == mwNumCurAlloc ) {
+        mwWrite("relink: successful, ");
+        if( size == mwStatCurAlloc ) {
+            mwWrite("no allocations lost\n");
+            }
+        else {
+            if( mw != NULL ) {
+                mwWrite("size information lost for MW-%p\n", mw);
+                mw->size = 0;
+                }
+            }
+        }
+    else {
+        mwWrite("relink: partial, %ld MW-blocks of %ld bytes lost\n",
+			mwNmlNumAlloc+mwNumCurAlloc-count, mwNmlCurAlloc+mwStatCurAlloc-size );
+        return 0;
+        }
+
+    return 1;
+    }
+
+/*
+**  If mwData* is NULL:
+**      Returns 0 if heap chain is broken.
+**      Returns 1 if heap chain is intact.
+**  If mwData* is not NULL:
+**      Returns 0 if mwData* is missing or if chain is broken.
+**      Returns 1 if chain is intact and mwData* is found.
+*/
+static int mwIsHeapOK( mwData *includes_mw ) {
+    int found = 0;
+    mwData *mw;
+
+    for( mw = mwHead; mw; mw=mw->next ) {
+        if( includes_mw == mw ) found++;
+        if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0;
+        if( mw->prev ) {
+            if( !mwIsSafeAddr( mw->prev, mwDataSize ) ) return 0;
+            if( mw==mwHead || mw->prev->next != mw ) return 0;
+            }
+        if( mw->next ) {
+            if( !mwIsSafeAddr( mw->next, mwDataSize ) ) return 0;
+            if( mw==mwTail || mw->next->prev != mw ) return 0;
+            }
+        else if( mw!=mwTail ) return 0;
+        }
+
+    if( includes_mw != NULL && !found ) return 0;
+
+    return 1;
+    }
+
+static int mwIsOwned( mwData* mw, const char *file, int line ) {
+    int retv;
+    mwStat *ms;
+
+    /* see if the address is legal according to OS */
+    if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0;
+
+    /* make sure we have _anything_ allocated */
+    if( mwHead == NULL && mwTail == NULL && mwStatCurAlloc == 0 )
+        return 0;
+
+    /* calculate checksum */
+    if( mw->check != CHKVAL(mw) ) {
+        /* may be damaged checksum, see if block is in heap */
+        if( mwIsHeapOK( mw ) ) {
+            /* damaged checksum, repair it */
+            mwWrite( "internal: <%ld> %s(%d), checksum for MW-%p is incorrect\n",
+                mwCounter, file, line, mw );
+            mwIncErr();
+            if( mwIsReadAddr( mw->file, 1 ) ) {
+                ms = mwStatGet( mw->file, -1, 0 );
+                if( ms == NULL ) mw->file = "<relinked>";
+                }
+            else mw->file = "<unknown>";
+            mw->size = 0;
+            mw->check = CHKVAL(mw);
+            return 1;
+            }
+        /* no, it's just some garbage data */
+        return 0;
+        }
+
+	/* check that the non-NULL pointers are safe */
+	if( mw->prev && !mwIsSafeAddr( mw->prev, mwDataSize ) ) mwRelink( mw, file, line );
+	if( mw->next && !mwIsSafeAddr( mw->next, mwDataSize ) ) mwRelink( mw, file, line );
+
+    /* safe address, checksum OK, proceed with heap checks */
+
+    /* see if the block is in the heap */
+    retv = 0;
+    if( mw->prev ) { if( mw->prev->next == mw ) retv ++; }
+    else { if( mwHead == mw ) retv++; }
+    if( mw->next ) { if( mw->next->prev == mw ) retv ++; }
+    else { if( mwTail == mw ) retv++; }
+    if( mw->check == CHKVAL(mw) ) retv ++;
+    if( retv > 2 ) return 1;
+
+    /* block not in heap, check heap for corruption */
+
+    if( !mwIsHeapOK( mw ) ) {
+        if( mwRelink( mw, file, line ) )
+            return 1;
+        }
+
+    /* unable to repair */
+    mwWrite( "internal: <%ld> %s(%d), mwIsOwned fails for MW-%p\n",
+       mwCounter, file, line, mw );
+    mwIncErr();
+
+    return 0;
+    }
+
+/*
+** mwTestBuf:
+**  Checks a buffers links and pre/postfixes.
+**  Writes errors found to the log.
+**  Returns zero if no errors found.
+*/
+static int mwTestBuf( mwData* mw, const char* file, int line ) {
+    int retv = 0;
+    char *p;
+
+    if( file == NULL ) file = "unknown";
+
+    if( !mwIsSafeAddr( mw, mwDataSize + mwOverflowZoneSize ) ) {
+        mwWrite( "internal: <%ld> %s(%d): pointer MW-%p is invalid\n",
+            mwCounter, file, line, mw );
+        mwIncErr();
+        return 2;
+        }
+
+    if( mw->check != CHKVAL(mw) ) {
+        mwWrite( "internal: <%ld> %s(%d), info trashed; relinking\n",
+            mwCounter, file, line );
+        mwIncErr();
+        if( !mwRelink( mw, file, line ) ) return 2;
+        }
+
+    if( mw->prev && mw->prev->next != mw ) {
+        mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link1 broken\n",
+            mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
+        mwIncErr();
+        if( !mwRelink( mw, file, line ) ) retv = 2;
+        }
+    if( mw->next && mw->next->prev != mw ) {
+        mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link2 broken\n",
+            mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
+        mwIncErr();
+        if( !mwRelink( mw, file, line ) ) retv = 2;
+        }
+
+    p = ((char*)mw) + mwDataSize;
+    if( mwCheckOF( p ) ) {
+        mwWrite( "underflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n",
+            mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
+        mwIncErr();
+        retv = 1;
+        }
+    p += mwOverflowZoneSize + mw->size;
+    if( mwIsReadAddr( p, mwOverflowZoneSize ) && mwCheckOF( p ) ) {
+        mwWrite( "overflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n",
+            mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
+        mwIncErr();
+        retv = 1;
+        }
+
+    return retv;
+    }
+
+static void mwDefaultOutFunc( int c ) {
+    if( mwLogR() ) fputc( c, mwLogR() );
+    }
+
+static void mwWrite( const char *format, ... ) {
+    int tot, oflow = 0;
+    va_list mark;
+    mwAutoInit();
+    if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
+    va_start( mark, format );
+    tot = vsprintf( mwPrintBuf, format, mark );
+    va_end( mark );
+    if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; }
+    for(tot=0;mwPrintBuf[tot];tot++)
+        (*mwOutFunction)( mwPrintBuf[tot] );
+    if( oflow ) {
+        mwWrite( "\ninternal: mwWrite(): WARNING! OUTPUT EXCEEDED %u CHARS: SYSTEM UNSTABLE\n", MW_TRACE_BUFFER-1 );
+        FLUSH();
+        }
+    return;
+    }
+
+static void mwLogFile( const char *name ) {
+    time_t tid;
+    (void) time( &tid );
+    if( mwLogR() != NULL ) {
+        fclose( mwLogR() );
+        mwLogW( NULL );
+        }
+    if( name == NULL ) return;
+    mwLogW( fopen( name, "a" COMMIT ) );
+    if( mwLogR() == NULL )
+        mwWrite( "logfile: failed to open/create file '%s'\n", name );
+    }
+
+/*
+** Try to free NML memory until a contiguous allocation of
+** 'needed' bytes can be satisfied. If this is not enough
+** and the 'urgent' parameter is nonzero, grabbed memory is
+** also freed.
+*/
+static size_t mwFreeUp( size_t needed, int urgent ) {
+    void *p;
+    mwData *mw, *mw2;
+    char *data;
+
+    /* free grabbed NML memory */
+    for(;;) {
+        if( mwDrop_( 1, MW_VAL_NML, 1 ) == 0 ) break;
+        p = malloc( needed );
+        if( p == NULL ) continue;
+        free( p );
+        return needed;
+        }
+
+    /* free normal NML memory */
+    mw = mwHead;
+    while( mw != NULL ) {
+        if( !(mw->flag & MW_NML) ) mw = mw->next;
+        else {
+            data = ((char*)mw)+mwDataSize+mwOverflowZoneSize;
+            if( mwTestMem( data, mw->size, MW_VAL_NML ) ) {
+                mwIncErr();
+                mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
+                    mw->count, data + mwOverflowZoneSize, mw->file, mw->line );
+                }
+            mw2 = mw->next;
+            mwUnlink( mw, "mwFreeUp", 0 );
+            free( mw );
+            mw = mw2;
+            p = malloc( needed );
+            if( p == NULL ) continue;
+            free( p );
+            return needed;
+            }
+        }
+
+    /* if not urgent (for internal purposes), fail */
+    if( !urgent ) return 0;
+
+    /* free grabbed memory */
+    for(;;) {
+        if( mwDrop_( 1, MW_VAL_GRB, 1 ) == 0 ) break;
+        p = malloc( needed );
+        if( p == NULL ) continue;
+        free( p );
+        return needed;
+        }
+
+    return 0;
+    }
+
+static const void * mwTestMem( const void *p, unsigned len, int c ) {
+    const unsigned char *ptr;
+    ptr = (const unsigned char *) p;
+    while( len-- ) {
+        if( *ptr != (unsigned char)c ) return (const void*)ptr;
+        ptr ++;
+        }
+    return NULL;
+    }
+
+static int mwStrCmpI( const char *s1, const char *s2 ) {
+    if( s1 == NULL || s2 == NULL ) return 0;
+    while( *s1 ) {
+        if( toupper(*s2) == toupper(*s1) ) { s1++; s2++; continue; }
+        return 1;
+        }
+    return 0;
+    }
+
+#define AIPH() if( always_invoked ) { mwWrite("autocheck: <%ld> %s(%d) ", mwCounter, file, line ); always_invoked = 0; }
+
+static int mwTestNow( const char *file, int line, int always_invoked ) {
+    int retv = 0;
+    mwData *mw;
+    char *data;
+
+    if( file && !always_invoked )
+        mwWrite("check: <%ld> %s(%d), checking %s%s%s\n",
+            mwCounter, file, line,
+			(mwTestFlags & MW_TEST_CHAIN) ? "chain ": "",
+		    (mwTestFlags & MW_TEST_ALLOC) ? "alloc ": "",
+		    (mwTestFlags & MW_TEST_NML) ? "nomansland ": ""
+			);
+
+    if( mwTestFlags & MW_TEST_CHAIN ) {
+        for( mw = mwHead; mw; mw=mw->next ) {
+			if( !mwIsSafeAddr(mw, mwDataSize) ) {
+				AIPH();
+				mwWrite("check: heap corruption detected\n");
+				mwIncErr();
+				return retv + 1;
+				}
+			if( mw->prev ) {
+				if( !mwIsSafeAddr(mw->prev, mwDataSize) ) {
+					AIPH();
+					mwWrite("check: heap corruption detected\n");
+					mwIncErr();
+					return retv + 1;
+					}
+				if( mw==mwHead || mw->prev->next != mw ) {
+					AIPH();
+					mwWrite("check: heap chain broken, prev link incorrect\n");
+					mwIncErr();
+					retv ++;
+					}
+				}
+			if( mw->next ) {
+				if( !mwIsSafeAddr(mw->next, mwDataSize) ) {
+					AIPH();
+					mwWrite("check: heap corruption detected\n");
+					mwIncErr();
+					return retv + 1;
+					}
+				if( mw==mwTail || mw->next->prev != mw ) {
+					AIPH();
+					mwWrite("check: heap chain broken, next link incorrect\n");
+					mwIncErr();
+					retv ++;
+					}
+				}
+			else if( mw!=mwTail ) {
+				AIPH();
+				mwWrite("check: heap chain broken, tail incorrect\n");
+				mwIncErr();
+				retv ++;
+				}
+            }
+        }
+    if( mwTestFlags & MW_TEST_ALLOC ) {
+        for( mw = mwHead; mw; mw=mw->next ) {
+            if( mwTestBuf( mw, file, line ) ) retv ++;
+            }
+        }
+    if( mwTestFlags & MW_TEST_NML ) {
+        for( mw = mwHead; mw; mw=mw->next ) {
+            if( (mw->flag & MW_NML) ) {
+                data = ((char*)mw)+mwDataSize+mwOverflowZoneSize;
+                if( mwTestMem( data, mw->size, MW_VAL_NML ) ) {
+                    mwIncErr();
+                    mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
+                        mw->count, data + mwOverflowZoneSize, mw->file, mw->line );
+                    }
+                }
+            }
+        }
+
+
+	if( file && !always_invoked && !retv )
+        mwWrite("check: <%ld> %s(%d), complete; no errors\n",
+            mwCounter, file, line );
+    return retv;
+    }
+
+/**********************************************************************
+** Statistics
+**********************************************************************/
+
+static void mwStatReport()
+{
+    mwStat* ms, *ms2;
+    const char *modname;
+    int modnamelen;
+
+    /* global statistics report */
+    mwWrite( "\nMemory usage statistics (global):\n" );
+    mwWrite( " N)amber of allocations made: %ld\n", mwStatNumAlloc );
+    mwWrite( " L)argest memory usage      : %ld\n", mwStatMaxAlloc );
+    mwWrite( " T)otal of all alloc() calls: %ld\n", mwStatTotAlloc );
+    mwWrite( " U)nfreed bytes totals      : %ld\n", mwStatCurAlloc );
+    FLUSH();
+
+    if( mwStatLevel < 1 ) return;
+
+    /* on a per-module basis */
+    mwWrite( "\nMemory usage statistics (detailed):\n");
+    mwWrite( " Module/Line                                Number   Largest  Total    Unfreed \n");
+    for( ms=mwStatList; ms; ms=ms->next )
+    {
+        if( ms->line == -1 )
+        {
+			if( ms->file == NULL || !mwIsReadAddr(ms->file,22) ) modname = "<unknown>";
+			else modname = ms->file;
+			modnamelen = strlen(modname);
+			if( modnamelen > 42 )
+			{
+				modname = modname + modnamelen - 42;
+			}
+
+            mwWrite(" %-42s %-8ld %-8ld %-8ld %-8ld\n",
+            	modname, ms->num, ms->max, ms->total, ms->curr );
+            if( ms->file && mwStatLevel > 1 )
+            {
+                for( ms2=mwStatList; ms2; ms2=ms2->next )
+                {
+                    if( ms2->line!=-1 && ms2->file!=NULL && !mwStrCmpI( ms2->file, ms->file ) )
+					{
+					mwWrite( "  %-8d                                  %-8ld %-8ld %-8ld %-8ld\n",
+						ms2->line, ms2->num, ms2->max, ms2->total, ms2->curr );
+					}
+				}
+			}
+		}
+	}
+}
+
+static mwStat* mwStatGet( const char *file, int line, int makenew ) {
+    mwStat* ms;
+
+    if( mwStatLevel < 2 ) line = -1;
+
+    for( ms=mwStatList; ms!=NULL; ms=ms->next ) {
+        if( line != ms->line ) continue;
+        if( file==NULL ) {
+            if( ms->file == NULL ) break;
+            continue;
+            }
+        if( ms->file == NULL ) continue;
+        if( !strcmp( ms->file, file ) ) break;
+        }
+
+    if( ms != NULL ) return ms;
+
+    if( !makenew ) return NULL;
+
+    ms = (mwStat*) malloc( sizeof(mwStat) );
+    if( ms == NULL ) {
+        if( mwFreeUp( sizeof(mwStat), 0 ) < sizeof(mwStat) ||
+            (ms=(mwStat*)malloc(sizeof(mwStat))) == NULL ) {
+            mwWrite("internal: memory low, statistics incomplete for '%s'\n", file );
+            return NULL;
+            }
+        }
+    ms->file = file;
+    ms->line = line;
+    ms->total = 0L;
+    ms->max = 0L;
+    ms->num = 0L;
+    ms->curr = 0L;
+    ms->next = mwStatList;
+    mwStatList = ms;
+    return ms;
+    }
+
+static void mwStatAlloc( size_t size, const char* file, int line ) {
+    mwStat* ms;
+
+    /* update the module statistics */
+    ms = mwStatGet( file, -1, 1 );
+    if( ms != NULL ) {
+        ms->total += (long) size;
+        ms->curr += (long) size;
+        ms->num ++;
+        if( ms->curr > ms->max ) ms->max = ms->curr;
+        }
+
+    /* update the line statistics */
+    if( mwStatLevel > 1 && line != -1 && file ) {
+        ms = mwStatGet( file, line, 1 );
+        if( ms != NULL ) {
+            ms->total += (long) size;
+            ms->curr += (long) size;
+            ms->num ++;
+            if( ms->curr > ms->max ) ms->max = ms->curr;
+            }
+        }
+
+    }
+
+static void mwStatFree( size_t size, const char* file, int line ) {
+    mwStat* ms;
+
+    /* update the module statistics */
+    ms = mwStatGet( file, -1, 1 );
+    if( ms != NULL ) ms->curr -= (long) size;
+
+    /* update the line statistics */
+    if( mwStatLevel > 1 && line != -1 && file ) {
+        ms = mwStatGet( file, line, 1 );
+        if( ms != NULL ) ms->curr -= (long) size;
+        }
+    }
+
+/***********************************************************************
+** Safe memory checkers
+**
+** Using ifdefs, implement the operating-system specific mechanism
+** of identifying a piece of memory as legal to access with read
+** and write priviliges. Default: return nonzero for non-NULL pointers.
+***********************************************************************/
+
+static char mwDummy( char c )
+{
+	return c;
+}
+
+#ifndef MW_SAFEADDR
+#ifdef WIN32
+#define MW_SAFEADDR
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+int mwIsReadAddr( const void *p, unsigned len )
+{
+    if( p == NULL ) return 0;
+    if( IsBadReadPtr(p,len) ) return 0;
+    return 1;
+}
+int mwIsSafeAddr( void *p, unsigned len )
+{
+    /* NOTE: For some reason, under Win95 the IsBad... */
+    /* can return false for invalid pointers. */
+    if( p == NULL ) return 0;
+    if( IsBadReadPtr(p,len) || IsBadWritePtr(p,len) ) return 0;
+    return 1;
+}
+#endif /* WIN32 */
+#endif /* MW_SAFEADDR */
+
+#ifndef MW_SAFEADDR
+#ifdef SIGSEGV
+#define MW_SAFEADDR
+
+typedef void (*mwSignalHandlerPtr)( int );
+mwSignalHandlerPtr mwOldSIGSEGV = (mwSignalHandlerPtr) 0;
+jmp_buf mwSIGSEGVjump;
+static void mwSIGSEGV( int n );
+
+static void mwSIGSEGV( int n )
+{
+	n = n;
+	longjmp( mwSIGSEGVjump, 1 );
+}
+
+int mwIsReadAddr( const void *p, unsigned len )
+{
+	const char *ptr;
+
+    if( p == NULL ) return 0;
+	if( !len ) return 1;
+
+	/* set up to catch the SIGSEGV signal */
+	mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
+
+	if( setjmp( mwSIGSEGVjump ) )
+	{
+		signal( SIGSEGV, mwOldSIGSEGV );
+		return 0;
+	}
+
+	/* read all the bytes in the range */
+	ptr = (const char *)p;
+	ptr += len;
+
+	/* the reason for this rather strange construct is that */
+	/* we want to keep the number of used parameters and locals */
+	/* to a minimum. if we use len for a counter gcc will complain */
+	/* it may get clobbered by longjmp() at high warning levels. */
+	/* it's a harmless warning, but this way we don't have to see it. */
+	do
+	{
+		ptr --;
+		if( *ptr == 0x7C ) (void) mwDummy( (char)0 );
+	} while( (const void*) ptr != p );
+
+	/* remove the handler */
+	signal( SIGSEGV, mwOldSIGSEGV );
+
+    return 1;
+}
+int mwIsSafeAddr( void *p, unsigned len )
+{
+	char *ptr;
+
+	if( p == NULL ) return 0;
+	if( !len ) return 1;
+
+	/* set up to catch the SIGSEGV signal */
+	mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
+
+	if( setjmp( mwSIGSEGVjump ) )
+	{
+		signal( SIGSEGV, mwOldSIGSEGV );
+		return 0;
+	}
+
+	/* read and write-back all the bytes in the range */
+	ptr = (char *)p;
+	ptr += len;
+
+	/* the reason for this rather strange construct is that */
+	/* we want to keep the number of used parameters and locals */
+	/* to a minimum. if we use len for a counter gcc will complain */
+	/* it may get clobbered by longjmp() at high warning levels. */
+	/* it's a harmless warning, but this way we don't have to see it. */
+	do
+	{
+		ptr --;
+		*ptr = mwDummy( *ptr );
+	} while( (void*) ptr != p );
+
+	/* remove the handler */
+	signal( SIGSEGV, mwOldSIGSEGV );
+
+    return 1;
+}
+#endif /* SIGSEGV */
+#endif /* MW_SAFEADDR */
+
+#ifndef MW_SAFEADDR
+int mwIsReadAddr( const void *p, unsigned len )
+{
+    if( p == NULL ) return 0;
+    if( len == 0 ) return 1;
+    return 1;
+}
+int mwIsSafeAddr( void *p, unsigned len )
+{
+    if( p == NULL ) return 0;
+    if( len == 0 ) return 1;
+    return 1;
+}
+#endif
+
+/**********************************************************************
+** Mutex handling
+**********************************************************************/
+
+#if defined(WIN32) || defined(__WIN32__)
+
+static void	mwMutexInit( void )
+{
+	mwGlobalMutex = CreateMutex( NULL, FALSE, NULL);
+	return;
+}
+
+static void	mwMutexTerm( void )
+{
+	CloseHandle( mwGlobalMutex );
+	return;
+}
+
+static void	mwMutexLock( void )
+{
+	if( WaitForSingleObject(mwGlobalMutex, 1000 ) == WAIT_TIMEOUT )
+	{
+		mwWrite( "mwMutexLock: timed out, possible deadlock\n" );
+	}
+	return;
+}
+
+static void	mwMutexUnlock( void )
+{
+	ReleaseMutex( mwGlobalMutex );
+	return;
+}
+
+#endif
+
+#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
+
+static void	mwMutexInit( void )
+{
+	pthread_mutex_init( &mwGlobalMutex, NULL );
+	return;
+}
+
+static void	mwMutexTerm( void )
+{
+	pthread_mutex_destroy( &mwGlobalMutex );
+	return;
+}
+
+static void	mwMutexLock( void )
+{
+	pthread_mutex_lock(&mwGlobalMutex);
+	return;
+}
+
+static void	mwMutexUnlock( void )
+{
+	pthread_mutex_unlock(&mwGlobalMutex);
+	return;
+}
+
+#endif
+
+/**********************************************************************
+** C++ new & delete
+**********************************************************************/
+
+#if 0 /* 980317: disabled C++ */
+
+#ifdef __cplusplus
+#ifndef MEMWATCH_NOCPP
+
+int mwNCur = 0;
+const char *mwNFile = NULL;
+int mwNLine = 0;
+
+class MemWatch {
+public:
+    MemWatch();
+    ~MemWatch();
+    };
+
+MemWatch::MemWatch() {
+    if( mwInited ) return;
+    mwUseAtexit = 0;
+    mwInit();
+    }
+
+MemWatch::~MemWatch() {
+    if( mwUseAtexit ) return;
+    mwTerm();
+    }
+
+/*
+** This global new will catch all 'new' calls where MEMWATCH is
+** not active.
+*/
+void* operator new( unsigned size ) {
+    mwNCur = 0;
+    return mwMalloc( size, "<unknown>", 0 );
+    }
+
+/*
+** This is the new operator that's called when a module uses mwNew.
+*/
+void* operator new( unsigned size, const char *file, int line ) {
+    mwNCur = 0;
+    return mwMalloc( size, file, line );
+    }
+
+/*
+** This is the new operator that's called when a module uses mwNew[].
+** -- hjc 07/16/02
+*/
+void* operator new[] ( unsigned size, const char *file, int line ) {
+    mwNCur = 0;
+    return mwMalloc( size, file, line );
+    }
+
+/*
+** Since this delete operator will recieve ALL delete's
+** even those from within libraries, we must accept
+** delete's before we've been initialized. Nor can we
+** reliably check for wild free's if the mwNCur variable
+** is not set.
+*/
+void operator delete( void *p ) {
+    if( p == NULL ) return;
+    if( !mwInited ) {
+        free( p );
+        return;
+        }
+    if( mwNCur ) {
+        mwFree( p, mwNFile, mwNLine );
+        mwNCur = 0;
+        return;
+        }
+    mwFree_( p );
+    }
+
+void operator delete[]( void *p ) {
+    if( p == NULL ) return;
+    if( !mwInited ) {
+        free( p );
+        return;
+        }
+    if( mwNCur ) {
+        mwFree( p, mwNFile, mwNLine );
+        mwNCur = 0;
+        return;
+        }
+    mwFree_( p );
+    }
+
+#endif /* MEMWATCH_NOCPP */
+#endif /* __cplusplus */
+
+#endif /* 980317: disabled C++ */
+
+/* MEMWATCH.C */
diff --git a/memwatch.h b/memwatch.h
new file mode 100644
index 0000000..d63fd76
--- /dev/null
+++ b/memwatch.h
@@ -0,0 +1,707 @@
+/*
+** MEMWATCH.H
+** Nonintrusive ANSI C memory leak / overwrite detection
+** Copyright (C) 1992-2002 Johan Lindh
+** All rights reserved.
+** Version 2.71
+**
+************************************************************************
+**
+** PURPOSE:
+**
+**  MEMWATCH has been written to allow guys and gals that like to
+**  program in C a public-domain memory error control product.
+**  I hope you'll find it's as advanced as most commercial packages.
+**  The idea is that you use it during the development phase and
+**  then remove the MEMWATCH define to produce your final product.
+**  MEMWATCH is distributed in source code form in order to allow
+**  you to compile it for your platform with your own compiler.
+**  It's aim is to be 100% ANSI C, but some compilers are more stingy
+**  than others. If it doesn't compile without warnings, please mail
+**  me the configuration of operating system and compiler you are using
+**  along with a description of how to modify the source, and the version
+**  number of MEMWATCH that you are using.
+**
+************************************************************************
+
+	This file is part of MEMWATCH.
+
+    MEMWATCH 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; either version 2 of the License, or
+    (at your option) any later version.
+
+    MEMWATCH 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.
+
+    You should have received a copy of the GNU General Public License
+    along with MEMWATCH; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+************************************************************************
+**
+** REVISION HISTORY:
+**
+** 920810 JLI   [1.00]
+** 920830 JLI   [1.10 double-free detection]
+** 920912 JLI   [1.15 mwPuts, mwGrab/Drop, mwLimit]
+** 921022 JLI   [1.20 ASSERT and VERIFY]
+** 921105 JLI   [1.30 C++ support and TRACE]
+** 921116 JLI   [1.40 mwSetOutFunc]
+** 930215 JLI   [1.50 modified ASSERT/VERIFY]
+** 930327 JLI   [1.51 better auto-init & PC-lint support]
+** 930506 JLI   [1.55 MemWatch class, improved C++ support]
+** 930507 JLI   [1.60 mwTest & CHECK()]
+** 930809 JLI   [1.65 Abort/Retry/Ignore]
+** 930820 JLI   [1.70 data dump when unfreed]
+** 931016 JLI   [1.72 modified C++ new/delete handling]
+** 931108 JLI   [1.77 mwSetAssertAction() & some small changes]
+** 940110 JLI   [1.80 no-mans-land alloc/checking]
+** 940328 JLI   [2.00 version 2.0 rewrite]
+**              Improved NML (no-mans-land) support.
+**              Improved performance (especially for free()ing!).
+**              Support for 'read-only' buffers (checksums)
+**              ^^ NOTE: I never did this... maybe I should?
+**              FBI (free'd block info) tagged before freed blocks
+**              Exporting of the mwCounter variable
+**              mwBreakOut() localizes debugger support
+**              Allocation statistics (global, per-module, per-line)
+**              Self-repair ability with relinking
+** 950913 JLI   [2.10 improved garbage handling]
+** 951201 JLI   [2.11 improved auto-free in emergencies]
+** 960125 JLI   [X.01 implemented auto-checking using mwAutoCheck()]
+** 960514 JLI   [2.12 undefining of existing macros]
+** 960515 JLI   [2.13 possibility to use default new() & delete()]
+** 960516 JLI   [2.20 suppression of file flushing on unfreed msgs]
+** 960516 JLI   [2.21 better support for using MEMWATCH with DLL's]
+** 960710 JLI   [X.02 multiple logs and mwFlushNow()]
+** 960801 JLI   [2.22 merged X.01 version with current]
+** 960805 JLI   [2.30 mwIsXXXXAddr() to avoid unneeded GP's]
+** 960805 JLI   [2.31 merged X.02 version with current]
+** 961002 JLI   [2.32 support for realloc() + fixed STDERR bug]
+** 961222 JLI   [2.40 added mwMark() & mwUnmark()]
+** 970101 JLI   [2.41 added over/underflow checking after failed ASSERT/VERIFY]
+** 970113 JLI   [2.42 added support for PC-Lint 7.00g]
+** 970207 JLI   [2.43 added support for strdup()]
+** 970209 JLI   [2.44 changed default filename to lowercase]
+** 970405 JLI   [2.45 fixed bug related with atexit() and some C++ compilers]
+** 970723 JLI   [2.46 added MW_ARI_NULLREAD flag]
+** 970813 JLI   [2.47 stabilized marker handling]
+** 980317 JLI   [2.48 ripped out C++ support; wasn't working good anyway]
+** 980318 JLI   [2.50 improved self-repair facilities & SIGSEGV support]
+** 980417 JLI	[2.51 more checks for invalid addresses]
+** 980512 JLI	[2.52 moved MW_ARI_NULLREAD to occur before aborting]
+** 990112 JLI	[2.53 added check for empty heap to mwIsOwned]
+** 990217 JLI	[2.55 improved the emergency repairs diagnostics and NML]
+** 990224 JLI	[2.56 changed ordering of members in structures]
+** 990303 JLI	[2.57 first maybe-fixit-for-hpux test]
+** 990516 JLI	[2.58 added 'static' to the definition of mwAutoInit]
+** 990517 JLI	[2.59 fixed some high-sensitivity warnings]
+** 990610 JLI	[2.60 fixed some more high-sensitivity warnings]
+** 990715 JLI	[2.61 changed TRACE/ASSERT/VERIFY macro names]
+** 991001 JLI	[2.62 added CHECK_BUFFER() and mwTestBuffer()]
+** 991007 JLI	[2.63 first shot at a 64-bit compatible version]
+** 991009 JLI	[2.64 undef's strdup() if defined, mwStrdup made const]
+** 000704 JLI	[2.65 added some more detection for 64-bits]
+** 010502 JLI   [2.66 incorporated some user fixes]
+**              [mwRelink() could print out garbage pointer (thanks mac at phobos.ca)]
+**				[added array destructor for C++ (thanks rdasilva at connecttel.com)]
+**				[added mutex support (thanks rdasilva at connecttel.com)]
+** 010531 JLI	[2.67 fix: mwMutexXXX() was declared even if MW_HAVE_MUTEX was not defined]
+** 010619 JLI	[2.68 fix: mwRealloc() could leave the mutex locked]
+** 020918 JLI	[2.69 changed to GPL, added C++ array allocation by Howard Cohen]
+** 030212 JLI	[2.70 mwMalloc() bug for very large allocations (4GB on 32bits)]
+** 030520 JLI	[2.71 added ULONG_LONG_MAX as a 64-bit detector (thanks Sami Salonen)]
+**
+** To use, simply include 'MEMWATCH.H' as a header file,
+** and add MEMWATCH.C to your list of files, and define the macro
+** 'MEMWATCH'. If this is not defined, MEMWATCH will disable itself.
+**
+** To call the standard C malloc / realloc / calloc / free; use mwMalloc_(),
+** mwCalloc_() and mwFree_(). Note that mwFree_() will correctly
+** free both malloc()'d memory as well as mwMalloc()'d.
+**
+** 980317: C++ support has been disabled.
+**         The code remains, but is not compiled.
+**
+**         For use with C++, which allows use of inlining in header files
+**         and class specific new/delete, you must also define 'new' as
+**         'mwNew' and 'delete' as 'mwDelete'. Do this *after* you include
+**         C++ header files from libraries, otherwise you can mess up their
+**         class definitions. If you don't define these, the C++ allocations
+**         will not have source file and line number information. Also note,
+**         most C++ class libraries implement their own C++ memory management,
+**         and don't allow anyone to override them. MFC belongs to this crew.
+**         In these cases, the only thing to do is to use MEMWATCH_NOCPP.
+**
+** You can capture output from MEMWATCH using mwSetOutFunc().
+** Just give it the adress of a "void myOutFunc(int c)" function,
+** and all characters to be output will be redirected there.
+**
+** A failing ASSERT() or VERIFY() will normally always abort your
+** program. This can be changed using mwSetAriFunc(). Give it a
+** pointer to a "int myAriFunc(const char *)" function. Your function
+** must ask the user whether to Abort, Retry or Ignore the trap.
+** Return 2 to Abort, 1 to Retry or 0 to Ignore. Beware retry; it
+** causes the expression to be evaluated again! MEMWATCH has a
+** default ARI handler. It's disabled by default, but you can enable
+** it by calling 'mwDefaultAri()'. Note that this will STILL abort
+** your program unless you define MEMWATCH_STDIO to allow MEMWATCH
+** to use the standard C I/O streams. Also, setting the ARI function
+** will cause MEMWATCH *NOT* to write the ARI error to stderr. The
+** error string is passed to the ARI function instead, as the
+** 'const char *' parameter.
+**
+** You can disable MEMWATCH's ASSERT/VERIFY and/or TRACE implementations.
+** This can be useful if you're using a debug terminal or smart debugger.
+** Disable them by defining MW_NOASSERT, MW_NOVERIFY or MW_NOTRACE.
+**
+** MEMWATCH fills all allocated memory with the byte 0xFE, so if
+** you're looking at erroneous data which are all 0xFE:s, the
+** data probably was not initialized by you. The exception is
+** calloc(), which will fill with zero's. All freed buffers are
+** zapped with 0xFD. If this is what you look at, you're using
+** data that has been freed. If this is the case, be aware that
+** MEMWATCH places a 'free'd block info' structure immediately
+** before the freed data. This block contains info about where
+** the block was freed. The information is in readable text,
+** in the format "FBI<counter>filename(line)", for example:
+** "FBI<267>test.c(12)". Using FBI's slows down free(), so it's
+** disabled by default. Use mwFreeBufferInfo(1) to enable it.
+**
+** To aid in tracking down wild pointer writes, MEMWATCH can perform
+** no-mans-land allocations. No-mans-land will contain the byte 0xFC.
+** MEMWATCH will, when this is enabled, convert recently free'd memory
+** into NML allocations.
+**
+** MEMWATCH protects it's own data buffers with checksums. If you
+** get an internal error, it means you're overwriting wildly,
+** or using an uninitialized pointer.
+**
+************************************************************************
+**
+** Note when compiling with Microsoft C:
+**  -   MSC ignores fflush() by default. This is overridden, so that
+**      the disk log will always be current.
+**
+** This utility has been tested with:
+**  PC-lint 7.0k, passed as 100% ANSI C compatible
+**  Microsoft Visual C++ on Win16 and Win32
+**  Microsoft C on DOS
+**  SAS C on an Amiga 500
+**  Gnu C on a PC running Red Hat Linux
+**  ...and using an (to me) unknown compiler on an Atari machine.
+**
+************************************************************************
+**
+** Format of error messages in MEMWATCH.LOG:
+**  message: <sequence-number> filename(linenumber), information
+**
+** Errors caught by MemWatch, when they are detected, and any
+** actions taken besides writing to the log file MEMWATCH.LOG:
+**
+**  Double-freeing:
+**      A pointer that was recently freed and has not since been
+**      reused was freed again. The place where the previous free()
+**      was executed is displayed.
+**      Detect: delete or free() using the offending pointer.
+**      Action: The delete or free() is cancelled, execution continues.
+**  Underflow:
+**      You have written just ahead of the allocated memory.
+**      The size and place of the allocation is displayed.
+**      Detect: delete or free() of the damaged buffer.
+**      Action: The buffer is freed, but there may be secondary damage.
+**  Overflow:
+**      Like underflow, but you've written after the end of the buffer.
+**      Detect: see Underflow.
+**      Action: see Underflow.
+**  WILD free:
+**      An unrecognized pointer was passed to delete or free().
+**      The pointer may have been returned from a library function;
+**      in that case, use mwFree_() to force free() of it.
+**      Also, this may be a double-free, but the previous free was
+**      too long ago, causing MEMWATCH to 'forget' it.
+**      Detect: delete or free() of the offending pointer.
+**      Action: The delete or free() is cancelled, execution continues.
+**  NULL free:
+**      It's unclear to me whether or not freeing of NULL pointers
+**      is legal in ANSI C, therefore a warning is written to the log file,
+**      but the error counter remains the same. This is legal using C++,
+**      so the warning does not appear with delete.
+**      Detect: When you free(NULL).
+**      Action: The free() is cancelled.
+**  Failed:
+**      A request to allocate memory failed. If the allocation is
+**      small, this may be due to memory depletion, but is more likely
+**      to be memory fragmentation problems. The amount of memory
+**      allocated so far is displayed also.
+**      Detect: When you new, malloc(), realloc() or calloc() memory.
+**      Action: NULL is returned.
+**  Realloc:
+**      A request to re-allocate a memory buffer failed for reasons
+**      other than out-of-memory. The specific reason is shown.
+**      Detect: When you realloc()
+**      Action: realloc() is cancelled, NULL is returned
+**  Limit fail:
+**      A request to allocate memory failed since it would violate
+**      the limit set using mwLimit(). mwLimit() is used to stress-test
+**      your code under simulated low memory conditions.
+**      Detect: At new, malloc(), realloc() or calloc().
+**      Action: NULL is returned.
+**  Assert trap:
+**      An ASSERT() failed. The ASSERT() macro works like C's assert()
+**      macro/function, except that it's interactive. See your C manual.
+**      Detect: On the ASSERT().
+**      Action: Program ends with an advisory message to stderr, OR
+**              Program writes the ASSERT to the log and continues, OR
+**              Program asks Abort/Retry/Ignore? and takes that action.
+**  Verify trap:
+**      A VERIFY() failed. The VERIFY() macro works like ASSERT(),
+**      but if MEMWATCH is not defined, it still evaluates the
+**      expression, but it does not act upon the result.
+**      Detect: On the VERIFY().
+**      Action: Program ends with an advisory message to stderr, OR
+**              Program writes the VERIFY to the log and continues, OR
+**              Program asks Abort/Retry/Ignore? and takes that action.
+**  Wild pointer:
+**      A no-mans-land buffer has been written into. MEMWATCH can
+**      allocate and distribute chunks of memory solely for the
+**      purpose of trying to catch random writes into memory.
+**      Detect: Always on CHECK(), but can be detected in several places.
+**      Action: The error is logged, and if an ARI handler is installed,
+**              it is executed, otherwise, execution continues.
+**  Unfreed:
+**      A memory buffer you allocated has not been freed.
+**      You are informed where it was allocated, and whether any
+**      over or underflow has occured. MemWatch also displays up to
+**      16 bytes of the data, as much as it can, in hex and text.
+**      Detect: When MemWatch terminates.
+**      Action: The buffer is freed.
+**  Check:
+**      An error was detected during a CHECK() operation.
+**      The associated pointer is displayed along with
+**      the file and line where the CHECK() was executed.
+**      Followed immediately by a normal error message.
+**      Detect: When you CHECK()
+**      Action: Depends on the error
+**  Relink:
+**      After a MEMWATCH internal control block has been trashed,
+**      MEMWATCH tries to repair the damage. If successful, program
+**      execution will continue instead of aborting. Some information
+**      about the block may be gone permanently, though.
+**      Detect: N/A
+**      Action: Relink successful: program continues.
+**              Relink fails: program aborts.
+**  Internal:
+**      An internal error is flagged by MEMWATCH when it's control
+**      structures have been damaged. You are likely using an uninitialized
+**      pointer somewhere in your program, or are zapping memory all over.
+**      The message may give you additional diagnostic information.
+**      If possible, MEMWATCH will recover and continue execution.
+**      Detect: Various actions.
+**      Action: Whatever is needed
+**  Mark:
+**      The program terminated without umarking all marked pointers. Marking
+**      can be used to track resources other than memory. mwMark(pointer,text,...)
+**      when the resource is allocated, and mwUnmark(pointer) when it's freed.
+**      The 'text' is displayed for still marked pointers when the program
+**      ends.
+**      Detect: When MemWatch terminates.
+**      Action: The error is logged.
+**
+**
+************************************************************************
+**
+**  The author may be reached by e-mail at the address below. If you
+**  mail me about source code changes in MEMWATCH, remember to include
+**  MW's version number.
+**
+**      Johan Lindh
+**      johan at linkdata.se
+**
+** The latest version of MEMWATCH may be downloaded from
+** http://www.linkdata.se/
+*/
+
+#ifndef __MEMWATCH_H
+#define __MEMWATCH_H
+
+/* Make sure that malloc(), realloc(), calloc() and free() are declared. */
+/*lint -save -e537 */
+#include <stdlib.h>
+/*lint -restore */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+** Constants used
+**  All MEMWATCH constants start with the prefix MW_, followed by
+**  a short mnemonic which indicates where the constant is used,
+**  followed by a descriptive text about it.
+*/
+
+#define MW_ARI_NULLREAD 0x10    /* Null read (to start debugger) */
+#define MW_ARI_ABORT    0x04    /* ARI handler says: abort program! */
+#define MW_ARI_RETRY    0x02    /* ARI handler says: retry action! */
+#define MW_ARI_IGNORE   0x01    /* ARI handler says: ignore error! */
+
+#define MW_VAL_NEW      0xFE    /* value in newly allocated memory */
+#define MW_VAL_DEL      0xFD    /* value in newly deleted memory */
+#define MW_VAL_NML      0xFC    /* value in no-mans-land */
+#define MW_VAL_GRB      0xFB    /* value in grabbed memory */
+
+#define MW_TEST_ALL     0xFFFF  /* perform all tests */
+#define MW_TEST_CHAIN   0x0001  /* walk the heap chain */
+#define MW_TEST_ALLOC   0x0002  /* test allocations & NML guards */
+#define MW_TEST_NML     0x0004  /* test all-NML areas for modifications */
+
+#define MW_NML_NONE     0       /* no NML */
+#define MW_NML_FREE     1       /* turn FREE'd memory into NML */
+#define MW_NML_ALL      2       /* all unused memory is NML */
+#define MW_NML_DEFAULT  0       /* the default NML setting */
+
+#define MW_STAT_GLOBAL  0       /* only global statistics collected */
+#define MW_STAT_MODULE  1       /* collect statistics on a module basis */
+#define MW_STAT_LINE    2       /* collect statistics on a line basis */
+#define MW_STAT_DEFAULT 0       /* the default statistics setting */
+
+/*
+** MemWatch internal constants
+**  You may change these and recompile MemWatch to change the limits
+**  of some parameters. Respect the recommended minimums!
+*/
+#define MW_TRACE_BUFFER 2048    /* (min 160) size of TRACE()'s output buffer */
+#define MW_FREE_LIST    64      /* (min 4) number of free()'s to track */
+
+/*
+** Exported variables
+**  In case you have to remove the 'const' keyword because your compiler
+**  doesn't support it, be aware that changing the values may cause
+**  unpredictable behaviour.
+**  - mwCounter contains the current action count. You can use this to
+**      place breakpoints using a debugger, if you want.
+*/
+#ifndef __MEMWATCH_C
+extern const unsigned long mwCounter;
+#endif
+
+/*
+** System functions
+**  Normally, it is not nessecary to call any of these. MEMWATCH will
+**  automatically initialize itself on the first MEMWATCH function call,
+**  and set up a call to mwAbort() using atexit(). Some C++ implementations
+**  run the atexit() chain before the program has terminated, so you
+**  may have to use mwInit() or the MemWatch C++ class to get good
+**  behaviour.
+**  - mwInit() can be called to disable the atexit() usage. If mwInit()
+**      is called directly, you must call mwTerm() to end MemWatch, or
+**      mwAbort().
+**  - mwTerm() is usually not nessecary to call; but if called, it will
+**      call mwAbort() if it finds that it is cancelling the 'topmost'
+**      mwInit() call.
+**  - mwAbort() cleans up after MEMWATCH, reports unfreed buffers, etc.
+*/
+void  mwInit( void );
+void  mwTerm( void );
+void  mwAbort( void );
+
+/*
+** Setup functions
+**  These functions control the operation of MEMWATCH's protective features.
+**  - mwFlushNow() causes MEMWATCH to flush it's buffers.
+**  - mwDoFlush() controls whether MEMWATCH flushes the disk buffers after
+**      writes. The default is smart flushing: MEMWATCH will not flush buffers
+**      explicitly until memory errors are detected. Then, all writes are
+**      flushed until program end or mwDoFlush(0) is called.
+**  - mwLimit() sets the allocation limit, an arbitrary limit on how much
+**      memory your program may allocate in bytes. Used to stress-test app.
+**      Also, in virtual-memory or multitasking environs, puts a limit on
+**      how much MW_NML_ALL can eat up.
+**  - mwGrab() grabs up X kilobytes of memory. Allocates actual memory,
+**      can be used to stress test app & OS both.
+**  - mwDrop() drops X kilobytes of grabbed memory.
+**  - mwNoMansLand() sets the behaviour of the NML logic. See the
+**      MW_NML_xxx for more information. The default is MW_NML_DEFAULT.
+**  - mwStatistics() sets the behaviour of the statistics collector. See
+**      the MW_STAT_xxx defines for more information. Default MW_STAT_DEFAULT.
+**  - mwFreeBufferInfo() enables or disables the tagging of free'd buffers
+**      with freeing information. This information is written in text form,
+**      using sprintf(), so it's pretty slow. Disabled by default.
+**  - mwAutoCheck() performs a CHECK() operation whenever a MemWatch function
+**      is used. Slows down performance, of course.
+**  - mwCalcCheck() calculates checksums for all data buffers. Slow!
+**  - mwDumpCheck() logs buffers where stored & calc'd checksums differ. Slow!!
+**  - mwMark() sets a generic marker. Returns the pointer given.
+**  - mwUnmark() removes a generic marker. If, at the end of execution, some
+**      markers are still in existence, these will be reported as leakage.
+**      returns the pointer given.
+*/
+void        mwFlushNow( void );
+void        mwDoFlush( int onoff );
+void        mwLimit( long bytes );
+unsigned    mwGrab( unsigned kilobytes );
+unsigned    mwDrop( unsigned kilobytes );
+void        mwNoMansLand( int mw_nml_level );
+void        mwStatistics( int level );
+void        mwFreeBufferInfo( int onoff );
+void        mwAutoCheck( int onoff );
+void        mwCalcCheck( void );
+void        mwDumpCheck( void );
+void *      mwMark( void *p, const char *description, const char *file, unsigned line );
+void *      mwUnmark( void *p, const char *file, unsigned line );
+
+/*
+** Testing/verification/tracing
+**  All of these macros except VERIFY() evaluates to a null statement
+**  if MEMWATCH is not defined during compilation.
+**  - mwIsReadAddr() checks a memory area for read privilige.
+**  - mwIsSafeAddr() checks a memory area for both read & write privilige.
+**      This function and mwIsReadAddr() is highly system-specific and
+**      may not be implemented. If this is the case, they will default
+**      to returning nonzero for any non-NULL pointer.
+**  - CHECK() does a complete memory integrity test. Slow!
+**  - CHECK_THIS() checks only selected components.
+**  - CHECK_BUFFER() checks the indicated buffer for errors.
+**  - mwASSERT() or ASSERT() If the expression evaluates to nonzero, execution continues.
+**      Otherwise, the ARI handler is called, if present. If not present,
+**      the default ARI action is taken (set with mwSetAriAction()).
+**      ASSERT() can be disabled by defining MW_NOASSERT.
+**  - mwVERIFY() or VERIFY() works just like ASSERT(), but when compiling without
+**      MEMWATCH the macro evaluates to the expression.
+**      VERIFY() can be disabled by defining MW_NOVERIFY.
+**  - mwTRACE() or TRACE() writes some text and data to the log. Use like printf().
+**      TRACE() can be disabled by defining MW_NOTRACE.
+*/
+int   mwIsReadAddr( const void *p, unsigned len );
+int   mwIsSafeAddr( void *p, unsigned len );
+int   mwTest( const char *file, int line, int mw_test_flags );
+int   mwTestBuffer( const char *file, int line, void *p );
+int   mwAssert( int, const char*, const char*, int );
+int   mwVerify( int, const char*, const char*, int );
+
+/*
+** User I/O functions
+**  - mwTrace() works like printf(), but dumps output either to the
+**      function specified with mwSetOutFunc(), or the log file.
+**  - mwPuts() works like puts(), dumps output like mwTrace().
+**  - mwSetOutFunc() allows you to give the adress of a function
+**      where all user output will go. (exeption: see mwSetAriFunc)
+**      Specifying NULL will direct output to the log file.
+**  - mwSetAriFunc() gives MEMWATCH the adress of a function to call
+**      when an 'Abort, Retry, Ignore' question is called for. The
+**      actual error message is NOT printed when you've set this adress,
+**      but instead it is passed as an argument. If you call with NULL
+**      for an argument, the ARI handler is disabled again. When the
+**      handler is disabled, MEMWATCH will automatically take the
+**      action specified by mwSetAriAction().
+**  - mwSetAriAction() sets the default ARI return value MEMWATCH should
+**      use if no ARI handler is specified. Defaults to MW_ARI_ABORT.
+**  - mwAriHandler() is an ANSI ARI handler you can use if you like. It
+**      dumps output to stderr, and expects input from stdin.
+**  - mwBreakOut() is called in certain cases when MEMWATCH feels it would
+**      be nice to break into a debugger. If you feel like MEMWATCH, place
+**      an execution breakpoint on this function.
+*/
+void  mwTrace( const char* format_string, ... );
+void  mwPuts( const char* text );
+void  mwSetOutFunc( void (*func)(int) );
+void  mwSetAriFunc( int (*func)(const char*) );
+void  mwSetAriAction( int mw_ari_value );
+int   mwAriHandler( const char* cause );
+void  mwBreakOut( const char* cause );
+
+/*
+** Allocation/deallocation functions
+**  These functions are the ones actually to perform allocations
+**  when running MEMWATCH, for both C and C++ calls.
+**  - mwMalloc() debugging allocator
+**  - mwMalloc_() always resolves to a clean call of malloc()
+**  - mwRealloc() debugging re-allocator
+**  - mwRealloc_() always resolves to a clean call of realloc()
+**  - mwCalloc() debugging allocator, fills with zeros
+**  - mwCalloc_() always resolves to a clean call of calloc()
+**  - mwFree() debugging free. Can only free memory which has
+**      been allocated by MEMWATCH.
+**  - mwFree_() resolves to a) normal free() or b) debugging free.
+**      Can free memory allocated by MEMWATCH and malloc() both.
+**      Does not generate any runtime errors.
+*/
+void* mwMalloc( size_t, const char*, int );
+void* mwMalloc_( size_t );
+void* mwRealloc( void *, size_t, const char*, int );
+void* mwRealloc_( void *, size_t );
+void* mwCalloc( size_t, size_t, const char*, int );
+void* mwCalloc_( size_t, size_t );
+void  mwFree( void*, const char*, int );
+void  mwFree_( void* );
+char* mwStrdup( const char *, const char*, int );
+
+/*
+** Enable/disable precompiler block
+**  This block of defines and if(n)defs make sure that references
+**  to MEMWATCH is completely removed from the code if the MEMWATCH
+**  manifest constant is not defined.
+*/
+#ifndef __MEMWATCH_C
+#ifdef MEMWATCH
+
+#define mwASSERT(exp)   while(mwAssert((int)(exp),#exp,__FILE__,__LINE__))
+#ifndef MW_NOASSERT
+#ifndef ASSERT
+#define ASSERT          mwASSERT
+#endif /* !ASSERT */
+#endif /* !MW_NOASSERT */
+#define mwVERIFY(exp)   while(mwVerify((int)(exp),#exp,__FILE__,__LINE__))
+#ifndef MW_NOVERIFY
+#ifndef VERIFY
+#define VERIFY          mwVERIFY
+#endif /* !VERIFY */
+#endif /* !MW_NOVERIFY */
+#define mwTRACE         mwTrace
+#ifndef MW_NOTRACE
+#ifndef TRACE
+#define TRACE           mwTRACE
+#endif /* !TRACE */
+#endif /* !MW_NOTRACE */
+
+/* some compilers use a define and not a function */
+/* for strdup(). */
+#ifdef strdup
+#undef strdup
+#endif
+
+#define malloc(n)       mwMalloc(n,__FILE__,__LINE__)
+#define strdup(p)       mwStrdup(p,__FILE__,__LINE__)
+#define realloc(p,n)    mwRealloc(p,n,__FILE__,__LINE__)
+#define calloc(n,m)     mwCalloc(n,m,__FILE__,__LINE__)
+#define free(p)         mwFree(p,__FILE__,__LINE__)
+#define CHECK()         mwTest(__FILE__,__LINE__,MW_TEST_ALL)
+#define CHECK_THIS(n)   mwTest(__FILE__,__LINE__,n)
+#define CHECK_BUFFER(b) mwTestBuffer(__FILE__,__LINE__,b)
+#define MARK(p)         mwMark(p,#p,__FILE__,__LINE__)
+#define UNMARK(p)       mwUnmark(p,__FILE__,__LINE__)
+
+#else /* MEMWATCH */
+
+#define mwASSERT(exp)
+#ifndef MW_NOASSERT
+#ifndef ASSERT
+#define ASSERT          mwASSERT
+#endif /* !ASSERT */
+#endif /* !MW_NOASSERT */
+
+#define mwVERIFY(exp)    exp
+#ifndef MW_NOVERIFY
+#ifndef VERIFY
+#define VERIFY          mwVERIFY
+#endif /* !VERIFY */
+#endif /* !MW_NOVERIFY */
+
+/*lint -esym(773,mwTRACE) */
+#define mwTRACE         /*lint -save -e506 */ 1?(void)0:mwDummyTraceFunction /*lint -restore */
+#ifndef MW_NOTRACE
+#ifndef TRACE
+/*lint -esym(773,TRACE) */
+#define TRACE           mwTRACE
+#endif /* !TRACE */
+#endif /* !MW_NOTRACE */
+
+extern void mwDummyTraceFunction(const char *,...);
+/*lint -save -e652 */
+#define mwDoFlush(n)
+#define mwPuts(s)
+#define mwInit()
+#define mwGrab(n)
+#define mwDrop(n)
+#define mwLimit(n)
+#define mwTest(f,l)
+#define mwSetOutFunc(f)
+#define mwSetAriFunc(f)
+#define mwDefaultAri()
+#define mwNomansland()
+#define mwStatistics(f)
+#define mwMark(p,t,f,n)     (p)
+#define mwUnmark(p,f,n)     (p)
+#define mwMalloc(n,f,l)     malloc(n)
+#define mwStrdup(p,f,l)     strdup(p)
+#define mwRealloc(p,n,f,l)  realloc(p,n)
+#define mwCalloc(n,m,f,l)   calloc(n,m)
+#define mwFree(p)           free(p)
+#define mwMalloc_(n)        malloc(n)
+#define mwRealloc_(p,n)     realloc(p,n)
+#define mwCalloc_(n,m)      calloc(n,m)
+#define mwFree_(p)          free(p)
+#define mwAssert(e,es,f,l)
+#define mwVerify(e,es,f,l)  (e)
+#define mwTrace             mwDummyTrace
+#define mwTestBuffer(f,l,b) (0)
+#define CHECK()
+#define CHECK_THIS(n)
+#define CHECK_BUFFER(b)
+#define MARK(p)             (p)
+#define UNMARK(p)           (p)
+/*lint -restore */
+
+#endif /* MEMWATCH */
+#endif /* !__MEMWATCH_C */
+
+#ifdef __cplusplus
+    }
+#endif
+
+#if 0 /* 980317: disabled C++ */
+
+/*
+** C++ support section
+**  Implements the C++ support. Please note that in order to avoid
+**  messing up library classes, C++ support is disabled by default.
+**  You must NOT enable it until AFTER the inclusion of all header
+**  files belonging to code that are not compiled with MEMWATCH, and
+**  possibly for some that are! The reason for this is that a C++
+**  class may implement it's own new() function, and the preprocessor
+**  would substitute this crucial declaration for MEMWATCH new().
+**  You can forcibly deny C++ support by defining MEMWATCH_NOCPP.
+**  To enble C++ support, you must be compiling C++, MEMWATCH must
+**  be defined, MEMWATCH_NOCPP must not be defined, and finally,
+**  you must define 'new' to be 'mwNew', and 'delete' to be 'mwDelete'.
+**  Unlike C, C++ code can begin executing *way* before main(), for
+**  example if a global variable is created. For this reason, you can
+**  declare a global variable of the class 'MemWatch'. If this is
+**  is the first variable created, it will then check ALL C++ allocations
+**  and deallocations. Unfortunately, this evaluation order is not
+**  guaranteed by C++, though the compilers I've tried evaluates them
+**  in the order encountered.
+*/
+#ifdef __cplusplus
+#ifndef __MEMWATCH_C
+#ifdef MEMWATCH
+#ifndef MEMWATCH_NOCPP
+extern int mwNCur;
+extern const char *mwNFile;
+extern int mwNLine;
+class MemWatch {
+public:
+    MemWatch();
+    ~MemWatch();
+    };
+void * operator new(size_t);
+void * operator new(size_t,const char *,int);
+void * operator new[] (size_t,const char *,int);	// hjc 07/16/02
+void operator delete(void *);
+#define mwNew new(__FILE__,__LINE__)
+#define mwDelete (mwNCur=1,mwNFile=__FILE__,mwNLine=__LINE__),delete
+#endif /* MEMWATCH_NOCPP */
+#endif /* MEMWATCH */
+#endif /* !__MEMWATCH_C */
+#endif /* __cplusplus */
+
+#endif /* 980317: disabled C++ */
+
+#endif /* __MEMWATCH_H */
+
+/* EOF MEMWATCH.H */
diff --git a/package.sh b/package.sh
new file mode 100755
index 0000000..48b5d1e
--- /dev/null
+++ b/package.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# package.sh - automated packaging in Guy's developer environment.
+#
+# You may use a command like
+#   dpkg-buildpackage -B -uc -rfakeroot
+# or similar instead
+
+if [ -e ../../scripts/package.sh ]; then
+   ../../scripts/package.sh guymager-beta
+else
+   ../../../scripts/package.sh guymager-beta # when called from the branches or tags directories
+fi
+
+./compileinfo.sh | grep Version | awk -F\" ' { print "Version "$2 } '
+

-- 
debian-forensics/guymager



More information about the forensics-changes mailing list