/******************* 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 * Date: June 5, 1992, version 2.0 * * 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 */ register int c; int rc, func; 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 rc, prompt_line, func; 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 rc, prompt_line, func; 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 * 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: pointer to current window * Notes: Keep the search string and boyer-moore stuff until changed. */ int 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 */ int rc; 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 ); /* * string to find: */ if (get_name( find4, win->bottom_line, pattern, g_display.message_color ) != OK) return( ERROR ); bm.search_defined = OK; strcpy( bm.pattern, pattern ); build_boyer_array( ); } rc = OK; 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) { if (g_status.wrapped && g_status.macro_executing) rc = ask_wrap_replace( win, &new_string ); if (rc == OK) find_adjust( win, pattern_location ); } } else { if ((pattern_location = backward_boyer_moore_search( win )) != NULL) { if (g_status.wrapped && g_status.macro_executing) rc = ask_wrap_replace( win, &new_string ); if (rc == OK) 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) { /* * string not found */ combine_strings( pattern, find5a, bm.pattern, find5b ); error( WARNING, win->bottom_line, pattern ); rc = ERROR; } show_curl_line( win ); make_ruler( win ); show_ruler( win ); } else { /* * find pattern not defined */ 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 ) { 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: pointer 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; } /* * every 10,000 characters, check the text pointer */ 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: pointer 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 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; } /* * every 10,000 characters, check the text pointer */ 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 ) { /* * 0 = blank * 1 = wrapped... * 2 = searching */ s_output( find7[i], g_display.mode_line, 67, color ); } /* * Name: find_adjust * Purpose: place cursor on screen given a position in file - default cline * Date: June 5, 1991 * Passed: window: pointer to current window * found: position anywhere in file * 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 is the number of lines between rline and found 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: pointer to current window */ int 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; 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 ); /* * string to find */ if (get_name( find9, win->bottom_line, pattern, g_display.message_color ) != OK) return( ERROR ); strcpy( g_status.pattern, pattern ); /* * get the replacement text, using the previous as the default */ strcpy( pattern, g_status.subst ); if (get_name( find10, win->bottom_line, pattern, g_display.message_color ) != OK) return( ERROR ); 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( ERROR ); build_boyer_array( ); dup_window_info( &wp, win ); update_line( win ); rc = OK; finished = FALSE; file_changed = FALSE; if (direction == FORWARD) { if ((replace_start = forward_boyer_moore_search( &wp )) != NULL && !g_status.control_break) { rs = ptoul( replace_start ); replace_and_display( &wp, replace_start, &finished, &file_changed, direction ); } else { /* * string not found */ error( WARNING, win->bottom_line, find8 ); finished = TRUE; rc = ERROR; } while (finished == FALSE) { update_line( &wp ); if ((pattern_location = forward_boyer_moore_search( &wp )) != NULL && !g_status.control_break) { 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 { if (g_status.control_break) rc = getkey( ); /* * string not found or control break */ error( WARNING, win->bottom_line, g_status.control_break ? cb : find8 ); finished = TRUE; rc = ERROR; } } } else { if ((replace_start = backward_boyer_moore_search( &wp )) != NULL && !g_status.control_break) { rs = ptoul( replace_start ); replace_and_display( &wp, replace_start, &finished, &file_changed, direction ); } else { /* * string not found */ error( WARNING, win->bottom_line, find8 ); finished = TRUE; rc = ERROR; } while (finished == FALSE) { update_line( &wp ); if ((pattern_location = backward_boyer_moore_search( &wp )) != NULL && !g_status.control_break) { 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 { if (g_status.control_break) rc = getkey( ); /* * string not found or control break */ error( WARNING, win->bottom_line, g_status.control_break ? cb : find8 ); finished = TRUE; rc = ERROR; } } } 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; return( rc ); } /* * Name: replace_and_display * Purpose: To make room for replacement string * Date: June 5, 1991 * Passed: window: pointer to current window * pattern_location: pointer to position of pattern in file * finished: stop replacing on this occurrence? * modified: 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: pointer to current window */ int 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 ); return( OK ); } /* * Name: goto_end_file * Purpose: To move the cursor to the end of the file. * Date: June 5, 1991 * Passed: window: pointer to current window */ int 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 ); return( OK ); } /* * 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 * target: the string to be found * rc: OK if found, ERROR otherwise * 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, int *rc ) { text_ptr orig; int count = 0; /* number of unmatched opposites found */ register int check = 0; register char c; rc = OK; orig = start = cpf( start ); while ((c = *++start) && (c != CONTROL_Z)) { check++; if (opp == c) count++; else if (target == c) { if (count == 0) break; --count; } /* * after every 8,000 characters, check that pointer. */ if (check > 8000) { start = cpf( start ); check = 0; } } if (c == CONTROL_Z) { start = orig; *rc = ERROR; } 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 * target: the string to be found * rc: OK if found, ERROR otherwise * Returns: the location of the corresponding target in the text buffer */ text_ptr scan_backward( text_ptr start, char opp, char target, int *rc ) { text_ptr orig; int count = 0; /* number of unmatched opposites found */ register int check = 0; register char c; *rc = OK; orig = start = cpb( start ); while ((c = *--start) && (c != CONTROL_Z)) { check++; if (opp == c) count++; else if (target == c) { if (count == 0) break; --count; } /* * after every 8,000 characters, check that pointer. */ if (check > 8000) { start = cpb( start ); check = 0; } } if (c == CONTROL_Z) { start = orig; *rc = ERROR; } return( start ); } /* * Name: match_pair * Purpose: To find the corresponding pair to the character under the * cursor. * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: Searching is very simple-minded, and does not cope with things * like brackets embedded within quoted strings. */ int match_pair( WINDOW *window ) { text_ptr orig; /* cursor location in text */ char c; register WINDOW *win; /* put window pointer in a register */ int rc; win = window; un_copy_line( win->cursor, win, TRUE ); /* * make sure the character under the cursor is one that has a * matched pair */ if ((unsigned)win->rcol >= linelen( win->cursor )) return( ERROR ); win->cursor = cpf( win->cursor ); orig = win->cursor + win->rcol; c = *orig; /* * find the matching pair */ switch (c) { case '[': orig = scan_forward( orig, '[', ']', &rc ); break; case '(': orig = scan_forward( orig, '(', ')', &rc ); break; case '{': orig = scan_forward( orig, '{', '}', &rc ); break; case ']': orig = scan_backward( orig, ']', '[', &rc ); break; case ')': orig = scan_backward( orig, ')', '(', &rc ); break; case '}': orig = scan_backward( orig, '}', '{', &rc ); break; default : return( ERROR ); } /* * 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 ); return( rc ); } /* * Name: goto_line * Purpose: To move the cursor to a particular line in the file * Date: June 5, 1991 * Passed: window: pointer to current window */ int 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 */ int rc; win = window; un_copy_line( win->cursor, win, TRUE ); /* * find out where we are going */ num_str[0] = '\0'; /* * line number: */ if (get_name( find11, win->bottom_line, num_str, g_display.message_color ) != OK) return( ERROR ); 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 (; ifile_info->dirty) show_curl_line( win ); rc = OK; } else { /* * out of range. must be in the range 1 - */ strcat( num_str, find12 ); ltoa( win->file_info->length, num_str+25, 10 ); error( WARNING, win->bottom_line, num_str ); rc = ERROR; } return( rc ); }