text: /*----------------------------------------------------------------------------*/
  /* Hobbit                                                                     */
  /*                                                                            */
  /* This is a library module, part of libbbgen.                                */
  /* It contains memory management routines.                                    */
  /*                                                                            */
  /* Copyright (C) 2002-2005 Henrik Storner <henrik@storner.dk>                 */
  /*                                                                            */
  /* This program is released under the GNU General Public License (GPL),       */
  /* version 2. See the file "COPYING" for details.                             */
  /*                                                                            */
  /*----------------------------------------------------------------------------*/
  
  static char rcsid[] = "$Id: memory.c,v 1.4 2005-01-23 14:41:13 henrik Exp $";
  
  #include <ctype.h>
  #include <string.h>
  #include <stdlib.h>
  #include <stdarg.h>
  
  #define LIB_MEMORY_C_COMPILE 1
  
  #include "libbbgen.h"
  
  
  static xmemory_t *mhead = NULL;
  
  void add_to_memlist(void *ptr, size_t memsize)
  {
  	xmemory_t *newitem;
  
  	newitem = (xmemory_t *)malloc(sizeof(xmemory_t));
  	newitem->sdata = ptr;
  	newitem->ssize = memsize;
  	newitem->next = mhead;
  	mhead = newitem;
  }
  
  static void dump_memitems(void)
  {
  	xmemory_t *mwalk;
  
  	for (mwalk = mhead; (mwalk); mwalk = mwalk->next) {
  		errprintf("%8x  : %5d\n", mwalk->sdata, mwalk->ssize);
  	}
  }
  
  static xmemory_t *find_in_memlist(void *ptr)
  {
  	xmemory_t *mwalk = mhead;
  	int found = 0;
  
  	while (mwalk) {
  		found = (((void *)ptr >= (void *)mwalk->sdata) && ((void *)ptr < (void *)(mwalk->sdata + mwalk->ssize)));
  		if (found) return mwalk;
  
  		mwalk = mwalk->next;
  	}
  
  	return NULL;
  }
  
  
  void remove_from_memlist(void *ptr)
  {
  	xmemory_t *mwalk, *mitem;
  	
  	if (ptr == NULL) {
  		errprintf("remove_from_memlist called with NULL pointer\n");
  		dump_memitems();
  		abort();
  	}
  
  	mitem= find_in_memlist(ptr);
  	if (mitem == NULL) {
  		errprintf("remove_from_memlist called with bogus pointer\n");
  		abort();
  	}
  
  	if (mitem == mhead) {
  		mhead = mhead->next;
  		free(mitem);
  	}
  	else {
  		for (mwalk = mhead; (mwalk->next != mitem); mwalk = mwalk->next) ;
  		mwalk->next = mitem->next;
  		free(mitem);
  	}
  }
  
  
  const char *xfreenullstr = "xfree: Trying to free a NULL pointer";
  
  void *xcalloc(size_t nmemb, size_t size)
  {
  	void *result;
  
  	result = calloc(nmemb, size);
  	if (result == NULL) {
  		errprintf("xcalloc: Out of memory!\n");
  		abort();
  	}
  
  	add_to_memlist(result, nmemb*size);
  	return result;
  }
  
  
  void *xmalloc(size_t size)
  {
  	void *result;
  
  	result = malloc(size);
  	if (result == NULL) {
  		errprintf("xmalloc: Out of memory!\n");
  		abort();
  	}
  
  	add_to_memlist(result, size);
  	return result;
  }
  
  
  void *xrealloc(void *ptr, size_t size)
  {
  	void *result;
  	xmemory_t *mitem;
  
  	if (ptr == NULL) {
  		errprintf("xrealloc: Cannot realloc NULL pointer\n");
  		abort();
  	}
  
  	mitem = find_in_memlist(ptr);
  	if (mitem == NULL) {
  		errprintf("xrealloc: Called with bogus pointer\n");
  		abort();
  	}
  
  	result = realloc(ptr, size);
  	if (result == NULL) {
  		errprintf("xrealloc: Out of memory!\n");
  		abort();
  	}
  
  	mitem->sdata = result;
  	mitem->ssize = size;
  	return result;
  }
  
  char *xstrdup(const char *s)
  {
  	char *result;
  
  	if (s == NULL) {
  		errprintf("xstrdup: Cannot dup NULL string\n");
  		abort();
  	}
  
  	result = strdup(s);
  	if (result == NULL) {
  		errprintf("xstrdup: Out of memory\n");
  		abort();
  	}
  
  	add_to_memlist(result, strlen(result)+1);
  	return result;
  }
  
  char *xstrcat(char *dest, const char *src)
  {
  	xmemory_t *dmem;
  	void *allocend, *copyend;
  
  	if (src == NULL) {
  		errprintf("xstrcat: NULL destination\n");
  		abort();
  	}
  
  	if (dest == NULL) {
  		errprintf("xstrcat: NULL destination\n");
  		abort();
  	}
  	dmem = find_in_memlist(dest);
  	if (dmem == NULL) {
  		errprintf("xstrcat: Bogus destination\n");
  		abort();
  	}
  
  	allocend = dmem->sdata + dmem->ssize - 1;
  	copyend = dest + strlen(dest) + strlen(src);
  	if ((void *)copyend > (void *)allocend) {
  		errprintf("xstrcat: Overwrite of %d bytes\n", (copyend - allocend));
  		abort();
  	}
  
  	strcat(dest, src);
  	return dest;
  }
  
  char *xstrncat(char *dest, const char *src, size_t maxlen)
  {
  	xmemory_t *dmem;
  	void *allocend, *copyend;
  
  	if (src == NULL) {
  		errprintf("xstrcat: NULL destination\n");
  		abort();
  	}
  
  	if (dest == NULL) {
  		errprintf("xstrcat: NULL destination\n");
  		abort();
  	}
  	dmem = find_in_memlist(dest);
  	if (dmem == NULL) {
  		errprintf("xstrcat: Bogus destination\n");
  		abort();
  	}
  
  	allocend = dmem->sdata + dmem->ssize - 1;
  	copyend = dest + strlen(dest) + maxlen;
  	if ((void *)copyend > (void *)allocend) {
  		errprintf("xstrncat: Potential overwrite of %d bytes\n", (copyend - allocend));
  		abort();
  	}
  
  	if (strlen(dest) + strlen(src) >= maxlen) {
  		errprintf("xstrncat: destination is not NULL terminated - dst '%s', src '%s', max %d\n", dest, src, maxlen);
  	}
  
  	strncat(dest, src, maxlen);
  	return dest;
  }
  
  char *xstrcpy(char *dest, const char *src)
  {
  	xmemory_t *dmem;
  	void *allocend, *copyend;
  
  	if (src == NULL) {
  		errprintf("xstrcat: NULL destination\n");
  		abort();
  	}
  
  	if (dest == NULL) {
  		errprintf("xstrcat: NULL destination\n");
  		abort();
  	}
  	dmem = find_in_memlist(dest);
  	if (dmem == NULL) {
  		errprintf("xstrcat: Bogus destination\n");
  		abort();
  	}
  
  	allocend = dmem->sdata + dmem->ssize - 1;
  	copyend = dest + strlen(src);
  	if ((void *)copyend > (void *)allocend) {
  		errprintf("xstrcpy: Overwrite of %d bytes\n", (copyend - allocend));
  		abort();
  	}
  
  	strcpy(dest, src);
  	return dest;
  }
  
  char *xstrncpy(char *dest, const char *src, size_t maxlen)
  {
  	xmemory_t *dmem;
  	void *allocend, *copyend;
  
  	if (src == NULL) {
  		errprintf("xstrcat: NULL destination\n");
  		abort();
  	}
  
  	if (dest == NULL) {
  		errprintf("xstrcat: NULL destination\n");
  		abort();
  	}
  	dmem = find_in_memlist(dest);
  	if (dmem == NULL) {
  		errprintf("xstrcat: Bogus destination\n");
  		abort();
  	}
  
  	allocend = dmem->sdata + dmem->ssize - 1;
  	copyend = dest + maxlen;
  	if ((void *)copyend > (void *)allocend) {
  		errprintf("xstrncpy: Potential overwrite of %d bytes\n", (copyend - allocend));
  		abort();
  	}
  
  	if (strlen(src) >= maxlen) {
  		errprintf("xstrncpy: destination is not NULL terminated - dst '%s', src '%s', max %d\n", dest, src, maxlen);
  	}
  
  	strncpy(dest, src, maxlen);
  	return dest;
  }
  
  int xsprintf(char *dest, const char *fmt, ...)
  {
  	va_list args;
  	size_t availablebytes, printedbytes;
  	xmemory_t *dmem;
  
  	if (dest == NULL) {
  		errprintf("xsprintf: NULL destination\n");
  		abort();
  	}
  	dmem = find_in_memlist(dest);
  	if (dmem == NULL) {
  		errprintf("xsprintf: Bogus destination\n");
  		abort();
  	}
  
  	availablebytes = (dmem->sdata + dmem->ssize - dest);
  	va_start(args, fmt);
  	printedbytes = vsnprintf(dest, availablebytes, fmt, args);
  	va_end(args);
  
  	if (printedbytes >= availablebytes) {
  		errprintf("xsprintf: Output was truncated\n");
  		abort();
  	}
  
  	return printedbytes;
  }
  
  