/*@z28.c:Error Service:ErrorInit(), ErrorSeen()@******************************/
/* */
/* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.26) */
/* COPYRIGHT (C) 1991, 2002 Jeffrey H. Kingston */
/* */
/* Jeffrey H. Kingston (jeff@cs.usyd.edu.au) */
/* Basser Department of Computer Science */
/* The University of Sydney 2006 */
/* AUSTRALIA */
/* */
/* 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, 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., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA */
/* */
/* FILE: z28.c */
/* MODULE: Error Service */
/* EXTERNS: ErrorInit(), Error(), ErrorSeen() */
/* */
/*****************************************************************************/
#include "externs.h"
#define MAX_BLOCKS 20 /* max number of error blocks */
#define MAX_ERRORS 20 /* max number of held error messages */
static BOOLEAN print_block[MAX_BLOCKS]; /* TRUE if print this block */
static int start_block[MAX_BLOCKS]; /* first message of block */
static char message[MAX_ERRORS][MAX_BUFF]; /* the error messages */
static int message_fnum[MAX_ERRORS]; /* file number of error mess */
static FILE *fp = NULL; /* file pointer of log file */
static BOOLEAN error_seen = FALSE; /* TRUE after first error */
static int block_top = 0; /* first free error block */
static int mess_top = 0; /* first free error message */
/*****************************************************************************/
/* */
/* ErrorInit(str) */
/* */
/* Open log file str and initialise this module. */
/* */
/*****************************************************************************/
void ErrorInit(FULL_CHAR *str)
{ if( fp != NULL )
Error(28, 1, "-e argument appears twice in command line", FATAL, no_fpos);
fp = StringFOpen(str, WRITE_TEXT);
if( fp == NULL )
Error(28, 2, "cannot open error file %s", FATAL, no_fpos, str);
} /* end ErrorInit */
/*****************************************************************************/
/* */
/* BOOLEAN ErrorSeen() */
/* */
/* TRUE once an error has been found. */
/* */
/*****************************************************************************/
BOOLEAN ErrorSeen(void)
{ return error_seen;
} /* end ErrorSeen */
/*****************************************************************************/
/* */
/* PrintFileBanner(fnum) */
/* */
/* If fnum was not the subject of the previous call to PrintFileBanner, */
/* print a file banner for fnum. */
/* */
/*****************************************************************************/
static void PrintFileBanner(int fnum)
{ static int CurrentFileNum = -1;
if( fnum != CurrentFileNum )
{ fprintf(fp, "lout%s:\n", EchoFileSource(fnum));
CurrentFileNum = fnum;
}
} /* end PrintFileBanner */
/*@::EnterErrorBlock(), LeaveErrorBlock()@************************************/
/* */
/* EnterErrorBlock(ok_to_print) */
/* */
/* Start off a new block of error messages. If ok_to_print, they do not */
/* need to be held for a later commit. */
/* */
/*****************************************************************************/
void EnterErrorBlock(BOOLEAN ok_to_print)
{ if( block_top < MAX_BLOCKS )
{ print_block[block_top] = ok_to_print;
start_block[block_top] = mess_top;
block_top++;
}
else Error(28, 3, "too many levels of error messages", FATAL, no_fpos);
} /* end EnterErrorBlock */
/*****************************************************************************/
/* */
/* LeaveErrorBlock(commit) */
/* */
/* Finish off a block of error messages. If commit is true, print them, */
/* otherwise discard them. */
/* */
/*****************************************************************************/
void LeaveErrorBlock(BOOLEAN commit)
{ int i;
debug0(DYY, D, " leaving error block");
assert( block_top > 0, "LeaveErrorBlock: no matching EnterErrorBlock!" );
assert( commit || !print_block[block_top - 1], "LeaveErrorBlock: commit!" );
if( fp == NULL ) fp = stderr;
if( commit )
{ for( i = start_block[block_top - 1]; i < mess_top; i++ )
{
if( AltErrorFormat )
{ fputs(message[i], fp);
}
else
{ PrintFileBanner(message_fnum[i]);
fputs(message[i], fp);
}
}
}
block_top--;
mess_top = start_block[block_top];
} /* end LeaveErrorBlock */
/*****************************************************************************/
/* */
/* CheckErrorBlocks() */
/* */
/* Check (at end of run) that all error blocks have been unstacked. */
/* */
/*****************************************************************************/
void CheckErrorBlocks(void)
{ assert( block_top == 0, "CheckErrorBlocks: block_top != 0!" );
} /* end CheckErrorBlocks */
/*@::Error()@*****************************************************************/
/* */
/* Error(etype, pos, str, p1, p2, p3, p4, p5, p6) */
/* */
/* Report error of type etype at position *pos in input. */
/* The error message is str with parameters p1 - p6. */
/* */
/*****************************************************************************/
POINTER Error(int set_num, int msg_num, char *str, int etype, FILE_POS *pos, ...)
{
va_list ap;
char val[MAX_BUFF];
va_start(ap, pos);
vsprintf(val, condcatgets(MsgCat, set_num, msg_num, str), ap);
if( fp == NULL ) fp = stderr;
switch( etype )
{
case INTERN:
while( block_top > 0 ) LeaveErrorBlock(TRUE);
if( AltErrorFormat )
{
fprintf(fp, condcatgets(MsgCat, 28, 7, "%s internal error: %s\n"),
EchoAltFilePos(pos), val);
/* for estrip's benefit: Error(28, 7, "%s internal error: %s\n") */
}
else
{
PrintFileBanner(file_num(*pos));
fprintf(fp, condcatgets(MsgCat, 28, 4, " %6s internal error: %s\n"),
EchoFileLine(pos), val);
/* for estrip's benefit: Error(28, 4, " %6s internal error: %s\n") */
}
#if DEBUG_ON
abort();
#else
exit(1);
#endif
break;
case FATAL:
while( block_top > 0 ) LeaveErrorBlock(TRUE);
if( AltErrorFormat )
{
fprintf(fp, condcatgets(MsgCat, 28, 8, "%s: fatal error: %s\n"),
EchoAltFilePos(pos), val);
}
else
{
PrintFileBanner(file_num(*pos));
fprintf(fp, condcatgets(MsgCat, 28, 5, " %6s: fatal error: %s\n"),
EchoFileLine(pos), val);
}
/* for estrip's benefit: Error(28, 5, " %6s: fatal error: %s\n") */
/* for estrip's benefit: Error(28, 8, "%s: fatal error: %s\n") */
exit(1);
break;
case WARN:
if( block_top == 0 || print_block[block_top - 1] )
{
if( AltErrorFormat )
{
fprintf(fp, "%s: %s\n", EchoAltFilePos(pos), val);
}
else
{
PrintFileBanner(file_num(*pos));
fprintf(fp, " %6s: %s\n", EchoFileLine(pos), val);
}
}
else if( mess_top < MAX_ERRORS )
{
if( AltErrorFormat )
{
sprintf(message[mess_top++], "%s: %s\n", EchoAltFilePos(pos), val);
}
else
{ message_fnum[mess_top] = file_num(*pos);
sprintf(message[mess_top++], " %6s: %s\n",
EchoFileLine(pos), val);
}
}
else Error(28, 6, "too many error messages", FATAL, pos);
error_seen = TRUE;
break;
default:
assert(FALSE, "Error: invalid error type");
break;
}
va_end(ap);
return 0;
} /* end Error */