/* * * (c) Copyright 1989 OPEN SOFTWARE FOUNDATION, INC. * (c) Copyright 1989 HEWLETT-PACKARD COMPANY * (c) Copyright 1989 DIGITAL EQUIPMENT CORPORATION * To anyone who acknowledges that this file is provided "AS IS" * without any express or implied warranty: * permission to use, copy, modify, and distribute this * file for any purpose is hereby granted without fee, provided that * the above copyright notices and this notice appears in all source * code copies, and that none of the names of Open Software * Foundation, Inc., Hewlett-Packard Company, or Digital Equipment * Corporation be used in advertising or publicity pertaining to * distribution of the software without specific, written prior * permission. Neither Open Software Foundation, Inc., Hewlett- * Packard Company, nor Digital Equipment Corporation makes any * representations about the suitability of this software for any * purpose. * */ /* ** ** NAME ** ** ERRORS.C ** ** FACILITY: ** ** Interface Definition Language (IDL) Compiler ** ** ABSTRACT: ** ** IDL Error logging and reporting routines. ** ** VERSION: DCE 1.0 ** */ #include #include #include #include #include #include #include #include #define MAX_LINE_LEN 256 #define WHERE_TEXT_LEN 20 #define MAX_WARNINGS 5 #define MAX_ERROR_FILES 10 /* * Error log record format. */ typedef struct error_log_rec_t { STRTAB_str_t filename; /* Error file name */ int lineno; /* Source line number */ idl_error_list_t msgs; /* msgid + args */ union /* Tree node or List node */ { struct { /* As tree node: */ struct error_log_rec_t *left; /* Left pointer */ struct error_log_rec_t *right; /* Right pointer */ } asBinTree; struct { /* As list node: */ struct error_log_rec_t *next; /* Ptr to next for this lineno */ } asList; } links; struct error_log_rec_t *first_this_line; /* 1st addtl msg this line */ struct error_log_rec_t *last_this_line; /* last addtl msg this line */ } error_log_rec_t; /* Pointers to IDL parser or ACF parser global variables. */ FILE **yyin_p; /* Points to yyin or acf_yyin */ int *yylineno_p; /* Points to yylineno or acf_yylineno */ int *yynerrs_p; /* Points to yynerrs or acf_yynerrs */ char ** yytext_p; boolean ERR_no_warnings; /* Global copy of -no_warn command line option */ static int warnings = 0; /* Warning count */ static STRTAB_str_t error_files[MAX_ERROR_FILES]; /* List of all files with errors */ static int error_file_count = 0; /* Number of files with errors */ static int last_error_line = 0; /* Line of last error */ #if !YYDEBUG static #endif char const *current_file = NULL; /* Current source file name */ error_log_rec_t *errors = NULL; /* Tree root for error nodes */ int error_count = 0; /* Error count */ STRTAB_str_t error_file_name_id; /* Id of current source file */ extern void sysdep_cleanup_temp ( void ); /* * y y w h e r e * * Function: Returns current input position for yyparse. * * Globals: yy*_p * */ void yywhere ( void ) { boolean have_text = false; /* True if have source text to output */ int text_len = 0; /* Length of source text to output */ int lineno; /* Source line number of relevant text */ long msg_id; /* ID of message to output */ char const *near_text; /* Text of object near error */ STRTAB_str_t string_id; /* Entry in string table of near text */ char wherebuf[WHERE_TEXT_LEN+1]; char * text_p = *yytext_p; lineno = *yylineno_p; if (*text_p) { for (text_len = 0; text_len < WHERE_TEXT_LEN; ++text_len) { if (text_p[text_len] == '\0' || text_p[text_len] == '\n') break; wherebuf[text_len] = text_p[text_len]; } wherebuf[text_len] = '\0'; if (text_len > 0) { have_text = true; lineno = lineno - (*text_p == '\n' || ! *text_p); } /* printf("wherebuf is %s, yytext has %s\n", wherebuf, *yytext_p); */ } /* * If there is some text to show, put it in the string table */ if (have_text) { string_id = STRTAB_add_string(wherebuf); STRTAB_str_to_string(string_id, &near_text); } if (have_text) { if (feof(*yyin_p)) msg_id = NIDL_EOFNEAR; else msg_id = NIDL_SYNTAXNEAR; } else { if (feof(*yyin_p)) msg_id = NIDL_EOF; else msg_id = NIDL_SYNTAXERR; } log_error(lineno, msg_id, text_len, near_text, NULL); } /* * y y e r r o r * * Function: Called by yypaser when a parse error is encountered. * * Inputs: message - error message to display * token - expected token * * Globals: yynerrs_p * * Notes: This was adapted from the book * "Compiler Construction under Unix" * by A. T. Schreiner & H. G. Friedman */ void yyerror ( char const *message ) { static int list = 0; /* Note: Currently always 0 */ if (message || !list) { (*yynerrs_p)++; yywhere(); /* * Only print the yacc version of errors if it isn't for a syntax error. */ if (strcmp(message,"syntax error") != 0) { fputs(message, stderr); putc('\n', stderr); return; } return; } putc('\n', stderr); list = 0; } /* * a c f _ y y e r r o r * n i d l _ y y e r r o r * * * Function: Stub functions for the ACF and NIDL parsers * */ void nidl_yyerror(m) char * m; { yyerror(m); } void acf_yyerror(m) char * m; { yyerror(m); } /* * a l l o c _ l o g _ r e c * * Function: Allocates and initializes error log record. * * Inputs: lineno - source line number * message - message text * * Outputs: Address of error log record. */ static error_log_rec_t *alloc_log_rec ( STRTAB_str_t filename, int lineno, idl_error_list_t *msgs ) { error_log_rec_t *log_rec_p; int i; log_rec_p = NEW (error_log_rec_t); log_rec_p->lineno = lineno; log_rec_p->filename = filename; log_rec_p->msgs = *msgs; log_rec_p->first_this_line = 0; log_rec_p->last_this_line = 0; log_rec_p->links.asBinTree.left = 0; log_rec_p->links.asBinTree.right = 0; log_rec_p->links.asList.next = 0; /* * If this file is not listed in the error file list */ for (i = 0; i < error_file_count; i++) if (error_files[i] == filename) break; /* * Add the file with errors to the error_file list */ if (i == error_file_count) error_files[error_file_count++] = filename; /* * If we have too many files with errors, just ignore some */ if (error_file_count >= MAX_ERROR_FILES) error_file_count--; return log_rec_p; } /* * f r e e _ l o g _ r e c * * Function: Frees an error log record and anything below it * * Inputs: record - error log record to free * Outputs: none */ static void free_log_rec ( error_log_rec_t *log_rec_p ) { if (log_rec_p->links.asBinTree.left != NULL) { free_log_rec(log_rec_p->links.asBinTree.left); log_rec_p->links.asBinTree.left = NULL; } if (log_rec_p->links.asBinTree.right != NULL) { free_log_rec(log_rec_p->links.asBinTree.right); log_rec_p->links.asBinTree.right = NULL; } /* * Free all errors logged for this line number */ while (log_rec_p->first_this_line != NULL) { error_log_rec_t *ep; ep = log_rec_p->first_this_line; log_rec_p->first_this_line = log_rec_p->links.asList.next; FREE(ep); } FREE(log_rec_p); } /* * q u e u e _ e r r o r * * Function: Adds an error message to the end of a list of * errors queued for a particular line. * * Inputs: log_rec_p - a pointer to the header error log rec. * message - the error message. */ static void queue_error ( error_log_rec_t *log_rec_p, STRTAB_str_t filename, idl_error_list_t *msgs ) { error_log_rec_t *new_log_rec_p; new_log_rec_p = alloc_log_rec(filename, log_rec_p->lineno, msgs); if (log_rec_p->first_this_line == NULL) { log_rec_p->first_this_line = new_log_rec_p; log_rec_p->last_this_line = new_log_rec_p; return; } log_rec_p->last_this_line->links.asList.next = new_log_rec_p; log_rec_p->last_this_line = new_log_rec_p; } /* * a d d _ e r r o r _ l o g _ r e c * * Function: Adds an error log to the sorted binary tree of * error messages. * * Inputs: log_rec_p - pointer to current root of tree. * lineno - line number on which error occurred. * message - the error message. */ static void add_error_log_rec ( error_log_rec_t *log_rec_p, STRTAB_str_t filename, int lineno, idl_error_list_t *msgs ) { if (log_rec_p->lineno < lineno) { if (log_rec_p->links.asBinTree.right != NULL) add_error_log_rec(log_rec_p->links.asBinTree.right, filename, lineno, msgs); else log_rec_p->links.asBinTree.right = alloc_log_rec(filename, lineno, msgs); return; } if (log_rec_p->lineno > lineno) { if (log_rec_p->links.asBinTree.left != NULL) add_error_log_rec(log_rec_p->links.asBinTree.left, filename, lineno, msgs); else log_rec_p->links.asBinTree.left = alloc_log_rec(filename, lineno, msgs); return; } if (log_rec_p->lineno == lineno) queue_error(log_rec_p, filename, msgs); } /* * l o g _ s o u r c e _ v a * * Function: Accumulates a warning or error message for later printout. * All accumulated errors are printed by print_errors. * Errors are kept sorted by line number and source * file name. * * Inputs: * counter - which counter should be increased (error/warning) * filename - STRTAB_str_t of full source file name * lineno - the line number of the error. * msg_id - the error message ID. * ap - va_list for the parameter last must be NULL if # < IDL_ERROR_LIST_SIZE * * Outputs: An error log record is inserted in the error tree. * */ static void log_source_va ( int* counter, STRTAB_str_t filename, int lineno, long msg_id, va_list ap ) { idl_error_list_t msgs = {0, {NULL}}; size_t idx; ++*counter; msgs.msg_id = msg_id; for (idx = 0; idx < IDL_ERROR_LIST_SIZE; idx++) { msgs.arg[idx] = va_arg(ap, void*); if (!msgs.arg[idx]) break; } if (errors == NULL) errors = alloc_log_rec(filename, lineno, &msgs); else add_error_log_rec(errors, filename, lineno, &msgs); } /* * l o g _ s o u r c e _ e r r o r * * Function: Accumulates an error message for later printout. * All accumulated errors are printed by print_errors. * Errors are kept sorted by line number and source * file name. * * Inputs: * filename - STRTAB_str_t of full source file name * lineno - the line number of the error. * msg_id - the error message ID. * [arg1,...,arg5] - 0 to 5 arguments for error message formatting * * Outputs: An error log record is inserted in the error tree. * */ void log_source_error ( STRTAB_str_t filename, int lineno, long msg_id, ... ) { va_list ap; va_start(ap, msg_id); log_source_va(&error_count, filename, lineno, msg_id, ap); va_end(ap); } /* * l o g _ s o u r c e _ w a r n i n g * * Function: Accumulates a warning message for later printout. * All accumulated errors are printed by print_errors. * Errors are kept sorted by line number and source * file name. * * Inputs: * filename - STRTAB_str_t of full source file name * lineno - the line number of the error. * msg_id - the error message ID. * [arg1,...,arg5] - 0 to 5 arguments for error message formatting * * Outputs: An error log record is inserted in the error tree. * */ void log_source_warning ( STRTAB_str_t filename, int lineno, long msg_id, ... ) { va_list ap; /* Return if warnings are suppressed. */ if (ERR_no_warnings) return; va_start(ap, msg_id); log_source_va(&warnings, filename, lineno, msg_id, ap); va_end(ap); } /* * l o g _ e r r o r * * Function: Accumulates an error message for later printout. * All accumulated errors are printed by print_errors. * Errors are kept sorted by line number. The error * is logged on the file for which set_name_for_errors * was most recently called. * * Inputs: lineno - the line number of the error. * msg_id - the error message ID. * [arg1,...,arg5] - 0 to 5 arguments for error message formatting * * Outputs: An error log record is inserted in the error tree. * */ void log_error ( int lineno, long msg_id, ... ) { va_list ap; va_start(ap, msg_id); log_source_va(&error_count, error_file_name_id, lineno, msg_id, ap); va_end(ap); } /* * l o g _ w a r n i n g * * Function: Accumulates a warning message for later printout. * All accumulated errors are printed by print_errors. * Errors are kept sorted by line number. The warning * is logged on the file for which set_name_for_errors * was most recently called. * * Inputs: lineno - the line number of the warning. * msg_id - the error message ID. * [arg1,...,arg5] - 0 to 5 arguments for error message formatting * * Outputs: An error log record is inserted in the error tree. * */ void log_warning ( int lineno, long msg_id, ... ) { va_list ap; if (ERR_no_warnings) return; va_start(ap, msg_id); log_source_va(&warnings, error_file_name_id, lineno, msg_id, ap); va_end(ap); } /* * s e e k _ f o r _ l i n e * * Function: Reads the line specified by lineno. * * Inputs: source - the file descriptor for the source file. * lineno - the number of the line in error. * * Outputs: source_line - the source line is returned through here * * Globals: last_error_line */ void seek_for_line ( FILE *source_file, int lineno, char *source_line ) { int lines_to_skip; int i; /* * If the FILE is NULL then can't get the source */ if (source_file == NULL) { source_line[0] = 0; return; } lines_to_skip = lineno - last_error_line; for (i=0; ifilename) { source_printed = true; seek_for_line(fd, log_rec_ptr->lineno, source_line); message_print( NIDL_FILESOURCE, source, log_rec_ptr->lineno, source_line ); message_print( log_rec_ptr->msgs.msg_id, log_rec_ptr->msgs.arg[0], log_rec_ptr->msgs.arg[1], log_rec_ptr->msgs.arg[2], log_rec_ptr->msgs.arg[3], log_rec_ptr->msgs.arg[4] ); } for (erp = log_rec_ptr->first_this_line; erp; erp=erp->links.asList.next) { /* Print the error only if it in this file */ if (source_id == erp->filename) { /* If we haven't output the source line text yet, the do so */ if (!source_printed) { source_printed = true; seek_for_line(fd, log_rec_ptr->lineno, source_line); message_print( NIDL_FILESOURCE, source, log_rec_ptr->lineno, source_line ); } /* Now print out the actual error message */ message_print( erp->msgs.msg_id, erp->msgs.arg[0], erp->msgs.arg[1], erp->msgs.arg[2], erp->msgs.arg[3], erp->msgs.arg[4] ); } } } /* * p r i n t _ e r r o r _ m e s s a g e s * * Function: Recursively prints all accumulated error messages. * * Inputs: fd - file descriptor for source file * source - name of source file * log_rec_ptr - root of error log tree */ void print_error_messages ( FILE *fd, char const *source, STRTAB_str_t source_id, error_log_rec_t *log_rec_ptr ) { if (log_rec_ptr->links.asBinTree.left != NULL) print_error_messages(fd, source, source_id, log_rec_ptr->links.asBinTree.left); print_errors_for_line(fd, source, source_id, log_rec_ptr); if (log_rec_ptr->links.asBinTree.right != NULL) print_error_messages(fd, source, source_id, log_rec_ptr->links.asBinTree.right); } /* * p r i n t _ e r r o r s * * Function: Prints all accumulated error messages. * * Inputs: source - String table ID of source file name * * Functional value: true - if any errors were printed * false otherwise * */ boolean print_errors ( void ) { FILE *fd; char const *fn; int i; STRTAB_str_t source_id; error_log_rec_t *error_root; /* * If there are no errors, just return */ if (errors == NULL) return 0; /* * Copy the root of the error tree and null it out so that * it looks like all the errors have been printed if we get * an error while printing them out. */ error_root = errors; errors = NULL; /* * Loop through all files with errors */ for (i = 0; i < error_file_count; i++) { source_id = error_files[i]; STRTAB_str_to_string(source_id, &fn); fd = fopen(fn, "r"); print_error_messages(fd, fn, source_id, error_root); last_error_line = 0; } /* * Free the tree of errors, */ free_log_rec(error_root); error_file_count = 0; /* * Return true if we found any errors. */ return (error_file_count != 0); } /* * e r r o r * * Function: Prints the specifed error message and terminates the program * * Inputs: msg_id - the error message ID. * [arg1,...,arg5] - 0 to 5 arguments for error message formatting * * Notes: This call terminates the calling program with a failure status * */ void error ( long msg_id, char *arg1, char *arg2, char *arg3, char *arg4, char *arg5 ) { if (current_file) message_print(NIDL_LINEFILE, current_file, *yylineno_p); message_print(msg_id, arg1, arg2, arg3, arg4, arg5); #ifndef HASPOPEN sysdep_cleanup_temp(); #endif nidl_terminate(); } /* * e r r o r _ l i s t * * Function: Prints the specifed error message(s) and terminates the program * * Inputs: vecsize - number of messages * errvec - pointer to one or more message info elements * exitflag - TRUE => exit program * * Notes: This call terminates the calling program with a failure status * */ void error_list ( int vecsize, idl_error_list_p errvec, boolean exitflag ) { int i; if (current_file) message_print(NIDL_LINEFILE, current_file, *yylineno_p); for (i = 0; i < vecsize; i++) message_print(errvec[i].msg_id, errvec[i].arg[0], errvec[i].arg[1], errvec[i].arg[2], errvec[i].arg[3], errvec[i].arg[4] ); if (!exitflag) return; #ifndef HASPOPEN sysdep_cleanup_temp(); #endif nidl_terminate(); } /* * w a r n i n g * * Function: Prints the specifed error message. Terminates if the * error count excees the threshold. * * Inputs: msg_id - the error message ID. * [arg1,...,arg5] - 0 to 5 arguments for error message formatting * * Globals: yylineno_p * * Notes: This call terminates the calling program with a status of -2. * */ void warning ( long msg_id, char *arg1, char *arg2, char *arg3, char *arg4, char *arg5 ) { /* Return if warnings are suppressed. */ if (ERR_no_warnings) return; if (current_file) message_print(NIDL_LINEFILE, current_file, *yylineno_p); message_print(msg_id, arg1, arg2, arg3, arg4, arg5); if (++warnings > MAX_WARNINGS) { message_print(NIDL_MAXWARN, MAX_WARNINGS); nidl_terminate(); } } /* * s e t _ n a m e _ f o r _ e r r o r s * * Function: Records the name of the file being processed. This name * will be prepended onto error messages. * * Inputs: name - a pointer to the file name. * */ void set_name_for_errors ( char const *filename ) { if (filename != NULL) { error_file_name_id = STRTAB_add_string(filename); STRTAB_str_to_string(error_file_name_id, ¤t_file); } else current_file = NULL; } /* * i n q _ n a m e _ f o r _ e r r o r s * * Function: Returns the name of the file being processed. * * Outputs: name - the file name is copied through this. * */ void inq_name_for_errors ( char *name ) { if (current_file) strcpy(name, current_file); else *name = '\0'; } /* preserve coding style vim: set tw=78 sw=4 ts=4: */