/******************* start of original comments ********************/ /* * Written by Douglas Thomson (1989/1990) * * This source code is released into the public domain. */ /* * Name: dte - Doug's Text Editor program - hardware dependent module * Purpose: This file contains all the code that needs to be different on * different hardware. * File: hwibm.c * Author: Douglas Thomson * System: This particular version is for the IBM PC and close compatibles. * It write directly to video RAM, so it is faster than other * techniques, but will cause "snow" on most CGA cards. See the * file "hwibmcga.c" for a version that avoids snow. * The compiler is Turbo C 2.0, using one of the large data memory * models. * Date: October 10, 1989 * Notes: This module has been kept as small as possible, to facilitate * porting between different systems. */ /********************* end of original comments ********************/ /* * These routines were rewritten for Microsoft C. They are pretty much system * dependent and pretty much Microsoft C dependent. I also renamed this file * "main.c" - easier to find the main function. * * 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 * Date: October 31, 1992, version 2.1 * Date: April 1, 1993, version 2.2 * Date: June 5, 1993, version 3.0 * Date: August 29, 1993, version 3.1 * Date: November 13, 1993, version 3.2 * Date: June 5, 1994, version 4.0 * * This modification of Douglas Thomson's code is released into the * public domain, Frank Davis. You may distribute it freely. */ char *greatest_composer_ever = "W. A. Mozart, 1756-1791"; #include "tdestr.h" /* tde types */ #include "common.h" #include "define.h" #include "help.h" #include "tdefunc.h" #include /* open flags */ #if defined( __UNIX__ ) #include /* unix critical errors */ #else #include /* for renaming files */ #include /* for direct BIOS keyboard input */ #include /* for file attribute code */ #if defined( __MSC__ ) #include #include /* S_IWRITE etc */ #endif #include /* S_IWRITE etc */ #endif #if defined( __MSC__ ) void (interrupt FAR *old_control_c)( ); /* variable for old CNTL-C */ void (interrupt FAR *old_int1b)( ); /* variable for old int 1b */ #endif /* * original control-break checking flag */ static int s_cbrk; /* * Name: main * Purpose: To do any system dependent command line argument processing, * and then call the main editor function. * Date: October 10, 1989 * Passed: argc: number of command line arguments * argv: text of command line arguments */ int main( int argc, char *argv[] ) { #if defined( __MSC__ ) union REGS inregs, outregs; #endif g_status.found_first = FALSE; g_status.arg = 1; g_status.argc = argc; g_status.argv = argv; #if defined( __UNIX__ ) /* * unix signals are kinda analagous to DOS critical errors. */ /* signal( SIGABRT, crit_err_handler ); signal( SIGALRM, crit_err_handler ); signal( SIGCHLD, crit_err_handler ); signal( SIGCONT, crit_err_handler ); signal( SIGFPE, crit_err_handler ); signal( SIGHUP, crit_err_handler ); signal( SIGILL, crit_err_handler ); signal( SIGINT, crit_err_handler ); signal( SIGIO, crit_err_handler ); signal( SIGIOT, crit_err_handler ); signal( SIGKILL, crit_err_handler ); signal( SIGPIPE, crit_err_handler ); signal( SIGPOLL, crit_err_handler ); signal( SIGPWR, crit_err_handler ); signal( SIGQUIT, crit_err_handler ); signal( SIGSEGV, crit_err_handler ); signal( SIGSTOP, crit_err_handler ); signal( SIGTERM, crit_err_handler ); signal( SIGTRAP, crit_err_handler ); signal( SIGTSTP, crit_err_handler ); signal( SIGTTIN, crit_err_handler ); signal( SIGTTOU, crit_err_handler ); signal( SIGURG, crit_err_handler ); signal( SIGUSR1, crit_err_handler ); signal( SIGUSR2, crit_err_handler ); signal( SIGVTALRM, crit_err_handler ); signal( SIGWINCH, crit_err_handler ); signal( SIGXCPU, crit_err_handler ); signal( SIGXFSZ, crit_err_handler ); */ #else /* * trap control-break to make it harmless, and turn checking off. * trap control-C to make it harmless. */ # if defined( __MSC__ ) inregs.h.ah = 0x33; inregs.h.al = 0; intdos( &inregs, &outregs ); s_cbrk = outregs.h.dl; old_control_c = _dos_getvect( (unsigned)0x23 ); _dos_setvect( 0x23, harmless ); old_int1b = _dos_getvect( (unsigned)0x1b ); _dos_setvect( 0x1b, ctrl_break ); inregs.h.ah = 0x33; inregs.h.al = 1; inregs.h.dl = 0; intdos( &inregs, &outregs ); # else s_cbrk = getcbrk( ); ctrlbrk( harmless ); setcbrk( 0 ); # endif /* * now, install and initialize our simple Critical Error Handler. */ install_ceh( &ceh ); #endif ceh.flag = OK; if (initialize( ) != ERROR) editor( ); terminate( ); return( 0 ); } /* * Name: error * Purpose: To report an error, and usually make the user type before * continuing. * Date: June 5, 1991 * Passed: kind: an indication of how serious the error was: * WARNING: continue after pressing a key * FATAL: abort the editor * line: line to display message * message: string to be printed * Notes: Show user the message and ask for a key if needed. */ void error( int kind, int line, char *message ) { char buff[MAX_COLS+2]; /* somewhere to store error before printing */ #if defined( __UNIX__ ) chtype display_buff[MAX_COLS+2]; /* chtype is defined in curses.h */ #else char display_buff[(MAX_COLS+2)*2]; #endif /* * tell the user what kind of an error it is */ switch (kind) { case FATAL: /* * fatal error */ assert( strlen( main1 ) < (size_t)g_display.ncols ); strcpy( buff, main1 ); break; case WARNING: default: /* * warning */ assert( strlen( main2 ) < (size_t)g_display.ncols ); strcpy( buff, main2 ); break; } /* * prepare the error message itself */ strcat( buff, message ); /* * tell the user how to continue editing if necessary */ if (kind == WARNING) /* * press a key */ strcat( buff, main3 ); /* * output the error message */ save_screen_line( 0, line, display_buff ); set_prompt( buff, line ); if (kind == FATAL) { /* * no point in making the user type , since the program is * about to abort anyway... */ terminate( ); exit( 1 ); } getkey( ); restore_screen_line( 0, line, display_buff ); if (g_status.wrapped) { g_status.wrapped = FALSE; show_search_message( CLR_SEARCH, g_display.mode_color ); } } /* * Name: harmless * Purpose: Do nothing when control-C is pressed * Date: June 5, 1991 * Notes: Interrupt 23, the Control-C handler, is a MS DOS system function. * Since we want to use Control-C as a regular function key, * let's do absolutely nothing when Control-C is pressed. */ #if defined( __UNIX__ ) void harmless( void ) #else #if defined( __MSC__ ) void interrupt FAR harmless( void ) #else static int harmless( void ) #endif #endif { } /* * Name: ctrl_break * Purpose: Set our control-break flag when control-break is pressed. * Date: June 5, 1992 * Notes: Control-break is a little different from Control-C. When * Control-C is pressed, MS DOS processes it as soon as possible, * which may be quite a while. On the other hand, when * Control-break is pressed on IBM and compatibles, interrupt 0x1b * is generated immediately. Since an interrupt is generated * immediately, we can gain control of run-away functions, like * recursive macros, by checking our Control-break flag. */ #if !defined( __UNIX__ ) void interrupt FAR ctrl_break( void ) { g_status.control_break = TRUE; } #endif /* * Name: terminate * Purpose: To free all dynamic structures and unload anything we loaded * Date: June 5, 1991 */ void terminate( void ) { #if !defined( __UNIX__ ) union REGS inregs, outregs; #endif register TDE_WIN *wp; /* register for scanning windows */ TDE_WIN *w; /* free window */ register file_infos *fp; /* register for scanning files */ file_infos *f; /* free files */ int i; /* * restore control-break checking */ #if defined( __UNIX__ ) noraw( ); endwin( ); /* * if we were doing any multi-file searching, close the directory pointer */ if (g_status.dp != NULL) closedir( g_status.dp ); if (g_status.sas_dp != NULL) closedir( g_status.sas_dp ); #elif defined( __MSC__ ) _dos_setvect( 0x1b, old_int1b ); _dos_setvect( 0x23, old_control_c ); inregs.h.ah = 0x33; inregs.h.al = 1; inregs.h.dl = (char)s_cbrk; intdos( &inregs, &outregs ); #else setcbrk( s_cbrk ); #endif /* * free the file structures, if not already free. */ fp = g_status.file_list; while (fp != NULL) { f = fp; fp = fp->next; free( f ); } /* * free the window structures, if not already free. */ wp = g_status.window_list; while (wp != NULL) { w = wp; wp = wp->next; free( w ); } /* * free any character classes in the nfa's. */ for (i=0; i < REGX_SIZE; i++) { if (sas_nfa.class[i] == nfa.class[i] && nfa.class[i] != NULL) free( nfa.class[i] ); else if (sas_nfa.class[i] != NULL) free( sas_nfa.class[i] ); else if (nfa.class[i] != NULL) free( nfa.class[i] ); } #if defined( __UNIX__ ) /* * leave residue from the editing session on the screen. */ puts( "" ); #else /* * reset the cursor size and unload the 83/84 key keyboard utility */ set_cursor_size( mode.cursor_size == SMALL_INS ? g_display.insert_cursor : g_display.overw_cursor ); if (mode.enh_kbd == FALSE) simulate_enh_kbd( 0 ); /* * restore the overscan (border) color */ if (g_display.adapter != MDA) set_overscan_color( g_display.old_overscan ); #endif } /* * Name: initialize * Purpose: To initialize all the screen status info that is not hardware * dependent, and call the hardware initialization routine to * pick up the hardware dependent stuff. * Date: June 5, 1991 * Returns: [g_status and g_display]: all set up ready to go * Notes: It is assumed that g_status and g_display are all \0's to begin * with (the default if they use static storage). If this may * not be the case, then clear them explicitly here. */ int initialize( void ) { int i; int rc; rc = OK; /* * do the hardware initialization first. */ hw_initialize( ); /* * now, initialize the editor modes, pointers, and counters. */ bm.search_defined = ERROR; sas_bm.search_defined = ERROR; g_status.sas_defined = ERROR; g_status.sas_search_type = ERROR; regx.search_defined = ERROR; sas_regx.search_defined = ERROR; if (mode.undo_max < 2) mode.undo_max = 2; g_status.marked_file = NULL; g_status.current_window = NULL; g_status.current_file = NULL; g_status.window_list = NULL; g_status.file_list = NULL; g_status.buff_node = NULL; g_status.window_count = 0; g_status.file_count = 0; g_status.line_buff_len = 0; g_status.tabout_buff_len = 0; g_status.jump_to = 0; g_status.command = 0; g_status.key_pressed = 0; g_status.sas_rcol = 0; g_status.sas_rline = 0; g_status.recording_key = 0; g_status.key_pending = FALSE; g_status.found_first = FALSE; g_status.sas_found_first = FALSE; g_status.copied = FALSE; g_status.wrapped = FALSE; g_status.marked = FALSE; g_status.macro_executing = FALSE; g_status.replace_defined = FALSE; g_status.screen_display = TRUE; g_status.file_chunk = DEFAULT_BIN_LENGTH; g_status.sas_tokens[0] = '\0'; g_status.path[0] = '\0'; g_status.sas_path[0] = '\0'; g_status.rw_name[0] = '\0'; g_status.pattern[0] = '\0'; g_status.subst[0] = '\0'; /* * set the number of lines from one page that should still be visible * on the next page after page up or page down. */ g_status.overlap = 1; #if defined( __UNIX__ ) g_status.dp = NULL; g_status.sas_dp = NULL; #endif /* * initialize the nodes in the nfa. */ for (i=0; i < REGX_SIZE; i++) { sas_nfa.node_type[i] = nfa.node_type[i] = 0; sas_nfa.term_type[i] = nfa.term_type[i] = 0; sas_nfa.c[i] = nfa.c[i] = 0; sas_nfa.next1[i] = nfa.next1[i] = 0; sas_nfa.next2[i] = nfa.next2[i] = 0; sas_nfa.class[i] = nfa.class[i] = NULL; } /* * no macro is executing */ connect_macros( ); /* * clear the screen and show the author's names */ cls( ); show_credits( ); return( rc ); } /* * Name: hw_initialize * Purpose: To initialize the display ready for editor use. * Date: June 5, 1991 */ void hw_initialize( void ) { #if defined( __UNIX__ ) int i; int y; int x; register int *clr; /* * if we are in a linux environment, init the curses package. */ initscr( ); keypad( stdscr, TRUE ); cbreak( ); noecho( ); raw( ); scrollok( stdscr, TRUE ); if (has_colors( )) { start_color( ); g_display.adapter = CGA; clr = &colour.clr[1][0]; } else { g_display.adapter = MDA; clr = &colour.clr[0][0]; } move( 0, 0 ); if (g_display.adapter == CGA) { init_pair( 0, COLOR_WHITE, COLOR_BLACK ); init_pair( 1, COLOR_WHITE, COLOR_BLUE ); init_pair( 2, COLOR_BLUE, COLOR_BLACK ); /* init_pair( 2, COLOR_RED, COLOR_GREEN ); */ init_pair( 3, COLOR_YELLOW, COLOR_CYAN ); init_pair( 4, COLOR_WHITE, COLOR_RED ); /* init_pair( 5, COLOR_BLUE, COLOR_CYAN ); */ init_pair( 5, COLOR_GREEN, COLOR_MAGENTA ); /* init_pair( 6, COLOR_MAGENTA, COLOR_YELLOW ); */ init_pair( 6, COLOR_GREEN, COLOR_BLACK ); init_pair( 7, COLOR_BLUE, COLOR_WHITE ); /* * lets try to emulate the PC color table. in normal color mode, * there are 8 background colors and 16 foreground colors. */ for (i=0; i<8; i++) { tde_color_table[i] = COLOR_PAIR( 0 ); tde_color_table[i+16] = COLOR_PAIR( 1 ); tde_color_table[i+32] = COLOR_PAIR( 2 ); tde_color_table[i+48] = COLOR_PAIR( 3 ); tde_color_table[i+64] = COLOR_PAIR( 4 ); tde_color_table[i+80] = COLOR_PAIR( 5 ); tde_color_table[i+96] = COLOR_PAIR( 6 ); /* tde_color_table[i+112] = COLOR_PAIR( 7 ) | A_DIM; */ tde_color_table[i+112] = COLOR_PAIR( 7 ); } for (i=0; i<8; i++) { tde_color_table[i+8] = COLOR_PAIR( 0 ) | A_BOLD; tde_color_table[i+24] = COLOR_PAIR( 1 ) | A_BOLD; tde_color_table[i+40] = COLOR_PAIR( 2 ) | A_BOLD; tde_color_table[i+56] = COLOR_PAIR( 3 ) | A_BOLD; tde_color_table[i+72] = COLOR_PAIR( 4 ) | A_BOLD; tde_color_table[i+88] = COLOR_PAIR( 5 ) | A_BOLD; tde_color_table[i+104] = COLOR_PAIR( 6 ) | A_BOLD; tde_color_table[i+120] = COLOR_PAIR( 7 ) | A_BOLD; } g_display.head_color = *clr++; g_display.text_color = *clr++; g_display.dirty_color = *clr++; g_display.mode_color = *clr++; g_display.block_color = *clr++; g_display.message_color = *clr++; g_display.help_color = *clr++; g_display.diag_color = *clr++; g_display.eof_color = *clr++; g_display.curl_color = *clr++; g_display.ruler_color = *clr++; g_display.ruler_pointer = *clr++; g_display.hilited_file = *clr++; g_display.overscan = *clr; g_display.dirty_color = 96; g_display.hilited_file = 96; /* g_display.head_color = 64; g_display.ruler_pointer = 104; */ g_display.help_color = 48; g_display.eof_color = 40; /* g_display.dirty_color = 96; g_display.help_color = 56; g_display.hilited_file = 16; */ } else { for (i=0; i<16; i++) { tde_color_table[i] = A_NORMAL; tde_color_table[i+16] = A_REVERSE; tde_color_table[i+32] = A_STANDOUT; tde_color_table[i+48] = A_UNDERLINE; tde_color_table[i+64] = A_BOLD; tde_color_table[i+80] = A_BOLD | A_UNDERLINE; tde_color_table[i+96] = A_BLINK; tde_color_table[i+112] = A_BLINK | A_BOLD; } g_display.head_color = 16; g_display.text_color = 0; g_display.dirty_color = 32; g_display.mode_color = 16; g_display.block_color = 16; g_display.message_color = 48; g_display.help_color = 0; g_display.diag_color = 0; g_display.eof_color = 80; g_display.curl_color = 64; g_display.ruler_color = 0; g_display.ruler_pointer = 64; g_display.hilited_file = 16; g_display.overscan = 0; } #else struct vcfg cfg; /* defined in .h */ register int *clr; int j; /* * work out what kind of display is in use, and set attributes and * display address accordingly. Note that this will only work with * close IBM compatibles. */ video_config( &cfg ); g_display.display_address = (char FAR *)cfg.videomem; /* * Use an integer pointer to go thru the color array for setting up the * various color fields. */ clr = cfg.color == FALSE ? &colour.clr[0][0] : &colour.clr[1][0]; g_display.head_color = *clr++; g_display.text_color = *clr++; g_display.dirty_color = *clr++; g_display.mode_color = *clr++; g_display.block_color = *clr++; g_display.message_color = *clr++; g_display.help_color = *clr++; g_display.diag_color = *clr++; g_display.eof_color = *clr++; g_display.curl_color = *clr++; g_display.ruler_color = *clr++; g_display.ruler_pointer = *clr++; g_display.hilited_file = *clr++; g_display.overscan = *clr; /* * set the overscan color. * in terminate( ), the overscan color is returned to old state. */ if (g_display.adapter != MDA) set_overscan_color( g_display.overscan ); #endif /* * set up screen size */ #if defined( __UNIX__ ) /* * getmaxyx( ) is a curses macro that sets y and x. stdscr is the * standard curses screen. */ getmaxyx( stdscr, y, x ); g_display.ncols = x; g_display.nlines = y - 2; g_display.mode_line = y - 1; #else /* g_display.ncols = MAX_COLS; g_display.nlines = MAX_LINES - 1; g_display.mode_line = MAX_LINES; */ /* * this code was written by Liang (Bill) Chen . * it figures the current screen dimensions in DOS. */ g_display.mode_line = cfg.rows; g_display.nlines = g_display.mode_line-1; if (cfg.regen_len <= 4096) { g_display.nlines = 23; g_display.mode_line = 24; } if (g_display.nlines != 23 && g_display.nlines != 26 && g_display.nlines != 41 && g_display.nlines != 58 && g_display.nlines != 48) { g_display.nlines = 23; g_display.mode_line = 24; } g_display.ncols = cfg.cols; if (g_display.ncols != 80 && g_display.ncols != 100 && g_display.ncols != 132 ) { g_display.ncols = 80; } #endif g_display.line_length = MAX_LINE_LENGTH; #if defined( __UNIX__ ) tdecfgfile( NULL ); #endif } /* * Name: get_help * Purpose: save the screen and display key definitions * Date: June 5, 1991 * Notes: This routine is dependent on the length of the strings in the * help screen. To make it easy to load in a new help screen, * the strings are assumed to be 80 characters long followed by * the '\0' character. It is assumed each that string contains * exactly 81 characters. */ int get_help( TDE_WIN *window ) { register char *help; register int line; xygoto( -1, -1 ); help = help_screen[1]; for (line=0; help != NULL; line++) { s_output( help, line, 0, g_display.help_color ); help = help_screen[line+2]; } #if defined( __UNIX__ ) refresh( ); #endif line = getkey( ); #if defined( __UNIX__ ) cls( ); #endif redraw_screen( window ); return( OK ); } /* * Name: show_credits * Purpose: display authors * Date: June 5, 1991 */ void show_credits( void ) { register char *credit; int line; #if defined( __UNIX__ ) refresh( ); #endif xygoto( -1, -1 ); credit = credit_screen[0]; for (line=0; credit != NULL; ) { s_output( credit, line+2, 11, g_display.text_color ); credit = credit_screen[++line]; } #if defined( __UNIX__ ) refresh( ); #endif }