home *** CD-ROM | disk | FTP | other *** search
- /******************* 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 reworked. 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.
- *
- * 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?).
- *
- * I felt that the insert routine should be separated into two routines. One
- * for inserting the various combinations of newlines and one for inserting
- * 'regular' text characters (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.
- *
- * Also note that using functions copy_line and un_copy_line to change a line
- * automatically adjusts the g_status.end_mem pointer. If a function bypasses
- * those functions, adjusting the g_status.end_mem pointer must be done
- * explicitly.
- *
- * 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
- *
- * This modification of Douglas Thomson's code is released into the
- * public domain, Frank Davis. You may distribute it freely.
- */
-
- #include "tdestr.h" /* global variables */
- #include "define.h"
- #include "tdefunc.h"
- #include "global.h" /* global variables */
-
- /*
- * Name: tab_key
- * Purpose: To make the necessary changes after the user types the tab key.
- * Date: June 5, 1991
- * Passed: window: information allowing access to the current window
- * Notes: If in insert mode, then this function adds the required
- * number of spaces in the file.
- * If not in insert mode, then tab simply moves the cursor right
- * the required distance.
- */
- void tab_key( windows *window )
- {
- int spaces; /* the spaces to move to the next tab stop */
- char *source; /* source for block move to make room for c */
- char *dest; /* destination for block move */
- int pad, len, rcol, ccol;
- register int i;
- file_infos *file;
- int prompt_line;
-
- if (*window->cursor == CONTROL_Z)
- return;
- prompt_line = window->bottom_line;
- rcol = window->rcol;
- ccol = window->ccol;
- /*
- * work out the number of spaces to the next tab stop
- */
- spaces = mode.tab_size - (rcol % mode.tab_size);
-
- if (mode.insert && rcol + spaces < g_display.line_length) {
- copy_line( window->cursor, prompt_line );
- /*
- * work out how many characters need to be inserted
- */
- len = linelen( g_status.line_buff );
- if (rcol > len) /* padding required */
- pad = rcol - len;
- else
- pad = 0;
- if (g_status.line_buff[len] == CONTROL_Z)
- ++pad;
- if (len + pad + spaces >= g_display.line_length)
- error( WARNING, window->bottom_line, "line too long to add" );
- else {
- file = window->file_info;
- if (pad > 0 || spaces > 0) {
- if (g_status.line_buff[len] == CONTROL_Z) {
- g_status.line_buff[len] = '\n';
- g_status.line_buff[len+1] = CONTROL_Z;
- ++file->length;
- show_size( window );
- --pad;
- ++len;
- }
- source = g_status.line_buff + rcol - pad;
- dest = source + pad + spaces;
- len = len + pad - rcol + 2;
- memmove( dest, source, len );
-
- /*
- * if padding was required, then put in the required spaces
- */
- for (i=pad; i>0; i--)
- *source++ = ' ';
- for (i=spaces; i>0; i--)
- *source++ = ' ';
- }
-
- file->dirty = GLOBAL;
- show_changed_line( window );
- rcol += spaces;
- ccol += spaces;
- }
- } else if (rcol + spaces <= g_display.line_length) {
- /*
- * advance the cursor without changing the text underneath
- */
- rcol += spaces;
- ccol += spaces;
- }
- check_virtual_col( window, rcol, ccol );
- }
-
-
- /*
- * Name: insert_newline
- * Purpose: insert a newline
- * Date: June 5, 1991
- * Passed: window: information allowing access to the current window
- * carriage_return: TRUE if carriage return, FALSE if insert line
- * split_line: TRUE if split line, FALSE otherwise
- */
- void insert_newline( windows *window )
- {
- char *source; /* source for block move to make room for c */
- char *dest; /* destination for block move */
- int len; /* length of current line */
- register int add; /* characters to be added (usually 1 in insert mode) */
- int i; /* counter for adding autoindenting */
- int rcol;
- text_ptr prev; /* previous lines scanned for autoindent */
- file_infos *file;
- int prompt_line;
- long length;
- int carriage_return;
- int split_line;
-
- file = window->file_info;
- length = file->length;
- if (window->rline > length && *window->cursor != CONTROL_Z)
- return;
- switch (g_status.command) {
- case Rturn :
- carriage_return = TRUE;
- split_line = FALSE;
- break;
- case AddLine :
- split_line = carriage_return = FALSE;
- break;
- case SplitLine :
- split_line = carriage_return = TRUE;
- break;
- }
- window->cursor = cpf( window->cursor );
- prompt_line = window->bottom_line;
- copy_line( window->cursor, prompt_line );
- len = linelen( g_status.line_buff );
-
- source = g_status.line_buff + len;
- if (carriage_return || split_line) {
- if (window->rcol < len)
- source = g_status.line_buff + window->rcol;
- }
- /*
- * make room for '\n' just after source (source+1)
- */
- memmove( source+1, source, linelen( source )+2 );
-
- *source = '\n';
- un_copy_line( window->cursor, window, TRUE );
- adjust_windows_cursor( window, 1 );
-
- if (carriage_return || split_line)
- update_line( window );
-
- file->dirty = NOT_LOCAL;
- if (length == 0l)
- file->dirty = GLOBAL;
- else if (window->cline == prompt_line)
- window_scroll_up( window->top_line, prompt_line );
- else
- window_scroll_down( window->cline+1, prompt_line );
-
- /*
- * If the cursor is to move down to the next line, then update
- * the line and column appropriately.
- */
- if (carriage_return || split_line) {
- window->cursor = find_next( window->cursor );
- if (window->cline < prompt_line)
- window->cline++;
- window->rline++;
- rcol = window->rcol;
-
- /*
- * indentation is only required if we are in the right mode,
- * the user typed <CR>, and if there is not space followed
- * by something after the cursor.
- */
- if (mode.indent) {
- /*
- * autoindentation is required. Match the indentation of
- * the first line above that is not blank.
- */
- add = first_non_blank( g_status.line_buff );
- if (g_status.line_buff[add] == '\n' ||
- g_status.line_buff[add] == CONTROL_Z) {
- prev = cpb( window->cursor );
- while ((prev = find_prev( prev )) != NULL) {
- add = first_non_blank( prev );
- if (prev[add] != '\n')
- break;
- }
- }
- copy_line( window->cursor, prompt_line );
- len = linelen( g_status.line_buff );
- source = g_status.line_buff;
- dest = source + add;
- memmove( dest, source, len+add+2 );
-
- /*
- * now put in the autoindent characters
- */
- for (i=add; i>0; i--)
- *source++ = ' ';
-
- window->rcol = add;
- un_copy_line( window->cursor, window, TRUE );
- update_line( window );
- } else
- window->rcol = 0;
- if (split_line) {
- window->cursor = cpb( window->cursor );
- window->cursor = find_prev( window->cursor );
- if (window->cline > window->top_line)
- window->cline--;
- window->rline--;
- window->rcol = rcol;
- }
- check_virtual_col( window, window->rcol, window->ccol );
- if (file->dirty)
- file->dirty = GLOBAL;
- }
-
- /*
- * record that file has been modified
- */
- ++file->length;
- restore_marked_block( window, 1 );
- show_size( window );
- }
-
-
- /*
- * Name: insert_overwrite
- * Purpose: To make the necessary changes after the user has typed a normal
- * printable character
- * Date: June 5, 1991
- * Passed: window: information allowing access to the current window
- */
- void insert_overwrite( windows *window )
- {
- char *source; /* source for block move to make room for c */
- char *dest; /* destination for block move */
- int c; /* text key just pressed */
- int len; /* length of current line */
- int pad; /* padding to add if cursor beyond end of line */
- int i;
- int add; /* characters to be added (usually 1 in insert mode) */
- int line; /* line on screen to save and show prompt */
- int rcol, ccol;
- file_infos *file;
-
- if (*window->cursor == CONTROL_Z || g_status.key_pressed >= 256)
- return;
- line = window->bottom_line;
- rcol = window->rcol;
- ccol = window->ccol;
- /*
- * first check we have room - the editor can not
- * cope with lines wider than g_display.line_length
- */
- if (rcol >= g_display.line_length)
- error( WARNING, line, "cannot insert more characters" );
- else {
- c = g_status.key_pressed;
- file = window->file_info;
- copy_line( window->cursor, line );
-
- /*
- * work out how many characters need to be inserted
- */
- len = linelen( g_status.line_buff );
- if (rcol > len) /* padding required */
- pad = rcol - len;
- else
- pad = 0;
-
- /*
- * if this is the last line in a file, the last character in the
- * line buffer will be CONTROL_Z. increment pad and insert a \n.
- */
- if (g_status.line_buff[len] == CONTROL_Z)
- ++pad;
-
- 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. Note that there must
- * be space for both the old line and any indentation.
- */
- if (len + pad + add >= g_display.line_length)
- error( WARNING, line, "no more room to add" );
- else {
- /*
- * all clear to add new character!
- */
-
- /*
- * move character to make room for whatever needs to be inserted
- */
- if (pad > 0 || add > 0) {
- source = g_status.line_buff + len;
- if (*source == CONTROL_Z) {
- if (rcol > len)
- source = g_status.line_buff + rcol + 1;
- *source++ = '\n';
- *source = CONTROL_Z;
- ++file->length;
- show_size( window );
- --pad;
- ++len;
- }
- source = g_status.line_buff + rcol - pad;
- dest = source + pad + add;
- len = len + pad - rcol + 2;
- memmove( dest, source, len );
- /*
- * if padding was required, then put in the required spaces
- */
- for (i=pad; i>0; i--)
- *source++ = ' ';
- } else
- source = g_status.line_buff + rcol;
- /*
- * now place the new character
- */
- *source = c;
-
- /*
- * if we added anything, show the changed line.
- */
- if (pad > 0 || add > 0)
- update_line( window );
- else
- update_char( window, c, ccol, window->cline );
-
- /*
- * always increment the real column (rcol) and adjust the
- * logical and base column as needed.
- */
- file->dirty = GLOBAL;
- if (ccol < g_display.ncols - 1) {
- ccol++;
- show_changed_line( window );
- } else
- window->bcol++;
- rcol++;
-
- /*
- * record that file has been modified and adjust cursors and
- * file start and end markers as needed.
- */
- }
- window->rcol = rcol;
- window->ccol = ccol;
- file->modified = TRUE;
- }
- }
-
-
- /*
- * Name: join_line
- * Purpose: To join current line and line below at cursor
- * Date: June 5, 1991
- * Passed: window: information allowing access to the current window
- * Notes: trunc the line then join with line below if it exists
- */
- void join_line( windows *window )
- {
- register int len; /* length of current line */
- char *source; /* source for block move to delete word */
- char *dest; /* destination for block move */
- text_ptr p; /* next line in file */
- int pad, i; /* padding spaces required */
- int cr; /* does current line end with carriage return? */
- int line; /* line on screen to save and show prompt */
- file_infos *file;
- int rcol;
-
- file = window->file_info;
- if (window->rline > file->length || *window->cursor == CONTROL_Z)
- return;
- line = window->bottom_line;
- rcol = window->rcol;
-
- window->cursor = cpf( window->cursor );
- load_undo_buffer( window->cursor );
- copy_line( window->cursor, window->bottom_line );
- if (rcol < (len = linelen( g_status.line_buff ))) {
- /*
- * delete rest of line
- */
- dest = g_status.line_buff + rcol;
-
- /*
- * the \n at the end of the line must NOT be deleted
- */
- if (g_status.line_buff[len] == '\n')
- *dest++ = '\n';
-
- len = find_CONTROL_Z( dest );
- *dest = CONTROL_Z;
- un_copy_line( window->cursor, window, FALSE );
- file->dirty = GLOBAL;
- }
- /*
- * we need to combine with the next line, if any
- */
- if ((p = find_next( window->cursor )) != NULL && *p != CONTROL_Z) {
- /*
- * add padding if required
- */
- len = linelen( g_status.line_buff );
- if (g_status.line_buff[len] == '\n')
- cr = 1;
- else
- cr = 0;
- if (rcol > len)
- pad = rcol - len;
- else
- pad = 0;
-
- /*
- * check room to combine lines
- */
- if (len + pad + cr + linelen( p ) >= g_display.line_length)
- error( WARNING, line, "cannot combine lines" );
- else {
-
- /*
- * do the move
- */
- source = g_status.line_buff + rcol - pad;
- dest = source + pad;
- len = len + pad - rcol + 1 + cr;
- memmove( dest, source, len );
-
- /*
- * insert the padding
- */
- for (i=pad; i>0; i--)
- *source++ = ' ';
-
- /*
- * remove the \n separating the two lines.
- */
- i = 0;
- if (*source == '\n') {
- *source = CONTROL_Z;
- i = -1;
- }
- g_status.copied = TRUE;
- un_copy_line( window->cursor, window, FALSE );
- adjust_windows_cursor( window, i );
- --file->length;
- restore_marked_block( window, -1 );
- show_size( window );
- file->dirty = GLOBAL;
- }
- }
- }
-
-
- /*
- * Name: word_delete
- * Purpose: To delete from the cursor to the start of the next word.
- * Date: September 1, 1991
- * Passed: window: information allowing access to the 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.
- */
- void word_delete( windows *window )
- {
- int len; /* length of current 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 */
- int alpha; /* is the cursor char alphanumeric? */
- int bottom_line;
- int rcol;
- file_infos *file;
- text_ptr p;
-
- file = window->file_info;
- if (window->rline > file->length || *window->cursor == CONTROL_Z)
- return;
- bottom_line = window->bottom_line;
- rcol = window->rcol;
- window->cursor = cpf( window->cursor );
- copy_line( window->cursor, bottom_line );
- if (rcol >= (len = linelen( g_status.line_buff ))) {
- join_line( window );
- p = window->cursor + rcol;
- if (*p != CONTROL_Z)
- load_undo_buffer( p );
- } else {
- /*
- * normal word delete
- *
- * find the start of the next word
- */
- start = rcol;
- if (g_status.line_buff[start] == ' ') {
- /*
- * the cursor was on a space, so eat all consecutive spaces
- * from the cursor onwards.
- */
- while (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)
- */
- alpha = myisalnum( g_status.line_buff[start++] );
- while (start < len) {
- if (g_status.line_buff[start] == ' ')
- /*
- * the next character that is not a space will
- * end the delete
- */
- alpha = -1;
- else if (alpha != myisalnum( g_status.line_buff[start] )) {
- if (g_status.line_buff[start] != ' ')
- break;
- }
- ++start;
- }
- }
-
- /*
- * move text to delete word
- */
- source = g_status.line_buff + start;
- dest = g_status.line_buff + rcol;
- len = len - start + 2;
- memmove( dest, source, len );
- file->modified = TRUE;
- file->dirty = GLOBAL;
- show_changed_line( window );
- }
- }
-
-
- /*
- * Name: dup_line
- * Purpose: Duplicate current line
- * Date: June 5, 1991
- * Passed: window: information allowing access to the current window
- * Notes: cursor stays on current line
- */
- void dup_line( windows *window )
- {
- int len; /* length of current line */
- int line; /* line on screen to save and show prompt */
- long number;
- file_infos *file;
- text_ptr d, s;
-
- if (window->rline > window->file_info->length)
- return;
- line = window->bottom_line;
- window->cursor = cpf( window->cursor );
-
- un_copy_line( window->cursor, window, TRUE );
- /*
- * don't dup the ^Z or a NULL line
- */
- if (*window->cursor != CONTROL_Z && (d=find_next( window->cursor )) !=NULL) {
- file = window->file_info;
-
- /*
- * don't use buffers to dup the line. use hw_move to make space and
- * copy current line at same time. d is set to beginning of next line.
- */
- s = window->cursor;
- len = linelen( s );
- if (s[len] == '\n')
- ++len;
- number = ptoul( g_status.end_mem ) - ptoul( s );
- hw_move( d, s, number );
- g_status.end_mem = addltop( len, g_status.end_mem );
- adjust_start_end( file, len );
- addorsub_all_cursors( window, len );
- adjust_windows_cursor( window, 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 (window->cline != line) {
- window_scroll_down( window->cline, line );
- update_line( window );
- }
- file->dirty = NOT_LOCAL;
-
- /*
- * record that file has been modified
- */
- file->modified = TRUE;
- ++file->length;
- restore_marked_block( window, 1 );
- show_size( window );
- show_avail_mem( );
- } else
- error( WARNING, line, "cannot duplicate line" );
- }
-
-
- /*
- * Name: back_space
- * Purpose: To delete the character to the left of the cursor.
- * Date: June 5, 1991
- * Passed: window: information allowing access to the 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.
- */
- void back_space( windows *window )
- {
- 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 */
- int prompt_line; /* line on screen to save and show prompt */
- register int rcol;
- int ccol;
- file_infos *file;
-
- file = window->file_info;
- if (window->rline > file->length || *window->cursor == CONTROL_Z)
- return;
- prompt_line = window->bottom_line;
- window->cursor = cpf( window->cursor );
- copy_line( window->cursor, prompt_line );
- len = linelen( g_status.line_buff );
- rcol = window->rcol;
- ccol = window->ccol;
- if (rcol == 0) {
- /*
- * combine this line with the previous, if any
- */
- window->cursor = cpb( window->cursor );
- if ((p = find_prev( window->cursor )) != NULL) {
- if (len + 2 + (plen = linelen( p )) >= g_display.line_length) {
- error( WARNING, prompt_line, "cannot combine lines" );
- return;
- }
-
- un_copy_line( window->cursor, window, TRUE );
- copy_line( p, prompt_line );
- load_undo_buffer( p );
- g_status.line_buff[plen] = CONTROL_Z;
- window->cursor = p;
- un_copy_line( window->cursor, window, FALSE );
-
- /*
- * make sure cursor stays on the screen, at the end of the
- * previous line
- */
- if (window->cline > window->top_line)
- --window->cline;
- --window->rline;
- rcol = plen;
- ccol = rcol - window->bcol;
- --file->length;
- restore_marked_block( window, -1 );
- adjust_windows_cursor( window, -1 );
- show_size( window );
- check_virtual_col( window, rcol, ccol );
- file->dirty = GLOBAL;
- }
- } 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
- */
- if ((pos = first_non_blank( g_status.line_buff )) == rcol
- || g_status.line_buff[pos] == '\n'
- || g_status.line_buff[pos] == CONTROL_Z) {
- /*
- * now work out how much to indent
- */
- p = cpb( window->cursor );
- for (p=find_prev( p ); p != NULL; p=find_prev( p )) {
- if ((plen = first_non_blank( p )) < rcol && *(p+plen) != '\n') {
- /*
- * 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;
- len = 2;
- } else {
- source = g_status.line_buff + rcol;
- len = len - rcol + 2;
- }
- memmove( dest, source, len );
- }
- rcol -= del_count;
- ccol -= del_count;
- check_virtual_col( window, rcol, ccol );
- file->dirty = GLOBAL;
- show_changed_line( window );
- }
- file->modified = TRUE;
- }
-
-
- /*
- * Name: line_kill
- * Purpose: To delete the line the cursor is on.
- * Date: June 5, 1991
- * Passed: window: information allowing access to the current window
- * Notes: If *window->cursor is pointing to CONTROL_Z then do not do a
- * line kill (can't kill a NULL line).
- */
- void line_kill( windows *window )
- {
- int i = 0;
- text_ptr s; /* next line in file */
- windows w;
- file_infos *file;
- long length;
-
- file = window->file_info;
- if (file->length > 0 && *window->cursor != CONTROL_Z) {
-
- if (g_status.copied == FALSE)
- load_undo_buffer( window->cursor );
- else
- load_undo_buffer( g_status.line_buff );
- g_status.copied = TRUE;
- g_status.line_buff[0] = CONTROL_Z;
- s = window->cursor = cpf( window->cursor );
- /*
- * if line to delete has \n at end of line then decrement file length.
- */
- if (*(s + linelen( s )) == '\n') {
- --file->length;
- --i;
- }
- un_copy_line( s, window, FALSE );
- file->dirty = NOT_LOCAL;
-
- /*
- * move all cursors one according to i, restore begin and end block
- */
- adjust_windows_cursor( window, i );
- restore_marked_block( window, i );
-
- /*
- * we are not doing a GLOBAL update, so update current window here
- */
- if (file->dirty == NOT_LOCAL) {
- length = file->length;
- window_scroll_up( window->cline, window->bottom_line );
- dup_window_info( &w, window );
- for (; w.cursor != NULL; w.cline++, w.rline++) {
- if (w.cline == w.bottom_line) {
- if (w.rline <= length && length != 1l)
- update_line( &w );
- else
- show_eof( w.cline );
- break;
- }
- w.cursor = find_next( w.cursor );
- }
- }
- show_size( window );
- }
- }
-
-
- /*
- * Name: char_del_under
- * Purpose: To delete the character under the cursor.
- * Date: June 5, 1991
- * Passed: window: information allowing access to the current window
- * Notes: If the cursor is beyond the end of the line, then this
- * command is ignored.
- */
- void char_del_under( windows *window )
- {
- char *source; /* source of block move to delete character */
- register int len;
- int rcol;
- file_infos *file;
-
- file = window->file_info;
- if (window->rline > file->length || *window->cursor == CONTROL_Z)
- return;
- rcol = window->rcol;
- copy_line( window->cursor, window->bottom_line );
- if (rcol < (len = linelen( g_status.line_buff ))) {
- /*
- * move text to delete char using buffer
- */
- source = g_status.line_buff + rcol + 1;
- memmove( source-1, source, len-rcol+2 );
- file->dirty = GLOBAL;
- file->modified = TRUE;
- show_changed_line( window );
- } else if (mode.sdel)
- join_line( window );
- }
-
-
- /*
- * Name: eol_kill
- * Purpose: To delete everything from the cursor to the end of the line.
- * Date: June 5, 1991
- * Passed: window: information allowing access to the current window
- * Notes: If the cursor is beyond the end of the line, then this
- * command is ignored.
- */
- void eol_kill( windows *window )
- {
- register char *dest; /* the start of the delete area */
-
- if (window->rline > window->file_info->length || *window->cursor == CONTROL_Z)
- return;
- copy_line( window->cursor, window->bottom_line );
- load_undo_buffer( g_status.line_buff );
- if (window->rcol < linelen( g_status.line_buff )) {
- /*
- * truncate to delete rest of line
- */
- dest = g_status.line_buff + window->rcol;
- *dest++ = '\n';
- *dest = CONTROL_Z;
- window->file_info->dirty = GLOBAL;
- show_changed_line( window );
- }
- }
-
-
- /*
- * Name: undo_line
- * Purpose: To retrieve unaltered line if possible.
- * Date: June 5, 1991
- * Passed: window: information allowing access to the current window
- * Notes: Changes are made to the line buffer so the underlying text has
- * not changed. put the unchanged line in the line buffer.
- */
- void undo_line( windows *window )
- {
-
- if (window->rline > window->file_info->length)
- return;
- if (g_status.copied) {
- g_status.copied = FALSE;
- copy_line( window->cursor, window->bottom_line );
- window->file_info->dirty = GLOBAL;
- show_changed_line( window );
- }
- }
-
-
- /*
- * Name: undo
- * Purpose: To retrieve (pop) a line from the undo stack
- * Date: September 26, 1991
- * Passed: window: information allowing access to the 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.
- */
- void undo( windows *window )
- {
- char *source;
- char *undo_line;
- int len;
- int head;
- file_infos *file;
-
- if (g_status.undo_head < 0)
- return;
- --g_status.undo_head;
- window->cursor = cpf( window->cursor );
- un_copy_line( window->cursor, window, TRUE );
- copy_line( window->cursor, window->bottom_line );
-
- source = g_status.line_buff;
- /*
- * make room for '\n'. then, after we un_copy the g_status.line_buff, we
- * have added a line to the file.
- */
- memmove( source+1, source, linelen( source )+2 );
- *source = '\n';
- un_copy_line( window->cursor, window, TRUE );
-
- /*
- * ajust cursors in other windows opened to the same file.
- */
- adjust_windows_cursor( window, 1 );
-
- /*
- * copy the line in the top of the stack to the line_buffer. then, copy
- * the line buffer to the file.
- */
- g_status.copied = TRUE;
- head = g_status.undo_head;
- undo_line = &g_status.undo_buffer[head][0];
- len = find_CONTROL_Z( undo_line ) + 1;
- memcpy( source, undo_line, len );
- un_copy_line( window->cursor, window, TRUE );
-
- /*
- * we have now undeleted a line. increment the file length and display
- * it.
- */
- file = window->file_info;
- ++file->length;
- file->dirty = GLOBAL;
- show_size( window );
-
- /*
- * if g_status.undo_head == 0, we just popped the last line in the stack.
- * set the stack pointer to -1 to show there are no more lines.
- */
- if (g_status.undo_head == 0)
- g_status.undo_head = -1;
- }
-
-
- /*
- * Name: beg_next_line
- * Purpose: To move the cursor to the beginning of the next line.
- * Date: October 4, 1991
- * Passed: window: information allowing access to the current window
- */
- void beg_next_line( windows *window )
- {
- window->rcol = 0;
- check_virtual_col( window, window->rcol, window->ccol );
- move_down( window );
- }
-
-
- /*
- * Name: next_line
- * Purpose: To move the cursor to the first character of the next line.
- * Date: October 4, 1991
- * Passed: window: information allowing access to the current window
- */
- void next_line( windows *window )
- {
- register int rcol;
-
- move_down( window );
- rcol = first_non_blank( window->cursor );
- if (window->cursor[rcol] == '\n')
- rcol = 0;
- check_virtual_col( window, rcol, window->ccol );
- }
-
-
- /*
- * Name: goto_left
- * Purpose: To move the cursor to the left of the current line.
- * Date: June 5, 1991
- * Passed: window: information allowing access to the current window
- */
- void goto_left( windows *window )
- {
- register int rcol;
-
- if (g_status.copied)
- rcol = first_non_blank( g_status.line_buff );
- else
- rcol = first_non_blank( window->cursor );
- if (window->cursor[rcol] == '\n')
- rcol = 0;
- if (window->rcol == rcol)
- rcol = 0;
- check_virtual_col( window, rcol, window->ccol );
- }
-
-
- /*
- * Name: goto_right
- * Purpose: To move the cursor to the right of the current line.
- * Date: June 5, 1991
- * Passed: window: information allowing access to the current window
- */
- void goto_right( windows *window )
- {
- register int rcol;
-
- if (g_status.copied)
- rcol = linelen( g_status.line_buff );
- else
- rcol = linelen( window->cursor );
- window->ccol = rcol - window->bcol;
- check_virtual_col( window, rcol, window->ccol );
- }
-
-
- /*
- * Name: goto_top
- * Purpose: To move the cursor to the top of the current window.
- * Date: June 5, 1991
- * Passed: window: information allowing access to the 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.
- */
- void goto_top( windows *window )
- {
- text_ptr cursor; /* anticipated cursor line */
-
- un_copy_line( window->cursor, window, TRUE );
- window->cursor = cpb( window->cursor );
- for (; window->cline > window->top_line; window->cline--,window->rline--) {
- if ((cursor = find_prev( window->cursor )) == NULL)
- break;
- window->cursor = cursor;
- }
- }
-
-
- /*
- * Name: goto_bottom
- * Purpose: To move the cursor to the bottom of the current window.
- * Date: June 5, 1991
- * Passed: window: information allowing access to the current window
- */
- void goto_bottom( windows *window )
- {
- text_ptr cursor;
-
- un_copy_line( window->cursor, window, TRUE );
- window->cursor = cpf( window->cursor );
- for (; window->cline < window->bottom_line; window->cline++,window->rline++) {
- if ((cursor = find_next( window->cursor )) == NULL)
- break;
- window->cursor = cursor;
- }
- }
-
-
- /*
- * 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 MAX_COLS / 2.
- */
- void set_tabstop( windows *window )
- {
- register int line;
- char num_str[MAX_COLS]; /* tab interval as a character string */
- int tab; /* new tab interval */
- int rc;
-
- line = window->bottom_line;
- rc = OK;
- while (rc == OK) {
- itoa( mode.tab_size, num_str, 10 );
- rc = get_name( "Tab interval: ", line, num_str, g_display.message_color );
- if (rc == OK) {
- tab = atoi( num_str );
- if (tab < MAX_COLS/2) {
- mode.tab_size = tab;
- rc = ERROR;
- } else
- error( WARNING, line, "tab size too long" );
- }
- }
- }
-
-
- /*
- * Name: show_line_col
- * Purpose: show current real line and column of current cursor position
- * Date: June 5, 1991
- * Passed: window: information allowing access to the 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
- * 999 columns and 99,999,999 lines.
- */
- void show_line_col( windows *window )
- {
- int i, pline;
- register int k;
- char line_col[20], num[10];
-
- /*
- * blank out current line:column position.
- */
- strcpy( line_col, " " );
-
- /*
- * convert column to ascii and store in display buffer.
- */
- itoa( window->rcol+1, num, 10 );
- i = strlen( num ) - 1;
- for (k=11; 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.
- */
- 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
- */
- pline = window->top_line - 1;
- s_output( line_col, pline, MAX_COLS-12, g_display.head_color );
-
- show_asterisk( window->file_info->modified, pline );
- }
-
-
- /*
- * Name: show_asterisk
- * Purpose: give user an indication if file is dirty
- * Date: September 16, 1991
- * Passed: modified: boolean - TRUE if modified, FALSE otherwise
- * line: line to display asterisk
- */
- void show_asterisk( int modified, int line )
- {
- register int c;
-
- if (modified)
- c = '*';
- else
- c = ' ';
- c_output( c, 4, line, g_display.head_color );
- }
-
-
- /*
- * Name: toggle_overwrite
- * Purpose: toggle overwrite-insert mode
- * Date: September 16, 1991
- * Passed: window
- */
- void toggle_overwrite( windows *window )
- {
- int temp;
-
- mode.insert = !mode.insert;
- show_insert_mode( );
- if (mode.insert)
- temp = g_display.insert_cursor;
- else
- temp = g_display.overw_cursor;
- set_cursor_size( temp );
- }
-
- /*
- * Name: toggle_sdel
- * Purpose: toggle stream delete mode
- * Date: September 16, 1991
- * Passed: window
- */
- void toggle_sdel( windows *window )
- {
- mode.sdel = !mode.sdel;
- show_sdelete_mode( );
- }
-
-
- /*
- * Name: toggle_sdel
- * Purpose: toggle stream delete mode
- * Date: September 16, 1991
- * Passed: window
- */
- void toggle_indent( windows *window )
- {
- mode.indent = !mode.indent;
- show_indent_mode( );
- }
-
-
- /*
- * Name: toggle_search_case
- * Purpose: toggle search case
- * Date: September 16, 1991
- * Passed: window
- */
- void toggle_search_case( windows *window )
- {
- if (bm.search_case == IGNORE)
- bm.search_case = MATCH;
- else
- bm.search_case = IGNORE;
- show_search_case( );
- if (bm.search_defined == OK)
- build_boyer_array( );
- }
-
-
- /*
- * Name: editor
- * Purpose: Set up the editor structures and display changes as needed.
- * Date: June 5, 1991
- * Passed: argc: number of command line arguments
- * argv: text of command line arguments
- */
- void editor( int argc, char *argv[] )
- {
- char *name; /* name of file to start editing */
- windows *window; /* current active window */
- windows *above; /* window above current */
- windows *below; /* window below current */
- register file_infos *file; /* temporary file structure */
- int c;
-
- /*
- * Check that user specified file to edit, if not offer help
- */
- if (argc > 1)
- name = argv[1];
- else {
- g_status.rw_name[0] = '\0';
- name = g_status.rw_name;
- if (get_name( "File name to edit : ", g_display.nlines, name,
- g_display.text_color ) != OK)
- return;
- if (*name == '\0')
- return;
- }
-
- if (edit_file( name ) == ERROR)
- return;
- if (initialize_window( ) != ERROR) {
- g_status.stop = FALSE;
- window = g_status.current_window;
- window->file_info->dirty = FALSE;
- show_window_header( window->file_info->file_name, window );
- show_size_name( window );
- show_size( window );
-
- /*
- * display the current window
- */
- display_current_window( window );
- show_modes( );
- if (mode.insert)
- c = g_display.insert_cursor;
- else
- c = g_display.overw_cursor;
- set_cursor_size( c );
- } else
- g_status.stop = TRUE;
-
- /*
- * 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;
-
- /*
- * update all the other windows that point to file that has been changed
- */
- above = below = window;
- while (above->prev || below->next) {
- if (above->prev) {
- above = above->prev;
- if (above->visible) {
- file = above->file_info;
- if (file->dirty == GLOBAL || file->dirty == NOT_LOCAL) {
- display_current_window( above );
- show_size( above );
- }
- show_asterisk( file->modified, above->top_line-1 );
- }
- }
- if (below->next) {
- below = below->next;
- if (below->visible) {
- file = below->file_info;
- if (file->dirty == GLOBAL || file->dirty == NOT_LOCAL) {
- display_current_window( below );
- show_size( below );
- }
- show_asterisk( file->modified, below->top_line-1 );
- }
- }
- }
- file = window->file_info;
- if (file->dirty == LOCAL || file->dirty == GLOBAL)
- display_current_window( window );
- 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 );
-
- /*
- * 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.
- */
- g_status.key_pressed = getkey( );
- g_status.command = getfunc( g_status.key_pressed );
- s_output( " ", g_display.mode_line, 63, g_display.mode_color );
- if (g_status.command >= 0 && g_status.command < 77)
- (*do_it[g_status.command])( window );
- }
- cls( );
- xygoto( 0, 0 );
- }