/**************************************************************************** * * Open Watcom Project * * Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved. * * ======================================================================== * * This file contains Original Code and/or Modifications of Original * Code as defined in and that are subject to the Sybase Open Watcom * Public License version 1.0 (the 'License'). You may not use this file * except in compliance with the License. BY USING THIS FILE YOU AGREE TO * ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is * provided with the Original Code and Modifications, and is also * available at www.sybase.com/developer/opensource. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR * NON-INFRINGEMENT. Please see the License for the specific language * governing rights and limitations under the License. * * ======================================================================== * * Description: Diagnostics routines: (fatal) errors, warnings, notes * ****************************************************************************/ #include #include #include #include "globals.h" #include "memalloc.h" #include "parser.h" #include "input.h" #include "tokenize.h" #include "macro.h" #include "msgtext.h" #include "listing.h" #include "segment.h" extern void print_source_nesting_structure( void ); extern jmp_buf jmpenv; //static bool Errfile_Written; //static void PrtMsg( int severity, int msgnum, va_list args1, va_list args2 ); //void PutMsg( FILE *fp, int severity, int msgnum, va_list args ); char banner_printed = FALSE; static const char usage[] = { #include "usage.h" }; #ifdef DEBUG_OUT /* there are intransparent IDEs that don't want to tell you the real, current command line arguments * and often those tools also swallow anything that is written to stdout or stderr. * To make jwasm write a trace log to a file, enable the next line! * Additionally, you'll probably have to enable line Set_dt() in cmdline.c, function ParseCmdline(). */ //#define DBGLOGFILE "jwasm.log" #ifdef DBGLOGFILE FILE *fdbglog = NULL; #endif void DoDebugMsg( const char *format, ... ) /****************************************/ { va_list args; if( !Options.debug ) return; if( ModuleInfo.cref == FALSE && CurrFName[ASM] != NULL ) return; va_start( args, format ); #ifdef DBGLOGFILE if ( fdbglog == NULL ) fdbglog = fopen( DBGLOGFILE, "w" ); vfprintf( fdbglog, format, args ); #else vprintf( format, args ); #endif va_end( args ); #if 0 #ifdef DBGLOGFILE fflush( fdbglog ); #else fflush( stdout ); #endif #endif } void DoDebugMsg1( const char *format, ... ) /****************************************/ { va_list args; char buffer[MAX_LINE_LEN]; if( !Options.debug ) return; if( ModuleInfo.cref == FALSE ) return; #ifdef DBGLOGFILE if ( fdbglog == NULL ) fdbglog = fopen( DBGLOGFILE, "w" ); #endif //if ( CurrFName[ASM] ) if ( ModuleInfo.g.src_stack ) { #ifdef DBGLOGFILE fprintf( fdbglog, "%" I32_SPEC "u%s. ", GetLineNumber(), GetTopLine( buffer ) ); #else printf( "%" I32_SPEC "u%s. ", GetLineNumber(), GetTopLine( buffer ) ); #endif } va_start( args, format ); #ifdef DBGLOGFILE vfprintf( fdbglog, format, args ); #else vprintf( format, args ); #endif va_end( args ); #if 0 #ifdef DBGLOGFILE fflush( fdbglog ); #else fflush( stdout ); #endif #endif } #endif int write_logo( void ) /********************/ { if( banner_printed == FALSE ) { banner_printed = TRUE; printf( "%s, %s\n", MsgGetEx( MSG_JWASM ), MsgGetEx( MSG_JWASM2 ) ); return( 4 ); /* return number of lines printed */ } return( 0 ); } void PrintUsage( void ) /*********************/ { const char *p; write_logo(); for ( p = usage; *p != '\n'; ) { const char *p2 = p + strlen( p ) + 1; printf("%-20s %s\n", p, p2 ); p = p2 + strlen( p2 ) + 1; } } static void PutMsg( FILE *fp, int severity, int msgnum, va_list args ) /********************************************************************/ { int i,j; const char *type; const char *pMsg; char buffer[MAX_LINE_LEN+128]; if( fp != NULL ) { if ( severity && ( j = GetCurrSrcPos( buffer ) ) ) { fwrite( buffer, 1, j, fp ); } pMsg = MsgGetEx( msgnum ); switch (severity ) { case 1: type = MsgGetEx( MSG_FATAL_PREFIX ); break; case 2: type = MsgGetEx( MSG_ERROR_PREFIX ); break; case 4: type = MsgGetEx( MSG_WARNING_PREFIX ); break; default: type = NULL; i = 0; break; } if ( type ) i = sprintf( buffer, "%s A%4u: ", type, severity * 1000 + msgnum ); i += vsprintf( buffer+i, pMsg, args ); //buffer[i] = NULLC; fwrite( buffer, 1, i, fp ); fwrite( "\n", 1, 1, fp ); /* if in Pass 1, add the error msg to the listing */ if ( CurrFile[LST] && severity && Parse_Pass == PASS_1 && fp == CurrFile[ERR] ) { LstWrite( LSTTYPE_DIRECTIVE, GetCurrOffset(), 0 ); /* size of "blank" prefix to be explained! */ LstPrintf( " %s", buffer ); LstNL(); } } } static void PrtMsg( int severity, int msgnum, va_list args1, va_list args2 ) /**************************************************************************/ { #ifndef __SW_BD write_logo(); #endif /* open .err file if not already open and a name is given */ if( CurrFile[ERR] == NULL && CurrFName[ERR] != NULL ) { CurrFile[ERR] = fopen( CurrFName[ERR], "w" ); if( CurrFile[ERR] == NULL ) { /* v2.06: no fatal error anymore if error file cannot be written */ char *p = CurrFName[ERR]; CurrFName[ERR] = NULL; /* set to NULL before EmitErr()! */ Options.no_error_disp = FALSE; /* disable -eq! */ EmitErr( CANNOT_OPEN_FILE, p, ErrnoStr() ); LclFree( p ); } } /* v2.05: new option -eq */ if ( Options.no_error_disp == FALSE ) { PutMsg( errout, severity, msgnum, args1 ); fflush( errout ); /* 27-feb-90 */ } if( CurrFile[ERR] ) { //Errfile_Written = TRUE; PutMsg( CurrFile[ERR], severity, msgnum, args2 ); } } /* notes: "included by", "macro called from", ... */ void PrintNote( int msgnum, ... ) /*******************************/ { va_list args1, args2; va_start( args1, msgnum ); va_start( args2, msgnum ); PrtMsg( 0, msgnum, args1, args2 ); va_end( args1 ); va_end( args2 ); } int EmitErr( int msgnum, ... ) /****************************/ { va_list args1, args2; #ifdef DEBUG_OUT printf( "%s\n", ModuleInfo.tokenarray ? ModuleInfo.tokenarray[0].tokpos : "" ); #endif va_start( args1, msgnum ); va_start( args2, msgnum ); PrtMsg( 2, msgnum, args1, args2 ); va_end( args1 ); va_end( args2 ); ModuleInfo.g.error_count++; write_to_file = FALSE; print_source_nesting_structure(); if( Options.error_limit != -1 && ModuleInfo.g.error_count == Options.error_limit+1 ) Fatal( TOO_MANY_ERRORS ); return( ERROR ); } int EmitError( int msgnum ) /*************************/ { return( EmitErr( msgnum ) ); } void EmitWarn( int level, int msgnum, ... ) /*****************************************/ { va_list args1, args2; if( level <= Options.warning_level ) { #ifdef DEBUG_OUT printf( "%s\n", ModuleInfo.tokenarray ? ModuleInfo.tokenarray[0].tokpos : "" ); #endif va_start( args1, msgnum ); va_start( args2, msgnum ); if( !Options.warning_error ) { PrtMsg( 4, msgnum, args1, args2 ); ModuleInfo.g.warning_count++; } else { PrtMsg( 2, msgnum, args1, args2 ); ModuleInfo.g.error_count++; } va_end( args1 ); va_end( args2 ); print_source_nesting_structure(); } } char *ErrnoStr( void ) /********************/ { static char buffer[32]; return( ( errno == ENOENT ) ? "ENOENT" : myltoa( errno, buffer, 10, FALSE, FALSE ) ); } /* fatal error (out of memory, unable to open files for write, ...) * don't use functions which need to alloc memory here! * v2.08: do not exit(), just a longjmp() into AssembleModule(). */ void Fatal( int msgnum, ... ) /***************************/ { va_list args1, args2; /* v2.11: call PrtMsg() instead of PutMsg(). * Makes the fatal error appear in the .ERR and .LST files */ va_start( args1, msgnum ); va_start( args2, msgnum ); PrtMsg( 1, msgnum, args1, args2 ); va_end( args1 ); va_end( args2 ); ModuleInfo.g.error_count++; //write_to_file = FALSE; /* setjmp() has been called in AssembleModule(). * if a fatal error happens outside of this function, longjmp() * is NOT to be used ( out of memory condition, @cmd file open error, ... ) */ if ( CurrFName[ASM] ) longjmp( jmpenv, 2 ); exit(1); } #if 0 void SeekError( void ) /********************/ { DebugMsg(("SeekError occured\n")); Fatal( FILE_SEEK_ERROR, CurrFName[OBJ], errno ); }; #endif void WriteError( void ) /*********************/ { DebugMsg(("WriteError occured\n")); Fatal( FILE_WRITE_ERROR, CurrFName[OBJ], errno ); }; #ifndef NDEBUG int InternalError( const char *file, unsigned line ) /**************************************************/ /* it's used by myassert() function in debug version */ { #if 1 char buffer[MAX_LINE_LEN]; DebugMsg(("InternalError enter\n")); ModuleInfo.g.error_count++; GetCurrSrcPos( buffer ); fprintf( errout, "%s", buffer ); fprintf( errout, MsgGetEx( INTERNAL_ERROR ), file, line ); close_files(); exit( EXIT_FAILURE ); #else Fatal( INTERNAL_ERROR, file, line ); #endif return( 0 ); } #endif