summaryrefslogtreecommitdiff
path: root/reference/C/CONTRIB/SNIP/mem.c
diff options
context:
space:
mode:
Diffstat (limited to 'reference/C/CONTRIB/SNIP/mem.c')
-rwxr-xr-xreference/C/CONTRIB/SNIP/mem.c681
1 files changed, 681 insertions, 0 deletions
diff --git a/reference/C/CONTRIB/SNIP/mem.c b/reference/C/CONTRIB/SNIP/mem.c
new file mode 100755
index 0000000..493ae2b
--- /dev/null
+++ b/reference/C/CONTRIB/SNIP/mem.c
@@ -0,0 +1,681 @@
+/*
+** This is a copyrighted work which is functionally identical to work
+** originally published in Micro Cornucopia magazine (issue #52, March-April,
+** 1990) and is freely licensed by the author, Walter Bright, for any use.
+*/
+
+/*_ mem.c Fri Jan 26 1990 Modified by: Walter Bright */
+/* $Header: /home/cvs/c_cpp_reference/reference/C/CONTRIB/SNIP/mem.c,v 1.1.1.1 2000/02/24 23:01:18 tasin Exp $ */
+/* Memory management package */
+
+#if defined(VAX11C)
+#define __FILE__ "mem.c"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <io.h>
+
+#ifndef MEM_H
+#include "mem.h"
+#endif
+
+#ifndef assert
+#include <assert.h>
+#endif
+
+#if defined(_MSC_VER)
+#include <dos.h>
+#endif
+
+#if !defined(VAX11C)
+#ifdef BSDUNIX
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+#else
+extern char *strcpy(),*memcpy();
+extern int strlen();
+#endif /* VAX11C */
+
+int mem_inited = 0; /* != 0 if initialized */
+
+static int mem_behavior = MEM_ABORTMSG;
+static int (*fp)() = NULL; /* out-of-memory handler */
+static int mem_count; /* # of allocs that haven't been free'd */
+static int mem_scount; /* # of sallocs that haven't been free'd */
+static int near mem_exception(); /* called when out of memory */
+
+/* Determine where to send error messages */
+#ifdef MSDOS
+#define ferr stdout /* stderr can't be redirected with MS-DOS */
+#else
+#define ferr stderr
+#endif
+
+/*******************************/
+
+void mem_setexception(flag,handler_fp)
+#if __cplusplus
+enum MEM_E flag;
+#else
+int flag;
+#endif
+int (*handler_fp)();
+{
+ mem_behavior = flag;
+ fp = (mem_behavior == MEM_CALLFP) ? handler_fp : 0;
+#if MEM_DEBUG
+ assert(0 <= flag && flag <= MEM_RETRY);
+#endif
+}
+
+/*************************
+ * This is called when we're out of memory.
+ * Returns:
+ * 1: try again to allocate the memory
+ * 0: give up and return NULL
+ */
+
+static int near mem_exception()
+{ int behavior;
+
+ behavior = mem_behavior;
+ while (1)
+ {
+ switch (behavior)
+ {
+ case MEM_ABORTMSG:
+#if defined(MSDOS) || defined(__OS2__)
+ /* Avoid linking in buffered I/O */
+ { static char msg[] = "Fatal error: out of memory\r\n";
+
+ write(1,msg,sizeof(msg) - 1);
+ }
+#else
+ fputs("Fatal error: out of memory\n",ferr);
+#endif
+ /* FALL-THROUGH */
+ case MEM_ABORT:
+ exit(EXIT_FAILURE);
+ /* NOTREACHED */
+ case MEM_CALLFP:
+ assert(fp);
+ behavior = (*fp)();
+ break;
+ case MEM_RETNULL:
+ return 0;
+ case MEM_RETRY:
+ return 1;
+ default:
+ assert(0);
+ }
+ }
+}
+
+/****************************/
+
+#if MEM_DEBUG
+
+#undef mem_strdup
+
+char *mem_strdup(s)
+const char *s;
+{
+ return mem_strdup_debug(s,__FILE__,__LINE__);
+}
+
+char *mem_strdup_debug(s,file,line)
+char *file;
+const char *s;
+int line;
+{
+ char *p;
+
+ p = s
+ ? (char *) mem_malloc_debug((unsigned) strlen(s) + 1,file,line)
+ : NULL;
+ return p ? strcpy(p,s) : p;
+}
+#else
+char *mem_strdup(s)
+const char *s;
+{
+ char *p;
+
+ p = s ? (char *) mem_malloc((unsigned) strlen(s) + 1) : NULL;
+ return p ? strcpy(p,s) : p;
+}
+
+#endif /* MEM_DEBUG */
+
+#ifdef MEM_DEBUG
+
+static long mem_maxalloc; /* max # of bytes allocated */
+static long mem_numalloc; /* current # of bytes allocated */
+
+#define BEFOREVAL 0x12345678 /* value to detect underrun */
+#define AFTERVAL 0x87654321 /* value to detect overrun */
+
+#if SUN || SUN386
+static long afterval = AFTERVAL; /* so we can do &afterval */
+#endif
+
+/* The following should be selected to give maximum probability that */
+/* pointers loaded with these values will cause an obvious crash. On */
+/* Unix machines, a large value will cause a segment fault. */
+/* MALLOCVAL is the value to set malloc'd data to. */
+
+#if MSDOS || __OS2__
+#define BADVAL 0xFF
+#define MALLOCVAL 0xEE
+#else
+#define BADVAL 0x7A
+#define MALLOCVAL 0xEE
+#endif
+
+/* Disable mapping macros */
+#undef mem_malloc
+#undef mem_calloc
+#undef mem_realloc
+#undef mem_free
+
+/* Create a list of all alloc'ed pointers, retaining info about where */
+/* each alloc came from. This is a real memory and speed hog, but who */
+/* cares when you've got obscure pointer bugs. */
+
+static struct mem_debug
+{ struct mh
+ { struct mem_debug *Mnext; /* next in list */
+ struct mem_debug *Mprev; /* previous value in list */
+ char *Mfile; /* filename of where allocated */
+ int Mline; /* line number of where allocated */
+ unsigned Mnbytes; /* size of the allocation */
+ long Mbeforeval; /* detect underrun of data */
+ } m;
+ char data[1]; /* the data actually allocated */
+} mem_alloclist =
+{
+ { (struct mem_debug *) NULL,
+ (struct mem_debug *) NULL,
+ "noname",
+ 11111,
+ 0,
+ BEFOREVAL
+ },
+ AFTERVAL
+};
+
+/* Convert from a void *to a mem_debug struct. */
+#define mem_ptrtodl(p) ((struct mem_debug *) ((char *)p - sizeof(struct mh)))
+
+/* Convert from a mem_debug struct to a mem_ptr. */
+#define mem_dltoptr(dl) ((void *) &((dl)->data[0]))
+
+#define next m.Mnext
+#define prev m.Mprev
+#define file m.Mfile
+#define line m.Mline
+#define nbytes m.Mnbytes
+#define beforeval m.Mbeforeval
+
+/*****************************
+ * Set new value of file,line
+ */
+
+void mem_setnewfileline(ptr,fil,lin)
+void *ptr;
+char *fil;
+int lin;
+{
+ struct mem_debug *dl;
+
+ dl = mem_ptrtodl(ptr);
+ dl->file = fil;
+ dl->line = lin;
+}
+
+/****************************
+ * Print out struct mem_debug.
+ */
+
+static void near mem_printdl(dl)
+struct mem_debug *dl;
+{
+#if LPTR
+ fprintf(ferr,"alloc'd from file '%s' line %d nbytes %d ptr x%lx\n",
+ dl->file,dl->line,dl->nbytes,mem_dltoptr(dl));
+#else
+ fprintf(ferr,"alloc'd from file '%s' line %d nbytes %d ptr x%x\n",
+ dl->file,dl->line,dl->nbytes,mem_dltoptr(dl));
+#endif
+}
+
+/****************************
+ * Print out file and line number.
+ */
+
+static void near mem_fillin(fil,lin)
+char *fil;
+int lin;
+{
+ fprintf(ferr,"File '%s' line %d\n",fil,lin);
+ fflush(ferr);
+}
+
+/****************************
+ * If MEM_DEBUG is not on for some modules, these routines will get
+ * called.
+ */
+
+void *mem_calloc(u)
+unsigned u;
+{
+ return mem_calloc_debug(u,__FILE__,__LINE__);
+}
+
+void *mem_malloc(u)
+unsigned u;
+{
+ return mem_malloc_debug(u,__FILE__,__LINE__);
+}
+
+void *mem_realloc(p,u)
+void *p;
+unsigned u;
+{
+ return mem_realloc_debug(p,u,__FILE__,__LINE__);
+}
+
+void mem_free(p)
+void *p;
+{
+ mem_free_debug(p,__FILE__,__LINE__);
+}
+
+
+/**************************/
+
+void mem_freefp(p)
+void *p;
+{
+ mem_free(p);
+}
+
+/***********************
+ * Debug versions of mem_calloc(), mem_free() and mem_realloc().
+ */
+
+void *mem_malloc_debug(n,fil,lin)
+unsigned n;
+char *fil;
+int lin;
+{ void *p;
+
+ p = mem_calloc_debug(n,fil,lin);
+ if (p)
+ memset(p,MALLOCVAL,n);
+ return p;
+}
+
+void *mem_calloc_debug(n,fil,lin)
+unsigned n;
+char *fil;
+int lin;
+{
+ struct mem_debug *dl;
+
+ do
+ dl = (struct mem_debug *)
+ calloc(sizeof(*dl) + n + sizeof(AFTERVAL) - 1,1);
+ while (dl == NULL && mem_exception());
+ if (dl == NULL)
+ {
+#if 0
+ printf("Insufficient memory for alloc of %d at ",n);
+ mem_fillin(fil,lin);
+ printf("Max allocated was: %ld\n",mem_maxalloc);
+#endif
+ return NULL;
+ }
+ dl->file = fil;
+ dl->line = lin;
+ dl->nbytes = n;
+ dl->beforeval = BEFOREVAL;
+#if SUN || SUN386 /* bus error if we store a long at an odd address */
+ memcpy(&(dl->data[n]),&afterval,sizeof(AFTERVAL));
+#else
+ *(long *) &(dl->data[n]) = AFTERVAL;
+#endif
+
+ /* Add dl to start of allocation list */
+ dl->next = mem_alloclist.next;
+ dl->prev = &mem_alloclist;
+ mem_alloclist.next = dl;
+ if (dl->next != NULL)
+ dl->next->prev = dl;
+
+ mem_count++;
+ mem_numalloc += n;
+ if (mem_numalloc > mem_maxalloc)
+ mem_maxalloc = mem_numalloc;
+ return mem_dltoptr(dl);
+}
+
+void mem_free_debug(ptr,fil,lin)
+void *ptr;
+char *fil;
+int lin;
+{
+ struct mem_debug *dl;
+
+ if (ptr == NULL)
+ return;
+#if 0
+ { fprintf(ferr,"Freeing NULL pointer at ");
+ goto err;
+ }
+#endif
+ if (mem_count <= 0)
+ { fprintf(ferr,"More frees than allocs at ");
+ goto err;
+ }
+ dl = mem_ptrtodl(ptr);
+ if (dl->beforeval != BEFOREVAL)
+ {
+#if LPTR
+ fprintf(ferr,"Pointer x%lx underrun\n",ptr);
+#else
+ fprintf(ferr,"Pointer x%x underrun\n",ptr);
+#endif
+ goto err2;
+ }
+#if SUN || SUN386 /* Bus error if we read a long from an odd address */
+ if (memcmp(&dl->data[dl->nbytes],&afterval,sizeof(AFTERVAL)) != 0)
+#else
+ if (*(long *) &dl->data[dl->nbytes] != AFTERVAL)
+#endif
+ {
+#if LPTR
+ fprintf(ferr,"Pointer x%lx overrun\n",ptr);
+#else
+ fprintf(ferr,"Pointer x%x overrun\n",ptr);
+#endif
+ goto err2;
+ }
+ mem_numalloc -= dl->nbytes;
+ if (mem_numalloc < 0)
+ { fprintf(ferr,"error: mem_numalloc = %ld, dl->nbytes = %d\n",
+ mem_numalloc,dl->nbytes);
+ goto err2;
+ }
+
+ /* Remove dl from linked list */
+ if (dl->prev)
+ dl->prev->next = dl->next;
+ if (dl->next)
+ dl->next->prev = dl->prev;
+
+ /* Stomp on the freed storage to help detect references */
+ /* after the storage was freed. */
+ memset((void *) dl,BADVAL,sizeof(*dl) + dl->nbytes);
+ mem_count--;
+
+ /* Some compilers can detect errors in the heap. */
+#if defined(DLC)
+ { int i;
+ i = free(dl);
+ assert(i == 0);
+ }
+#else
+ free((void *) dl);
+#endif
+ return;
+
+err2:
+ mem_printdl(dl);
+err:
+ fprintf(ferr,"free'd from ");
+ mem_fillin(fil,lin);
+ assert(0);
+ /* NOTREACHED */
+}
+
+/*******************
+ * Debug version of mem_realloc().
+ */
+
+void *mem_realloc_debug(oldp,n,fil,lin)
+void *oldp;
+unsigned n;
+char *fil;
+int lin;
+{ void *p;
+ struct mem_debug *dl;
+
+ if (n == 0)
+ { mem_free_debug(oldp,fil,lin);
+ p = NULL;
+ }
+ else if (oldp == NULL)
+ p = mem_malloc_debug(n,fil,lin);
+ else
+ {
+ p = mem_malloc_debug(n,fil,lin);
+ if (p != NULL)
+ {
+ dl = mem_ptrtodl(oldp);
+ if (dl->nbytes < n)
+ n = dl->nbytes;
+ memcpy(p,oldp,n);
+ mem_free_debug(oldp,fil,lin);
+ }
+ }
+ return p;
+}
+
+/***************************/
+
+void mem_check()
+{ register struct mem_debug *dl;
+
+ for (dl = mem_alloclist.next; dl != NULL; dl = dl->next)
+ mem_checkptr(mem_dltoptr(dl));
+}
+
+/***************************/
+
+void mem_checkptr(p)
+register void *p;
+{ register struct mem_debug *dl;
+
+ for (dl = mem_alloclist.next; dl != NULL; dl = dl->next)
+ {
+ if (p >= (void *) &(dl->data[0]) &&
+ p < (void *)((char *)dl + sizeof(struct mem_debug)-1 + dl->nbytes))
+ goto L1;
+ }
+ assert(0);
+
+L1:
+ dl = mem_ptrtodl(p);
+ if (dl->beforeval != BEFOREVAL)
+ {
+#if LPTR
+ fprintf(ferr,"Pointer x%lx underrun\n",p);
+#else
+ fprintf(ferr,"Pointer x%x underrun\n",p);
+#endif
+ goto err2;
+ }
+#if SUN || SUN386 /* Bus error if we read a long from an odd address */
+ if (memcmp(&dl->data[dl->nbytes],&afterval,sizeof(AFTERVAL)) != 0)
+#else
+ if (*(long *) &dl->data[dl->nbytes] != AFTERVAL)
+#endif
+ {
+#if LPTR
+ fprintf(ferr,"Pointer x%lx overrun\n",p);
+#else
+ fprintf(ferr,"Pointer x%x overrun\n",p);
+#endif
+ goto err2;
+ }
+ return;
+
+err2:
+ mem_printdl(dl);
+ assert(0);
+}
+
+#else
+
+/***************************/
+
+void *mem_malloc(numbytes)
+unsigned numbytes;
+{ void *p;
+
+ if (numbytes == 0)
+ return NULL;
+ while (1)
+ {
+ p = malloc(numbytes);
+ if (p == NULL)
+ { if (mem_exception())
+ continue;
+ }
+ else
+ mem_count++;
+ break;
+ }
+ /*printf("malloc(%d) = x%lx\n",numbytes,p);*/
+ return p;
+}
+
+/***************************/
+
+void *mem_calloc(numbytes)
+unsigned numbytes;
+{ void *p;
+
+ if (numbytes == 0)
+ return NULL;
+ while (1)
+ {
+ p = calloc(numbytes,1);
+ if (p == NULL)
+ { if (mem_exception())
+ continue;
+ }
+ else
+ mem_count++;
+ break;
+ }
+ /*printf("calloc(%d) = x%lx\n",numbytes,p);*/
+ return p;
+}
+
+/***************************/
+
+void *mem_realloc(oldmem_ptr,newnumbytes)
+void *oldmem_ptr;
+unsigned newnumbytes;
+{ void *p;
+
+ if (oldmem_ptr == NULL)
+ p = mem_malloc(newnumbytes);
+ else if (newnumbytes == 0)
+ { mem_free(oldmem_ptr);
+ p = NULL;
+ }
+ else
+ {
+ do
+ p = realloc(oldmem_ptr,newnumbytes);
+ while (p == NULL && mem_exception());
+ }
+ /*printf("realloc(x%lx,%d) = x%lx\n",oldmem_ptr,newnumbytes,p);*/
+ return p;
+}
+
+/***************************/
+
+void mem_free(ptr)
+void *ptr;
+{
+ /*printf("free(x%lx)\n",ptr);*/
+ if (ptr != NULL)
+ { assert(mem_count > 0);
+ mem_count--;
+#if DLC
+ { int i;
+
+ i = free(ptr);
+ assert(i == 0);
+ }
+#else
+ free(ptr);
+#endif
+ }
+}
+
+#endif /* MEM_DEBUG */
+
+/***************************/
+
+void mem_init()
+{
+ if (mem_inited == 0)
+ { mem_count = 0;
+#if MEM_DEBUG
+ mem_numalloc = 0;
+ mem_maxalloc = 0;
+ mem_alloclist.next = NULL;
+#endif
+#if defined(__ZTC__) || defined(__SC__)
+ /* Necessary if mem_sfree() calls free() before any */
+ /* calls to malloc(). */
+ free(malloc(1)); /* initialize storage allocator */
+#endif
+ mem_inited++;
+ }
+}
+
+/***************************/
+
+void mem_term()
+{
+
+ if (mem_inited)
+ {
+#if MEM_DEBUG
+ register struct mem_debug *dl;
+
+ for (dl = mem_alloclist.next; dl; dl = dl->next)
+ { fprintf(ferr,"Unfreed pointer: ");
+ mem_printdl(dl);
+ }
+#if 0
+ fprintf(ferr,"Max amount ever allocated == %ld bytes\n",
+ mem_maxalloc);
+#endif
+#else
+ if (mem_count)
+ fprintf(ferr,"%d unfreed items\n",mem_count);
+ if (mem_scount)
+ fprintf(ferr,"%d unfreed s items\n",mem_scount);
+#endif /* MEM_DEBUG */
+ assert(mem_count == 0 && mem_scount == 0);
+ mem_inited = 0;
+ }
+}
+
+#undef next
+#undef prev
+#undef file
+#undef line
+#undef nbytes
+#undef beforeval
+