📄 findrep.c
字号:
#include "tdestr.h"
#include "common.h"
#include "tdefunc.h"
#include "define.h"
/*
* Name: get_replacement_flags
* Purpose: To input find and replace flags.
* Date: June 5, 1991
* Passed: line: prompt line
* Returns: OK if flags were entered, ERROR if user wanted to abort
*/
int get_replacement_flags( int line )
{
char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
register int c;
int func;
int rc;
save_screen_line( 0, line, line_buff );
eol_clear( 0, line, g_display.text_color );
/*
* options: prompt or no prompt (p/n)?
*/
s_output( find1, line, 0, g_display.message_color );
xygoto( strlen( find1 ) + 2, line );
do {
c = getkey( );
func = getfunc( c );
} while (c != 'P' && c != 'p' && c != 'N' && c != 'n' &&
c != RTURN && c != ESC && func != AbortCommand);
restore_screen_line( 0, line, line_buff );
switch (c) {
case 'P' :
case 'p' :
case RTURN :
g_status.replace_flag = PROMPT;
rc = OK;
break;
case 'N' :
case 'n' :
g_status.replace_flag = NOPROMPT;
rc = OK;
break;
default :
rc = ERROR;
}
bm.search_defined = rc;
return( rc );
}
/*
* Name: ask_replace
* Purpose: Ask user if he wants to (r)place, (s)kip, or (e)xit.
* Date: June 5, 1991
* Returns: TRUE if user wants to replace, ERROR otherwise.
* Passed: window: pointer to current window
* finished: TRUE if user pressed ESC or (e)xit.
*/
int ask_replace( WINDOW *window, int *finished )
{
char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
register int c;
int func;
int prompt_line;
int rc;
prompt_line = window->cline - 1;
c = 39 - (strlen( find2 ) >> 1);
save_screen_line( 0, prompt_line, line_buff );
/*
* replace skip exit (r/s/e)?
*/
s_output( find2, prompt_line, c, g_display.message_color );
do {
c = getkey( );
func = getfunc( c );
} while (c != 'R' && c != 'r' && c != 'S' && c != 's' && c != 'E' && c != 'e'
&& c != ESC && func != AbortCommand);
restore_screen_line( 0, prompt_line, line_buff );
switch (c) {
case 'R' :
case 'r' :
rc = OK;
break;
case 'E' :
case 'e' :
*finished = TRUE;
case 'S' :
case 's' :
rc = ERROR;
break;
default :
*finished = TRUE;
rc = ERROR;
break;
}
return( rc );
}
/*
* Name: ask_wrap_replace
* Purpose: After a wrap, ask user if he wants to (q)uit or (c)ontine.
* Date: June 5, 1991
* Returns: TRUE if user wants to continue, ERROR otherwise.
* Passed: window: pointer to current window
* finished: TRUE if user pressed ESC or (q)uit.
*/
int ask_wrap_replace( WINDOW *window, int *finished )
{
char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
register int c;
int func;
int prompt_line;
int rc;
prompt_line = window->bottom_line;
save_screen_line( 0, prompt_line, line_buff );
/*
* search has wrapped. continue or quit (c/q)?
*/
set_prompt( find3, prompt_line );
do {
c = getkey( );
func = getfunc( c );
} while (c != 'Q' && c != 'q' && c != 'C' && c != 'c' &&
c != ESC && func != AbortCommand);
restore_screen_line( 0, prompt_line, line_buff );
switch (c) {
case 'C' :
case 'c' :
rc = OK;
break;
case 'Q' :
case 'q' :
default :
*finished = TRUE;
rc = ERROR;
break;
}
return( rc );
}
/*
* Name: do_replace
* Purpose: To replace text once match has been found.
* Date: June 5, 1991
* Passed: window: pointer to current window
* direction: direction of search
*/
void do_replace( WINDOW *window, int direction )
{
int old_len; /* length of original text */
int new_len; /* length of replacement text */
int rcol;
register int net_change;
char *source; /* source of block move */
char *dest; /* destination of block move */
old_len = strlen( g_status.pattern );
new_len = strlen( g_status.subst );
net_change = new_len - old_len;
rcol = window->rcol;
/*
* move the text to either make room for the extra replacement text
* or to close up the gap left
*/
g_status.copied = FALSE;
copy_line( window->ll );
detab_linebuff( );
if (net_change != 0) {
assert( rcol + old_len >= 0);
assert( net_change <= rcol + old_len );
source = g_status.line_buff + rcol + old_len;
dest = source + net_change;
assert( g_status.line_buff_len - rcol - old_len >= 0 );
assert( g_status.line_buff_len - rcol - old_len < MAX_LINE_LENGTH );
memmove( dest, source, g_status.line_buff_len - rcol - old_len );
g_status.line_buff_len += net_change;
}
/*
* insert the replacement text
*/
assert( rcol >= 0 );
assert( rcol < MAX_LINE_LENGTH );
assert( g_status.line_buff_len >= 0 );
assert( g_status.line_buff_len >= rcol );
for (dest=g_status.line_buff+rcol, source=g_status.subst; *source;)
*dest++ = *source++;
entab_linebuff( );
window->file_info->modified = TRUE;
un_copy_line( window->ll, window, TRUE );
window->ll->dirty = TRUE;
if (direction == FORWARD)
window->rcol += (new_len - 1);
assert( window->rcol >= 0 );
show_avail_mem( );
}
/*
* 作用: 建立并且执行查找操作
* 参数: window: 当前窗口的指针
*/
int find_string( WINDOW *window )
{
int direction;
int new_string;
char pattern[MAX_COLS]; /* 想要查找的文本 */
long found_line;
long bin_offset;
line_list_ptr ll;
register WINDOW *win; /* 把文件指针放到一个寄存器中 */
int rc;
int old_rcol;
int rcol;
switch (g_status.command) {
case FindForward :
direction = FORWARD;
new_string = TRUE;
break;
case FindBackward :
direction = BACKWARD;
new_string = TRUE;
break;
case RepeatFindForward1 :
case RepeatFindForward2 :
direction = FORWARD;
new_string = bm.search_defined != OK ? TRUE : FALSE;
break;
case RepeatFindBackward1 :
case RepeatFindBackward2 :
direction = BACKWARD;
new_string = bm.search_defined != OK ? TRUE : FALSE;
break;
default :
direction = 0;
new_string = 0;
assert( FALSE );
break;
}
win = window;
entab_linebuff( );
if (un_copy_line( win->ll, win, TRUE ) == ERROR)
return( ERROR );
/*
* 得到搜索文本,上次的搜索文本做为缺省值
*/
if (new_string == TRUE) {
*pattern = '\0';
if (bm.search_defined == OK) {
assert( strlen( (char *)bm.pattern ) < MAX_COLS );
strcpy( pattern, (char *)bm.pattern );
}
/*
* 查找
*/
if (get_name( find4, win->bottom_line, pattern,
g_display.message_color ) != OK || *pattern == '\0')
return( ERROR );
bm.search_defined = OK;
assert( strlen( pattern ) < MAX_COLS );
strcpy( (char *)bm.pattern, pattern );
build_boyer_array( );
}
rc = OK;
if (bm.search_defined == OK) {
old_rcol = win->rcol;
if (mode.inflate_tabs)
win->rcol = entab_adjust_rcol( win->ll->line, win->ll->len, win->rcol);
update_line( win );
show_search_message( SEARCHING, g_display.diag_color );
bin_offset = win->bin_offset;
if (direction == FORWARD) {
if ((ll = forward_boyer_moore_search( win, &found_line, &rcol )) != NULL) {
if (g_status.wrapped && g_status.macro_executing)
rc = ask_wrap_replace( win, &new_string );
if (rc == OK)
find_adjust( win, ll, found_line, rcol );
else
win->bin_offset = bin_offset;
}
} else {
if ((ll = backward_boyer_moore_search( win, &found_line, &rcol )) != NULL) {
if (g_status.wrapped && g_status.macro_executing)
rc = ask_wrap_replace( win, &new_string );
if (rc == OK)
find_adjust( win, ll, found_line, rcol );
else
win->bin_offset = bin_offset;
}
}
if (g_status.wrapped)
show_search_message( WRAPPED, g_display.diag_color );
else
show_search_message( CLR_SEARCH, g_display.mode_color );
if (ll == NULL) {
/*
* 没有找到
*/
if (mode.inflate_tabs)
win->rcol = old_rcol;
combine_strings( pattern, find5a, (char *)bm.pattern, find5b );
error( WARNING, win->bottom_line, pattern );
rc = ERROR;
}
show_curl_line( win );
make_ruler( win );
show_ruler( win );
} else {
/*
* 没有定义查找模式
*/
error( WARNING, win->bottom_line, find6 );
rc = ERROR;
}
return( rc );
}
/*
* Name: build_boyer_array
* Purpose: To set up the boyer array for forward and backward searches.
* Date: June 5, 1991
* Notes: Set up one array for forward searches and another for backward
* searches. If user decides to ignore case then fill in array
* with reverse case characters so both upper and lower case
* characters are defined.
*/
void build_boyer_array( void )
{
/*
* set up for forward search
*/
if (g_status.command == DefineGrep || g_status.command == RepeatGrep) {
assert( strlen( (char *)sas_bm.pattern ) + 1 < MAX_COLS );
memcpy( bm.pattern, sas_bm.pattern, strlen( (char *)sas_bm.pattern ) +1 );
bm.search_defined = OK;
}
if (bm.search_defined == OK) {
build_forward_skip( &bm );
bm.forward_md2 = calculate_forward_md2( (char *)bm.pattern,
bm.pattern_length );
/*
* set up for backward search
*/
build_backward_skip( &bm );
bm.backward_md2 = calculate_backward_md2( (char *)bm.pattern,
bm.pattern_length );
}
/*
* build an array for search and seize.
*/
if (sas_bm.search_defined == OK) {
build_forward_skip( &sas_bm );
sas_bm.forward_md2 = calculate_forward_md2( (char *)sas_bm.pattern,
sas_bm.pattern_length );
/*
* set up for backward search
*/
build_backward_skip( &sas_bm );
sas_bm.backward_md2 = calculate_backward_md2( (char *)sas_bm.pattern,
sas_bm.pattern_length );
}
}
/*
* Name: build_forward_skip
* Purpose: build Boyer-Moore forward skip array
* Date: October 31, 1992
* Passed: bmp: pointer to Boyer-Moore structure
* Notes: build standard Boyer-Moore forward skip array.
* Thanks to Tom Waters, twaters@relay.nswc.navy.mil, for finding a
* bug in TDE 1.3 when building the ignore skip index array.
*/
void build_forward_skip( boyer_moore_type *bmp )
{
register unsigned char *p;
register int i;
assert( strlen( (char *)bmp->pattern ) < MAX_COLS );
i = bmp->pattern_length = (int)strlen( (char *)bmp->pattern );
/*
* set skip index of all characters to length of string
*/
memset( bmp->skip_forward, i, 256 );
i--;
/*
* for each character in string, set the skip index
*/
for (p=bmp->pattern; i>=0; i--, p++) {
assert( (char)i < bmp->skip_forward[*p] );
bmp->skip_forward[*p] = (char)i;
if (mode.search_case == IGNORE) {
if (*p >= 'A' && *p <= 'Z') {
assert( (char)i < bmp->skip_forward[*p+32] );
bmp->skip_forward[*p+32] = (char)i;
} else if (*p >= 'a' && *p <= 'z') {
assert( (char)i < bmp->skip_forward[*p-32] );
bmp->skip_forward[*p-32] = (char)i;
}
}
}
}
/*
* Name: build_backward_skip
* Purpose: build Boyer-Moore backward skip array
* Date: October 31, 1992
* Passed: bmp: pointer to Boyer-Moore structure
* Notes: build standard Boyer-Moore backward skip array.
* Thanks to Tom Waters, twaters@relay.nswc.navy.mil, for finding a
* bug in TDE 1.3 when building the ignore skip index array.
*/
void build_backward_skip( boyer_moore_type *bmp )
{
register unsigned char *p;
register int i;
i = -bmp->pattern_length;
memset( bmp->skip_backward, i, 256 );
i++;
for (p=bmp->pattern + bmp->pattern_length - 1; i<=0; i++, p--) {
assert( (char)i > bmp->skip_backward[*p] );
bmp->skip_backward[*p] = (char)i;
if (mode.search_case == IGNORE) {
if (*p >= 'A' && *p <= 'Z') {
assert( (char)i > bmp->skip_backward[*p+32] );
bmp->skip_backward[*p+32] = (char)i;
} else if (*p >= 'a' && *p <= 'z') {
assert( (char)i > bmp->skip_backward[*p-32] );
bmp->skip_backward[*p-32] = (char)i;
}
}
}
}
/*
* Name: calculate_forward_md2
* Purpose: Calculate mini delta2 for forward searches
* Date: October 31, 1992
* Passed: p: pointer to pattern
* len: length of pattern
* Notes: Hume and Sunday (see above) demonstrate in their paper that
* using a simple shift function on mismatches with BM
* gives one of the fastest run times for general text searching.
* mini delta2 is, from the end of the string, the first leftmost
* occurrence of the rightmost character. mini delta2 is 1 in
* the worst case. in previous versions of TDE, the shift function
* was hard-coded as 1 -- the worst case. typically, mini delta2
* will be the length of the search pattern.
*/
int calculate_forward_md2( char *p, int len )
{
int last_c;
register int i;
register int md2;
md2 = 1;
i = len - 1;
last_c = p[i];
if (mode.search_case == IGNORE) {
last_c = tolower( last_c );
for (i--; i >= 0 && last_c != tolower( p[i] ); i--)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -