/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1987, 1991 by John E. Lloyd.			    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

#include <stdio.h>
#include <varargs.h>
#include "../h/cdefs.h"
#include "../h/errorStack.h"
#include "../h/assignMem.h"

/* =-=-=-=-=-= the basic (low level) error management routines =-=-=-=-=-= 

	Posting error messages:

	errMsg (estk, code, format, args)

	Examining errors:

	getErrCode (estk, num)
	getErrMsg (estk, num)
	setErrCode (estk, num, value)

	Clearing errors:

	popErr (estk)
	clearErrs (estk)

  -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */

#define MAXSTRING	1024

static char *vprintToBuf(str, size, fmt, ap)
char *str;
int size;
char *fmt;
va_list ap;
{
	/* Special hack sprintf() that (1) restricts the size of the
	   printed string, and (2) places it at the RIGHT of the buffer.

	   There is a real problem with this routine right now in that
	   if the output message exceeds 1024 bytes, we die. The
	   sprintf() interface doesn't allow any easy way around this
	   (yet !?).

	 */

	char buf[MAXSTRING];	/* XXX */
	int len;

	vsnprintf(buf, MAXSTRING, fmt, ap);
	buf[MAXSTRING-1] = '\0';
	if ((len = (strlen(buf)+1)) > size)
	 { buf[size-1] = '\0';
	   len = size;
	 }
	strcpy (str+size-len, buf);
	return (str+size-len);
}

ERROR_STACK_DESC *errStackInit (estk, pool, size)
ERROR_STACK_DESC *estk;
char *pool;
int size;
{
	if (pool + size < ALIGN_MEM(pool))
	 { estk->desc = NULL;
	   estk->top = NULL;
	   estk->msgPtr = NULL;
	   return (NULL);
	 }
	estk->desc = (ERROR_DESC*)ALIGN_MEM(pool);
	estk->top = pool + size;
	estk->msgPtr = estk->top;
	estk->overflow = 0;
	estk->num = 0;
	return (estk);
}

errMsg (va_alist)
va_dcl
{
	ERROR_STACK_DESC *estk;
	int code;
	char *format;
	va_list ap;
	int retval;

	va_start(ap);
	estk = va_arg(ap, ERROR_STACK_DESC*);
	code = va_arg(ap, int);
	format = va_arg(ap, char*);

	retval = verrMsg (estk, code, format, ap);
	va_end(ap);
	return (retval);
}

verrMsg (estk, code, format, ap)
ERROR_STACK_DESC *estk;
int code;
char *format;
va_list ap;
{
	int spaceLeft;
	int k;

	k = estk->num;
	if ((spaceLeft = estk->msgPtr - (char*)&estk->desc[k+1]) < 0)
	 { estk->overflow = 1;
	   return (0);
	 }
	estk->desc[k].code = code;
	estk->desc[k].prevMsg = estk->msgPtr;
	if (format && spaceLeft > 2)
	 { char *ptr;
	   ptr = vprintToBuf (estk->msgPtr-spaceLeft, spaceLeft, format, ap);
	   estk->desc[k].msg = ptr;
	   estk->msgPtr = ptr;
	 }
	else
	 { estk->desc[k].msg = NULL;
	 }
	estk->num++;
	return (1);
}

char *getErrMsg (estk, k)
ERROR_STACK_DESC *estk;
int k;
{
	if (k < estk->num)
	 { return (estk->desc[estk->num-k-1].msg);
	 }
 	else
	 { return (NULL);
	 }
}

char *dumpErrMsgs (estk, buf, size)
ERROR_STACK_DESC *estk;
char *buf;
int size;
{
	register char *to;
	register char *from;
	register char *toEnd;
	register char *fromEnd;

	to = buf;
	toEnd = buf + size - 1;
	from = estk->msgPtr;
	fromEnd = estk->top;

	while (to != toEnd && from != fromEnd)
	 { if (*from == '\0')
	    { from++;	/* ignore end-of-string characters */
	    }
	   else
	    { *to++ = *from++;
	    }
	 }
	*to = '\0';
	return (to);		
}

getErrCode (estk, k)
ERROR_STACK_DESC *estk;
int k;
{
	if (k < estk->num)
	 { return (estk->desc[estk->num-k-1].code);
	 }
 	else
	 { return (0);
	 }
}

setErrCode (estk, k, e)
ERROR_STACK_DESC *estk;
int k, e;
{
	if (k < estk->num)
	 { estk->desc[estk->num-k-1].code = e;
	   return (1);
	 }
 	else
	 { return (0);
	 }
}

popErr (estk)
ERROR_STACK_DESC *estk;
{
	char *ptr;

	if (estk->num)
	 { estk->msgPtr = estk->desc[--estk->num].prevMsg;
	   return (1);
	 }
	else
	 { return (0);
	 }
}

clearErrs (estk)
ERROR_STACK_DESC *estk;
{
	estk->msgPtr = estk->top;
	estk->num = 0;
 	estk->overflow = 0;
}
