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 - block commands module
- * Purpose: This file contains all the commands than manipulate blocks.
- * File: block.c
- * Author: Douglas Thomson
- * System: this file is intended to be system-independent
- * Date: October 1, 1989
- */
- /********************* end of original comments ********************/
-
- /*
- * The block routines have been EXTENSIVELY rewritten. I am not very fond of
- * stream blocks. This editor uses LINE blocks and BOX blocks. That is,
- * one may either mark entire lines or column blocks. Block operations are
- * done in place. There are no paste and cut buffers. In limited memory
- * situations, larger block operations can be carried out. Block operations
- * can be done within or across files. One disadvantage of not using buffers
- * is that block operations can be slow. The most complicated routine in
- * this editor is by far "move_copy_delete_overlay_block( window )". I put
- * some comments in, but it is still a bitch.
- *
- * Maybe in the next version I'll use buffers to speed up block operations.
- *
- * In tde, version 1.1, I separated the BOX and LINE actions. LINE actions
- * are a LOT faster, now. Still need to speed up BOX actions.
- *
- * New editor name: tde, the Thomson-Davis Editor.
- * Author: Frank Davis
- * Date: June 5, 1991
- *
- * This modification of Douglas Thomson's code is released into the
- * public domain, Frank Davis. You may distribute it freely.
- */
-
- #include "tdestr.h"
- #include "common.h"
- #include "tdefunc.h"
- #include "define.h"
-
-
- /*
- * Name: mark_block
- * Purpose: To record the position of the start of the block in the file.
- * Date: June 5, 1991
- * Passed: window: information required to access current window
- * Notes: Assume the user will mark begin and end of a block in either
- * line mode or box mode. If the user mixes types, then block
- * type defaults to LINE.
- */
- void mark_block( windows *window )
- {
- int type;
- register file_infos *file; /* temporary file variable */
- int num;
- long lnum;
-
- file = window->file_info;
- if (window->rline > file->length)
- return;
- if (g_status.marked == FALSE) {
- g_status.marked = TRUE;
- g_status.marked_file = file;
- }
- if (g_status.command == MarkBlock)
- type = BOX;
- else
- type = LINE;
-
- /*
- * define blocks for only one file. it is ok to modify blocks in any window
- * pointing to original marked file.
- */
- if (file == g_status.marked_file) {
- g_status.marked_window = window;
-
- /*
- * mark beginning and ending column regardless of block mode.
- */
- if (file->block_type == NOTMARKED) {
- file->block_ec = file->block_bc = window->rcol;
- file->block_er = file->block_br = window->rline;
- } else {
- if (file->block_br > window->rline) {
- file->block_br = window->rline;
- if (file->block_bc < window->rcol)
- file->block_ec = window->rcol;
- else
- file->block_bc = window->rcol;
- } else {
- file->block_ec = window->rcol;
- file->block_er = window->rline;
- }
-
- /*
- * if user marks ending line less than beginning line then switch
- */
- if (file->block_er < file->block_br) {
- lnum = file->block_er;
- file->block_er = file->block_br;
- file->block_br = lnum;
- }
-
- /*
- * if user marks ending column less than beginning column then switch
- */
- if (file->block_ec < file->block_bc) {
- num = file->block_ec;
- file->block_ec = file->block_bc;
- file->block_bc = num;
- }
- }
-
- /*
- * block type in now defined. if user mixes block types then default to
- * LINE block.
- */
- if (file->block_type == NOTMARKED)
- file->block_type = type;
- else if (file->block_type == BOX && type == LINE)
- file->block_type = LINE;
- file->dirty = GLOBAL;
- }
- }
-
- /*
- * Name: unmark_block
- * Purpose: To set all block information to NULL or 0
- * Date: June 5, 1991
- * Passed: arg_filler: variable to match array of function pointers prototype
- * Notes: Reset all block variables if marked, otherwise return.
- * If a block is unmarked then redraw the screen(s).
- */
- void unmark_block( windows *arg_filler )
- {
- register file_infos *marked_file;
- windows *window;
-
- if (g_status.marked == TRUE) {
- window = g_status.marked_window;
- marked_file = g_status.marked_file;
- g_status.marked = FALSE;
- g_status.marked_file = NULL;
- g_status.marked_window = NULL;
- marked_file->block_start = NULL;
- marked_file->block_end = NULL;
- marked_file->block_bc = marked_file->block_ec = 0;
- marked_file->block_br = marked_file->block_er = 0l;
- if (marked_file->block_type)
- marked_file->dirty = GLOBAL;
- marked_file->block_type = NOTMARKED;
- }
- }
-
- /*
- * Name: restore_marked_block
- * Purpose: To restore block beginning and ending row after an editing function
- * Date: June 5, 1991
- * Passed: window: information required to access current window
- * net_change: number of bytes added or subtracted
- * Notes: If a change has been made before the marked block then the
- * beginning and ending row need to be adjusted by the number of
- * lines added or subtracted from file.
- */
- void restore_marked_block( windows *window, int net_change )
- {
- register file_infos *marked_file;
- long length;
-
- if (g_status.marked == TRUE && net_change != 0) {
- marked_file = g_status.marked_file;
- length = marked_file->length;
-
- /*
- * restore is needed only if a block is defined and window->file_info is
- * same as marked file and there was a net change in file length.
- */
- if (marked_file == window->file_info) {
-
- /*
- * if cursor is before marked block then adjust block by net change.
- */
- if (marked_file->block_br > window->rline) {
- marked_file->block_br += net_change;
- marked_file->block_er += net_change;
- marked_file->dirty = GLOBAL;
- /*
- * if cursor is somewhere in marked block don't restore, do redisplay
- */
- } else if (marked_file->block_er >= window->rline)
- marked_file->dirty = GLOBAL;
-
- /*
- * check for lines of marked block beyond end of file
- */
- if (marked_file->block_br > length)
- unmark_block( window );
- else if (marked_file->block_er > length) {
- marked_file->block_er = length;
- marked_file->dirty = GLOBAL;
- }
- }
- }
- }
-
- /*
- * Name: prepare_block
- * Purpose: To prepare a window/file for a block read, move or copy.
- * Date: June 5, 1991
- * Passed: window: current window
- * file: pointer to file information.
- * text_line: pointer to line in file to prepare.
- * lend: line length.
- * bc: beginning column of BOX.
- * Notes: The main complication is that the cursor may be beyond the end
- * of the current line, in which case extra padding spaces have
- * to be added before the block operation can take place.
- * This only occurs in BOX operations.
- */
- int prepare_block( windows *window, text_ptr text_line, int lend, int bc )
- {
- char *source; /* source for block moves */
- char *dest; /* destination for block moves */
- int pad; /* amount of padding to be added */
- register int i;
- int number; /* number of characters for block moves */
-
- copy_line( text_line, window->bottom_line );
-
- /*
- * work out how much padding is required to extend the current
- * line to the cursor position
- */
-
- pad = bc - lend;
-
- /*
- * make room for the padding spaces
- */
- source = g_status.line_buff + lend;
- dest = source + pad;
- number = pad + 2;
- memmove( dest, source, number );
-
- /*
- * insert the padding spaces
- */
- for (i=pad; i>0; i--)
- *source++ = ' ';
- un_copy_line( text_line, window, FALSE );
- return( pad );
- }
-
-
- /*
- * Name: pad_dest_line
- * Purpose: To prepare a window/file for a block move or copy.
- * Date: June 5, 1991
- * Passed: window: current window
- * dest_file: pointer to file information.
- * dest_line: pointer to line in file to prepare.
- * Notes: We are doing a BOX action (except DELETE). We have come to the
- * end of the file and have no more lines. All this routine does
- * is add a blank line to file.
- */
- void pad_dest_line( windows *window, file_infos *dest_file, text_ptr dest_line)
- {
- /*
- * put linefeed in line_buff. dest_line should be pointing to
- * file->end_text - 1. since we inserted line feed, increment file length.
- */
- g_status.line_buff[0] = '\n';
- g_status.line_buff[1] = CONTROL_Z;
- g_status.copied = TRUE;
- un_copy_line( dest_line, window, FALSE );
- ++dest_file->length;
- }
-
-
- /*
- * Name: move_copy_delete_overlay_block
- * Purpose: Master BOX or LINE routine.
- * Date: June 5, 1991
- * Passed: window: information required to access current window
- * Notes: Operations on BOXs or LINES require several common operations.
- * All require finding the beginning and ending marks. The
- * big differences are whether to delete the source block, copy the
- * source block, or leave the source block marked.
- * This routine will handle block operations across files. Since one
- * must determine the relationship of source and destination blocks
- * within a file, it is relatively easy to expand this relationship
- * across files. There are several caveats. Most deal with the
- * difference between LINE and BOX operations others deal with
- * differences between operations within a file and operations
- * across files.
- * This is probably the most complicated routine in the editor. It
- * is not easy to understand.
- */
- void move_copy_delete_overlay_block( windows *window )
- {
- int action;
- windows *source_window; /* source window for block moves */
- text_ptr source; /* source for block moves */
- text_ptr dest; /* destination for block moves */
- text_ptr p; /* temporary text pointer */
- long number; /* number of characters for block moves */
- int lens; /* length of source line */
- int lend; /* length of destination line */
- int add; /* characters being added from another line */
- int block_len; /* length of the block */
- text_ptr block_start; /* start of block in file */
- text_ptr block_end; /* end of block in file - not same for LINE or BOX */
- char block_buff[BUFF_SIZE+2];
- int prompt_line;
- int same; /* are these files the same */
- int source_first; /* is source file lower in memory than dest */
- file_infos *source_file, *dest_file;
- int rcol, bc, ec; /* temporary column variables */
- int xbc, xec; /* temporary column variables */
- long rline; /* temporary real line variable */
- long br, er, li; /* temporary line variables */
- long dest_add; /* number of bytes added to destination file */
- long source_sub; /* number of bytes sub from source file */
- long diff;
- unsigned long block_size;
- int block_type;
- int fill_char;
- windows s_w, d_w; /* a couple of temporary windows for BOX stuff */
-
- /*
- * initialize block variables
- */
- un_copy_line( window->cursor, window, TRUE );
- if (g_status.marked == FALSE)
- return;
- switch (g_status.command) {
- case MoveBlock :
- action = MOVE;
- break;
- case DeleteBlock :
- action = DELETE;
- break;
- case CopyBlock :
- action = COPY;
- break;
- case KopyBlock :
- action = KOPY;
- break;
- case FillBlock :
- action = FILL;
- break;
- case OverlayBlock :
- action = OVERLAY;
- break;
- }
- source_window = g_status.marked_window;
- prompt_line = window->bottom_line;
- dest_file = window->file_info;
- source_file = g_status.marked_file;
- check_block( );
- if (g_status.marked == FALSE)
- return;
- block_start = source_file->block_start;
- block_end = source_file->block_end;
- block_type = source_file->block_type;
- dest = window->cursor = cpf( window->cursor );
- rline = window->rline;
-
- /*
- * if this is a LINE action, put the text below the current line
- */
- if (block_type == LINE && action != DELETE)
- if ((p = find_next( dest )) != NULL)
- dest = p;
- /*
- * must find out if source and destination file are the same.
- * it don't matter with FILL and DELETE - those actions only modify the
- * source file.
- */
- same = FALSE;
- if (action == FILL) {
- if (block_type == BOX) {
- if (get_block_fill_char( window, &fill_char ) == ERROR)
- return;
- dest = block_start;
- same = TRUE;
- } else {
- error( WARNING, prompt_line, "can only fill box blocks" );
- return;
- }
- }
- if (source_file == dest_file && action != DELETE && action != FILL) {
- same = TRUE;
- if (block_type == BOX && action == MOVE) {
- if (rline == dest_file->block_br &&
- (window->rcol >= dest_file->block_bc &&
- window->rcol <= dest_file->block_ec))
- /*
- * a block moved to within the block itself has no effect
- */
- return;
- } else if (block_type == LINE) {
- if (rline >= dest_file->block_br && rline <= dest_file->block_er) {
- /*
- * if COPYing or KOPYing within the block itself, reposition the
- * destination to the next line after the block (if it exists)
- */
- if (action == COPY || action == KOPY)
- dest = cpf( block_end );
- /*
- * a block moved to within the block itself has no effect
- */
- else if (action == MOVE)
- return;
- }
- }
- }
-
- /*
- * set up Beginning Column, Ending Column, Beginning Row, Ending Row
- */
- bc = source_file->block_bc;
- ec = source_file->block_ec;
- br = source_file->block_br;
- er = source_file->block_er;
-
- /*
- * if we are BOX FILLing, beginning column is bc, not the column of cursor
- */
- if (action == FILL)
- rcol = bc;
- else
- rcol = window->rcol;
- dest_add = source_sub = 0;
-
- /*
- * must know if source of block is before or after destination
- */
- source_first = FALSE;
- if (ptoul( dest ) > ptoul( source_file->block_start ))
- source_first = TRUE;
- if (same && block_type == BOX) {
- if ( rline >= br)
- source_first = TRUE;
- }
-
- /*
- * work out how much has to be moved
- */
- if (block_type == BOX) {
- block_size = ((ec+1) - bc) * ((er+1) - br);
- if (action != DELETE)
- block_size += ((rcol+1) * ((er+1) - br));
- else
- block_size = 0;
- } else if (block_type == LINE) {
- if (action == COPY || action == KOPY)
- block_size = ptoul( block_end ) - ptoul( block_start );
- else
- block_size = 0;
- } else
- return;
-
- /*
- * check that there is room to add block to file
- */
- if (ptoul( g_status.end_mem ) + block_size >= ptoul( g_status.max_mem )) {
- error( WARNING, prompt_line, "not enough memory for block" );
- return;
- }
-
- /*
- * 1. can't create lines greater than g_display.line_length
- * 2. if we are FILLing a BOX - fill block buff once right here
- * 3. only allow overlaying BOXs
- */
- if (block_type == BOX) {
- block_len = (ec+1) - bc;
- if (action != DELETE && action != FILL) {
- if (rcol + block_len > MAX_LINE_LENGTH) {
- error( WARNING, prompt_line, "line would be too long" );
- return;
- }
- } else if (action == FILL)
- block_fill( block_buff, fill_char, block_len );
- } else {
- block_len = 0;
- if (action == OVERLAY) {
- error( WARNING, prompt_line, "can only overlay blocks" );
- return;
- }
- }
-
- /*
- * all block actions go forward thru file - check those pointers
- */
- source = cpf( block_start );
- dest = cpf( dest );
- if (block_type == LINE) {
- diff = ptoul( block_end ) - ptoul( block_start );
- dest_add = source_sub = diff;
- if (action != DELETE) {
- p = addltop( diff, dest );
- number = ptoul( g_status.end_mem ) - ptoul( dest );
- hw_move( p, dest, number );
- g_status.end_mem = addltop( diff, g_status.end_mem);
- }
- if (action != DELETE && !source_first)
- source = addltop( diff, source );
- if (action == COPY || action == KOPY || action == MOVE)
- hw_move( dest, source, diff );
- if (action == DELETE || action == MOVE) {
- p = addltop( diff, source );
- number = ptoul( g_status.end_mem ) - ptoul( p );
- hw_move( source, p, number );
- g_status.end_mem = addltop( -diff, g_status.end_mem);
- }
- if (action == DELETE)
- dest_add = 0;
- else if (action == COPY || action == KOPY)
- source_sub = 0;
- diff = (er+1l) - br;
- if (action == COPY || action == KOPY || action == MOVE)
- dest_file->length += diff;
- if (action == DELETE || action == MOVE)
- source_file->length -= diff;
- if (action == DELETE && source_window->rline >= br) {
- source_window->rline -= ((er + 1) - br);
- if (source_window->rline < br)
- source_window->rline = br;
- }
- /*
- * the block action is now complete. restore all the start_text and
- * end_text pointers for all open files.
- */
- if (action == MOVE || action == DELETE)
- restore_start_end( dest_file, source_file, dest_add, -source_sub,
- source_first );
- else
- restore_start_end( dest_file, source_file, dest_add, source_sub,
- source_first );
- /*
- * restore all cursors in all windows
- */
- restore_cursors( dest_file, source_file );
- } else {
- dup_window_info( &s_w, source_window );
- dup_window_info( &d_w, window );
- s_w.rline = br;
- for (li=br; li<=er; li++, s_w.rline++, d_w.rline++) {
- lens = linelen( source );
- lend = linelen( dest );
-
- if (action == FILL) {
- s_w.cursor = source;
- add = 0;
- if (lens < (rcol+1))
- add = prepare_block( &s_w, source, lens, rcol );
- add += copy_buff_2file( &s_w, block_buff, source, rcol,
- block_len, action );
-
- /*
- * if we are doing a BOX action and both the source and
- * destination are 0 then we have nothing to do. all LINE actions
- * require processing.
- */
- } else if (lens != 0 || lend != 0) {
-
- /*
- * do actions that may require adding to file
- */
- if (action==MOVE || action==COPY || action==KOPY ||
- action == OVERLAY) {
- d_w.cursor = dest;
- xbc = bc;
- xec = ec;
- if (action != OVERLAY && same) {
- if (rcol < bc && rline > br && rline <=er)
- if (li >= rline) {
- xbc = bc + block_len;
- xec = ec + block_len;
- }
- }
- load_buff( block_buff, source, xbc, xec, block_type );
- add = 0;
- if (lend < (rcol+1))
- add = prepare_block( &d_w, dest, lend, rcol );
- add += copy_buff_2file( &d_w, block_buff, dest, rcol,
- block_len, action );
- if (!source_first)
- source += add;
- }
-
- /*
- * do actions that may require deleting from file
- */
- if (action == MOVE || action == DELETE) {
- s_w.cursor = source;
- if (lens >= (bc + 1)) {
- add = block_len;
- xbc = bc;
- if (lens <= (ec + 1))
- add = lens - bc;
- if (same && action == MOVE) {
- if (rcol < bc && rline >= br && rline <=er)
- if (li >= rline)
- xbc = bc + block_len;
- }
- delete_box_block( &s_w, source, xbc, add, prompt_line );
- if (action == MOVE && source_first) {
- if (!same || s_w.rline != d_w.rline) {
- dest = addltop( -add, dest );
- dest = cpf( dest );
- }
- }
- }
- }
- }
-
- /*
- * if we are doing any BOX action we need to move the source pointer
- * to the next line.
- */
- source = find_next( source );
-
- /*
- * if we are doing any action other than DELETE, we need to move
- * the destination to the next line in marked block.
- * In BOX mode, we may need to pad the end of the file
- * with a blank line before we process the next line.
- */
- if (action != DELETE && action != FILL) {
- p = find_next( dest );
- if (p != NULL && *p != CONTROL_Z)
- dest = p;
- else {
- p = addltop( -1, dest_file->end_text );
- pad_dest_line( window, dest_file, p );
- dest = find_next( dest );
- if (!source_first)
- ++source;
- }
- }
- }
- }
-
- dest_file->modified = TRUE;
- dest_file->dirty = GLOBAL;
- if (action == MOVE || action == DELETE || action == FILL) {
- source_file->modified = TRUE;
- source_file->dirty = GLOBAL;
- }
-
- /*
- * unless we are doing a KOPY, FILL, or OVERLAY we need to unmark the
- * block. if we just did a KOPY, the beginning and ending may have
- * changed. so, we must readjust beginning and ending rows.
- */
- if (action == KOPY) {
- if (same && !source_first && block_type == LINE) {
- number = (er+1) - br;
- source_file->block_br += number;
- source_file->block_er += number;
- } else if (same && !source_first && window->rline == br &&
- block_type == BOX) {
- add = (ec+1) - bc;
- source_file->block_bc += add;
- source_file->block_ec += add;
- }
- } else if (action != FILL && action != OVERLAY)
- unmark_block( window );
- show_avail_mem( );
- }
-
-
- /*
- * Name: load_buff
- * Purpose: copy the contents of a line in a BOX to the block buffer.
- * Date: June 5, 1991
- * Passed: block_buff: local buffer for block moves
- * source: source line in file
- * bc: beginning column of BOX. used only in BOX operations.
- * ec: ending column of BOX. used only in BOX operations.
- * block_type: LINE or BOX
- * Notes: If the block is marked in LINE mode, copy the line to the
- * block buffer. If the block is marked in BOX mode, there are
- * several things to take care of. 1) The BOX begins and ends
- * within a line - just copy the blocked characters to the block buff.
- * 2) the BOX begins within a line but ends past the eol - copy
- * all the characters within the line to the block buff then fill with
- * padding. 3) the BOX begins and ends past eol - fill entire
- * block buff with padding.
- */
- void load_buff( char *block_buff, text_ptr source, int bc, int ec,
- int block_type )
- {
- int len, pad, avlen;
- register int i;
-
- len = linelen( source );
- if (block_type == LINE) {
- if (source[len] == '\n')
- ++len;
- for (i=len; i>0; i++)
- *block_buff++ = *source++;
- } else {
- /*
- * block start may be past eol
- */
- if (len < ec + 1) {
- /*
- * does block start past eol? - fill with pad
- */
- if (len < bc) {
- pad = (ec + 1) - bc;
- for (i=pad; i>0; i--)
- *block_buff++ = ' ';
- } else {
- /*
- * block ends past eol - fill with pad
- */
- pad = (ec + 1) - len;
- avlen = len - bc;
- source = source + bc;
- for (i=avlen; i>0; i--)
- *block_buff++ = *source++;
- for (i=pad; i>0; i--)
- *block_buff++ = ' ';
- }
- } else {
- /*
- * block is within line - copy block to buffer
- */
- avlen = (ec + 1) - bc;
- source = source + bc;
- for (i=avlen; i>0; i--)
- *block_buff++ = *source++;
- }
- }
- *block_buff++ = CONTROL_Z;
- *block_buff = '\0';
- }
-
-
- /*
- * Name: copy_buff_2file
- * Purpose: copy the contents of block buffer to destination file
- * Date: June 5, 1991
- * Passed: window: current window
- * block_buff: local buffer for moves
- * dest: pointer to destination line in destination file
- * rcol: if in BOX mode, destination column in destination file
- * block_len: if in BOX mode, width of block to copy
- * action: type of block action
- * Notes: In BOX mode, the destination line has already been prepared.
- * Just copy the BOX buffer to the destination line.
- */
- int copy_buff_2file( windows *window, char *block_buff, text_ptr dest,
- int rcol, int block_len, int action )
- {
- char *s;
- char *d;
- int i;
- int rc;
-
- rc = 0;
- copy_line( dest, window->bottom_line );
- s = g_status.line_buff + rcol;
-
- /*
- * s is pointing to location to perform BOX operation. If we do a
- * FILL or OVERLAY, we do not necessarily add any extra space. If the
- * line does not extend all the thru the BOX then we add.
- * we always add space when we COPY, KOPY, or MOVE
- */
- if (action == FILL || action == OVERLAY) {
- i = linelen( s );
- if (i < block_len) {
- rc = block_len - i;
- d = s + rc;
- i = block_len + 1 + linelen( g_status.line_buff ) - rcol;
- memmove( d, s, i );
- }
- } else {
- rc = block_len;
- d = s + block_len;
- i = block_len + 1 + linelen( g_status.line_buff ) - rcol;
- memmove( d, s, i );
- }
- memmove( s, block_buff, block_len );
- un_copy_line( dest, window, FALSE );
- return( rc );
- }
-
-
- /*
- * Name: block_fill
- * Purpose: fill the block buffer with character
- * Date: June 5, 1991
- * Passed: block_buff: local buffer for moves
- * fill_char: fill character
- * block_len: number of columns in block
- * Notes: Fill block_buffer for block_len characters using fill_char. This
- * function is used only for BOX blocks.
- */
- void block_fill( char *block_buff, int fill_char, int block_len )
- {
- memset( block_buff, fill_char, block_len );
- *(block_buff+block_len) = CONTROL_Z;
- }
-
-
- /*
- * Name: restore_start_end
- * Purpose: a file has been modified - must restore all start and end pointers
- * Date: June 5, 1991
- * Passed: dest_file: pointer to destination file structure
- * source_file: pointer to source file structure
- * dest_mod: net modifications in the destination file
- * source_mod: net modifications in the source file
- * source_first: we must know which file is stored first in memory
- * Notes: Go through the file list and adjust the start_text and end_text
- * file pointers as needed. There are several cases that must be
- * be considered. 1) destination file and source file could be the
- * same. 2) if the file pointer we're looking at is below both
- * the source and destination, no action is needed. 3) the file
- * we're looking at could be between the source and destination.
- * 4) the file we're looking at could be either source or destination.
- * 5) the file we're looking at could be past both source and dest.
- * Use unsigned longs to compare pointers.
- */
- void restore_start_end( file_infos *dest_file, file_infos *source_file,
- long dest_mod, long source_mod, int source_first )
- {
- int same;
- long net_mod;
- unsigned long sst; /* source start_text - keep these around for if's */
- unsigned long dst; /* destination start_text */
- unsigned long ost; /* open_file start_text */
- register file_infos *open_file;
-
- net_mod = dest_mod + source_mod;
- sst = ptoul( source_file->start_text );
- dst = ptoul( dest_file->start_text );
- same = (sst == dst) ? TRUE : FALSE;
- for (open_file=g_status.file_list; open_file != NULL;
- open_file=open_file->next) {
- sst = ptoul( source_file->start_text );
- dst = ptoul( dest_file->start_text );
- ost = ptoul( open_file->start_text );
- if (ost == sst) {
- if (same)
- source_file->end_text = addltop( net_mod, source_file->end_text);
- else if (source_first)
- source_file->end_text = addltop( source_mod,
- source_file->end_text);
- else {
- source_file->start_text = addltop( dest_mod,
- source_file->start_text);
- source_file->end_text = addltop( net_mod, source_file->end_text);
- }
- } else if (ost == dst) {
- if (source_first) {
- dest_file->start_text = addltop( source_mod,
- dest_file->start_text);
- dest_file->end_text = addltop( net_mod, dest_file->end_text);
- } else
- dest_file->end_text = addltop( dest_mod, dest_file->end_text);
- } else if (ost > sst) {
- if (ost < dst) {
- open_file->start_text = addltop( source_mod,
- open_file->start_text);
- open_file->end_text = addltop( source_mod, open_file->end_text);
- } else {
- open_file->start_text = addltop( net_mod, open_file->start_text);
- open_file->end_text = addltop( net_mod, open_file->end_text);
- }
- } else if (ost > dst) {
- if (ost < sst) {
- open_file->start_text = addltop( dest_mod, open_file->start_text);
- open_file->end_text = addltop( dest_mod, open_file->end_text);
- } else {
- open_file->start_text = addltop( net_mod, open_file->start_text);
- open_file->end_text = addltop( net_mod, open_file->end_text);
- }
- }
- }
- }
-
-
- /*
- * Name: restore_cursors
- * Purpose: a file has been modified - must restore all cursor pointers
- * Date: June 5, 1991
- * Passed: dest_file: target file for block actions
- * source_file: source file for block actions
- * Notes: Go through the window list and adjust the cursor pointers
- * as needed. This could be done by using the changes made by
- * the block actions, but it would be a real pain in the neck.
- * I chose to use the brute force approach.
- */
- void restore_cursors( file_infos *dest_file, file_infos *source_file )
- {
- register windows *window;
- text_ptr p;
- file_infos *file;
- long beg_line, cur_line, test_line;
- unsigned long df, sf, f;
-
- df = ptoul( (text_ptr)dest_file );
- sf = ptoul( (text_ptr)source_file );
- window = g_status.window_list;
- while (window != NULL) {
- file = window->file_info;
- f = ptoul( (text_ptr)file );
- beg_line = 1;
- cur_line = window->rline;
- if (cur_line > file->length) {
- file->end_text = cpb( file->end_text );
- p = find_prev( file->end_text-1 );
- if (p != NULL )
- window->cursor = p;
- else
- window->cursor = file->start_text;
- window->rline = file->length;
- test_line = cur_line - file->length;
- if (test_line < (long)(window->cline - (window->top_line - 1)))
- window->cline -= test_line;
- } else {
- file->start_text = cpf( file->start_text );
- for (p=file->start_text; p!=NULL && beg_line<cur_line; beg_line++)
- p = find_next( p );
- if (p != NULL )
- window->cursor = p;
- else {
- window->cursor = file->start_text;
- cur_line = file->length;
- }
- window->rline = cur_line;
- }
- if (window->rline <= 0l)
- window->rline = 1l;
- if (window->rline < (window->cline - (window->top_line - 1)))
- window->cline = (int)window->rline + window->top_line - 1;
- if (window->cline < window->top_line)
- window->cline = window->top_line;
- if ((f == df || f == sf) && window->visible )
- show_size( window );
- window = window->next;
- }
- }
-
-
- /*
- * Name: delete_box_block
- * Purpose: delete the marked text
- * Date: June 5, 1991
- * Passed: s_w: source window
- * source: pointer to line with block to delete
- * bc: beginning column of block - BOX mode only
- * add: number of characters in block to delete
- * prompt_line: line to display error message if needed
- * Notes: Used only for BOX blocks. Delete the block.
- */
- void delete_box_block( windows *s_w, text_ptr source, int bc, int add,
- int prompt_line )
- {
- char *s;
- char *d;
- register int number;
-
- number = linelen( source ) - bc + 2;
- copy_line( source, prompt_line );
- s = g_status.line_buff + bc + add;
- d = s - add;
- memmove( d, s, number );
- un_copy_line( source, s_w, FALSE );
- }
-
- /*
- * Name: check_block
- * Purpose: To check that the block is still valid.
- * Date: June 5, 1991
- * Notes: After some editing, the marked block may not be valid. For example,
- * deleting all the lines in a block in another window.
- */
- void check_block( void )
- {
- register file_infos *file;
- windows filler;
-
- file = g_status.marked_file;
- if (file == NULL || file->block_br > file->length)
- unmark_block( &filler );
- else {
- if (file->length < file->block_er)
- file->block_er = file->length;
- find_begblock( file );
- find_endblock( file );
- }
- }
-
-
- /*
- * Name: find_begblock
- * Purpose: find the beginning line in file with marked block
- * Date: June 5, 1991
- * Passed: file: file containing marked block
- * Notes: file->block_start contains starting line of marked block at end.
- */
- void find_begblock( file_infos *file )
- {
- text_ptr next; /* start from beginning of file and go to end */
- long i; /* line counter */
-
- next = cpf( file->start_text );
- for (i=1; i<file->block_br && next != NULL; i++)
- next = find_next( next );
- if (next != NULL)
- file->block_start = next;
- }
-
-
- /*
- * Name: find_endblock
- * Purpose: find the ending line in file with marked block
- * Date: June 5, 1991
- * Passed: file: file containing marked block
- * Notes: If in LINE mode, file->block_end is set to end of line of last
- * line in block. If in BOX mode, file->block_end is set to
- * beginning of last line in marked block. If the search for the
- * ending line of the marked block goes past the eof, set the
- * ending line of the block to the last line in the file.
- */
- void find_endblock( file_infos *file )
- {
- text_ptr next; /* start from beginning of file and go to end */
- long i; /* line counter */
- int end_column;
- register file_infos *fp;
-
- fp = file;
- next = cpf( fp->start_text );
- for (i=1; i<fp->block_er && next != NULL; i++)
- next = find_next( next );
- if (next != NULL) {
- end_column = linelen( next );
- if (next[end_column] == '\n')
- ++end_column;
- if (fp->block_type == LINE)
- fp->block_end = next + end_column;
- else
- fp->block_end = next;
- } else {
- fp->end_text = cpb( fp->end_text );
- if (fp->block_type == LINE)
- fp->block_end = fp->end_text - 1;
- else {
- next = find_prev( fp->end_text - 1 );
- if (next != NULL)
- fp->block_end = next;
- else
- fp->block_end = fp->end_text - 1;
- }
- fp->block_er = fp->length;
- }
- }
-
- /*
- * Name: block_write
- * Purpose: To write the currently marked block to a disk file.
- * Date: June 5, 1991
- * Passed: window: information required to access current window
- * Notes: If the file already exists, the user gets to choose whether
- * to overwrite or append.
- */
- void block_write( windows *window )
- {
- int prompt_line;
- int rc;
- char buff[MAX_COLS+2]; /* buffer for char and attribute */
- char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
- text_ptr block_start; /* start of block in file */
- text_ptr block_end; /* end of block in file */
- file_infos *file;
- int block_type;
-
- /*
- * make sure block is marked OK
- */
- un_copy_line( window->cursor, window, TRUE );
- check_block( );
- if (g_status.marked == TRUE) {
- prompt_line = window->bottom_line;
- file = g_status.marked_file;
- block_start = file->block_start;
- block_end = file->block_end;
- block_type = file->block_type;
-
- /*
- * find out which file to write to
- */
- save_screen_line( 0, prompt_line, line_buff );
- if (get_name( "Filename: ", prompt_line, g_status.rw_name,
- g_display.message_color ) == OK) {
- /*
- * if the file exists, find out whether to overwrite or append
- */
- if (hw_fattrib( g_status.rw_name ) != ERROR) {
- set_prompt( "File exists. Overwrite or Append? (o/a): ",
- prompt_line );
- switch (get_oa( )) {
- case A_OVERWRITE :
- hw_unlink( g_status.rw_name, prompt_line );
- combine_strings( buff, "writing block to '",
- g_status.rw_name, "'" );
- s_output( buff, prompt_line, 0, g_display.message_color );
- rc = hw_save( g_status.rw_name, block_start, block_end,
- block_type );
- if (rc == ERROR)
- error( WARNING, prompt_line, "could not write block" );
- break;
- case A_APPEND :
- combine_strings( buff, "appending block to '",
- g_status.rw_name, "'" );
- s_output( buff, prompt_line, 0, g_display.message_color );
- rc = hw_append( g_status.rw_name, block_start, block_end,
- block_type );
- if (rc == ERROR)
- error( WARNING, prompt_line, "could not append block" );
- break;
- }
- } else {
- combine_strings( buff, "writing block to '", g_status.rw_name,
- "'" );
- s_output( buff, prompt_line, 0, g_display.message_color );
- if (hw_save( g_status.rw_name, block_start, block_end,
- block_type ) == ERROR)
- error( WARNING, prompt_line, "could not write block" );
- }
- }
- restore_screen_line( 0, prompt_line, line_buff );
- }
- }
-
-
- /*
- * Name: block_print
- * Purpose: Print an entire file or the currently marked block.
- * Date: June 5, 1991
- * Passed: window: information required to access current window
- */
- void block_print( windows *window )
- {
- char answer[MAX_COLS]; /* entire file or just marked block? */
- char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
- int col, func;
- int prompt_line;
- text_ptr block_start; /* start of block in file */
- text_ptr block_end; /* end of block in file */
- file_infos *file;
- int block_type;
- FILE *fp; /* file pointer for PRN device */
- char *p;
- int len;
- int bc, ec, last_c;
- long lend;
- long l;
- int color;
-
- color = g_display.message_color;
- un_copy_line( window->cursor, window, TRUE );
- prompt_line = window->bottom_line;
- save_screen_line( 0, prompt_line, line_buff );
- /*
- * print entire file or just marked block?
- */
- strcpy( answer, "Print file or block? (f/b): " );
- col = strlen( answer );
- s_output( answer, prompt_line, 0, color );
- eol_clear( col, prompt_line, g_display.text_color );
- xygoto( col, prompt_line );
- func = col = 0;
- while (col != 'f' && col != 'F' && col != 'b' && col != 'B' &&
- func != AbortCommand) {
- col = getkey( );
- func = getfunc( col );
- if (col == ESC)
- func = AbortCommand;
- }
- if (func != AbortCommand) {
- file = window->file_info;
- if (col == 'f' || col == 'F') {
- block_start = file->start_text;
- block_end = cpb( file->end_text ) - 1;
- block_type = NOTMARKED;
- } else if (col == 'b' || col == 'B') {
- check_block( );
- if (g_status.marked == TRUE) {
- file = g_status.marked_file;
- block_start = file->block_start;
- block_end = file->block_end;
- block_type = file->block_type;
- } else
- col = AbortCommand;
- }
- if (block_type != BOX) {
- block_end = cpb( block_end );
- block_end = find_prev( block_end );
- }
- if (col != AbortCommand) {
- if ((fp = fopen( "PRN", "a" )) == NULL)
- error( WARNING, prompt_line, "error in printing text" );
- else {
- eol_clear( 0, prompt_line, color );
- s_output( "Printing line Press ESC to cancel.",
- prompt_line, 0, color );
- xygoto( 14, prompt_line );
- block_start = cpf( block_start );
- if (block_type == BOX) {
- bc = file->block_bc;
- ec = file->block_ec;
- last_c = ec + 1 - bc;
- }
- p = g_status.line_buff;
- lend = ptoul( block_end );
- for (l=1,col=OK; ptoul( block_start ) <= lend && col == OK; l++) {
- s_output( " ", prompt_line, 14, color );
- ltoa( l, answer, 10 );
- s_output( answer, prompt_line, 14, color );
- g_status.copied = FALSE;
- if (block_type == BOX) {
- load_buff( p, block_start, bc, ec, BOX );
- *(p+last_c) = '\n';
- *(p+last_c+1) = CONTROL_Z;
- } else
- copy_line( block_start, prompt_line );
- len = find_CONTROL_Z( p );
- if (fwrite( p, sizeof( char ), len, fp ) < len)
- col = ERROR;
- block_start = find_next( block_start );
- if (block_start == NULL)
- block_start = block_end + 1;
- if (kbhit()) {
- col = getkey( );
- if (col == ESC)
- col = AbortCommand;
- else
- col = getfunc( col );
- if (col != AbortCommand)
- col = OK;
- }
- }
- g_status.copied = FALSE;
- fclose( fp );
- }
- }
- }
- restore_screen_line( 0, prompt_line, line_buff );
- }
-
-
- /*
- * Name: get_block_fill_char
- * Purpose: get the character to fill marked block.
- * Date: June 5, 1991
- * Passed: window: information required to access current window
- * c: address of character to fill block
- */
- int get_block_fill_char( windows *window, int *c )
- {
- char answer[MAX_COLS]; /* entire file or just marked block? */
- char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
- register int col;
- int prompt_line;
- int rc;
-
- rc = OK;
- prompt_line = window->bottom_line;
- save_screen_line( 0, prompt_line, line_buff );
- strcpy( answer, "Enter character to fill block (ESC to exit): " );
- s_output( answer, prompt_line, 0, g_display.message_color );
- col = strlen( answer );
- eol_clear( col, prompt_line, g_display.text_color );
- xygoto( col, prompt_line );
- col = getkey( );
- if (col >= 256)
- rc = ERROR;
- else
- *c = col;
- restore_screen_line( 0, prompt_line, line_buff );
- return( rc );
- }
-
-
- /*
- * Name: block_expand_tabs
- * Purpose: Expand tabs in a marked block.
- * Date: June 5, 1991
- * Passed: window: pointer to current window
- * Notes: Tabs are expanded using the current tab interval.
- * Lines are checked to make sure they are not too long.
- */
- void block_expand_tabs( windows *window )
- {
- int prompt_line;
- int len;
- int tab;
- int tab_size;
- int dirty;
- int spaces;
- int net_change;
- text_ptr p; /* pointer to block line */
- file_infos *file;
- windows s_w;
- int block_type;
- long er, li;
- int bc, ec;
- int i, j;
- char exp_buff[BUFF_SIZE+2], *b, *q, *s, *d, *lb;
-
- /*
- * make sure block is marked OK
- */
- un_copy_line( window->cursor, window, TRUE );
- check_block( );
- if (g_status.marked == TRUE) {
-
- /*
- * initialize everything
- */
- prompt_line = window->bottom_line;
- dirty = FALSE;
- tab_size = mode.tab_size;
- file = g_status.marked_file;
- bc = file->block_bc;
- ec = file->block_ec;
- p = cpf( file->block_start );
- block_type = file->block_type;
- er = file->block_er;
- dup_window_info( &s_w, g_status.marked_window );
- lb = g_status.line_buff;
- for (s_w.rline = li = file->block_br; li<=er; li++, s_w.rline++) {
-
- /*
- * use the line buffer to expand LINE blocks.
- * use the line buffer and the exp buffer to expand BOX blocks.
- */
- tab = FALSE;
- len = linelen( p );
- net_change = 0;
- g_status.copied = FALSE;
- if (block_type == BOX) {
- if (len > bc) {
-
- /*
- * copy the line starting at the beginning column of BOX to the
- * line buffer.
- */
- copy_line( p+bc, prompt_line);
- b = lb;
-
- /*
- * put the characters in the BOX in the exp_buff.
- */
- for (j=0,i=bc; i<= ec && i<len; i++,j++)
- exp_buff[j] = *b++;
- exp_buff[j] = CONTROL_Z;
-
- /*
- * now, delete all characters in BOX from line buffer.
- */
- b = lb;
- i = (ec < len) ? ec+1 : len;
- i -= bc;
- s = b + i;
- j = linelen( s ) + 3;
- memmove( b, s, j );
-
- /*
- * expand the tabs in the line buffer.
- */
- b = exp_buff;
- for (b=exp_buff, i=bc+1; *b != CONTROL_Z; b++) {
- if (*b == '\t') {
- tab = TRUE;
- spaces = i % tab_size;
- if (spaces)
- spaces = tab_size - spaces;
- if (spaces) {
- d = b + spaces;
- j = linelen( b ) + 2;
- memmove( d, b, j );
- }
- for (j=0; j<=spaces; j++)
- *(b+j) = ' ';
- net_change += spaces;
- i += spaces + 1;
- b += spaces;
- } else
- i++;
- }
- if (tab == TRUE) {
-
- /*
- * make room in the line buffer for the expanded tabs.
- */
- i = linelen( exp_buff );
- s = lb;
- j = linelen( s ) + 2;
- d = s + i;
- memmove( d, s, j );
- for (q=s, b=exp_buff; *b != CONTROL_Z;)
- *q++ = *b++;
- un_copy_line( p+bc, &s_w, TRUE );
- }
- }
- } else if (block_type == LINE) {
-
- /*
- * LINE blocks are easy. copy the line into the line buffer (lb)
- * and expand the tabs if any.
- */
- copy_line( p, prompt_line);
- for (b=lb, i=1; *b != CONTROL_Z; b++) {
- if (*b == '\t') {
- tab = TRUE;
- spaces = i % tab_size;
- if (spaces)
- spaces = tab_size - spaces;
- if (spaces) {
- d = b + spaces;
- j = linelen( b ) + 2;
- memmove( d, b, j );
- }
- for (j=0; j<=spaces; j++)
- *(b+j) = ' ';
- net_change += spaces;
- i += spaces + 1;
- b += spaces;
- } else
- i++;
- }
- if (tab == TRUE)
- un_copy_line( p, &s_w, TRUE );
- }
- if (tab == TRUE)
- dirty = GLOBAL;
- p = find_next( p );
- }
-
- /*
- * IMPORTANT: we need to reset the copied flag because the cursor may
- * not necessarily be on the last line of the block.
- */
- g_status.copied = FALSE;
- if (dirty) {
- check_block( );
- g_status.marked_file->dirty = dirty;
- show_avail_mem( );
- }
- }
- }