home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Black Box 4
/
BlackBox.cdr
/
editors
/
tde150.arj
/
BLOCK.C
next >
Wrap
C/C++ Source or Header
|
1992-04-01
|
69KB
|
1,992 lines
/******************* 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. This editor uses LINE,
* STREAM, and BOX blocks. That is, one may mark entire lines, streams of
* characters, 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. Come to think of it, most of these block functions
* are 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.
*
* In tde, version 1.3, I put STREAM blocks back in. Added block upper case,
* block lower case, and block strip high bit.
*
* In tde, version 1.4, I added a block number function. Here at our lab,
* I often need to number samples, lines, etc..., comes in fairly useful.
*
* 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
*
* This modification of Douglas Thomson's code is released into the
* public domain, Frank Davis. You may distribute it freely.
*/
#include <bios.h>
#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, stream, or box mode. If the user mixes types, then block
* type defaults to current block type.
*/
void mark_block( WINDOW *window )
{
int type;
int num;
long lnum;
register file_infos *file; /* temporary file variable */
register WINDOW *win; /* put window pointer in a register */
win = window;
file = win->file_info;
if (win->rline > file->length)
return;
if (g_status.marked == FALSE) {
g_status.marked = TRUE;
g_status.marked_file = file;
}
if (g_status.command == MarkBox)
type = BOX;
else if (g_status.command == MarkLine)
type = LINE;
else if (g_status.command == MarkStream)
type = STREAM;
/*
* 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) {
/*
* mark beginning and ending column regardless of block mode.
*/
if (file->block_type == NOTMARKED) {
file->block_ec = file->block_bc = win->rcol;
file->block_er = file->block_br = win->rline;
} else {
if (file->block_br > win->rline) {
file->block_br = win->rline;
if (file->block_bc < win->rcol && type != STREAM)
file->block_ec = win->rcol;
else
file->block_bc = win->rcol;
} else {
if (type != STREAM) {
file->block_ec = win->rcol;
file->block_er = win->rline;
} else {
if (win->rline == file->block_br &&
win->rline == file->block_er) {
if (win->rcol < file->block_bc)
file->block_bc = win->rcol;
else
file->block_ec = win->rcol;
} else if (win->rline == file->block_br)
file->block_bc = win->rcol;
else {
file->block_ec = win->rcol;
file->block_er = win->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) && (type != STREAM ||
(type == STREAM && file->block_br == file->block_er))) {
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 block
* is defined as current block type.
*/
if (file->block_type != NOTMARKED) {
/*
* if block type goes to BOX, check to make sure ec is greater than
* or equal to bc. ec can be less than bc in STREAM blocks.
*/
if (type == BOX) {
if (file->block_ec < file->block_bc) {
num = file->block_ec;
file->block_ec = file->block_bc;
file->block_bc = num;
}
}
}
file->block_type = type;
file->dirty = GLOBAL;
} else
error( WARNING, win->bottom_line,
"a block is already defined in another file" );
}
/*
* 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( WINDOW *arg_filler )
{
register file_infos *marked_file;
if (g_status.marked == TRUE) {
marked_file = g_status.marked_file;
g_status.marked = FALSE;
g_status.marked_file = 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( WINDOW *window, int net_change )
{
long length;
register file_infos *marked_file;
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 and STREAM operations.
*/
int prepare_block( WINDOW *window, text_ptr text_line, int lend, int bc )
{
register int pad; /* amount of padding to be added */
register char *source; /* source 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;
memmove( source+pad, source, pad+2 );
/*
* insert the padding spaces
*/
memset( source, ' ', pad );
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( WINDOW *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, STREAM, or LINE routine.
* Date: June 5, 1991
* Passed: window: information required to access current window
* Notes: Operations on BOXs, STREAMs, 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( WINDOW *window )
{
int action;
WINDOW *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;
long block_num; /* starting number for block number */
long block_inc; /* increment to use for block number */
int block_just; /* left or right justify numbers? */
unsigned long block_size;
int block_type;
int fill_char;
WINDOW s_w, d_w; /* a couple of temporary WINDOWs for BOX stuff */
char *ltol = "Error: line would be too long.";
int padded_file;
WINDOW *w;
/*
* 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;
case NumberBlock :
action = NUMBER;
break;
}
source_file = g_status.marked_file;
source_window = g_status.window_list;
for (; ptoul( source_window->file_info ) != ptoul( source_file );)
source_window = source_window->next;
prompt_line = window->bottom_line;
dest_file = window->file_info;
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;
/*
* 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 or BOX NUMBERing, beginning column is bc,
* not the column of cursor
*/
rcol = (action == FILL || action == NUMBER) ? bc : window->rcol;
dest_add = source_sub = 0;
/*
* 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 (action == NUMBER) {
if (block_type == BOX) {
if (get_block_numbers( window, &block_num, &block_inc, &block_just )
== ERROR)
return;
dest = block_start;
same = TRUE;
} else {
error( WARNING, prompt_line, "can only number box blocks" );
return;
}
}
if (source_file == dest_file && action != DELETE && action != FILL) {
same = TRUE;
if (block_type == BOX && action == MOVE) {
if (rline == br && (rcol >= bc && rcol <= ec))
/*
* a block moved to within the block itself has no effect
*/
return;
} else if (block_type == LINE || block_type == STREAM) {
if (rline >= br && rline <= er) {
if (block_type == LINE) {
/*
* 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;
} else {
/*
* to find out if cursor is in a STREAM block we have to do
* a few more tests. if cursor is on the beginning row or
* ending row, then check the beginning and ending column.
*/
if ((rline > br && rline < er) || (rline == br && rcol >= bc) ||
(rline == er && rcol <= ec)) {
/*
* if the cursor is in middle of STREAM, make destination
* the last character following the STREAM block.
*/
if (action == COPY || action == KOPY) {
dest = cpf( block_end );
rcol = ec + 1;
rline = er;
} else if (action == MOVE)
return;
}
}
}
}
}
/*
* 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 || block_type == STREAM) {
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;
}
/*
* set the command to word wrap so the un_copy_line function will
* not display the lines while doing block stuff.
*/
g_status.command = WordWrap;
/*
* 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, ltol );
return;
}
} else if (action == FILL)
block_fill( block_buff, fill_char, block_len );
} else if (block_type == LINE) {
block_len = 0;
if (action == OVERLAY) {
error( WARNING, prompt_line, "can only overlay blocks" );
return;
}
} else if (block_type == STREAM) {
lend = linelen( block_end );
if (action == DELETE || action == MOVE) {
/*
* Is what's left on start of STREAM block line plus what's left at
* end of STREAM block line too long?
*/
if (lend > ec)
lend -= ec;
else
lend = 0;
if (bc + lend > MAX_LINE_LENGTH) {
error( WARNING, prompt_line, ltol );
return;
}
}
if (action != DELETE) {
/*
* We are doing a MOVE, COPY, or KOPY. Find out if what's on the
* current line plus the start of the STREAM line are too long.
* Then find out if end of the STREAM line plus what's left of
* the current line are too long.
*/
lens = linelen( block_start );
/*
* if we had to move the destination of the STREAM COPY or KOPY
* to the end of the STREAM block, then dest and window->cursor
* will not be the same. In this case, set length to length of
* first line in STREAM block. Then we can add the residue of
* the first line in block plus residue of the last line of block.
*/
if (ptoul( dest ) == ptoul( window->cursor ))
add = linelen( dest );
else
add = lens;
/*
* Is current line plus start of STREAM block line too long?
*/
if (lens > bc)
lens -= bc;
else
lens = 0;
if (rcol + lens > MAX_LINE_LENGTH) {
error( WARNING, prompt_line, ltol );
return;
}
/*
* Is residue of current line plus residue of STREAM block line
* too long?
*/
if (add > bc)
add -= bc;
else
add = 0;
if (lend > ec)
lend -= ec;
else
lend = 0;
if (add + lend > MAX_LINE_LENGTH) {
error( WARNING, prompt_line, ltol );
return;
}
}
}
/*
* all block actions go forward thru file - check those pointers
*/
source = cpf( block_start );
dest = cpf( dest );
if (block_type == LINE || block_type == STREAM) {
if (block_type == STREAM) {
dup_window_info( &s_w, source_window );
dup_window_info( &d_w, window );
s_w.rline = br;
d_w.rline = rline;
/*
* pad the start of the STREAM block if needed.
*/
lens = linelen( block_start );
if (lens < bc+1) {
add = prepare_block( &s_w, block_start, lens, bc );
if (br != er)
block_end += add;
if (source_first)
dest += add;
}
block_start += bc;
source = cpf( block_start );
/*
* pad the end of the STREAM block if needed.
*/
lens = linelen( block_end );
if (lens < ec+1) {
add = prepare_block( &s_w, block_end, lens, ec+1 );
if (source_first)
dest += add;
}
block_end += ec + 1;
/*
* pad the destination line if necessary
*/
lend = linelen( dest );
if (action==MOVE || action==COPY || action==KOPY) {
if (lend < rcol+1) {
add = prepare_block( &d_w, dest, lend, rcol );
if (!source_first) {
source += add;
block_start += add;
block_end += add;
}
}
dest += rcol;
}
}
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 = block_type == LINE ? (er+1l) - br : er - 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 -= diff;
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 {
padded_file = FALSE;
dup_window_info( &s_w, source_window );
dup_window_info( &d_w, window );
s_w.rline = br;
/*
* special case for block actions. since block actions always
* move forward thru the file, overlapping text in an OVERLAY
* action don't do right. make the operation start at the end
* of the block and work backwards.
*/
if (action == OVERLAY && same && rline > br && rline <= er) {
/*
* see if we need to add padd lines at eof.
*/
dest_add = rline - br;
if (dest_add + er > window->file_info->length) {
dest_add = dest_add - (window->file_info->length - er);
for (; dest_add > 0; dest_add--) {
p = addltop( -1, dest_file->end_text );
pad_dest_line( window, dest_file, p );
}
padded_file = TRUE;
dup_window_info( &s_w, source_window );
dup_window_info( &d_w, window );
}
/*
* move source and dest pointers to the end of the OVERLAY
*/
for (li=er-br; li > 0; li--) {
dest = find_next( dest );
++d_w.rline;
source = find_next( source );
++s_w.rline;
}
/*
* work backwards so the overlapped OVERLAY block don't use
* overlayed text to fill the block.
*/
source = cpb( source );
dest = cpb( dest );
for (li=er; li>=br; li--, s_w.rline--, d_w.rline--) {
lens = linelen( source );
lend = linelen( dest );
if (lens != 0 || lend != 0) {
d_w.cursor = dest;
load_box_buff( block_buff, cpf( source ), bc, ec );
if (lend < (rcol+1))
prepare_block( &d_w, cpf( dest ), lend, rcol );
copy_buff_2file( &d_w, block_buff, cpf( dest ), rcol, block_len,
OVERLAY );
}
source = find_prev( source );
dest = find_prev( dest );
}
} else {
for (li=br; li<=er; li++, s_w.rline++, d_w.rline++) {
lens = linelen( source );
lend = linelen( dest );
if (action == FILL || action == NUMBER) {
s_w.cursor = source;
add = 0;
if (lens < (rcol+1))
add = prepare_block( &s_w, source, lens, rcol );
if (action == NUMBER) {
number_block_buff( block_buff, block_len, block_num, block_just );
block_num += block_inc;
}
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.
*/
} 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_box_buff( block_buff, source, xbc, xec );
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)) {
if (same && action == MOVE)
lens = linelen( source );
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;
if (lens <= (ec + block_len + 1))
add = lens - xbc;
}
}
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 && action != NUMBER) {
p = find_next( dest );
if (p != NULL && *p != CONTROL_Z)
dest = p;
else {
padded_file = TRUE;
p = addltop( -1, dest_file->end_text );
pad_dest_line( window, dest_file, p );
dest = find_next( dest );
if (!source_first)
++source;
}
}
}
}
if (padded_file) {
w = g_status.window_list;
while (w != NULL) {
if (w->file_info == dest_file && w->visible )
show_size( w );
w = w->next;
}
}
}
dest_file->modified = TRUE;
dest_file->dirty = GLOBAL;
if (action == MOVE || action == DELETE || action == FILL || action==NUMBER) {
source_file->modified = TRUE;
source_file->dirty = GLOBAL;
}
/*
* unless we are doing a KOPY, FILL, NUMBER, 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 && action != NUMBER)
unmark_block( window );
show_avail_mem( );
g_status.copied = FALSE;
}
/*
* Name: load_box_buff
* Purpose: copy the contents of a BOX to a 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.
* Notes: For BOX blocks, 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_box_buff( char *block_buff, text_ptr source, int bc, int ec )
{
int len, pad, avlen;
register int i;
register char *bb;
bb = block_buff;
len = linelen( source );
/*
* 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--)
*bb++ = ' ';
} else {
/*
* block ends past eol - fill with pad
*/
pad = (ec + 1) - len;
avlen = len - bc;
source = source + bc;
for (i=avlen; i>0; i--)
*bb++ = *source++;
for (i=pad; i>0; i--)
*bb++ = ' ';
}
} else {
/*
* block is within line - copy block to buffer
*/
avlen = (ec + 1) - bc;
source = source + bc;
for (i=avlen; i>0; i--)
*bb++ = *source++;
}
*bb++ = CONTROL_Z;
*bb = '\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( WINDOW *window, char *block_buff, text_ptr dest,
int rcol, int block_len, int action )
{
register 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 || action == NUMBER) {
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: number_block_buff
* Purpose: put a number into the block buffer
* Date: June 5, 1991
* Passed: block_buff: local buffer for moves
* block_len: number of columns in block
* block_num: long number to fill block
* just: LEFT or RIGHT justified?
* Notes: Fill block_buffer for block_len characters with number.
* This function is used only for BOX blocks.
*/
void number_block_buff( char *block_buff, int block_len, long block_num,
int just )
{
int len; /* length of number buffer */
int i;
char temp[MAX_COLS]; /* buffer for long number to ascii conversion */
block_fill( block_buff, ' ', block_len );
len = strlen( ltoa( block_num, temp, 10 ) );
if (just == RIGHT) {
block_len--;
len--;
for (;block_len >= 0 && len >= 0; block_len--, len--)
block_buff[block_len] = temp[len];
} else {
for (i=0; block_len > 0 && i < len; block_len--, i++)
block_buff[i] = temp[i];
}
}
/*
* 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 *df, 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;
register file_infos *dest_file;
dest_file = df;
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 WINDOW *window;
register file_infos *file;
text_ptr p;
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 );
window->cursor = p != NULL ? p : file->start_text;
window->rline = file->length;
test_line = cur_line - file->length;
if (test_line<(long)(window->cline-(window->top_line+window->ruler-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+window->ruler-1)))
window->cline = (int)window->rline + window->top_line+window->ruler-1;
if (window->cline < window->top_line + window->ruler)
window->cline = window->top_line + window->ruler;
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( WINDOW *s_w, text_ptr source, int bc, int add,
int prompt_line )
{
char *s;
int number;
number = linelen( source ) - bc + 2;
copy_line( source, prompt_line );
s = g_status.line_buff + bc + add;
memmove( s - add, 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. We don't
* need to keep up with the block text pointers while doing normal
* editing; however, we need to refresh them before doing block stuff.
*/
void check_block( void )
{
register file_infos *file;
WINDOW 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.
*/
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 LINE block somewhere in the file, set block_end to first
* line past end of marked block.
*/
fp->block_end = fp->block_type == LINE ? next + end_column : next;
} else {
/*
* last line in marked block is NULL. if LINE block, set end to
* last character in the file. if STREAM or BOX block, set end to
* start of last line in file. ending row, or er, is then set to
* file length.
*/
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 );
fp->block_end = next != NULL ? next : 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( WINDOW *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
*/
rc = hw_fattrib( g_status.rw_name );
if (rc == OK) {
set_prompt( "File exists. Overwrite or Append? (o/a): ",
prompt_line );
switch (get_oa( )) {
case A_OVERWRITE :
change_mode( 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 if (rc != ERROR) {
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
* Notes: With the added Critical Error Handler routine, let's fflush
* the print buffer first.
*/
void block_print( WINDOW *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;
char *p;
int len;
int bc, ec, last_c;
unsigned long lbegin, 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;
}
fflush( stdprn );
if (ceh.flag == ERROR)
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;
l = file->length;
} 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;
l = file->block_er + 1l - file->block_br;
} else
col = AbortCommand;
}
if (block_type == LINE) {
block_end = cpb( block_end );
block_end = find_prev( block_end );
}
if (col != AbortCommand) {
eol_clear( 0, prompt_line, color );
s_output( "Printing line of Press ESC to cancel.",
prompt_line, 0, color );
ltoa( l, answer, 10 );
s_output( answer, prompt_line, 25, color );
xygoto( 14, prompt_line );
block_start = cpf( block_start );
if (block_type == BOX || block_type == STREAM) {
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++) {
ltoa( l, answer, 10 );
s_output( answer, prompt_line, 14, color );
g_status.copied = FALSE;
if (block_type == BOX) {
load_box_buff( p, block_start, bc, ec );
*(p+last_c) = '\n';
*(p+last_c+1) = CONTROL_Z;
} else if (block_type == STREAM && l == 1) {
len = linelen( block_start );
lbegin = ptoul( block_start );
block_start += bc < len ? bc : len;
copy_line( block_start, prompt_line );
if (lbegin == lend) {
if (len > ec) {
*(p+last_c) = '\n';
*(p+last_c+1) = CONTROL_Z;
}
}
} else if (block_type == STREAM && ptoul( block_start )==lend) {
copy_line( block_start, prompt_line );
if (linelen( block_start ) > ec) {
*(p+ec+1) = '\n';
*(p+ec+2) = CONTROL_Z;
}
} else
copy_line( block_start, prompt_line );
len = find_CONTROL_Z( p );
if (fwrite( p, sizeof( char ), len, stdprn ) < (unsigned)len ||
ceh.flag == ERROR)
col = ERROR;
if (col != ERROR) {
fputc( '\r', stdprn );
if (ceh.flag == ERROR)
col = ERROR;
}
block_start = find_next( block_start );
if (block_start == NULL)
block_start = block_end + 1;
if (col == OK && _bios_keybrd( mode.enh_kbd ? 0x11 : 0x01 )) {
col = getkey( );
col = col == ESC ? AbortCommand : getfunc( col );
if (col != AbortCommand)
col = OK;
}
}
g_status.copied = FALSE;
if (ceh.flag != ERROR)
fflush( stdprn );
}
}
g_status.copied = FALSE;
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( WINDOW *window, int *c )
{
char answer[MAX_COLS];
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: get_block_numbers
* Purpose: get the starting number and increment
* Date: June 5, 1991
* Passed: window: information required to access current window
* block_num: address of number to start numbering
* block_inc: address of number to add to block_num
* just: left or right justify numbers in block?
*/
int get_block_numbers( WINDOW *window, long *block_num, long *block_inc,
int *just )
{
char answer[MAX_COLS];
int prompt_line;
register int rc;
char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
register int col;
prompt_line = window->bottom_line;
/*
* don't assume anything on starting number - start w/ null string.
*/
answer[0] = '\0';
rc = get_name( "Enter starting number: ", prompt_line, answer,
g_display.message_color );
if (answer[0] == '\0')
rc = ERROR;
if (rc != ERROR) {
*block_num = atol( answer );
/*
* assume increment is 1
*/
answer[0] = '1';
answer[1] = '\0';
rc = get_name( "Enter increment: ", prompt_line, answer,
g_display.message_color );
if (answer[0] == '\0')
rc = ERROR;
if (rc != ERROR) {
*block_inc = atol( answer );
/*
* now, get left or right justification. save contents of screen
* in a buffer, then write contents of buffer back to screen when
* we get through w/ justification.
*/
save_screen_line( 0, prompt_line, line_buff );
strcpy( answer, "Left or Right justify numbers in block? (l/r): " );
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 );
rc = get_lr( );
if (rc != ERROR) {
*just = rc;
rc = OK;
}
restore_screen_line( 0, prompt_line, line_buff );
}
}
/*
* if everything is everything then return code = OK.
*/
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( WINDOW *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;
WINDOW *sw, s_w;
long er;
int i;
char *b, *d, *lb;
/*
* make sure block is marked OK and that this is a LINE block
*/
prompt_line = window->bottom_line;
un_copy_line( window->cursor, window, TRUE );
check_block( );
if (g_status.marked == TRUE) {
file = g_status.marked_file;
if (file->block_type != LINE) {
error( WARNING, prompt_line,
"can only expand tabs in line blocks" );
return;
}
/*
* set the command to word wrap so the un_copy_line function will
* not display the lines while expanding.
*/
g_status.command = WordWrap;
/*
* initialize everything
*/
dirty = FALSE;
tab_size = mode.tab_size;
sw = g_status.window_list;
for (; ptoul( sw->file_info ) != ptoul( file );)
sw = sw->next;
dup_window_info( &s_w, sw );
p = cpf( file->block_start );
er = file->block_er;
lb = g_status.line_buff;
s_w.rline = file->block_br;
for (; s_w.rline<=er; s_w.rline++) {
/*
* use the line buffer to expand LINE blocks.
*/
tab = FALSE;
len = linelen( p );
net_change = 0;
g_status.copied = FALSE;
copy_line( p, prompt_line );
for (b=lb, i=1; *b != CONTROL_Z; b++) {
/*
* each line in the LINE block is copied to the g_status.line_buff.
* look at the text in the buffer and expand tabs.
*/
if (*b == '\t') {
tab = TRUE;
spaces = i % tab_size;
if (spaces)
spaces = tab_size - spaces;
if (spaces) {
d = b + spaces;
memmove( d, b, linelen( b )+2 );
}
memset( b, ' ', spaces+1 );
net_change += spaces;
i += spaces + 1;
b += spaces;
} else
i++;
}
/*
* if any tabs were found, write g_status.line_buff to file.
*/
if (tab) {
un_copy_line( p, &s_w, TRUE );
dirty = TRUE;
}
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( );
file->dirty = GLOBAL;
}
}
}
/*
* Name: block_trim_trailing
* Purpose: Trim trailing space in a LINE block.
* Date: June 5, 1991
* Passed: window: pointer to current window
* Notes: Use copy_line and un_copy_line to do the work.
*/
void block_trim_trailing( WINDOW *window )
{
int prompt_line;
text_ptr p; /* pointer to block line */
file_infos *file;
WINDOW *sw, s_w;
long er;
int trailing; /* save trailing setting */
/*
* make sure block is marked OK and that this is a LINE block
*/
prompt_line = window->bottom_line;
un_copy_line( window->cursor, window, TRUE );
check_block( );
if (g_status.marked == TRUE) {
trailing = mode.trailing;
mode.trailing = TRUE;
file = g_status.marked_file;
if (file->block_type != LINE) {
error( WARNING, prompt_line,
"can only trim trailing space in line blocks" );
return;
}
/*
* set the command to word wrap so the un_copy_line function will
* not display the lines while trimming.
*/
g_status.command = WordWrap;
/*
* initialize everything
*/
sw = g_status.window_list;
for (; ptoul( sw->file_info ) != ptoul( file );)
sw = sw->next;
dup_window_info( &s_w, sw );
p = cpf( file->block_start );
er = file->block_er;
s_w.rline = file->block_br;
for (; s_w.rline<=er; s_w.rline++) {
/*
* use the line buffer to trim space.
*/
copy_line( p, prompt_line );
un_copy_line( p, &s_w, TRUE );
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;
file->dirty = GLOBAL;
mode.trailing = trailing;
}
}
/*
* Name: block_convert_case
* Purpose: convert characters to lower case, upper case, or strip hi bits
* Date: June 5, 1991
* Passed: window: pointer to current window
*/
void block_convert_case( WINDOW *window )
{
int len;
int block_type;
text_ptr begin;
text_ptr end; /* pointer to block line */
register file_infos *file;
unsigned long number;
unsigned long er;
unsigned int count;
int bc, ec;
int block_len;
void (*char_func)( text_ptr, unsigned int );
/*
* make sure block is marked OK
*/
un_copy_line( window->cursor, window, TRUE );
check_block( );
if (g_status.marked == TRUE) {
/*
* set char_func() to the required block function in tdeasm.c
*/
switch (g_status.command) {
case BlockUpperCase :
char_func = upper_asm;
break;
case BlockLowerCase :
char_func = lower_asm;
break;
case BlockStripHiBit :
char_func = strip_asm;
break;
}
file = g_status.marked_file;
block_type = file->block_type;
bc = file->block_bc;
ec = file->block_ec;
begin = cpf( file->block_start );
end = cpf( file->block_end );
/*
* if this is a LINE or STREAM block, process characters in
* chunks of 0xf000.
*/
if (block_type == LINE || block_type == STREAM) {
if (block_type == STREAM) {
len = linelen( begin );
begin += len < bc ? len : bc;
len = linelen( end );
end += len < ec ? len : ec + 1;
}
number = ptoul( end ) - ptoul( begin );
count = 0xf000;
begin = nptos( begin );
while (number > count) {
(*char_func)( begin, count );
number -= count;
begin = nptos( begin + count );
}
/*
* now less than 0xf000 is left, so finish off the conversion
*/
(*char_func)( begin, (unsigned)number );
/*
* For BOX blocks, process characters by lines
*/
} else {
begin = cpf( begin );
er = file->block_er;
block_len = ec + 1 - bc;
for (number=file->block_br; number <= er; number++) {
len = linelen( begin );
if (len > bc) {
count = len >= ec ? block_len : len - bc;
(*char_func)( begin+bc, count );
}
begin = find_next( begin );
}
}
/*
* 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;
file->dirty = GLOBAL;
file->modified = TRUE;
}
}