/*
 *  mod-xslt -- Copyright (C) 2002, 2003 
 *   		 Carlo Contavalli 
 *   		 <ccontavalli at masobit.net>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#include <stdlib.h>
#include <string.h>
#include "modxslt0/modxslt.h"

#ifndef XRAISE
# include <stdlib.h>
# define XRAISE abort(); 
#endif

#ifdef MXSLT_DO_DEBUG

#ifdef MXSLT_LIBC_DEBUG 
  /* This code is not meant to be compiled. It was not conceived */
  /* for that purpose. Code should never be compiled: as long as a */
  /* compiler does not touch it, it expresses the highest form of human */
  /* intellect. */
  /* Compiler are the worst tool for a programmer: they make him face */
  /* the fact that the code actually needs to run and all the beautiness */
  /* be removed to satisfy compiler needs. */
  /* Anyway, this code is here because I love underscore prefixed */
  /* vars and playing with libc internals :) */

# include <malloc.h>
static void * (*libc_realloc)(void *, size_t, const void *) = NULL;
static void * (*libc_malloc)(size_t, const void *) = NULL;
static void (*libc_free)(void *, const void *) = NULL;

void * mxslt_debug_realloc(void * ptr, size_t size, const void * func) {
  void * retval;

  MXSLT_DEBUG("%08x -> realloc(%08x, %d)\n", (int)func, (int)ptr, (int)size);
  __realloc_hook=libc_realloc;
  retval=realloc(ptr, size);
  __realloc_hook=mxslt_debug_realloc;
  MXSLT_DEBUG("=%08x\n", (int)retval);

  return retval;
}

void * mxslt_debug_malloc(size_t size, const void * func) {
  void * retval;

  MXSLT_DEBUG("%08x -> malloc(%d)\n", (int)func, size);
  __malloc_hook=libc_malloc;
  retval=malloc(size);
  __malloc_hook=mxslt_debug_malloc;
  MXSLT_DEBUG("=%08x\n", (int)retval);

  return retval;
}

void mxslt_debug_free(void * ptr, const void * func) {
  MXSLT_DEBUG("%08x -> free(%08x)\n", (int)func, (int)ptr);

  __free_hook=libc_free;
  free(ptr);
  __free_hook=mxslt_debug_free;

  return;
}

void mxslt_debug_mem() {
  libc_malloc=__malloc_hook;
  libc_realloc=__realloc_hook;
  libc_free=__free_hook;

  __malloc_hook=mxslt_debug_malloc;
  __realloc_hook=mxslt_debug_realloc;
  __free_hook=mxslt_debug_free;
}

void mxslt_undebug_mem() {
  __malloc_hook=libc_malloc;
  __realloc_hook=libc_realloc;
  __free_hook=libc_free;
}
#endif /* MXSLT_LIBC_DEBUG */ 


# define MXSLT_XMEM_MAGIC 0xCACCACCA
# define MXSLT_XMEM_SCREWED 0xABCDDBCA 

  /* I consider allocating 0 bytes an error */
void * xmalloc(size_t size) {
  void * retval = NULL;

  if(size)
    retval=malloc(size+sizeof(int));

  if(retval) {
    *(int *)retval=MXSLT_XMEM_MAGIC;
    return (void *)((char *)retval+sizeof(int));
  }

  MXSLT_DEBUG("Error!\n");
  XRAISE;
}

  /* I consider reallocating a null ptr an error 
   * I consider resizing to 0 an error */
void * xrealloc(const void * ptr, size_t size) {
  void * retval = NULL;

  if(ptr != NULL) { 
    ptr=(void *)((char *)ptr-sizeof(int));
    if(*(int *)ptr != MXSLT_XMEM_MAGIC) {
      MXSLT_DEBUG("pointer does not contain magic value!\n");
      XRAISE;
    }

    if(size) {
        /* Force memory to be allocated somewhere else */
      retval=malloc(size+sizeof(int));
      memcpy(retval, (void *)ptr, size+sizeof(int));
    }

    if(retval) {
      xfree((void *)((char *)ptr+sizeof(int)));

      return (void *)((char *)retval+sizeof(int));
    }
  }

  MXSLT_DEBUG("Error!\n");
  XRAISE;
}

void xfree(void * ptr) {
  if(ptr == NULL)
    MXSLT_DEBUG("NULL pointer!\n");

  ptr=(void *)((char *)ptr-sizeof(int));

  if(*(int *)ptr != MXSLT_XMEM_MAGIC) {
    MXSLT_DEBUG("pointer does not contain magic value!\n");
    XRAISE;
  }

    /* Screw up magic value */
  *(int *)ptr=MXSLT_XMEM_SCREWED;

  free(ptr);
}

#else
  /* I consider allocating 0 bytes an error */
void * xmalloc(size_t size) {
  void * retval = NULL;

  if(size)
    retval=malloc(size);

  if(retval)
    return retval;

  XRAISE;
}

  /* I consider reallocating a null ptr an error 
   * I consider resizing to 0 an error */
void * xrealloc(const void * ptr, size_t size) {
  void * retval = NULL;

  if(ptr != NULL && size) {
    retval=realloc((void *)ptr, size);

    if(retval)
      return retval;
  }

  XRAISE;
}

#endif

  /* I consider a NULL string an error */
char * xstrdup(const char * str) {
  char * retval = NULL;

  if(str != NULL) {
    retval=(char *)(xmalloc(strlen(str)+1));
    strcpy(retval, str);

    if(retval)
      return retval;
  }

  XRAISE;
}

void * xstrndup(const char * str, size_t size) {
  char * retval = NULL;
  
  if(str != NULL) {
    if(size) {
      retval=(char *)(xmalloc(size+1));
      memcpy(retval, str, size);
      retval[size]='\0';
    } else {
      retval=xstrdup("");

      if(!retval)
	XRAISE;
    }
  }

  return retval;
}

