/*@z28.c:Error Service:ErrorInit(), ErrorSeen()@******************************/ /* */ /* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.41) */ /* COPYRIGHT (C) 1991, 2023 Jeffrey H. Kingston */ /* */ /* Jeffrey H. Kingston (jeff@it.usyd.edu.au) */ /* School of Information Technologies */ /* 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 3, 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; /* file pointer of log file */ static BOOLEAN error_seen; /* TRUE after first error */ static int block_top; /* first free error block */ static int mess_top; /* first free error message */ static int CurrentFileNum; /*****************************************************************************/ /* */ /* void ErrorInit() */ /* */ /* Initialize this module (must be called before anything else). */ /* */ /*****************************************************************************/ void ErrorInit() { fp = NULL; error_seen = FALSE; block_top = 0; mess_top = 0; CurrentFileNum = -1; } /*****************************************************************************/ /* */ /* ErrorSetFile(str) */ /* */ /* Open log file str and initialise this module. */ /* */ /*****************************************************************************/ void ErrorSetFile(FULL_CHAR *str) { if( fp != NULL ) Error(28, 1, "-e argument appears twice in command line", FATAL, no_fpos); fp = StringFOpen(str, WRITE_FILE); if( fp == NULL ) Error(28, 2, "cannot open error file %s", FATAL, no_fpos, str); } /* end ErrorSetFile */ /*****************************************************************************/ /* */ /* 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) { if( fnum != CurrentFileNum ) { fprintf(fp, "lout%s:%s", EchoFileSource(fnum), (char *) STR_NEWLINE); 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%s"), EchoAltFilePos(pos), val, (char *) STR_NEWLINE); /* for estrip's benefit: Error(28, 7, "%s internal error: %s%s") */ } else { PrintFileBanner(file_num(*pos)); fprintf(fp, condcatgets(MsgCat, 28, 4, " %6s internal error: %s%s"), EchoFileLine(pos), val, (char *) STR_NEWLINE); /* for estrip's benefit: Error(28, 4, " %6s internal error: %s%s") */ } #if DEBUG_ON abort(); #else exit(1); #endif break; case FATAL: case FATAL_WITH_USAGE: while( block_top > 0 ) LeaveErrorBlock(TRUE); if( AltErrorFormat ) { fprintf(fp, condcatgets(MsgCat, 28, 8, "%s: fatal error: %s%s"), EchoAltFilePos(pos), val, (char *) STR_NEWLINE); } else { PrintFileBanner(file_num(*pos)); fprintf(fp, condcatgets(MsgCat, 28, 5, " %6s: fatal error: %s%s"), EchoFileLine(pos), val, (char *) STR_NEWLINE); } /* for estrip's benefit: Error(28, 5, " %6s: fatal error: %s%s") */ /* for estrip's benefit: Error(28, 8, "%s: fatal error: %s%s") */ if( etype == FATAL_WITH_USAGE ) PrintUsage(fp); exit(1); break; case WARN: if( block_top == 0 || print_block[block_top - 1] ) { if( AltErrorFormat ) { fprintf(fp, "%s: %s%s", EchoAltFilePos(pos), val, (char *) STR_NEWLINE); } else { PrintFileBanner(file_num(*pos)); fprintf(fp, " %6s: %s%s", EchoFileLine(pos), val, (char *) STR_NEWLINE); } } else if( mess_top < MAX_ERRORS ) { if( AltErrorFormat ) { sprintf(message[mess_top++], "%s: %s%s", EchoAltFilePos(pos), val, (char *) STR_NEWLINE); } else { message_fnum[mess_top] = file_num(*pos); sprintf(message[mess_top++], " %6s: %s%s", EchoFileLine(pos), val, (char *) STR_NEWLINE); } } 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 */