/*-=-=-=-=-=-=-=-=-=-=-=- 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/rciTask.h"

rciErrorMsg (va_alist)
va_dcl
{
	ERROR_STACK_DESC *estack;
	RCI_DESC *td;
	int code;
	char *format;
	va_list ap;
	int retval;

	va_start(ap);
	td = va_arg(ap, RCI_DESC*);
	code = va_arg(ap, int);
	format = va_arg(ap, char*);

	estack = (ERROR_STACK_DESC*)td->estk;

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

rciNumErrors (td)
RCI_DESC *td;
{
	ERROR_STACK_DESC *estack = (ERROR_STACK_DESC*)td->estk;

	return (estack->num);
}

char *rciGetErrorMsg (td, num)
RCI_DESC *td;
int num;
{
	ERROR_STACK_DESC *estack = (ERROR_STACK_DESC*)td->estk;
	 
	return ((char *)getErrMsg (estack, num));
}

rciGetErrorCode (td, num)
RCI_DESC *td;
int num;
{
	ERROR_STACK_DESC *estack = (ERROR_STACK_DESC*)td->estk;
	 
	return (getErrCode (estack, num));
}

rciSetErrorCode (td, num, value)
RCI_DESC *td;
int num;
int value;
{
	ERROR_STACK_DESC *estack = (ERROR_STACK_DESC*)td->estk;
	 
	return (setErrCode (estack, num, value));
}

rciPopError (td)
RCI_DESC *td;
{
	ERROR_STACK_DESC *estack = (ERROR_STACK_DESC*)td->estk;
	 
	return (popErr (estack));
}

rciClearErrors (td)
RCI_DESC *td;
{
	ERROR_STACK_DESC *estack = (ERROR_STACK_DESC*)td->estk;
	 
	clearErrs (estack);
}

char *rciDumpErrorMsgs (td, buf, size)
RCI_DESC *td;
char *buf;
int size;
{
	ERROR_STACK_DESC *estack = (ERROR_STACK_DESC*)td->estk;

	return (dumpErrMsgs (estack, buf, size));
}

#define EMSG_BUF_SIZE	1024	/* XXX */

rciPrintErrors (td)
RCI_DESC *td;
{
	ERROR_STACK_DESC *estack = (ERROR_STACK_DESC*)td->estk;
	char buf[EMSG_BUF_SIZE];

	/* this function does NOT clear the error stack */
	 
	dumpErrMsgs (estack, buf, EMSG_BUF_SIZE);
	rciPrintf ("%s", buf);
	if (estack->overflow)
	 { rciPrintf ("META-ERROR -- error stack overflow\n");
	 }
	return (1);
}

#if TEST

#include "../h/assignMem.h"

#define TESTMSG1	64
/* This format is assumed to result in a message TESTMSG1 bytes long */
char *testmsg1 =
"%5d 78901234567890123456789012345678901234567890123456789012\n";
#define TESTMSG2	61
/* This format is assumed to result in a message TESTMSG1 bytes long */
char *testmsg2 =
"%5d 789_123456789_123456789_123456789_123456789_123456789\n";

char *longmsg = 
"%5d 789012345678901234567890123456789012345678901234567890*\n\
______789012345678901234567890123456789012345678901234567890*\n\
______789012345678901234567890123456789012345678901234567890*\n";

char longbuf[1024];

main()
{
	int errsize;
	int bufsize;
	int maxerrs;
	int spaceLeft;
	int truncate;
	int k;

	bufsize = EBUFSIZE - (ALIGN_MEM(ebuf) - ebuf);
	errsize = sizeof(ERROR_DESC) + TESTMSG1;
	maxerrs = bufsize/errsize;
	spaceLeft = bufsize%errsize;

	/* fill the error stack error stack */

	if (maxerrs < 4)
	 { printf ("Test program trouble: maxerrors < 4\n");
	   return (1);
	 }
	for (k=0; k<maxerrs; k++)
	 { char *msg;
	   msg = (k & 1) ? testmsg2 : testmsg1;
	   if (!errorMsg (k, msg, k))
	    { printf ("ERROR(1) -- can't place test message %d\n", k);
	      return (1);
	    }
	 }
	/* now check each message */
	for (k=0; k<maxerrs; k++)
	 { if (!checkError (k))
	    { printf ("ERROR(2) -- message %d doesn't check out\n", k);
	      return (1);
	    }
	 }
	/* now check all the messages */
	if (!checkDump(maxerrs))
	 { printf ("ERROR(3) -- checkDump() failed\n");
	   return (1);
	 }
	/* check the number of errors */
	if (numErrors() != k)
	 { printf ("ERROR(4) -- numErrors() returns %d\n", numErrors());
	   return (1);
	 }
	/* now try to push the limit */
	if (spaceLeft >= sizeof(ERROR_DESC))
	 { if (!errorMsg (k, testmsg1, k))
	    { printf ("ERROR(5) -- errorMsg() failed\n");
	      return (1);
	    }
	   k++;
	   if (errorMsg (k, testmsg1, k))
	    { printf ("ERROR(6) -- errorMsg() suceeded\n");
	      return (1);
	    }
	   if (!popError())
	    { printf ("ERROR(7) -- popError() failed\n");
	      return (1);
	    }
	   k--;
	 }
	else
	 { if (errorMsg (k, testmsg1, k))
	    { printf ("ERROR(8) -- errorMsg() suceeded\n");
	      return (1);
	    }
	 }
	/* now test the truncation mechanism. Delete one msg, and 
	   create an error message much longer than the previous ones */
	if (!popError())
	 { printf ("ERROR(9) -- popError() failed\n");
	   return (1);
	 }
	k--;
	if (!errorMsg (k, longmsg, k))
	 { printf ("ERROR(10) -- errorMsg() failed\n");
	   return (1);
	 }
	sprintf (longbuf, longmsg, k);
	/* message should have been truncated. check this */
	truncate = spaceLeft + errsize - sizeof(ERROR_DESC);
	longbuf[truncate-1] = '\0';
	if (strcmp (getErrorMsg (numErrors()-k-1), longbuf) != 0)
	 { printf ("ERROR(11) -- longbuf is different\n");
	   return (1);
	 }
	/* now pop three errors of the stack and test the integrity
	   of the whole things again */
	if (!(popError()) || !(popError()) || !(popError()))
	 { printf ("ERROR(12) -- couldn't pop errors\n");
	   return (1);
	 }
	for (k=0; k<numErrors(); k++)
	 { if (!checkError (k))
	    { printf ("ERROR(13) -- message %d doesn't check out\n", k);
	      return (1);
	    }
	 }
	if (!checkDump(numErrors()))
	 { printf ("ERROR(14) -- checkDump() failed\n");
	   return (1);
	 }
	/* now pop the rest of everything */
	while (numErrors())
	 { if (!popError())
	    { printf ("ERROR(15) -- couldn't pop error\n");
	      return (1);
	    }
	 }
	if (popError())
	 { printf ("ERROR(16) -- pop error suceeded\n");
	   return (1);
	 }
	for (k=0; k<maxerrs; k++)
	 { char *msg;
	   msg = (k & 1) ? testmsg2 : testmsg1;
	   if (!errorMsg (k, msg, k))
	    { printf ("ERROR(17) -- can't place test message %d\n", k);
	      return (1);
	    }
	 }
	clearErrors();
	for (k=0; k<maxerrs; k++)
	 { char *msg;
	   msg = (k & 1) ? testmsg2 : testmsg1;
	   if (!errorMsg (k, msg, k))
	    { printf ("ERROR(18) -- can't place test message %d\n", k);
	      return (1);
	    }
	 }
	printErrors();
	printf ("\nROUTINES OK\n\n");	
	return (0);
}

checkError (k)
int k;
{
	char buf[1024];
	
	sprintf (buf, (k & 1) ? testmsg2 : testmsg1, k);
	if (strcmp (buf, getErrorMsg (numErrors()-k-1)) != 0)
	 { return (0);
	 }
	if (getErrorCode (numErrors()-k-1) != k)
	 { return (0);
	 }
	return (1);
}
	
checkDump (maxerrs)
int maxerrs;
{
	int k;
	char buf[1024];
	char checkbuf[EBUFSIZE*2];
	char dumpbuf[EBUFSIZE*2];

	checkbuf[0] = '\0';

	for (k=maxerrs-1; k>=0; k--)
	 { sprintf (buf, (k & 1) ? testmsg2 : testmsg1, k);
	   strcat (checkbuf, buf);
	 }
	dumpErrorMsgs (dumpbuf, EBUFSIZE*2);
	if (strcmp (checkbuf, dumpbuf) != 0)
	 { return (0);
	 }
	return (1);
}

#endif

