/******************* 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 - main editor module * Purpose: This file contains the main editor module, and a number of the * smaller miscellaneous editing commands. * It also contains the code for dispatching commands. * File: ed.c * Author: Douglas Thomson * System: this file is intended to be system-independent * Date: October 1, 1989 * I/O: file being edited * files read or written * user commands and prompts * Notes: see the file "dte.doc" for general program documentation */ /********************* end of original comments ********************/ /* * The basic editor routines have been EXTENSIVELY rewritten. I have added * support for lines longer than 80 columns and I have added line number * support. I like to know the real line number that editor functions are * working on and I like to know the total number of lines in a file. * * I rewrote the big series of ifs in the dispatch subroutine. It is now * an array of pointers to functions. We know what function to call as soon * as a key is pressed. It is also makes it easier to implement a configuration * utility and macros. * * I added a few functions that I use quite often and I deleted a few that I * rarely use. Added are Split Line, Join Line, and Duplicate Line. Deleted * are Goto Marker 0-9 (others?). * * ************ In TDE 1.3, I put Goto Marker 0-9 back in. *************** * * I felt that the insert routine should be separated into two routines. One * for inserting the various combinations of newlines and one for inserting * ASCII and extended ASCII characters. * * One of Doug's design considerations was keeping screen updates to a minimum. * I have expanded upon that idea and added support for updating windows * LOCALly, GLOBALly, or NOT_LOCALly. For example, scrolling in one window * does not affect the text in another window - LOCAL update. Adding, deleting, * or modifying text in one window may affect text in other windows - GLOBAL * update. Sometimes, updates to the current window are handled in the task * routines so updates to other windows are done NOT_LOCALly. * * In version 2.2, the big text buffer scheme was replaced by a double * linked list. * * 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. */ #include "tdestr.h" /* typedefs for global variables */ #include "define.h" /* editor function defs */ #include "tdefunc.h" /* prototypes for all functions in tde */ #include "global.h" /* global variables */ #include "prompts.h" /* prompt assignments */ #include "default.h" /* default function key assignments */ /* * Name: insert_newline * Purpose: insert a newline * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: There a several ways to insert a line into a file: 1) pressing * a key, 2) word wrap, 3) any others? * When doing word wrap or format paragraph, don't show any changes. * Wait until the function finishes then show all changes at once. */ int insert_newline( TDE_WIN *window ) { char *source; /* source for block move to make room for c */ char *dest; /* destination for block move */ int len; /* length of current line */ int split_len; int add; /* characters to be added (usually 1 in insert mode) */ int rcol; int rc; long length; int carriage_return; int split_line; int wordwrap; int dirty; int old_bcol; register TDE_WIN *win; /* put window pointer in a register */ file_infos *file; /* pointer to file structure in current window */ line_list_ptr new_node; text_ptr new_line; /* new line */ rc = OK; win = window; file = win->file_info; length = file->length; wordwrap = mode.word_wrap; switch (g_status.command) { case WordWrap : carriage_return = TRUE; split_line = FALSE; break; case AddLine : split_line = carriage_return = FALSE; break; case SplitLine : split_line = carriage_return = TRUE; break; case Rturn : default : /* * if file is opened in BINARY mode, lets keep the user from * unintentially inserting a line feed into the text. */ if (file->crlf == BINARY) return( next_line( win ) ); show_ruler_char( win ); carriage_return = TRUE; split_line = FALSE; break; } /* * make window temporarily invisible to the un_copy_line function */ new_node = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc ); new_line = NULL; win->visible = FALSE; old_bcol = win->bcol; if (rc == OK) { new_node->line = new_line; new_node->len = 0; new_node->dirty = FALSE; if (win->ll->len != EOF) { win->file_info->modified = TRUE; if (mode.do_backups == TRUE) rc = backup_file( win ); copy_line( win->ll ); detab_linebuff( ); len = g_status.line_buff_len; split_len = 0; if (win->rcol < len) win->ll->dirty = TRUE; source = g_status.line_buff + len; if (carriage_return || split_line) { if (win->rcol < len) { source = g_status.line_buff + win->rcol; split_len = len - win->rcol; len = win->rcol; } } g_status.line_buff_len = len; entab_linebuff( ); if (un_copy_line( win->ll, win, TRUE ) == OK) { assert( split_len >= 0 ); assert( split_len < MAX_LINE_LENGTH ); memmove( g_status.line_buff, source, split_len ); g_status.line_buff_len = len = split_len; g_status.copied = TRUE; entab_linebuff( ); } else rc = ERROR; } else { g_status.line_buff_len = len = 0; g_status.copied = TRUE; } if (rc == OK) { new_node->line = new_line; new_node->len = 0; new_node->dirty = TRUE; /* * we are somewhere in the list and we need to insert the new node. * if we are anywhere except the EOF node, insert the new node * after the current node. if the current node is the EOF node, * insert the new node before the EOF node. this keeps the * EOF node at the end of the list. */ if (win->ll->next != NULL) { win->ll->next->prev = new_node; new_node->next = win->ll->next; win->ll->next = new_node; new_node->prev = win->ll; } else { new_node->next = win->ll; if (win->ll->prev != NULL) win->ll->prev->next = new_node; new_node->prev = win->ll->prev; win->ll->prev = new_node; if (new_node->prev == NULL) win->file_info->line_list = new_node; win->ll = new_node; } ++file->length; detab_linebuff( ); entab_linebuff( ); rc = un_copy_line( new_node, win, FALSE ); adjust_windows_cursor( win, 1 ); file->dirty = NOT_LOCAL; if (length == 0l || wordwrap || win->cline == win->bottom_line) file->dirty = GLOBAL; else if (!split_line) update_line( win ); /* * If the cursor is to move down to the next line, then update * the line and column appropriately. */ if (rc == OK && (carriage_return || split_line)) { dirty = file->dirty; if (win->cline < win->bottom_line) win->cline++; win->rline++; if (win->ll->next != NULL) { win->bin_offset += win->ll->len; win->ll = win->ll->next; } rcol = win->rcol; old_bcol = win->bcol; if (win->ll->next != NULL) { if (mode.indent || wordwrap) { /* * autoindentation is required. Match the indentation of * the first line above that is not blank. */ add = find_left_margin( wordwrap == FIXED_WRAP ? win->ll : win->ll->prev, wordwrap ); assert( add >= 0 ); assert( add < MAX_LINE_LENGTH ); copy_line( win->ll ); detab_linebuff( ); len = g_status.line_buff_len; source = g_status.line_buff; if (len + add > MAX_LINE_LENGTH) add = MAX_LINE_LENGTH - len; dest = source + add; assert( len >= 0); assert( len < MAX_LINE_LENGTH ); memmove( dest, source, len ); /* * now put in the autoindent characters */ assert( add >= 0 ); assert( add < MAX_LINE_LENGTH ); memset( source, ' ', add ); win->rcol = add; g_status.line_buff_len += add; entab_linebuff( ); rc = un_copy_line( win->ll, win, TRUE ); } else win->rcol = 0; } if (rc == OK && split_line) { win->rline--; win->ll = win->ll->prev; if (win->cline > win->top_line + window->ruler) win->cline--; win->rcol = rcol; } check_virtual_col( win, win->rcol, win->ccol ); if (dirty == GLOBAL || file->dirty == LOCAL || wordwrap) file->dirty = GLOBAL; else file->dirty = dirty; } } else { if (new_node != NULL) my_free( new_node ); } } else { if (new_node != NULL) my_free( new_node ); error( WARNING, window->bottom_line, main4 ); } /* * record that file has been modified */ win->visible = TRUE; if (rc == OK) { if (file->dirty != GLOBAL) my_scroll_down( win ); restore_marked_block( win, 1 ); show_size( win ); show_avail_mem( ); if (old_bcol != win->bcol) { make_ruler( win ); show_ruler( win ); } } return( rc ); } /* * Name: insert_overwrite * Purpose: To make the necessary changes after the user has typed a normal * printable character * Date: June 5, 1991 * Passed: window: pointer to current window */ int insert_overwrite( TDE_WIN *window ) { char *source; /* source for block move to make room for c */ char *dest; /* destination for block move */ int len; /* length of current line */ int pad; /* padding to add if cursor beyond end of line */ int add; /* characters to be added (usually 1 in insert mode) */ register int rcol; register TDE_WIN *win; /* put window pointer in a register */ int rc; win = window; if (win->ll->len == EOF || g_status.key_pressed >= 256) rc = OK; else { rcol = win->rcol; /* * first check we have room - the editor can not * cope with lines wider than MAX_LINE_LENGTH */ if (rcol >= MAX_LINE_LENGTH) { /* * cannot insert more characters */ error( WARNING, win->bottom_line, ed2 ); rc = ERROR; } else { copy_line( win->ll ); detab_linebuff( ); /* * work out how many characters need to be inserted */ len = g_status.line_buff_len; pad = rcol > len ? rcol - len : 0; if (mode.insert || rcol >= len) /* * inserted characters, or overwritten characters at the end of * the line, are inserted. */ add = 1; else /* * and no extra space is required to overwrite existing characters */ add = 0; /* * check that current line would not get too long. */ if (len + pad + add >= MAX_LINE_LENGTH) { /* * no more room to add */ error( WARNING, win->bottom_line, ed3 ); rc = ERROR; } else { /* * make room for whatever needs to be inserted */ if (pad > 0 || add > 0) { source = g_status.line_buff + rcol - pad; dest = source + pad + add; assert( len + pad - rcol >= 0 ); assert( len + pad - rcol < MAX_LINE_LENGTH ); memmove( dest, source, len + pad - rcol ); /* * put in the required padding */ assert( pad >= 0 ); assert( pad < MAX_LINE_LENGTH ); memset( source, ' ', pad ); } g_status.line_buff[rcol] = (char)g_status.key_pressed; g_status.line_buff_len += pad + add; entab_linebuff( ); /* * always increment the real column (rcol) then adjust the * logical and base column as needed. show the changed line * in all but the LOCAL window. In the LOCAL window, there are * two cases: 1) update the line, or 2) redraw the window if * cursor goes too far right. */ win->file_info->dirty = NOT_LOCAL; win->ll->dirty = TRUE; show_changed_line( win ); if (win->ccol < win->end_col) { show_curl_line( win ); show_ruler_char( win ); win->ccol++; } else { win->bcol++; win->file_info->dirty = LOCAL; make_ruler( win ); show_ruler( win ); } rcol++; } /* * record that file has been modified and adjust cursors, * file start and end pointers as needed. */ check_virtual_col( win, rcol, win->ccol ); win->file_info->modified = TRUE; if (mode.word_wrap) { add = mode.right_justify; mode.right_justify = FALSE; g_status.command = FormatText; word_wrap( win ); mode.right_justify = add; } rc = OK; } } return( rc ); } /* * Name: join_line * Purpose: To join current line and line below at cursor * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: trunc the line. then, join with line below, if it exists. */ int join_line( TDE_WIN *window ) { int len; /* length of current line */ int new_len; /* length of the joined lines */ int next_len; /* length of the line below current line */ text_ptr q; /* next line in file */ text_ptr tab_free; /* next line in file -- with the tabs removed */ int pad; /* padding spaces required */ register TDE_WIN *win; /* put window pointer in a register */ TDE_WIN *wp; line_list_ptr next_node; int rc; win = window; if (win->ll->len == EOF || win->ll->next->len == EOF) return( ERROR ); rc = OK; assert( win->ll->next != NULL ); next_node = win->ll->next; load_undo_buffer( win->file_info, win->ll->line, win->ll->len ); copy_line( win->ll ); detab_linebuff( ); /* * if cursor is in line before eol, reset len to rcol */ if (win->rcol < (len = g_status.line_buff_len)) len = win->rcol; /* * calculate needed padding */ pad = win->rcol > len ? win->rcol - len : 0; assert( pad >= 0 ); assert( pad < MAX_LINE_LENGTH ); /* * if there any tabs in the next line, expand them because we * probably have to redo them anyway. */ next_len = next_node->len; tab_free = detab_a_line( next_node->line, &next_len ); assert( next_len >= 0 ); assert( next_len < MAX_LINE_LENGTH ); assert( len >= 0 ); assert( len < MAX_LINE_LENGTH ); /* * check room to combine lines */ new_len = len + pad + next_len; if (new_len >= MAX_LINE_LENGTH) { /* * cannot combine lines. */ error( WARNING, win->bottom_line, ed4 ); rc = ERROR; } else { if (mode.do_backups == TRUE) { win->file_info->modified = TRUE; rc = backup_file( win ); } q = (text_ptr)(g_status.line_buff + len); /* * insert padding */ if (pad > 0) { while (pad--) *q++ = ' '; } my_memcpy( q, tab_free, next_len ); g_status.line_buff_len = new_len; entab_linebuff( ); if ((rc = un_copy_line( win->ll, win, FALSE )) == OK) { if (next_node->next != NULL) next_node->next->prev = win->ll; win->ll->next = next_node->next; win->ll->dirty = TRUE; --win->file_info->length; ++win->rline; adjust_windows_cursor( win, -1 ); restore_marked_block( win, -1 ); --win->rline; wp = g_status.window_list; while (wp != NULL) { if (wp->file_info == win->file_info) { /* * make sure none of the window pointers point to the * node we are about to delete. */ if (wp != win) { if (wp->ll == next_node) wp->ll = win->ll->next; } } wp = wp->next; } /* * now, it's safe to delete the next_node line as well as * the next node. */ if (next_node->line != NULL) my_free( next_node->line ); my_free( next_node ); show_size( win ); show_avail_mem( ); win->file_info->dirty = GLOBAL; } } return( rc ); } /* * Name: word_delete * Purpose: To delete from the cursor to the start of the next word. * Date: September 1, 1991 * Passed: window: pointer to current window * Notes: If the cursor is at the right of the line, then combine the * current line with the next one, leaving the cursor where it * is. * If the cursor is on an alphanumeric character, then all * subsequent alphanumeric characters are deleted. * If the cursor is on a space, then all subsequent spaces * are deleted. * If the cursor is on a punctuation character, then all * subsequent punctuation characters are deleted. */ int word_delete( TDE_WIN *window ) { int len; /* length of current line */ int count; /* number of characters deleted from line */ register int start; /* column that next word starts in */ char *source; /* source for block move to delete word */ char *dest; /* destination for block move */ text_ptr p; register TDE_WIN *win; /* put window pointer in a register */ int rc; win = window; if (win->rline > win->file_info->length || win->ll->len == EOF) return( ERROR ); rc = OK; copy_line( win->ll ); detab_linebuff( ); if (win->rcol >= (len = g_status.line_buff_len)) { rc = join_line( win ); if (rc == OK) { p = win->ll->line; if (p != NULL) { p += win->rcol; if (win->rcol < win->ll->len) { len = win->ll->len - win->rcol; load_undo_buffer( win->file_info, p, len ); } } } } else { assert( len >= 0); assert( len < MAX_LINE_LENGTH ); /* * normal word delete * * find the start of the next word */ start = win->rcol; if (bj_isspace( g_status.line_buff[start] )) { /* * the cursor was on a space, so eat all consecutive spaces * from the cursor onwards. */ while (start < len && bj_isspace( g_status.line_buff[start] )) ++start; } else { /* * eat all consecutive characters in the same class (spaces * are considered to be in the same class as the cursor * character) */ while (start < len && !bj_isspace( g_status.line_buff[start] )) ++start; while (start < len && bj_isspace( g_status.line_buff[start] )) ++start; } /* * move text to delete word */ count = start - win->rcol; source = g_status.line_buff + start; dest = g_status.line_buff + win->rcol; assert( len - start >= 0 ); memmove( dest, source, len - start ); g_status.line_buff_len = len - count; entab_linebuff( ); win->file_info->modified = TRUE; win->file_info->dirty = GLOBAL; win->ll->dirty = TRUE; /* * word_delete is also called by the word processing functions to get * rid of spaces. */ if (g_status.command == WordDelete) show_changed_line( win ); } return( rc ); } /* * Name: dup_line * Purpose: Duplicate current line * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: cursor stays on current line */ int dup_line( TDE_WIN *window ) { register int len; /* length of current line */ text_ptr p; register TDE_WIN *win; /* put window pointer in a register */ line_list_ptr next_node; int rc; win = window; /* * don't dup a NULL line */ if (win->rline > win->file_info->length || win->ll->len == EOF) return( ERROR ); entab_linebuff( ); rc = un_copy_line( win->ll, win, TRUE ); len = win->ll->len; assert( len >= 0); assert( len < MAX_LINE_LENGTH ); p = NULL; next_node = NULL; if (rc == OK) { p = (text_ptr)my_malloc( len, &rc ); next_node = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc ); } if (rc == OK) { win->file_info->modified = TRUE; if (mode.do_backups == TRUE) rc = backup_file( win ); ++win->file_info->length; if (len > 0) my_memcpy( p, win->ll->line, len ); next_node->line = p; next_node->dirty = TRUE; next_node->len = len; if (win->ll->next != NULL) win->ll->next->prev = next_node; next_node->next = win->ll->next; next_node->prev = win->ll; win->ll->next = next_node; adjust_windows_cursor( win, 1 ); /* * if current line is the bottom line, we can't see the dup line because * cursor doesn't move and dup line is added after current line. */ if (win->cline != win->bottom_line) my_scroll_down( win ); win->file_info->dirty = NOT_LOCAL; /* * record that file has been modified */ restore_marked_block( win, 1 ); show_size( win ); show_avail_mem( ); } else { /* * cannot duplicate line */ if (p != NULL) my_free( p ); if (next_node != NULL) my_free( next_node ); error( WARNING, win->bottom_line, ed5 ); } return( rc ); } /* * Name: back_space * Purpose: To delete the character to the left of the cursor. * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: If the cursor is at the left of the line, then combine the * current line with the previous one. * If in indent mode, and the cursor is on the first non-blank * character of the line, then match the indentation of an * earlier line. */ int back_space( TDE_WIN *window ) { int rc; /* return code */ int len; /* length of the current line */ char *source; /* source of block move to delete character */ char *dest; /* destination of block move */ text_ptr p; /* previous line in file */ int plen; /* length of previous line */ int del_count; /* number of characters to delete */ int pos; /* the position of the first non-blank char */ register int rcol; int ccol; int old_bcol; register TDE_WIN *win; /* put window pointer in a register */ TDE_WIN *wp; line_list_ptr temp_ll; win = window; if (win->rline > win->file_info->length || win->ll->len == EOF) return( ERROR ); rc = OK; copy_line( win->ll ); detab_linebuff( ); len = g_status.line_buff_len; rcol = win->rcol; ccol = win->ccol; old_bcol = win->bcol; if (rcol == 0) { if (win->rline > 1) { /* * combine this line with the previous, if any */ assert( win->ll->prev != NULL ); p = win->ll->prev->line; plen = win->ll->prev->len; if (len + 2 + plen >= MAX_LINE_LENGTH) { /* * cannot combine lines */ error( WARNING, win->bottom_line, ed4 ); return( ERROR ); } win->file_info->modified = TRUE; if ((rc = un_copy_line( win->ll, win, TRUE )) == OK) { --win->rline; win->ll = win->ll->prev; win->bin_offset -= win->ll->len; win->ll->dirty = TRUE; copy_line( win->ll ); detab_linebuff( ); len = g_status.line_buff_len; rcol = len; p = win->ll->next->line; plen = win->ll->next->len; /* * copy previous line into new previous line. */ assert( plen >= 0 ); assert( len >= 0 ); my_memcpy( g_status.line_buff+len, p, plen ); g_status.line_buff_len = len + plen; load_undo_buffer( win->file_info, p, plen ); if (p != NULL) my_free( p ); temp_ll = win->ll->next; if (temp_ll->prev != NULL) temp_ll->prev->next = temp_ll->next; temp_ll->next->prev = temp_ll->prev; --win->file_info->length; ++win->rline; restore_marked_block( win, -1 ); adjust_windows_cursor( win, -1 ); --win->rline; wp = g_status.window_list; while (wp != NULL) { if (wp->file_info == win->file_info) { if (wp != win) { if (wp->ll == temp_ll) wp->ll = win->ll->next; } } wp = wp->next; } my_free( temp_ll ); if (win->cline > win->top_line + win->ruler) --win->cline; /* * make sure cursor stays on the screen, at the end of the * previous line */ ccol = rcol - win->bcol; show_size( win ); show_avail_mem( ); check_virtual_col( win, rcol, ccol ); win->file_info->dirty = GLOBAL; make_ruler( win ); show_ruler( win ); } } else return( ERROR ); } else { /* * normal delete * * find out how much to delete (depends on indent mode) */ del_count = 1; /* the default */ if (mode.indent) { /* * indent only happens if the cursor is on the first * non-blank character of the line */ pos = first_non_blank( (text_ptr)g_status.line_buff, len ); if (pos == rcol || is_line_blank( (text_ptr)g_status.line_buff, len )) { /* * now work out how much to indent */ temp_ll = win->ll->prev; for (; temp_ll != NULL; temp_ll=temp_ll->prev) { p = temp_ll->line; plen = first_non_blank( p, temp_ll->len ); if (plen < rcol && plen != temp_ll->len) { /* * found the line to match */ del_count = rcol - plen; break; } } } } /* * move text to delete char(s), unless no chars actually there */ if (rcol - del_count < len) { dest = g_status.line_buff + rcol - del_count; if (rcol > len) { source = g_status.line_buff + len; pos = 0; len = (rcol + 1) - del_count; } else { source = g_status.line_buff + rcol; pos = len - rcol; len = len - del_count; } assert( pos >= 0 ); assert( len >= 0 ); assert( len <= MAX_LINE_LENGTH ); memmove( dest, source, pos ); g_status.line_buff_len = len; entab_linebuff( ); } rcol -= del_count; ccol -= del_count; win->file_info->dirty = NOT_LOCAL; win->ll->dirty = TRUE; show_ruler_char( win ); show_changed_line( win ); check_virtual_col( win, rcol, ccol ); if (!win->file_info->dirty) show_curl_line( win ); if (old_bcol != win->bcol) { make_ruler( win ); show_ruler( win ); } } win->file_info->modified = TRUE; return( rc ); } /* * Name: line_kill * Purpose: To delete the line the cursor is on. * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: win->ll->s == NULL then do not do a * line kill (can't kill a NULL line). */ int line_kill( TDE_WIN *window ) { register TDE_WIN *win; /* put window pointer in a register */ register TDE_WIN *wp; line_list_ptr killed_node; int rc; win = window; killed_node = win->ll; rc = OK; if (killed_node->len != EOF) { win->file_info->modified = TRUE; if (mode.do_backups == TRUE) rc = backup_file( win ); if (rc == OK) { load_undo_buffer( win->file_info, g_status.copied ? (text_ptr)g_status.line_buff : killed_node->line, g_status.copied ? g_status.line_buff_len : killed_node->len ); --win->file_info->length; win->ll = win->ll->next; if (killed_node->prev != NULL) killed_node->prev->next = killed_node->next; else win->file_info->line_list = win->ll; killed_node->next->prev = killed_node->prev; wp = g_status.window_list; while (wp != NULL) { if (wp->file_info == win->file_info) { if (wp != win) { if (wp->ll == killed_node) wp->ll = win->ll; } } wp = wp->next; } /* * free the line and the node */ if (killed_node->line != NULL) my_free( killed_node->line ); my_free( killed_node ); win->file_info->dirty = NOT_LOCAL; g_status.copied = FALSE; /* * move all cursors one according to i, restore begin and end block */ adjust_windows_cursor( win, -1 ); restore_marked_block( win, -1 ); /* * we are not doing a GLOBAL update, so update current window here */ if (win->file_info->dirty == NOT_LOCAL) my_scroll_down( win ); show_size( win ); show_avail_mem( ); } } else rc = ERROR; return( rc ); } /* * Name: char_del_under * Purpose: To delete the character under the cursor. * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: If the cursor is beyond the end of the line, then this * command is ignored. * DeleteChar and StreamDeleteChar use this function. */ int char_del_under( TDE_WIN *window ) { char *source; /* source of block move to delete character */ int len; register TDE_WIN *win; /* put window pointer in a register */ win = window; if (win->rline > win->file_info->length || win->ll->len == EOF) return( OK ); copy_line( win->ll ); detab_linebuff( ); if (win->rcol < (len = g_status.line_buff_len)) { /* * move text to delete using buffer */ source = g_status.line_buff + win->rcol + 1; assert( len - win->rcol >= 0 ); memmove( source-1, source, len - win->rcol ); --g_status.line_buff_len; entab_linebuff( ); win->file_info->dirty = GLOBAL; win->file_info->modified = TRUE; win->ll->dirty = TRUE; show_changed_line( win ); } else if (g_status.command == StreamDeleteChar) join_line( win ); return( OK ); } /* * Name: eol_kill * Purpose: To delete everything from the cursor to the end of the line. * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: If the cursor is beyond the end of the line, then this * command is ignored. */ int eol_kill( TDE_WIN *window ) { register TDE_WIN *win; /* put window pointer in a register */ win = window; if (win->rline > win->file_info->length || win->ll->len == EOF) return( OK ); copy_line( win->ll ); detab_linebuff( ); load_undo_buffer( win->file_info, (text_ptr)g_status.line_buff, g_status.line_buff_len ); if (win->rcol < g_status.line_buff_len) { /* * truncate to delete rest of line */ g_status.line_buff_len = win->rcol; entab_linebuff( ); win->file_info->dirty = GLOBAL; win->ll->dirty = TRUE; show_changed_line( win ); } return( OK ); } /* * Name: undo_line * Purpose: To retrieve unaltered line if possible. * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: Changes are made to the line buffer so the underlying text has * not changed. Put the unchanged line from the file into the * line buffer and display it. */ int undo_line( TDE_WIN *window ) { register TDE_WIN *win; /* put window pointer in a register */ win = window; if (win->rline <= win->file_info->length && win->ll->len != EOF && g_status.copied) { g_status.copied = FALSE; copy_line( win->ll ); detab_linebuff( ); win->file_info->dirty = GLOBAL; show_changed_line( win ); } return( OK ); } /* * Name: undo * Purpose: To retrieve (pop) a line from the undo stack * Date: September 26, 1991 * Passed: window: pointer to current window * Notes: Insert an empty line into the file then pop the line in the undo * stack. When we pop line 0, there are no more lines on the stack. * Set the stack pointer to -1 to indicate an empty stack. */ int undo( TDE_WIN *window ) { register TDE_WIN *win; /* put window pointer in a register */ line_list_ptr node; win = window; if (win->file_info->undo_count > 0) { entab_linebuff( ); if (un_copy_line( win->ll, win, TRUE ) == ERROR) return( ERROR ); node = win->file_info->undo_top; win->file_info->undo_top = node->next; win->file_info->undo_top->prev = NULL; --win->file_info->undo_count; node->next = node->prev = NULL; ++win->file_info->length; if (win->ll->prev != NULL) win->ll->prev->next = node; node->prev = win->ll->prev; win->ll->prev = node; node->next = win->ll; win->ll = node; win->ll->dirty = TRUE; if (win->ll->prev == NULL) win->file_info->line_list = win->ll; adjust_windows_cursor( win, 1 ); /* * we have now undeleted a line. increment the file length and display * it. */ win->file_info->dirty = GLOBAL; show_size( win ); show_avail_mem( ); } return( OK ); } /* * Name: beg_next_line * Purpose: To move the cursor to the beginning of the next line. * Date: October 4, 1991 * Passed: window: pointer to current window */ int beg_next_line( TDE_WIN *window ) { int rc; window->rcol = 0; rc = prepare_move_down( window ); check_virtual_col( window, window->rcol, window->ccol ); cursor_sync( window ); make_ruler( window ); show_ruler( window ); return( rc ); } /* * Name: next_line * Purpose: To move the cursor to the first character of the next line. * Date: October 4, 1991 * Passed: window: pointer to current window */ int next_line( TDE_WIN *window ) { register int rcol; register TDE_WIN *win; /* put window pointer in a register */ int rc; win = window; rc = prepare_move_down( win ); rcol = first_non_blank( win->ll->line, win->ll->len ); check_virtual_col( win, rcol, win->ccol ); cursor_sync( win ); make_ruler( win ); show_ruler( win ); return( rc ); } /* * Name: home * Purpose: To move the cursor to the left of the current line. * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: this routine is made a little more complicated with cursor sync. * if the g_status.copied flag is set we need to see from what file * the line_buff was copied. */ int home( TDE_WIN *window ) { register int rcol; register TDE_WIN *win; /* put window pointer in a register */ text_ptr p; win = window; if (g_status.copied && win->file_info == g_status.current_window->file_info){ rcol = first_non_blank( (text_ptr)g_status.line_buff, g_status.line_buff_len ); if (is_line_blank( (text_ptr)g_status.line_buff, g_status.line_buff_len)) rcol = 0; } else { p = win->ll->line; if (p == NULL) rcol = 0; else { rcol = first_non_blank( p, win->ll->len ); if (is_line_blank( p, win->ll->len )) rcol = 0; } } if (win->rcol == rcol) rcol = 0; check_virtual_col( win, rcol, win->ccol ); cursor_sync( win ); make_ruler( win ); show_ruler( win ); return( OK ); } /* * Name: goto_eol * Purpose: To move the cursor to the eol character of the current line. * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: this routine is made a little more complicated with cursor sync. * if the g_status.copied flag is set we need to see from what file * the line_buff was copied. */ int goto_eol( TDE_WIN *window ) { register int rcol; register TDE_WIN *win; /* put window pointer in a register */ win = window; rcol = find_end( win->ll->line, win->ll->len ); if (g_status.copied) { if (win->file_info == g_status.current_window->file_info) rcol = find_end( (text_ptr)g_status.line_buff, g_status.line_buff_len); } win->ccol = win->start_col + rcol - win->bcol; check_virtual_col( win, rcol, win->ccol ); cursor_sync( win ); make_ruler( win ); show_ruler( win ); return( OK ); } /* * Name: goto_top * Purpose: To move the cursor to the top of the current window. * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: If the start of the file occurs before the top of the window, * then the start of the file is moved to the top of the window. */ int goto_top( TDE_WIN *window ) { register TDE_WIN *win; /* put window pointer in a register */ win = window; entab_linebuff( ); if (un_copy_line( win->ll, win, TRUE ) == ERROR) return( ERROR ); update_line( win ); for (; win->cline > win->top_line+win->ruler; win->cline--,win->rline--) { if (win->rline <= 1L) break; else { win->ll = win->ll->prev; win->bin_offset -= win->ll->len; } } show_curl_line( win ); cursor_sync( win ); return( OK ); } /* * Name: goto_bottom * Purpose: To move the cursor to the bottom of the current window. * Date: June 5, 1991 * Passed: window: pointer to current window */ int goto_bottom( TDE_WIN *window ) { register TDE_WIN *win; /* put window pointer in a register */ int at_top; win = window; entab_linebuff( ); if (un_copy_line( win->ll, win, TRUE ) == ERROR) return( ERROR ); if (win->ll->len == EOF) { if (win->rline > 1) { at_top = FALSE; if (win->cline == win->top_line + win->ruler) { win->file_info->dirty = LOCAL; at_top = TRUE; } if (!at_top) update_line( win ); --win->rline; /* ALWAYS decrement line counter */ win->ll = win->ll->prev; win->bin_offset -= win->ll->len; if (!at_top) { --win->cline; /* we aren't at top of screen - so move up */ show_curl_line( win ); } } } else { update_line( win ); for (; win->cline < win->bottom_line; win->cline++,win->rline++) { if (win->ll == NULL || win->ll->next == NULL || win->ll->next->len == EOF) break; else { win->bin_offset += win->ll->len; win->ll = win->ll->next; } } show_curl_line( win ); } cursor_sync( win ); return( OK ); } /* * Name: set_tabstop * Purpose: To set the current interval between tab stops * Date: October 1, 1989 * Notes: Tab interval must be reasonable, and this function will * not allow tabs more than g_display.ncols / 2. */ int set_tabstop( TDE_WIN *window ) { int tab; /* new tab interval */ register int rc; register file_infos *file; char temp[MAX_COLS+2]; my_ltoa( mode.ltab_size, temp, 10 ); /* * tab interval: */ rc = get_name( ed7a, window->bottom_line, temp, g_display.message_color ); if (rc == OK && *temp != '\0') { tab = atoi( temp ); if (tab < g_display.ncols / 2) { mode.ltab_size = tab; if (mode.inflate_tabs) { for (file=g_status.file_list; file != NULL; file=file->next) file->dirty = GLOBAL; } } else { /* * tab size too long */ error( WARNING, window->bottom_line, ed8 ); rc = ERROR; } } my_ltoa( mode.ptab_size, temp, 10 ); /* * tab interval: */ rc = get_name( ed7b, window->bottom_line, temp, g_display.message_color ); if (rc == OK && *temp != '\0') { tab = atoi( temp ); if (tab < g_display.ncols / 2) { mode.ptab_size = tab; show_tab_modes( ); if (mode.inflate_tabs) { for (file=g_status.file_list; file != NULL; file=file->next) file->dirty = GLOBAL; } } else { /* * tab size too long */ error( WARNING, window->bottom_line, ed8 ); rc = ERROR; } } return( rc ); } /* * Name: show_line_col * Purpose: show current real line and column of current cursor position * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: Blank old position and display new position. current line and * column may take up to 12 columns, which allows the display of * 9,999 columns and 9,999,999 lines. */ void show_line_col( TDE_WIN *window ) { int i; register int k; char line_col[20], num[10]; char *hex_digit = "0123456789abcdef"; /* * blank out current line:column position. */ memset( line_col, ' ', 13 ); line_col[13] = '\0'; /* * convert column to ascii and store in display buffer. */ my_ltoa( window->rcol+1, num, 10 ); i = strlen( num ) - 1; for (k=12; i>=0; i--, k--) line_col[k] = num[i]; /* * put in colon to separate line and column */ line_col[k--] = ':'; /* * convert line to ascii and store in display buffer. */ my_ltoa( window->rline, num, 10 ); i = strlen( num ) - 1; for (; i>=0; i--, k--) line_col[k] = num[i]; /* * find line to start line:column display then output */ s_output( line_col, window->top_line-1, window->end_col-12, g_display.head_color ); strcpy( line_col, " = " ); i = window->rcol; if (g_status.copied) { if (mode.inflate_tabs) i = entab_adjust_rcol( (text_ptr)g_status.line_buff, g_status.line_buff_len, i ); if (i < g_status.line_buff_len) { k = (unsigned char)g_status.line_buff[i]; line_col[2] = *(hex_digit + (k >> 4)); line_col[3] = *(hex_digit + (k & 0x000f)); line_col[4] = 'x'; i = TRUE; } else i = FALSE; } else { if (mode.inflate_tabs && window->ll->len != EOF) i = entab_adjust_rcol( window->ll->line, window->ll->len, i ); if (i < window->ll->len) { k = (int)window->ll->line[i]; line_col[2] = *(hex_digit + (k >> 4)); line_col[3] = *(hex_digit + (k & 0x000f)); line_col[4] = 'x'; i = TRUE; } else i = FALSE; } s_output( line_col, g_display.mode_line, 58, g_display.mode_color ); if (i == TRUE) c_output( k, 58, g_display.mode_line, g_display.mode_color ); /* * if file was opened in binary mode, show offset from beginning of file. */ if (window->file_info->crlf == BINARY && !window->vertical) { k = window->ll->line == NULL ? 0 : window->rcol; memset( line_col, ' ', 7 ); line_col[7] = '\0'; s_output( line_col, window->top_line-1, 61, g_display.head_color ); my_ltoa( window->bin_offset + k, line_col, 10 ); s_output( line_col, window->top_line-1, 61, g_display.head_color ); } show_asterisk( window ); } /* * Name: show_asterisk * Purpose: give user an indication if file is dirty * Date: September 16, 1991 * Passed: window: pointer to current window */ void show_asterisk( TDE_WIN *window ) { c_output( window->file_info->modified ? '*' : ' ', window->start_col+4, window->top_line-1, g_display.head_color ); } /* * Name: toggle_overwrite * Purpose: toggle overwrite-insert mode * Date: September 16, 1991 * Passed: arg_filler: argument to satify function prototype */ int toggle_overwrite( TDE_WIN *arg_filler ) { mode.insert = !mode.insert; show_insert_mode( ); set_cursor_size( mode.insert ? g_display.insert_cursor : g_display.overw_cursor ); return( OK ); } /* * Name: toggle_smart_tabs * Purpose: toggle smart tab mode * Date: June 5, 1992 * Passed: arg_filler: argument to satify function prototype */ int toggle_smart_tabs( TDE_WIN *arg_filler ) { mode.smart_tab = !mode.smart_tab; show_tab_modes( ); return( OK ); } /* * Name: toggle_indent * Purpose: toggle indent mode * Date: September 16, 1991 * Passed: arg_filler: argument to satify function prototype */ int toggle_indent( TDE_WIN *arg_filler ) { mode.indent = !mode.indent; show_indent_mode( ); return( OK ); } /* * Name: set_left_margin * Purpose: set left margin for word wrap * Date: November 27, 1991 * Passed: window */ int set_left_margin( TDE_WIN *window ) { register int rc; char temp[MAX_COLS+2]; my_ltoa( mode.left_margin + 1, temp, 10 ); /* * enter left margin */ rc = get_name( ed9, window->bottom_line, temp, g_display.message_color ); if (rc == OK && *temp != '\0') { rc = atoi( temp ) - 1; if (rc < 0 || rc >= mode.right_margin) { /* * left margin out of range */ error( WARNING, window->bottom_line, ed10 ); rc = ERROR; } else { mode.left_margin = rc; show_all_rulers( ); } } return( rc ); } /* * Name: set_right_margin * Purpose: set right margin for word wrap * Date: November 27, 1991 * Passed: window */ int set_right_margin( TDE_WIN *window ) { register int rc; int prompt_line; char temp[MAX_COLS+2]; #if defined( __UNIX__ ) chtype display_buff[MAX_COLS+2]; /* chtype is defined in curses.h */ #else char display_buff[(MAX_COLS+2)*2]; #endif prompt_line = window->bottom_line; save_screen_line( 0, prompt_line, display_buff ); set_prompt( ed11a, prompt_line ); rc = get_yn( ); restore_screen_line( 0, prompt_line, display_buff ); if (rc != ERROR) { mode.right_justify = rc == A_YES ? TRUE : FALSE; my_ltoa( mode.right_margin + 1, temp, 10 ); /* * enter right margin */ rc = get_name( ed11, prompt_line, temp, g_display.message_color ); if (rc == OK && *temp != '\0') { rc = atoi( temp ) - 1; if (rc <= mode.left_margin || rc > MAX_LINE_LENGTH) { /* * right margin out of range */ error( WARNING, prompt_line, ed12 ); rc = ERROR; } else { mode.right_margin = rc; show_all_rulers( ); } } } return( rc ); } /* * Name: set_paragraph_margin * Purpose: set column to begin paragraph * Date: November 27, 1991 * Passed: window * Notes: paragraph may be indented, flush, or offset. */ int set_paragraph_margin( TDE_WIN *window ) { register int rc; char temp[MAX_COLS+2]; my_ltoa( mode.parg_margin + 1, temp, 10 ); /* * enter paragraph margin */ rc = get_name( ed13, window->bottom_line, temp, g_display.message_color ); if (rc == OK && *temp != '\0') { rc = atoi( temp ) - 1; if (rc < 0 || rc >= mode.right_margin) { /* * paragraph margin out of range */ error( WARNING, window->bottom_line, ed14 ); rc = ERROR; } else { mode.parg_margin = rc; show_all_rulers( ); } } return( rc ); } /* * Name: toggle_crlf * Purpose: toggle crlf mode * Date: November 27, 1991 * Passed: arg_filler: argument to satify function prototype */ int toggle_crlf( TDE_WIN *window ) { register TDE_WIN *w; ++window->file_info->crlf; if (window->file_info->crlf > BINARY) window->file_info->crlf = CRLF; w = g_status.window_list; while (w != NULL) { if (w->file_info == window->file_info && w->visible) show_crlf_mode( w ); w = w->next; } return( OK ); } /* * Name: toggle_ww * Purpose: toggle word wrap mode * Date: November 27, 1991 * Passed: arg_filler: argument to satify function prototype */ int toggle_ww( TDE_WIN *arg_filler ) { ++mode.word_wrap; if (mode.word_wrap > DYNAMIC_WRAP) mode.word_wrap = NO_WRAP; show_wordwrap_mode( ); return( OK ); } /* * Name: toggle_trailing * Purpose: toggle eleminating trainling space at eol * Date: November 25, 1991 * Passed: arg_filler: argument to satify function prototype */ int toggle_trailing( TDE_WIN *arg_filler ) { mode.trailing = !mode.trailing; show_trailing( ); return( OK ); } /* * Name: toggle_z * Purpose: toggle writing control z at eof * Date: November 25, 1991 * Passed: arg_filler: argument to satify function prototype */ int toggle_z( TDE_WIN *arg_filler ) { mode.control_z = !mode.control_z; show_control_z( ); return( OK ); } /* * Name: toggle_eol * Purpose: toggle writing eol character at eol * Date: November 25, 1991 * Passed: arg_filler: argument to satify function prototype */ int toggle_eol( TDE_WIN *arg_filler ) { register file_infos *file; mode.show_eol = !mode.show_eol; for (file=g_status.file_list; file != NULL; file=file->next) file->dirty = GLOBAL; return( OK ); } /* * Name: toggle_search_case * Purpose: toggle search case * Date: September 16, 1991 * Passed: arg_filler: argument to satify function prototype */ int toggle_search_case( TDE_WIN *arg_filler ) { mode.search_case = (mode.search_case == IGNORE) ? MATCH : IGNORE; show_search_case( ); build_boyer_array( ); return( OK ); } /* * Name: toggle_sync * Purpose: toggle sync mode * Date: January 15, 1992 * Passed: arg_filler: argument to satify function prototype */ int toggle_sync( TDE_WIN *arg_filler ) { mode.sync = !mode.sync; show_sync_mode( ); return( OK ); } /* * Name: toggle_ruler * Purpose: toggle ruler * Date: March 5, 1992 * Passed: arg_filler: argument to satify function prototype */ int toggle_ruler( TDE_WIN *arg_filler ) { register TDE_WIN *wp; mode.ruler = !mode.ruler; wp = g_status.window_list; while (wp != NULL) { if (mode.ruler) { /* * there has to be more than one line in a window to display a ruler. * even if the ruler mode is on, we need to check the num of lines. */ if (wp->bottom_line - wp->top_line >0) { if (wp->cline == wp->top_line) ++wp->cline; if (wp->cline > wp->bottom_line) wp->cline = wp->bottom_line; wp->ruler = TRUE; } else wp->ruler = FALSE; } else { /* * if this is the first page in a file, then we may need to "pull" * the file up before displaying the first page. */ if (wp->rline == ((wp->cline - wp->ruler) - (wp->top_line - 1))) --wp->cline; if (wp->cline < wp->top_line) wp->cline = wp->top_line; wp->ruler = FALSE; } make_ruler( wp ); setup_window( wp ); if (wp->visible) redraw_current_window( wp ); wp = wp->next; } return( OK ); } /* * Name: toggle_tabinflate * Purpose: toggle inflating tabs * Date: October 31, 1992 * Passed: arg_filler: argument to satify function prototype */ int toggle_tabinflate( TDE_WIN *arg_filler ) { register file_infos *file; mode.inflate_tabs = !mode.inflate_tabs; for (file=g_status.file_list; file != NULL; file=file->next) file->dirty = GLOBAL; show_tab_modes( ); return( OK ); } /* * Name: cursor_sync * Purpose: carry out cursor movements in all visible windows * Date: January 15, 1992 * Passed: window * Notes: switch sync semaphore when we do this so we don't get into a * recursive loop. all cursor movement commands un_copy_line before * moving the cursor off the current line. you MUST make certain * that the current line is uncopied in the task routines that * move the cursor off the current line before calling sync. */ void cursor_sync( TDE_WIN *window ) { register TDE_WIN *wp; register file_infos *fp; if (mode.sync && mode.sync_sem) { /* * these functions must un_copy a line before sync'ing */ #if defined( __MSC__ ) switch (g_status.command) { case NextLine : case BegNextLine : case LineDown : case LineUp : case WordRight : case WordLeft : case ScreenDown : case ScreenUp : case EndOfFile : case TopOfFile : case BotOfScreen : case TopOfScreen : case JumpToLine : case CenterWindow : case CenterLine : case ScrollDnLine : case ScrollUpLine : case PanUp : case PanDn : case NextDirtyLine : case PrevDirtyLine : case ParenBalance : assert( g_status.copied == FALSE ); break; default : break; } #endif mode.sync_sem = FALSE; for (wp = g_status.window_list; wp != NULL; wp = wp->next) { if (wp->visible && wp != window) { /* * when we sync a command, we need to use the same assertions * as those in editor( ). * * if everything is everything, these core asserts are TRUE. */ #if defined( __MSC__ ) assert( wp != NULL ); assert( wp->file_info != NULL ); assert( wp->file_info->line_list != NULL ); assert( wp->file_info->line_list_end != NULL ); assert( wp->file_info->line_list_end->len == EOF ); assert( wp->visible == TRUE ); assert( wp->rline >= 0 ); assert( wp->rline <= wp->file_info->length + 1 ); assert( wp->rcol >= 0 ); assert( wp->rcol < MAX_LINE_LENGTH ); assert( wp->ccol >= wp->start_col ); assert( wp->ccol <= wp->end_col ); assert( wp->bcol >= 0 ); assert( wp->bcol < MAX_LINE_LENGTH ); assert( wp->bcol == wp->rcol-(wp->ccol - wp->start_col) ); assert( wp->start_col >= 0 ); assert( wp->start_col < wp->end_col ); assert( wp->end_col < g_display.ncols ); assert( wp->cline >= wp->top_line ); assert( wp->cline <= wp->bottom_line ); assert( wp->top_line > 0 ); assert( wp->top_line <= wp->bottom_line ); assert( wp->bottom_line <= g_display.nlines ); assert( wp->bin_offset >= 0 ); if (wp->ll->next == NULL) assert( wp->ll->len == EOF ); else assert( wp->ll->len >= 0 ); assert( wp->ll->len < MAX_LINE_LENGTH ); #endif (*do_it[g_status.command])( wp ); show_line_col( wp ); show_ruler_pointer( wp ); } } mode.sync_sem = TRUE; for (fp = g_status.file_list; fp != NULL; fp = fp->next) if (fp->dirty != FALSE) fp->dirty = GLOBAL; } } /* * Name: editor * Purpose: Set up the editor structures and display changes as needed. * Date: June 5, 1991 * Notes: Master editor routine. */ void editor( ) { char *name; /* name of file to start editing */ register TDE_WIN *window; /* current active window */ int c; #if defined( __UNIX__ ) mode_t fattr; #endif /* * initialize search and seize */ g_status.sas_defined = FALSE; for (c=0; c 1) { c = *g_status.argv[1]; #if defined( __UNIX__ ) if (c == '-' || c == '+') #else if (c == '/' || c == '-' || c == '+') #endif { c = *(g_status.argv[1] + 1); if (c == 'f' || c == 'F' || c == 'g' || c == 'G') { /* * with search and seize their has to be at least 4 arg's, e.g. * tde -f findme *.c */ if (c == 'F' || c == 'G') { mode.search_case = MATCH; c = bj_tolower( c ); } if (g_status.argc >= 4) { assert( strlen( g_status.argv[2] ) < (size_t)g_display.ncols ); if (c == 'f') { g_status.command = DefineGrep; strcpy( (char *)sas_bm.pattern, g_status.argv[2] ); } else { g_status.command = DefineRegXGrep; strcpy( (char *)regx.pattern, g_status.argv[2] ); } #if defined( __UNIX__ ) g_status.sas_argc = g_status.argc - 3; g_status.sas_arg = 0; g_status.sas_argv = g_status.argv + 3; #else for (c=3; c <= g_status.argc; c++) g_status.sas_arg_pointers[c-3] = g_status.argv[c]; g_status.sas_argc = g_status.argc - 3; g_status.sas_arg = 0; g_status.sas_argv = g_status.sas_arg_pointers; #endif g_status.sas_found_first = FALSE; if (g_status.command == DefineGrep) { g_status.sas_defined = TRUE; g_status.sas_search_type = BOYER_MOORE; bm.search_defined = sas_bm.search_defined = OK; build_boyer_array( ); c = OK; } else { c = build_nfa( ); if (c == OK) { g_status.sas_defined = TRUE; g_status.sas_search_type = REG_EXPRESSION; regx.search_defined = sas_regx.search_defined = OK; } else g_status.sas_defined = FALSE; } if (c != ERROR) c = search_and_seize( g_status.current_window ); } else c = ERROR; } else if (c == 'b' || c == 'B') { c = atoi( g_status.argv[1] + 2 ); if (c <= 0 || c >= MAX_LINE_LENGTH) c = DEFAULT_BIN_LENGTH; ++g_status.arg; g_status.file_mode = BINARY; g_status.file_chunk = c; c = edit_next_file( g_status.current_window ); } else if (c >= '0' && c <= '9') { c = atoi( g_status.argv[1] + 1 ); g_status.jump_to = c; ++g_status.arg; c = edit_next_file( g_status.current_window ); } else c = ERROR; } else c = edit_next_file( g_status.current_window ); } else { name = g_status.rw_name; *name = '\0'; /* * file name to edit */ c = get_name( ed15, g_display.nlines, name, g_display.text_color ); assert( strlen( name ) < (size_t)g_display.ncols ); if (c == OK) { if (*name != '\0') { #if defined( __UNIX__ ) if (get_fattr( name, &fattr) == 0) #else if (get_fattr( name, &c) == 0) #endif c = attempt_edit_display( name, GLOBAL, TEXT, 0 ); else c = dir_help_name( (TDE_WIN *)NULL, name ); } else c = dir_help( (TDE_WIN *)NULL ); } } g_status.stop = c == OK ? FALSE : TRUE; if (c == OK) set_cursor_size( mode.insert ? g_display.insert_cursor : g_display.overw_cursor ); /* * main loop - keep updating the display and processing any commands * while user has not pressed the stop key */ for (; g_status.stop != TRUE;) { window = g_status.current_window; /* * before we do any editor commands, we start out with some basic * assumptions. * * if everything is everything, these core asserts are TRUE. */ assert( window != NULL ); assert( window->file_info != NULL ); assert( window->file_info->line_list != NULL ); assert( window->file_info->line_list_end != NULL ); assert( window->file_info->line_list_end->len == EOF ); assert( window->visible == TRUE ); assert( window->rline >= 0 ); assert( window->rline <= window->file_info->length + 1 ); assert( window->rcol >= 0 ); assert( window->rcol < MAX_LINE_LENGTH ); assert( window->ccol >= window->start_col ); assert( window->ccol <= window->end_col ); assert( window->bcol >= 0 ); assert( window->bcol < MAX_LINE_LENGTH ); assert( window->bcol == window->rcol-(window->ccol - window->start_col) ); assert( window->start_col >= 0 ); assert( window->start_col < window->end_col ); assert( window->end_col < g_display.ncols ); assert( window->cline >= window->top_line ); assert( window->cline <= window->bottom_line ); assert( window->top_line > 0 ); assert( window->top_line <= window->bottom_line ); assert( window->bottom_line <= g_display.nlines ); assert( window->bin_offset >= 0 ); if (window->ll->next == NULL) assert( window->ll->len == EOF ); else assert( window->ll->len >= 0 ); assert( window->ll->len < MAX_LINE_LENGTH ); display_dirty_windows( window ); /* * set the critical error handler flag to a known state before we * do each editor command. */ ceh.flag = OK; /* * this code is used during testing to check the amount of memory * in the near heap. * * ultoa( _fmsize( window->ll ), buff, 10 ); * s_output( "s= ", g_display.mode_line, 15, g_display.mode_color ); * s_output( buff, g_display.mode_line, 17, g_display.mode_color ); */ /* * Get a key from the user. Look up the function assigned to that key. * All regular text keys are assigned to function 0. Text characters * are less than 0x100, decimal 256, which includes the ASCII and * extended ASCII character set. */ #if defined( __UNIX__ ) xygoto( window->ccol, window->cline ); refresh( ); #endif g_status.key_pressed = getkey( ); g_status.command = getfunc( g_status.key_pressed ); if (g_status.wrapped || g_status.key_pending) { g_status.key_pending = FALSE; g_status.wrapped = FALSE; show_search_message( CLR_SEARCH, g_display.mode_color ); } g_status.control_break = FALSE; if (g_status.command >= 0 && g_status.command < NUM_FUNCS) { record_keys( window->bottom_line ); (*do_it[g_status.command])( window ); } } #if defined( __UNIX__ ) curs_set( CURSES_SMALL ); refresh( ); #else cls( ); xygoto( 0, 0 ); #endif } /* * Name: display_dirty_windows * Purpose: Set up the editor structures and display changes as needed. * Date: June 5, 1991 * Notes: Display all windows with dirty files. */ void display_dirty_windows( TDE_WIN *window ) { register TDE_WIN *below; /* window below current */ register TDE_WIN *above; /* window above current */ file_infos *file; /* temporary file structure */ /* * update all windows that point to any file that has been changed */ above = below = window; while (above->prev || below->next) { if (above->prev) { above = above->prev; show_dirty_window( above ); } if (below->next) { below = below->next; show_dirty_window( below ); } } file = window->file_info; if (file->dirty == LOCAL || file->dirty == GLOBAL) display_current_window( window ); for (file=g_status.file_list; file != NULL; file=file->next) file->dirty = FALSE; /* * Set the cursor position at window->ccol, window->cline. Show the * user where in the file the cursor is positioned. */ xygoto( window->ccol, window->cline ); show_line_col( window ); show_ruler_pointer( window ); } /* * Name: show_dirty_window * Purpose: show changes in non-current window * Date: June 5, 1991 * Passed: window: pointer to current window */ void show_dirty_window( TDE_WIN *window ) { register TDE_WIN *win; /* register window pointer */ int dirty; win = window; if (win->visible) { dirty = win->file_info->dirty; if (dirty == GLOBAL || dirty == NOT_LOCAL) { display_current_window( win ); show_size( win ); } show_asterisk( win ); } }