home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Black Box 4
/
BlackBox.cdr
/
editors
/
tde150.arj
/
FINDREP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-01
|
33KB
|
1,090 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 - find/replace module
* Purpose: This file contains the functions relating to finding text
* and replacing text.
* It also contains the code for moving the cursor to various
* other positions in the file.
* File: findrep.c
* Author: Douglas Thomson
* System: this file is intended to be system-independent
* Date: October 1, 1989
*/
/********************* end of original comments ********************/
/*
* The search and replace routines have been EXTENSIVELY rewritten. The
* "brute force" search algorithm has been replaced by the Boyer-Moore
* string search algorithm. This search algorithm really speeds up search
* and replace operations.
*
* If I am not mistook, seems like Boyer developed the array and Moore
* developed the search. For those interested, the algorithm is published in:
*
* R. S. Boyer and J. S. Moore, "A fast string searching algorithm."
* _Communications of the ACM_ 20 (No. 10): 762-772, 1977.
*
* I am not very fond of Wordstar/TURBO x style search and replace prompting.
* Once the search pattern has been defined, one only needs to press a key
* to search forwards or backwards. The forward or backward search key may
* be pressed at any time in any file once the pattern has been entered. Also,
* the search case may be toggled at any time in any file once the pattern has
* has been entered.
*
* 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 "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 */
char *find_opt = "Options (P)rompt before replace (N)o prompt: ";
register int c;
int rc, func;
c = strlen( find_opt );
save_screen_line( 0, line, line_buff );
s_output( find_opt, line, 0, g_display.message_color );
eol_clear( c, line, g_display.text_color );
c += 2;
xygoto( c, line );
c = getkey( );
func = getfunc( c );
while (c != 'P' && c != 'p' && c != 'N' && c != 'n' && c != RTURN &&
c != ESC && func != AbortCommand) {
c = getkey( );
func = getfunc( c );
}
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: information allowing access to current window etc
* 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 */
char *ask_opt = "(R)eplace (S)kip (E)xit";
register int c;
int rc, prompt_line, func;
prompt_line = window->cline - 1;
c = 39 - (strlen( ask_opt ) >> 1);
save_screen_line( 0, prompt_line, line_buff );
s_output( ask_opt, prompt_line, c, g_display.message_color );
c = getkey( );
func = getfunc( c );
while (c != 'R' && c != 'r' && c != 'S' && c != 's' && c != 'E' && c != 'e'
&& c != ESC && func != AbortCommand) {
c = getkey( );
func = getfunc( c );
}
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)place, (c)ontine.
* Date: June 5, 1991
* Returns: TRUE if user wants to continue, ERROR otherwise.
* Passed: window: information allowing access to current window etc
* 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 */
char *ask_opt = "Search has wrapped. (C)ontinue or (Q)uit replacing? ";
register int c;
int rc, prompt_line, func;
prompt_line = window->bottom_line;
save_screen_line( 0, prompt_line, line_buff );
set_prompt( ask_opt, prompt_line );
c = getkey( );
func = getfunc( c );
while (c != 'Q' && c != 'q' && c != 'C' && c != 'c' &&
c != ESC && func != AbortCommand) {
c = getkey( );
func = getfunc( c );
}
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: information allowing access to current window etc
* start: location of start of matched text
* direction: direction of search
*/
void do_replace( WINDOW *window, text_ptr start, int direction )
{
int old_len; /* length of original text */
int new_len; /* length of replacement text */
register int net_change;
text_ptr source; /* source of block move */
text_ptr dest; /* destination of block move */
long number; /* number of characters moved */
old_len = strlen( g_status.pattern );
new_len = strlen( g_status.subst );
/*
* move the text to either make room for the extra replacement text
* or to close up the gap left
*/
start = cpf( start );
source = start + old_len;
dest = start + new_len;
number = ptoul( g_status.end_mem ) - ptoul( source );
hw_move( dest, source, number );
/*
* insert the replacement text
*/
for (dest=start, source=g_status.subst; *source;)
*dest++ = *source++;
net_change = new_len - old_len;
adjust_start_end( window->file_info, net_change );
if (direction == FORWARD && net_change > 0)
window->rcol += net_change;
addorsub_all_cursors( window, net_change );
g_status.end_mem = addltop( (long)net_change, g_status.end_mem );
show_avail_mem( );
}
/*
* Name: find_string
* Purpose: To set up and perform a find operation.
* Date: June 5, 1991
* Passed: window: information allowing access to current window etc
* Notes: Keep the search string and boyer-moore stuff until changed.
*/
void find_string( WINDOW *window )
{
int direction;
int new_string;
char pattern[MAX_COLS]; /* text to be found */
text_ptr pattern_location;
register WINDOW *win; /* put window pointer in a register */
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 = FALSE;
break;
case RepeatFindBackward1 :
case RepeatFindBackward2 :
direction = BACKWARD;
new_string = FALSE;
break;
}
win = window;
un_copy_line( win->cursor, win, TRUE );
/*
* get search text, using previous as default
*/
if (new_string == TRUE) {
strcpy( pattern, bm.pattern );
if (get_name( "String to find: ", win->bottom_line, pattern,
g_display.message_color ) != OK)
return;
bm.search_defined = OK;
strcpy( bm.pattern, pattern );
build_boyer_array( );
}
if (bm.search_defined == OK) {
update_line( win );
show_search_message( SEARCHING, g_display.diag_color );
if (direction == FORWARD) {
if ((pattern_location = forward_boyer_moore_search( win )) != NULL)
find_adjust( win, pattern_location );
} else {
if ((pattern_location = backward_boyer_moore_search( win )) != NULL)
find_adjust( win, pattern_location );
}
if (g_status.wrapped)
show_search_message( WRAPPED, g_display.diag_color );
else
show_search_message( CLR_SEARCH, g_display.mode_color );
if (pattern_location == NULL) {
combine_strings( pattern, "string \"", bm.pattern, "\" not found " );
error( WARNING, win->bottom_line, pattern );
}
show_curl_line( win );
make_ruler( win );
show_ruler( win );
} else
error( WARNING, win->bottom_line, "find pattern not defined" );
}
/*
* 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 )
{
register int i;
register unsigned char *p;
/*
* set up for forward search
*/
i = bm.pattern_length = strlen( bm.pattern );
/*
* set skip index of all characters to length of string
*/
memset( bm.skip_forward, i, 256 );
i--;
/*
* for each character in string, set the skip index
*/
for (p=bm.pattern; i>=0; i--, p++) {
bm.skip_forward[*p] = (char)i;
if (bm.search_case == IGNORE) {
if (*p >= 'A' && *p <= 'Z')
bm.skip_forward[*p+32] = (char)i;
else if (*p >= 'a' && *p <= 'z')
bm.skip_forward[*p-32] = (char)i;
}
}
/*
* set up for backward search
*/
i = -bm.pattern_length;
memset( bm.skip_backward, i, 256 );
i++;
for (p=bm.pattern+bm.pattern_length-1; i<=0; i++, p--) {
bm.skip_backward[*p] = (char)i;
if (bm.search_case == IGNORE) {
if (*p >= 'A' && *p <= 'Z')
bm.skip_backward[*p+32] = (char)i;
else if (*p >= 'a' && *p <= 'z')
bm.skip_backward[*p-32] = (char)i;
}
}
}
/*
* Name: forward_boyer_moore_search
* Purpose: search forward for pattern using boyer array
* Passed: window: information allowing access to current window
* Returns: position in file if found or NULL if not found
* Date: June 5, 1991
* Notes: Start searching from cursor position to end of file. If we hit
* end of file without a match, start searching from the beginning
* of file to cursor position. (do wrapped searches)
*/
text_ptr forward_boyer_moore_search( WINDOW *window )
{
int i;
register int len;
text_ptr s, start;
long search_length;
register WINDOW *win; /* put window pointer in a register */
/*
* if cursor is beyond end of line then start at end of line
*/
win = window;
start = cpf( win->cursor );
i = win->rcol + 1;
len = linelen( start );
if (i > len) {
i = len;
len = 0;
} else
len = (i-1) + bm.pattern_length > len ? len - i : bm.pattern_length - 3;
/*
* make start of search 1 character greater than current position so
* we don't repeatedly find the pattern at current position.
*/
start += i;
/*
* find out how many character to search. do standard Boyer-Moore search
*/
search_length = (ptoul( win->file_info->end_text ) - 1) - ptoul( start );
if ((s = search_forward( start, search_length )) == NULL) {
/*
* haven't found pattern yet - now search from beginning of file
*/
g_status.wrapped = TRUE;
s = cpf( win->file_info->start_text );
search_length = ptoul( start ) - ptoul( s ) + len;
s = search_forward( s, search_length );
}
return( s );
}
/*
* Name: search_forward
* Purpose: search forward for pattern using boyer array
* Passed: s: text_ptr for search start
* search_length: number of characters to search
* Returns: position in file if found or NULL if not found
* Date: January 8, 1992
* Notes: Start searching from cursor position to end of file.
*/
text_ptr search_forward( text_ptr s, long search_length )
{
register int i;
register int j;
text_ptr p;
text_ptr q;
p = bm.pattern;
j = i = bm.pattern_length - 1;
for (search_length -= i; search_length >= 0; search_length -= i) {
s = s + i;
i = bm.skip_forward[(unsigned char)*s];
if (i == 0) {
q = addltop( 1 - bm.pattern_length, s );
q = cpf( q );
if (bm.search_case == MATCH)
i = _fmemcmp( q, p, bm.pattern_length );
else
i = _fmemicmp( q, p, bm.pattern_length );
if (i == 0)
return( q );
i = 1;
}
if ((j += i) > 10000) {
j = 0;
s = cpf( s );
}
}
return( NULL );
}
/*
* Name: backward_boyer_moore_search
* Purpose: search backward for pattern using boyer array
* Passed: window: information allowing access to current window etc
* Returns: position in file if found or NULL if not found
* Date: June 5, 1991
* Notes: Start searching from cursor position to beginning of file. If we
* hit beginning end of file without a match, start searching from the
* end of file to cursor position. (do wrapped searches)
*/
text_ptr backward_boyer_moore_search( WINDOW *window )
{
int i;
int len;
text_ptr s;
text_ptr start;
text_ptr end;
long search_length;
register WINDOW *win; /* put window pointer in a register */
win = window;
end = cpf( win->cursor );
i = win->rcol - 1;
i += bm.pattern_length - 1;
len = linelen( end );
if (i > len)
i = len;
end += win->rcol < len ? win->rcol + 1 : len;
start = addltop( i, win->cursor );
start = cpb( start );
search_length = ptoul( start ) - ptoul( win->file_info->start_text );
if ((s = search_backward( start, search_length )) == NULL) {
/*
* haven't found pattern yet - now search from end of file
*/
g_status.wrapped = TRUE;
s = addltop( -1, win->file_info->end_text );
s = cpb( s );
search_length = ptoul( s ) - ptoul( end );
s = search_backward( s, search_length );
}
return( s );
}
/*
* Name: search_backward
* Purpose: search backward for pattern using boyer array
* Passed: s: text_ptr for search start
* search_length: number of characters to search
* Returns: position in file if found else return NULL
* Date: January 8, 1992
* Notes: Start searching from cursor position to beginning of file.
*/
text_ptr search_backward( text_ptr s, long search_length )
{
register int i;
register int j;
text_ptr p;
p = bm.pattern;
j = i = -bm.pattern_length + 1;
for (search_length += i; search_length >= 0; search_length += i) {
s = s + i;
i = bm.skip_backward[(unsigned char)*s];
if (i == 0) {
if (bm.search_case == MATCH)
i = _fmemcmp( s, p, bm.pattern_length );
else
i = _fmemicmp( s, p, bm.pattern_length );
if (i == 0)
return( s );
i = -1;
}
if ((j += i) < -10000) {
j = 0;
s = cpb( s );
}
}
return( NULL );
}
/*
* Name: show_search_message
* Purpose: display search status
* Date: January 8, 1992
* Passed: i: index into message array
* color: color to display message
*/
void show_search_message( int i, int color )
{
char *s[] = {
" ",
"wrapped...",
"searching "
};
s_output( s[i], g_display.mode_line, 67, color );
}
/*
* Name: find_adjust
* Purpose: place cursor on screen given a position in file - default cline
* Passed: window: information allowing access to current window etc
* found: position anywhere in file
* Date: June 5, 1991
* Notes: found could be anywhere in file. Find the start of line that
* found is on. Determine if start of line is behind or ahead of
* current line. Once that is done, it is easy to determine if found
* is on screen. Lastly, current cursor position becomes start of
* found line - reposition and display.
*/
void find_adjust( WINDOW *window, text_ptr found )
{
int rcol;
int cmd;
long pattern_line, rline, test_line;
text_ptr p, q;
file_infos *file;
register WINDOW *win; /* put window pointer in a register */
win = window;
file = win->file_info;
/*
* find start of line found is on.
*/
found = cpb( found );
if (*(found - 1) != '\n' && *(found - 1) != CONTROL_Z)
p = find_prev( found );
else
p = found;
/*
* find real column found is on.
*/
rcol = (int)(ptoul( found ) - ptoul( p ));
rline = pattern_line = win->rline;
q = win->cursor = cpf( win->cursor );
/*
* if p, start of found line, is greater than current line, see if
* p is between current line and bottom line on screen.
*/
if (ptoul( q ) < ptoul( p )) {
while (ptoul( q ) != ptoul( p )) {
q = find_next( q );
++pattern_line;
}
test_line = pattern_line - rline;
if ((long)win->cline + test_line <= (long)win->bottom_line)
win->cline += test_line;
else
file->dirty = LOCAL;
/*
* if p, start of found line, is less than current line, see if
* p is between current line and top line on screen.
*/
} else if (ptoul( q ) > ptoul( p )) {
q = cpb( q );
while (ptoul( q ) != ptoul( p )) {
q = find_prev( q );
--pattern_line;
}
test_line = rline - pattern_line;
if ((long)win->cline - test_line > (long)(win->top_line+win->ruler-1))
win->cline -= test_line;
else
file->dirty = LOCAL;
if (pattern_line < (long)(win->cline - (win->top_line+win->ruler-1)))
win->cline = (int)pattern_line + win->top_line+win->ruler - 1;
}
/*
* cursor line becomes found line. check if column is on screen.
*/
win->cursor = p;
win->rline = pattern_line;
if (file->dirty == LOCAL && (win->cline == win->bottom_line ||
win->cline == win->top_line + win->ruler)) {
cmd = g_status.command;
if (cmd == RepeatFindForward1 || cmd == RepeatFindBackward1 ||
cmd == ReplaceForward || cmd == ReplaceBackward) {
g_status.command = CenterLine;
center_window( win );
g_status.command = cmd;
}
}
check_virtual_col( win, rcol, rcol );
}
/*
* Name: replace_string
* Purpose: To set up and perform a replace operation.
* Date: June 5, 1991
* Passed: window: information allowing access to current window etc
*/
void replace_string( WINDOW *window )
{
int direction;
char pattern[MAX_COLS]; /* the old and replacement text */
int net_change;
int sub_len;
int file_changed;
int finished;
int rc;
text_ptr pattern_location;
text_ptr replace_start;
unsigned long rs, pl;
WINDOW wp;
char *snf = "string not found";
register WINDOW *win; /* put window pointer in a register */
win = window;
direction = g_status.command == ReplaceForward ? FORWARD : BACKWARD;
un_copy_line( win->cursor, win, TRUE );
/*
* get the search pattern, using the previous as the default
*/
strcpy( pattern, g_status.pattern );
if (get_name( "String to find: ", win->bottom_line, pattern,
g_display.message_color ) != OK)
return;
strcpy( g_status.pattern, pattern );
/*
* get the replacement text, using the previous as the default
*/
strcpy( pattern, g_status.subst );
if (get_name( "Replacement: ", win->bottom_line, pattern,
g_display.message_color ) != OK)
return;
strcpy( g_status.subst, pattern );
sub_len = strlen( pattern );
strcpy( bm.pattern, g_status.pattern );
net_change = sub_len - strlen( g_status.pattern );
/*
* get the replace flags, Prompt or NoPrompt
*/
if (get_replacement_flags( win->bottom_line ) != OK)
return;
build_boyer_array( );
dup_window_info( &wp, win );
update_line( win );
finished = FALSE;
file_changed = FALSE;
if (direction == FORWARD) {
if ((replace_start = forward_boyer_moore_search( &wp )) != NULL) {
rs = ptoul( replace_start );
replace_and_display( &wp, replace_start, &finished, &file_changed,
direction );
} else {
error( WARNING, win->bottom_line, snf );
finished = TRUE;
}
while (finished == FALSE) {
update_line( &wp );
if ((pattern_location = forward_boyer_moore_search( &wp )) != NULL) {
pl = ptoul( pattern_location );
if (rs == pl)
finished = TRUE;
else {
rc = replace_and_display( &wp, pattern_location, &finished,
&file_changed, direction );
if (rc == OK && rs > pl)
rs += net_change;
}
} else {
error( WARNING, win->bottom_line, snf );
finished = TRUE;
}
}
} else {
if ((replace_start = backward_boyer_moore_search( &wp )) != NULL) {
rs = ptoul( replace_start );
replace_and_display( &wp, replace_start, &finished, &file_changed,
direction );
} else {
error( WARNING, win->bottom_line, snf );
finished = TRUE;
}
while (finished == FALSE) {
update_line( &wp );
if ((pattern_location = backward_boyer_moore_search( &wp )) != NULL) {
pl = ptoul( pattern_location );
if (rs == pl || (pl > rs && rs > pl - sub_len))
finished = TRUE;
else {
rc = replace_and_display( &wp, pattern_location, &finished,
&file_changed, direction );
if (rc == OK && rs > pl)
rs += net_change;
}
} else {
finished = TRUE;
error( WARNING, win->bottom_line, snf );
}
}
}
dup_window_info( win, &wp );
check_virtual_col( win, win->rcol, win->ccol );
if (win->file_info->dirty != LOCAL && win->file_info->dirty != GLOBAL)
show_curl_line( win );
if (file_changed)
win->file_info->modified = TRUE;
}
/*
* Name: replace_and_display
* Purpose: To make room for replacement string
* Date: June 5, 1991
* Passed: window: information allowing access to current window etc
* pattern_location: pointer to position of pattern in file
* finished: boolean - stop replacing on this occurrence
* modified: boolean - user may decide to skip this replacement
* direction: direction of search
* Notes: Show user where pattern_location is on screen if needed.
* Replace and display if needed. Always ask the user if he
* wants to do wrapped replacing.
*/
int replace_and_display( WINDOW *window, text_ptr pattern_location,
int *finished, int *modified, int direction )
{
register int rc;
file_infos *file;
register WINDOW *win; /* put window pointer in a register */
win = window;
file = win->file_info;
rc = OK;
if (g_status.wrapped) {
rc = ask_wrap_replace( win, finished );
g_status.wrapped = FALSE;
show_search_message( CLR_SEARCH, g_display.mode_color );
}
if (rc == OK) {
find_adjust( win, pattern_location );
make_ruler( win );
show_ruler( win );
show_ruler_pointer( win );
xygoto( win->ccol, win->cline );
if (file->dirty) {
display_current_window( win );
file->dirty = FALSE;
} else
show_curl_line( win );
if (g_status.replace_flag == PROMPT && rc == OK) {
show_line_col( win );
rc = ask_replace( win, finished );
}
if (rc == OK) {
do_replace( win, pattern_location, direction );
*modified = TRUE;
file->dirty = GLOBAL;
show_changed_line( win );
file->dirty = FALSE;
}
}
return( rc );
}
/*
* Name: goto_top_file
* Purpose: To move the cursor to the top of the file.
* Date: June 5, 1991
* Passed: window: information allowing access to current window etc
*/
void goto_top_file( WINDOW *window )
{
text_ptr next; /* successive lines above the cursor */
register int i;
register WINDOW *win; /* put window pointer in a register */
win = window;
un_copy_line( win->cursor, win, TRUE );
if (win->rline != win->cline - (win->top_line+win->ruler-1)) {
next = cpf( win->file_info->start_text );
for (i=win->cline; i>win->top_line+win->ruler; i--)
next = find_next( next );
win->cursor = next;
win->rline = win->cline - (win->top_line+win->ruler-1);
display_current_window( win );
}
sync( win );
}
/*
* Name: goto_end_file
* Purpose: To move the cursor to the end of the file.
* Date: June 5, 1991
* Passed: window: information allowing access to current window etc
*/
void goto_end_file( WINDOW *window )
{
text_ptr prev;
int i;
register int j;
file_infos *file;
register WINDOW *win; /* put window pointer in a register */
win = window;
un_copy_line( win->cursor, win, TRUE );
file = win->file_info;
if (file->length > win->rline + win->bottom_line - win->cline) {
prev = cpb( file->end_text ) - 1;
for (j=0,i=win->bottom_line; i>win->cline; i--, j++)
prev = find_prev( prev );
win->cursor = prev;
win->rline = file->length - j + 1;
display_current_window( win );
}
sync( win );
}
/*
* Name: scan_forward
* Purpose: To find the corresponding occurrence of target, ignoring
* embedded pairs of opp and target, searching forwards.
* Date: June 5, 1991
* Passed: start: position of character to be paired
* opp: the opposite to target, if any
* target: the string to be found
* Returns: the location of the corresponding target in the text buffer
* Notes: Every 8,000 characters, check pointer forward.
*/
text_ptr scan_forward( text_ptr start, char opp, char target )
{
text_ptr orig;
int count = 0; /* number of unmatched opposites found */
register int check = 0;
register char c;
orig = start = cpf( start );
while ((c = *++start) && (c != CONTROL_Z)) {
check++;
if (opp == c)
count++;
else if (target == c) {
if (count == 0)
break;
--count;
}
if (check > 8000) {
start = cpf( start );
check = 0;
}
}
if (c == CONTROL_Z)
start = orig;
return( start );
}
/*
* Name: scan_backward
* Purpose: To find the corresponding occurrence of target, ignoring
* embedded pairs of opp and target, searching backwards.
* Date: June 5, 1991
* Passed: start: position of character to be paired
* opp: the opposite to target, if any
* target: the string to be found
* Returns: the location of the corresponding target in the text buffer
*/
text_ptr scan_backward( text_ptr start, char opp, char target )
{
text_ptr orig;
int count = 0; /* number of unmatched opposites found */
register int check = 0;
register char c;
orig = start = cpb( start );
while ((c = *--start) && (c != CONTROL_Z)) {
check++;
if (opp == c)
count++;
else if (target == c) {
if (count == 0)
break;
--count;
}
if (check > 8000) {
start = cpb( start );
check = 0;
}
}
if (c == CONTROL_Z)
start = orig;
return( start );
}
/*
* Name: match_pair
* Purpose: To find the corresponding pair to the character under the
* cursor.
* Date: June 5, 1991
* Passed: window: information allowing access to current window etc
* Notes: Searching is very simple-minded, and does not cope with things
* like brackets embedded within quoted strings.
*/
void match_pair( WINDOW *window )
{
text_ptr orig; /* cursor location in text */
char c;
register WINDOW *win; /* put window pointer in a register */
win = window;
un_copy_line( win->cursor, win, TRUE );
/*
* make sure the character under the cursor is one that has a
* matched pair
*/
if (win->rcol >= linelen( win->cursor ))
return;
win->cursor = cpf( win->cursor );
orig = win->cursor + win->rcol;
c = *orig;
/*
* find the matching pair
*/
switch (c) {
case '[':
orig = scan_forward( orig, '[', ']' );
break;
case '(':
orig = scan_forward( orig, '(', ')' );
break;
case '{':
orig = scan_forward( orig, '{', '}' );
break;
case ']':
orig = scan_backward( orig, ']', '[' );
break;
case ')':
orig = scan_backward( orig, ')', '(' );
break;
case '}':
orig = scan_backward( orig, '}', '{' );
break;
default :
return;
}
/*
* now show the user what we have found
*/
update_line( win );
find_adjust( win, orig );
if (!win->file_info->dirty)
show_curl_line( win );
make_ruler( win );
show_ruler( win );
}
/*
* Name: goto_line
* Purpose: To move the cursor to a particular line in the file
* Date: June 5, 1991
* Passed: window: information allowing access to current window etc
*/
void goto_line( WINDOW *window )
{
long number; /* line number selected */
long i; /* line counter */
char num_str[MAX_COLS]; /* line number as string */
text_ptr p; /* used to scan through file counting lines */
register WINDOW *win; /* put window pointer in a register */
win = window;
un_copy_line( win->cursor, win, TRUE );
/*
* find out where we are going
*/
num_str[0] = '\0';
if (get_name( "Line number: ", win->bottom_line, num_str,
g_display.message_color ) != OK)
return;
number = atol( num_str );
if (number > 0 && number <= win->file_info->length) {
update_line( win );
p = win->cursor;
i = win->rline;
if (number < win->rline) {
p = cpb( p );
for (; i>number; i--)
p = find_prev( p );
} else {
cpf( p );
for (; i<number; i++)
p = find_next( p );
}
find_adjust( win, p );
if (!win->file_info->dirty)
show_curl_line( win );
} else {
strcat( num_str, "must be in the range 1 - " );
ltoa( win->file_info->length, num_str+25, 10 );
error( WARNING, win->bottom_line, num_str );
}
}