📄 block.c
字号:
* operations. All require finding the beginning and ending marks.
* 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.
* This is probably the most complicated routine in the editor. It
* is not easy to understand.
*/
int move_copy_delete_overlay_block( WINDOW *window )
{
int action;
WINDOW *source_window; /* source window for block moves */
line_list_ptr source; /* source for block moves */
line_list_ptr dest; /* destination for block moves */
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 */
line_list_ptr block_start; /* start of block in file */
line_list_ptr block_end; /* end of block in file - not same for LINE or BOX */
int prompt_line;
int same; /* are dest and source files the same file? */
int source_first; /* is source file lower in memory than dest */
file_infos *source_file;
file_infos *dest_file;
int rcol, bc, ec; /* temporary column variables */
long rline; /* temporary real line variable */
long br, er; /* temporary line variables */
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? */
int block_type;
int fill_char;
int rc;
/*
* initialize block variables
*/
entab_linebuff( );
rc = un_copy_line( window->ll, window, TRUE );
if (g_status.marked == FALSE || rc == ERROR)
return( ERROR );
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;
case SwapBlock :
action = SWAP;
break;
default :
return( ERROR );
}
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( ERROR );
block_start = source_file->block_start;
block_end = source_file->block_end;
if (block_start == NULL || block_end == NULL)
return( ERROR );
block_type = source_file->block_type;
if (block_type != LINE && block_type != STREAM && block_type != BOX)
return( ERROR );
dest = window->ll;
rline = window->rline;
if (dest->len == EOF)
return( ERROR );
rc = OK;
/*
* 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;
/*
* 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.
*/
source_first = same = FALSE;
if (action == FILL) {
if (block_type == BOX) {
if (get_block_fill_char( window, &fill_char ) == ERROR)
return( ERROR );
dest = block_start;
same = TRUE;
} else {
/*
* can only fill box blocks.
*/
error( WARNING, prompt_line, block2 );
return( ERROR );
}
}
block_inc = 1;
if (action == NUMBER) {
if (block_type == BOX) {
if (get_block_numbers( window, &block_num, &block_inc, &block_just )
== ERROR)
return( ERROR );
dest = block_start;
same = TRUE;
} else {
/*
* can only number box blocks.
*/
error( WARNING, prompt_line, block3a );
return( ERROR );
}
}
if (action == SWAP) {
if (block_type != BOX) {
/*
* can only swap box blocks.
*/
error( WARNING, prompt_line, block3b );
return( ERROR );
}
}
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( ERROR );
} 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 = block_end;
/*
* a block moved to within the block itself has no effect
*/
else if (action == MOVE)
return( ERROR );
} 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) ||
(br == er && rcol >= bc && rcol <= ec) ||
(br != 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 = block_end;
rcol = ec + 1;
rline = er;
} else if (action == MOVE)
return( ERROR );
}
}
}
}
}
if (br < rline)
source_first = TRUE;
/*
* 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
*/
block_len = (ec+1) - bc;
if (block_type == BOX) {
if (action != DELETE && action != FILL) {
if (rcol + block_len > MAX_LINE_LENGTH) {
/*
* line too long
*/
error( WARNING, prompt_line, ltol );
return( ERROR );
}
}
} else if (block_type == LINE) {
block_len = 0;
if (action == OVERLAY) {
/*
* can only overlay box blocks
*/
error( WARNING, prompt_line, block5 );
return( ERROR );
}
} else if (block_type == STREAM) {
if (action == OVERLAY) {
/*
* can only overlay box blocks
*/
error( WARNING, prompt_line, block5 );
return( ERROR );
}
lend = block_end->len;
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) {
/*
* line too long
*/
error( WARNING, prompt_line, ltol );
return( ERROR );
}
}
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 = block_start->len;
/*
* if we had to move the destination of the STREAM COPY or KOPY
* to the end of the STREAM block, then dest and window->ll->line
* 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 (dest->line == window->ll->line)
add = dest->len;
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) {
/*
* line too long
*/
error( WARNING, prompt_line, ltol );
return( ERROR );
}
/*
* 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) {
/*
* line too long
*/
error( WARNING, prompt_line, ltol );
return( ERROR );
}
}
if (ptoul( block_start ) == ptoul( block_end )) {
block_type = BOX;
block_len = (ec+1) - bc;
}
}
if (mode.do_backups == TRUE) {
switch (action) {
case MOVE :
case DELETE :
case COPY :
case KOPY :
case SWAP :
window->file_info->modified = TRUE;
rc = backup_file( window );
break;
}
switch (action) {
case MOVE :
case DELETE :
case FILL :
case NUMBER :
case SWAP :
source_window->file_info->modified = TRUE;
if (rc != ERROR)
rc = backup_file( source_window );
break;
}
}
source = block_start;
assert( block_start != NULL );
assert( block_start->len != EOF );
assert( block_end != NULL );
assert( block_end->len != EOF );
if (block_type == LINE)
do_line_block( window, source_window, action,
source_file, dest_file, block_start, block_end,
source, dest, br, er, &rc );
else if (block_type == STREAM)
do_stream_block( window, source_window, action,
source_file, dest_file, block_start, block_end,
source, dest, rline, br, er, bc, ec, rcol, &rc );
else
do_box_block( window, source_window, action,
source_file, dest_file, source, dest, br, er,
block_inc, rline, block_num, block_just, fill_char,
same, block_len, bc, ec, rcol, &rc );
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 && rc != ERROR) {
number = (er+1) - br;
source_file->block_br += number;
source_file->block_er += number;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -