/* * Instead of the Abort, Retry, Ignore thing, let's try to handle critical * errors within tde. Give the user some indication of the critical error * and then find out what the user wants to do. * * This is a very simple critical error handler. It's not much better than * Abort, Retry, Ignore, but at least the program will probably not terminate * with unsaved work. * * IMPORTANT: This is a replacement for the standard DOS critical error * handler. Since DOS is not re-entrant, do not call any functions that, * directly or indirectly, call DOS functions. We are in some DOS function * when a critical error occurs. Using BIOS and direct hardware I/O * functions, however, is allowed. * * New editor name: tde, the Thomson-Davis Editor. * Author: Frank Davis * Date: June 5, 1991, version 1.0 * Date: July 29, 1991, version 1.1 * Date: October 5, 1991, version 1.2 * Date: January 20, 1992, version 1.3 * Date: February 17, 1992, version 1.4 * Date: April 1, 1992, version 1.5 * Date: June 5, 1992, version 2.0 * * This code is released into the public domain, Frank Davis. * You may distribute it freely. */ #include "tdestr.h" #include "common.h" #include "tdefunc.h" #include "criterr.h" /* * Save the area of the screen that will display the Critical * Error info. CEH_WIDTH and CEH_HEIGHT are the dimensions of critical * error screen in criterr.h. CEH_OFFSET is the offset into the screen * refresh buffer. Let the compiler calculate the offset, 'cause the offset * don't change anyway. */ #define CEH_ROW 5 #define CEH_COL 6 #define CEH_WIDTH 69 #define CEH_HEIGHT 15 #define CEH_OFFSET ((CEH_ROW * 160) + (CEH_COL * 2)) /* * buffer for ceh info screen. make this an int array because we * need to save character and attribute. */ int ceh_buffer[CEH_HEIGHT][CEH_WIDTH]; /* * Name: crit_err_handler * Purpose: Show user something is wrong and get a response * Date: April 1, 1992 */ int far crit_err_handler( void ) { int rc; int c; save_area( (void far *)ceh_buffer ); show_error_screen( CEH_ROW, CEH_COL ); xygoto( 60, 17 ); do c = getkey( ); while (c != 'Q' && c != 'q' && c != 'R' && c != 'r'); switch ( c ) { case 'Q': case 'q': rc = FAIL; break; case 'R': case 'r': rc = RETRY; break; } restore_area( (void far *)ceh_buffer ); return( rc ); } /* * Name: show_error_screen * Purpose: Display error screen in window * Date: April 1, 1992 * Passed: row: line to display ceh screen * col: column to begin display ceh screen */ void show_error_screen( int row, int col ) { char **p; for (p=criterr_screen; *p != NULL; p++, row++) s_output( *p, row, col, g_display.help_color ); s_output( error_code[ceh.code], 8, 23, g_display.help_color ); s_output( operation[ceh.rw], 9, 23, g_display.help_color ); if (ceh.dattr == 0) c_output( ceh.drive + 'a', 23, 10, g_display.help_color ); else s_output( critt1, 10, 23, g_display.help_color ); s_output( ext_err[ceh.extended], 11, 23, g_display.help_color ); s_output( error_class[ceh.class], 12, 23, g_display.help_color ); s_output( locus[ceh.locus], 13, 23, g_display.help_color ); s_output( device_type[ceh.dattr], 14, 23, g_display.help_color ); s_output( ceh.dattr == 0 ? critt1 : ceh.dname, 15, 23, g_display.help_color ); } /* * Name: save_area * Purpose: save a region of the screen * Date: April 1, 1992 * Passed: dest: pointer to buffer for contents of screen under ceh * Notes: use an assembly routine to save the area. we could have used * a C library function instead of assembly, but the "rep movsw" * instruction is really easy to use. this function does not check * for snow. the source is the screen and the destination is the * buffer. */ void save_area( void far *dest ) { void far *source; /* * put the address of the display adapter in a local stack variable. */ source = (void far *)g_display.display_address; _asm { push ds ; save ds and any register vars push si push di mov dx, CEH_HEIGHT ; save height in dx (num of rows) mov di, WORD PTR dest ; load OFFSET of destination mov ax, WORD PTR dest+2 ; load SEGMENT of destination mov es, ax ; es:di == destination mov si, WORD PTR source ; load OFFSET of source mov ax, WORD PTR source+2 ; load SEGMENT of source mov ds, ax ; ds:si == source add si, CEH_OFFSET ; add offset into display screen ALIGN 2 top: cmp dx, 0 ; any more rows left? jbe getout ; if not, we're done mov cx, CEH_WIDTH ; load count register mov bx, si ; save videomem location rep movsw ; copy from screen area to buffer mov si, bx ; get back videomem location add si, 160 ; make videomem point to next line dec dx ; ready for another row jmp SHORT top getout: pop di pop si pop ds } } /* * Name: restore_area * Purpose: restore a region of the screen * Date: April 1, 1992 * Passed: source: pointer to buffer for contents of screen under ceh * Notes: use an assembly routine to restore the area. this function * does not check for snow. the source is the buffer and * the destination is the screen. */ void restore_area( void far *source ) { void far *dest; /* * put the address of the display adapter in a local stack variable. */ dest = (void far *)g_display.display_address; _asm { push ds ; save ds and any register vars push si push di mov dx, CEH_HEIGHT ; save height in dx (num of rows) mov di, WORD PTR dest ; load OFFSET of destination mov ax, WORD PTR dest+2 ; load SEGMENT of destination mov es, ax ; es:di == destination add di, CEH_OFFSET ; add offset into display screen mov si, WORD PTR source ; load OFFSET of source mov ax, WORD PTR source+2 ; load SEGMENT of source mov ds, ax ; ds:si == source ALIGN 2 top: cmp dx, 0 ; any more rows left? jbe getout ; if not, we're done mov cx, CEH_WIDTH ; load count register, number of words mov bx, di ; save videomem location rep movsw ; copy from buffer to screen area mov di, bx ; get back videomem location add di, 160 ; make videomem point to next line dec dx ; ready for another row jmp SHORT top getout: pop di pop si pop ds } }