/********** gpmmonitor.c **************************************************/

#define GPMMONITOR_C_

#include "gpmdefs.h"
#include "gpm.h"
#include "gpmmain.h"
#include "gpmmonitor.h"

static void ItemMacro();
static void Item();

static char *CloserMissing="Missing one or more %c.\n";
static char *monitor_hdr="\nMONITOR: ";


#ifdef DEBUG_MACROS
void MonitorExit()
{
	fprintf(stderr,"%sEXIT called from within input.\n",monitor_hdr);
	PrintErrorLine();
	exit(EXIT_EXIT);
}
#endif

void MonitorNotABuiltin()
{
	fprintf(stderr,"%sNot a builtin. Probably internal error.\n",monitor_hdr);
	exit(EXIT_INTERNAL);
}

void MonitorBadDEF(int i)
{
	fprintf(stderr,"%s%s argument to DEF is missing.\n",monitor_hdr,
		(i==1)?"first":"second");
	Monitor11();
}

void MonitorBadSUB()
{
	fprintf(stderr,"%sBad call to SUB.\n",monitor_hdr);
	Monitor11();
}


void Monitor1()
{
  fprintf(stderr, "%sUnmatched %c in definition of ",monitor_hdr, ApplyClose);
  ItemMacro(P + 2);
  fprintf(stderr, "\nIf this had been quoted the result would be ");
  fprintf(stderr, "\n");
}

void Monitor2()
{
  fprintf(stderr, "%sUnquoted %c in argument list of ",monitor_hdr, ArgStart);
  ItemMacro(F + 2);
  PrintErrorLine();
  fprintf(stderr, "\nIf this had been quoted the result would be ");
  fprintf(stderr, "\n");
}

void Monitor3()
{
  fprintf(stderr, "%sImpossible argument number in definition of ",monitor_hdr);
  ItemMacro(P + 2);
  Monitor11();
}

#ifdef EMPTYARG
void Monitor4()
{
  fprintf(stderr, "%sNo argument %c%c in call for ",monitor_hdr,ArgStart,A);
  ItemMacro(P + 2);
  PrintErrorLine();
}
#else
void Monitor4()
{
  fprintf(stderr, "%sNo argument %c%c",monitor_hdr,ArgStart,A);
  OutputPtr = OutputStream;
  Load();
  fprintf(stderr, " in call for ");
  ItemMacro(P + 2);
  Monitor11();
}
#endif

void Monitor5()
{
  fprintf(stderr, "%sTerminator in ",monitor_hdr);
  if (InputPtr == InputStream) {
    fprintf(stderr, "input stream. Probably machine error.");
    Monitor11();
  }
  fprintf(stderr, "argument list for ");
  Item(F + 2);
  fprintf(stderr, "\nProbably due to a %c missing from the definition of ", ApplyClose);
  Item(P + 2);
  PrintErrorLine();
  fprintf(stderr, "\nIf a final %c is added the result is ", ApplyClose);
  fprintf(stderr, "\n");
  InputPtr = InputPtr - 1;
}

void MonitorMacroNotFound()
{
  fprintf(stderr, "%sUndefined Name ",monitor_hdr);
  ItemMacro(W);
  Monitor11();
}

void Monitor8()
{
  fprintf(stderr, "%sUnmatched %c. Probably machine error.",monitor_hdr, QuoteClose);
  Monitor11();
}

void Monitor9()
{
  fprintf(stderr, "%sUpdate argument too long for ",monitor_hdr);
  Item(P + 9);
  Monitor11();
}

void Monitor10()
{
  fprintf(stderr, "%sNon-digit in Number.",monitor_hdr);
  Monitor11();
}

void Monitor11()
{
  W = 20;
  fprintf(stderr, "\nCurrent macros are:");
  while (! ((P == 0) && (F == 0))) {
    int W1;
    int r;
    if (P > F) {
      W1 = P + 2;
      P = Stack[P];
      fprintf(stderr, "\nAlready entered ");
    } else {
      W1 = F + 2;
      F = Stack[F];
      fprintf(stderr, "\nNot yet entered ");
    }
    for (r = 1; r <= W; r++) {
      Item(W1);
      if (Stack[W1] == 0)
        break;
      W1 = W1 + Stack[W1];
      if (Stack[W1] == Marker)
        break;
      if (W != 1) {
        char ibuf[5];
        sprintf(ibuf, "%4d", r);
        fprintf(stderr, "\nArg ");
        fprintf(stderr, ibuf);
        fprintf(stderr, "\t");
      }
    }
    W = 1;
  }
  PrintErrorLine();
  exit(EXIT_11);
}

#define OPENBRK	fprintf(stderr,"%c",ApplyOpen)
#define CLOSEBRK fprintf(stderr,"%c",ApplyClose)

void Item(x)
  int x;
{
  int k;
  for (k = 1; k <= (Stack[x] == 0 ? StackPtr - x - 1 : Stack[x] - 1) ; k++)
           fprintf(stderr,"%c",Stack[x+k]);
  if (Stack[x] == 0) { fprintf(stderr, "...\t(Incomplete)"); }
}

void ItemMacro(x)
int x;
{
#ifdef QUOTEMSET
  if (QuoteMLevel) OPENBRK;
#else
# ifdef QUOTEMDEF
  OPENBRK;
# endif
#endif
  Item(x);
#ifdef QUOTEMSET
    if (QuoteMLevel) CLOSEBRK;
#else
# ifdef QUOTEMDEF
    CLOSEBRK;
# endif
#endif
}
#undef CLOSEBRK
#undef OPENBRK

static char *monitor_string[]=
{
	"Unknown error. Probably a bug",
	"Bad parameter for DEC. Result is 0",
	"Bad parameter for BAR. Result is zero",
	"Escape character as last character in file. Set to \\n",
	"Bad operator for BAR. Result is zero",
	"Bad number or lengths of parameters for BAR. Result is zero",
	"Bad argument to DUMP",
	"Argument to DUMP is out of range",
	"Bad start position for SUB",
	"Bad length for SUB"
} ;

void Monitor(monitor_t m)
{
	int i;

/*
 * Map the enum m to the integer i; This might be redundant if
 * the enum is internally mapped to integers and they number
 * correctly, but this is the type-safe way to do things.
 */

	i=0;
	if (m==BadDEC) i=1;
	else if (m==BadBAR) i=2;
	else if (m==EscapeAtEOF) i=3;
	else if (m==BadBAROp) i=4;
	else if (m==BadBARcall) i=5;
	else if (m==BadDUMP) i=6;
	else if (m==BadDUMPrange) i=7;
	else if (m==BadDEF) i=-1, MonitorBadDEF(2);
	else if (m==BadDEF1) i=-1, MonitorBadDEF(1);
	else if (m==BadSUBcall) i=-1, MonitorBadSUB();
	else if (m==BadSUBshort) i=8;
	else if (m==BadSUBlong) i=9;
	else if (m==MacroNotFound) i=-1,MonitorMacroNotFound();
#ifdef DEBUG_MACROS
	else if (m==Exit) i=-1,MonitorExit();
#endif
	else if (m==NotABuiltin) i=-1,MonitorNotABuiltin();
	else i=0;

/*
 * Now print it.
 */

	if (i==-1) return;

	fprintf(stderr,"%s%s.\n",monitor_hdr,monitor_string[i]);
	PrintErrorLine();
}

