/*
 *	Copyright (C) 1992	TGV, Incorporated
 *
 *	Wrappers for memory management
 */
#include <stdio.h>
#include <ssdef.h>

/*
 *	Here is where we define our own memory allocation routines
 *	well, sort of.  We want to use the routines LIB$VM_*, but if
 *	it is not possible under (and its not under VMS 5.1), we will
 *	use the VAX C RTLs instead.
 *
 *	The routines we will define are
 *
 *		o mm_malloc
 *		o mm_calloc
 *		o mm_realloc
 *		o mm_free
 *		o mm_cfree
 */

static int Find_Image_Symbol();
static int SIG_TO_RET();

char *mm_malloc(size)
int size;
{
	static char *(*m_alloc)() = NULL;
	static int m_alloc_chk = 0;
	int Status;

	/*
	 *	if m_alloc has not been defined.  Try to locate the
	 *	image LIB$VM_MALLOC in SYS$SHARE:LIBRTL.EXE.  If we
	 *	cannot locate it then use the VAX C RTL routines.
	 */

	if (!m_alloc_chk) {
		Status = Find_Image_Symbol("LIBRTL", "LIB$VM_MALLOC",
						&m_alloc);
		m_alloc_chk++;
	}

	if (m_alloc)
		return (char *)(*m_alloc)(size);
	else
		return (char *)malloc(size);
}

char *mm_calloc(n, size)
int n;
int size;
{
	static char *(*c_alloc)() = NULL;
	static int c_alloc_chk = 0;
	int Status;

	/*
	 *	if c_alloc has not been defined.  Try to locate the
	 *	image LIB$VM_CALLOC in SYS$SHARE:LIBRTL.EXE.  If we
	 *	cannot locate it then use the VAX C RTL routines.
	 */

	if (!c_alloc_chk) {
		Status = Find_Image_Symbol("LIBRTL", "LIB$VM_CALLOC",
						&c_alloc);
		c_alloc_chk++;
	}

	if (c_alloc)
		return (char *)(*c_alloc)(n, size);
	else
		return (char *)calloc(n, size);
}

char *mm_realloc(ptr, size)
char *ptr;
int size;
{
	static char *(*re_alloc)() = NULL;
	static int re_alloc_chk = 0;
	int Status;

	/*
	 *	if re_alloc has not been defined.  Try to locate the
	 *	image LIB$VM_REALLOC in SYS$SHARE:LIBRTL.EXE.  If we
	 *	cannot locate it then use the VAX C RTL routines.
	 */

	if (!re_alloc_chk) {
		Status = Find_Image_Symbol("LIBRTL", "LIB$VM_REALLOC",
						&re_alloc);
		re_alloc_chk++;
	}

	if (re_alloc)
		return (char *)(*re_alloc)(ptr, size);
	else
		return (char *)realloc(ptr, size);
}

void mm_free(ptr)
char *ptr;
{
	static void (*m_free)() = NULL;
	static int m_free_chk = 0;
	int Status;

	/*
	 *	if m_free has not been defined.  Try to locate the
	 *	image LIB$VM_FREE in SYS$SHARE:LIBRTL.EXE.  If we
	 *	cannot locate it then use the VAX C RTL routines.
	 */

	if (!m_free_chk) {
		Status = Find_Image_Symbol("LIBRTL", "LIB$VM_FREE",
						&m_free);
		m_free_chk++;
	}

	if (m_free)
		(*m_free)(ptr);
	else
		free(ptr);
}

void mm_cfree(ptr)
char *ptr;
{
	static void (*c_free)() = NULL;
	static int c_free_chk = 0;
	int Status;

	/*
	 *	if c_free has not been defined.  Try to locate the
	 *	image LIB$VM_FREE in SYS$SHARE:LIBRTL.EXE.  If we
	 *	cannot locate it then use the VAX C RTL routines.
	 */

	if (!c_free_chk) {
		Status = Find_Image_Symbol("LIBRTL", "LIB$VM_FREE",
						&c_free);
		c_free_chk++;
	}

	if (c_free)
		(*c_free)(ptr);
	else
		cfree(ptr);
}

static int Find_Image_Symbol(Image, Symbol, Value)
char *Image, *Symbol;
int *Value;
{
	struct {int len; char *buf;} ImageDsc, SymbolDsc;
	int Status;

	/*
	 *	Return all errors as statuses, never allow
	 *	LIB$FIND_IMAGE_SYMBOL to signal.
	 */

	(void) LIB$ESTABLISH(SIG_TO_RET);

	ImageDsc.len = strlen(ImageDsc.buf=Image);
	SymbolDsc.len = strlen(SymbolDsc.buf=Symbol);
	Status = LIB$FIND_IMAGE_SYMBOL(&ImageDsc, &SymbolDsc, Value);
	return(Status);
}

/*
 *  This is a special version of LIB$SIG_TO_RET which is a little
 *  smarter about decoding the double-condition signals from
 *  LIB$FIND_IMAGE_SYMBOL
 *
 *  One of the signals signal array looks like:
 *
 *	00000006	# of args
 *	001512BA	LIB$_ACTIMAGE
 *	00000001	    1 arg
 *	????????	    Descriptor to image name
 *	********	Real reason
 *	????????	PC
 *	????????	PSL
 */

#define CHF$L_SIG_NAME 4
#define CHF$L_MCH_SAVR0 12

static int SIG_TO_RET(Sig_Args, Mch_Args)
int Sig_Args[];
int Mch_Args[];
{
	int Status;

	if (Sig_Args[CHF$L_SIG_NAME/4] == SS$_UNWIND) return(SS$_NORMAL);

	/*
	 * Copy condition value to saved image of R0
	 */

	Status = Sig_Args[CHF$L_SIG_NAME/4];
	if (((Status&0x1fff0000) == 0x150000) && Sig_Args[0] >= 6) {
	    Status = Sig_Args[Sig_Args[2]+3];
	}
	Mch_Args[CHF$L_MCH_SAVR0/4] = Status;

	/*
	 * Set to unwind stack using default depth and default new PC,
	 * namely return to caller of the procedure which established the handler
	 */

	return(SYS$UNWIND(0,0));
}
