From 1044d74fd33df1a6e1f720c4dedd30ab47e431e0 Mon Sep 17 00:00:00 2001 From: David Lawrence Ramsey Date: Tue, 24 Feb 2004 20:41:39 +0000 Subject: [PATCH] add DB's refactored search code and a few of his minor display code changes, plus a few minor search and display fixes of mine git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1660 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- ChangeLog | 85 +++++- src/nano.c | 40 ++- src/proto.h | 19 +- src/search.c | 781 +++++++++++++++++++++++---------------------------- src/utils.c | 62 ++-- src/winio.c | 38 +-- 6 files changed, 530 insertions(+), 495 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2a312549..f0d2dee1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -36,10 +36,17 @@ CVS code - - Remove the now-unneeded code to disable XON, XOFF, and suspend, since we now go into raw mode in get_verbatim_kbinput() and bypass them. (DLR) - do_spell(), do_int_speller(), do_alt_speller() + do_int_speller(), do_alt_speller(), do_spell() - Modify to write only the current selection from a file to the temporary file used for spell checking when the mark is on, and add a few miscellaneous cosmetic cleanups. (DLR) + do_int_spell_fix() + - Store the value of current_x in a size_t instead of an int, + and add a few minor efficiency tweaks. (David Benbennick) + - Remove comment explaining why findnextstr() is called with + bracket_mode set to TRUE even though we aren't doing a bracket + search, since after the above efficiency tweaks, it's now more + accurately called can_display_wrap. (DLR) signal_init() - Trap SIGQUIT in addition to turning it off via termios in main(). This is consistent with SIGINT, which we trap here @@ -59,10 +66,76 @@ CVS code - curses setup routines, and turn the keypad on before setting the input mode. (DLR) - search.c: + regexp_cleanup() + - Only do anything if REGEXP_COMPILED is set. (David Benbennick) + search_abort() + - Only test if the mark is set when NANO_SMALL isn't defined. + (David Benbennick) + search_init() + - Add some more comments and comment tweaks, don't indicate that + the search has been canceled when we enter a blank string in + replace mode, only call regexp_init() when USE_REGEXP is set, + and return -1 instead of -3 since a canceled search and a + canceled replace should be mostly equivalent. (David + Benbennick) DLR: Tweak to use the old behavior if we try to + search for invalid regexes. + findnextstr() + - Refactor to use a loop invariant, and tweak for greater + efficiency and simplicity. Also modify so that all searches + start one character after (or before, if we're doing a + backwards search) the current one, as opposed to all searches + except for regex searches for "^" and the like, for + consistency with other searches. (David Benbennick) + do_search() + - Handle search_init()'s no longer returning -3 above. (David + Benbennick) + - Port the code from do_replace_loop() to skip the current line + if we're searching for a regex with "^" and/or "$" in it and + end up on the same line to this function. This fixes a + problem where doing a forward search for "^" on a file with + more than one line would erroneously stop at the magicline and + indicate that that was the only occurrence. (DLR) + do_research() + - Port David Benbennick's efficiency tweaks and the + aforementioned code ported from do_replace_loop() to this + function. (DLR) + replace_regexp() + - Completely refactor for increased efficiency. (David + Benbennick) + replace_line() + - Use a char* parameter for the replacement string instead of + last_search, and add minor efficiency tweaks. (David + Benbennick) do_replace_loop() - Fix segfault when doing a regex replace of a string that matches inside a line (e.g. replace the "b" in "abc" with anything). (David Benbennick) + - If the mark is on at the beginning of the functio, turn it off + and turn it back on just before returning. Also overhaul to + rely on the return value of findnextstr() instead of a loop + invariant, to not need to take an int* parameter, and store + the beginning x-coordinate in a size_t instead of an int. + (David Benbennick) + do_replace() + - Handle search_init()'s no longer returning -3 above, and add + efficiency tweaks. (David Benbennick) DLR: Tweak to follow + the old behavior of adding non-blank strings entered at the + "Replace: " prompt to the search history. (DLR) + do_bracket() + - Add efficiency tweaks. (David Benbennick) DLR: Remove + reliance on the hardcoded bracket string length; instead, only + require that the bracket string length be even. +- utils.c: + regexec_safe() + - Wrap in HAVE_REGEX_H #ifdefs. (DLR) + regexp_bol_or_eol() + - New function used to check if a regex contains "^" and/or "$", + assuming that the regex would be found if the REG_NOT(BOL|EOL) + flags aren't used in the regexec() call; it replaces the + direct regexec()s used before. (DLR) + strstrwrapper() + - Refactor for increased efficiency, and eliminate the need for + the line_pos parameter. (David Benbennick) - winio.c: get_verbatim_kbinput() - Set keypad() to FALSE and switch to raw mode while reading @@ -96,6 +169,16 @@ CVS code - (a) when we move onto the "$" at the end of the line on the first page and (b) when we move onto the character just before the "$" on subsequent pages. (DLR) + reset_cursor() + - Tweak for efficiency. (David Benbennick) + update_line() + - Move leaveok() calls here from edit_refresh(), since the + places where they were used in edit_refresh() mainly affected + the update_line()s. (DLR) + edit_refresh() + - Tweak for efficiency. (David Benbennick) + - Remove the aforementioned leaveok() calls from this function. + (DLR) do_credits() - Use nanosleep() instead of usleep(). The latter is only standard under BSD, whereas the former is POSIX compliant. diff --git a/src/nano.c b/src/nano.c index 3fee0db1..22814782 100644 --- a/src/nano.c +++ b/src/nano.c @@ -1510,13 +1510,13 @@ int do_wrap(filestruct *inptr) #ifndef DISABLE_SPELLER /* A word is misspelled in the file. Let the user replace it. We - * return False if the user cancels. */ + * return zero if the user cancels. */ int do_int_spell_fix(const char *word) { char *save_search; char *save_replace; filestruct *current_save = current; - int current_x_save = current_x; + size_t current_x_save = current_x; filestruct *edittop_save = edittop; /* Save where we are. */ int i = 0; @@ -1527,37 +1527,35 @@ int do_int_spell_fix(const char *word) int mark_set = ISSET(MARK_ISSET); SET(CASE_SENSITIVE); - /* Make sure the marking highlight is off during Spell Check */ + /* Make sure the marking highlight is off during spell-check. */ UNSET(MARK_ISSET); #endif - /* Make sure Spell Check goes forward only */ + /* Make sure spell-check goes forward only. */ UNSET(REVERSE_SEARCH); - /* save the current search/replace strings */ + /* Save the current search/replace strings. */ search_init_globals(); save_search = last_search; save_replace = last_replace; - /* set search/replace strings to mis-spelt word */ + /* Set search/replace strings to misspelled word. */ last_search = mallocstrcpy(NULL, word); last_replace = mallocstrcpy(NULL, word); - /* start from the top of file */ + /* Start from the top of the file. */ current = fileage; current_x = -1; search_last_line = FALSE; - /* We find the first whole-word occurrence of word. We call - findnextstr() with bracket_mode set to TRUE in order to disable - search wrapping. */ - while (findnextstr(TRUE, TRUE, fileage, -1, word, 0)) + /* Find the first whole-word occurrence of word. */ + while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0) if (is_whole_word(current_x, current->data, word)) { edit_refresh(); do_replace_highlight(TRUE, word); - /* allow replace word to be corrected */ + /* Allow the replace word to be corrected. */ i = statusq(0, spell_list, word, #ifndef NANO_SMALL NULL, @@ -1567,26 +1565,26 @@ int do_int_spell_fix(const char *word) do_replace_highlight(FALSE, word); if (i != -1 && strcmp(word, answer)) { - int j = 0; - search_last_line = FALSE; current_x--; - do_replace_loop(word, current_save, ¤t_x_save, TRUE, &j); + do_replace_loop(word, current_save, ¤t_x_save, TRUE); } break; } - /* restore the search/replace strings */ - free(last_search); last_search=save_search; - free(last_replace); last_replace=save_replace; + /* Restore the search/replace strings. */ + free(last_search); + last_search = save_search; + free(last_replace); + last_replace = save_replace; - /* restore where we were */ + /* Restore where we were. */ current = current_save; current_x = current_x_save; edittop = edittop_save; - /* restore Search/Replace direction */ + /* Restore search/replace direction. */ if (reverse_search_set) SET(REVERSE_SEARCH); @@ -1594,7 +1592,7 @@ int do_int_spell_fix(const char *word) if (!case_sens_set) UNSET(CASE_SENSITIVE); - /* restore marking highlight */ + /* Restore marking highlight. */ if (mark_set) SET(MARK_ISSET); #endif diff --git a/src/proto.h b/src/proto.h index b09ed621..8eb94bce 100644 --- a/src/proto.h +++ b/src/proto.h @@ -364,19 +364,19 @@ void not_found_msg(const char *str); void search_abort(void); void search_init_globals(void); int search_init(int replacing); -int is_whole_word(int curr_pos, const char *datastr, const char *searchword); -filestruct *findnextstr(int quiet, int bracket_mode, - const filestruct *begin, int beginx, - const char *needle, int no_sameline); +int is_whole_word(int curr_pos, const char *datastr, const char + *searchword); +int findnextstr(int can_display_wrap, int wholeword, const filestruct + *begin, size_t beginx, const char *needle, int no_sameline); int do_search(void); int do_research(void); void replace_abort(void); #ifdef HAVE_REGEX_H int replace_regexp(char *string, int create_flag); #endif -char *replace_line(void); -int do_replace_loop(const char *prevanswer, const filestruct *begin, - int *beginx, int wholewords, int *i); +char *replace_line(const char *needle); +int do_replace_loop(const char *needle, const filestruct *real_current, + size_t *real_current_x, int wholewords); int do_replace(void); int do_gotoline(int line, int save_pos); int do_gotoline_void(void); @@ -401,10 +401,13 @@ void save_history(void); #endif /* Public functions in utils.c */ +#ifdef HAVE_REGEX_H #ifdef BROKEN_REGEXEC int regexec_safe(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags); #endif +int regexp_bol_or_eol(const regex_t *preg, const char *string); +#endif int is_cntrl_char(int c); int num_of_digits(int n); void align(char **strp); @@ -425,7 +428,7 @@ const char *revstristr(const char *haystack, const char *needle, #endif const char *stristr(const char *haystack, const char *needle); const char *strstrwrapper(const char *haystack, const char *needle, - const char *rev_start, int line_pos); + const char *start); void nperror(const char *s); void *nmalloc(size_t howmuch); void *nrealloc(void *ptr, size_t howmuch); diff --git a/src/search.c b/src/search.c index 69f9eba2..9ce635c3 100644 --- a/src/search.c +++ b/src/search.c @@ -23,8 +23,8 @@ #include #include -#include #include +#include #include #include #include @@ -47,8 +47,10 @@ int regexp_init(const char *regexp) void regexp_cleanup(void) { - UNSET(REGEXP_COMPILED); - regfree(&search_regexp); + if (ISSET(REGEXP_COMPILED)) { + UNSET(REGEXP_COMPILED); + regfree(&search_regexp); + } } #endif @@ -68,13 +70,12 @@ void not_found_msg(const char *str) void search_abort(void) { display_main_list(); - wrefresh(bottomwin); +#ifndef NANO_SMALL if (ISSET(MARK_ISSET)) - edit_refresh_clearok(); - + edit_refresh(); +#endif #ifdef HAVE_REGEX_H - if (ISSET(REGEXP_COMPILED)) - regexp_cleanup(); + regexp_cleanup(); #endif } @@ -90,9 +91,11 @@ void search_init_globals(void) } } -/* Set up the system variables for a search or replace. Return -1 on - * abort, 0 on success, and 1 on rerun calling program. Return -2 to - * run opposite program (search -> replace, replace -> search). +/* Set up the system variables for a search or replace. Return -1 if + * the search should be cancelled (due to Cancel, Go to Line, or a + * failed regcomp()). Return 0 on success, and 1 on rerun calling + * program. Return -2 to run opposite program (search -> replace, + * replace -> search). * * replacing = 1 if we call from do_replace(), 0 if called from * do_search(). */ @@ -101,9 +104,12 @@ int search_init(int replacing) int i = 0; char *buf; static char *backupstring = NULL; -#ifdef HAVE_REGEX_H - const char *regex_error = _("Invalid regex \"%s\""); -#endif /* HAVE_REGEX_H */ + + /* We display the search prompt below. If the user types a partial + * search string and then Replace or a toggle, we will return to + * do_search() or do_replace() and be called again. In that case, + * we should put the same search string back up. backupstring holds + * this string. */ search_init_globals(); @@ -119,7 +125,8 @@ int search_init(int replacing) char *disp = display_string(last_search, 0, COLS / 3); buf = charalloc(COLS / 3 + 7); - /* We use COLS / 3 here because we need to see more on the line */ + /* We use COLS / 3 here because we need to see more on the + * line. */ sprintf(buf, " [%s%s]", disp, strlenpt(last_search) > COLS / 3 ? "..." : ""); free(disp); @@ -128,7 +135,7 @@ int search_init(int replacing) buf[0] = '\0'; } - /* This is now one simple call. It just does a lot */ + /* This is now one simple call. It just does a lot. */ i = statusq(0, replacing ? replace_list : whereis_list, backupstring, #ifndef NANO_SMALL &search_history, @@ -137,19 +144,19 @@ int search_init(int replacing) _("Search"), #ifndef NANO_SMALL - /* This string is just a modifier for the search prompt, - no grammar is implied */ + /* This string is just a modifier for the search prompt; no + * grammar is implied. */ ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") : #endif "", - /* This string is just a modifier for the search prompt, - no grammar is implied */ + /* This string is just a modifier for the search prompt; no + * grammar is implied. */ ISSET(USE_REGEXP) ? _(" [Regexp]") : "", #ifndef NANO_SMALL - /* This string is just a modifier for the search prompt, - no grammar is implied */ + /* This string is just a modifier for the search prompt; no + * grammar is implied. */ ISSET(REVERSE_SEARCH) ? _(" [Backwards]") : #endif "", @@ -157,14 +164,15 @@ int search_init(int replacing) replacing ? _(" (to replace)") : "", buf); - /* Release buf now that we don't need it anymore */ + /* Release buf now that we don't need it anymore. */ free(buf); free(backupstring); backupstring = NULL; - /* Cancel any search, or just return with no previous search */ - if (i == -1 || (i < 0 && last_search[0] == '\0')) { + /* Cancel any search, or just return with no previous search. */ + if (i == -1 || (i < 0 && last_search[0] == '\0') || + (!replacing && i == 0 && answer[0] == '\0')) { statusbar(_("Search Cancelled")); reset_cursor(); #ifndef NANO_SMALL @@ -173,29 +181,24 @@ int search_init(int replacing) return -1; } else { switch (i) { - case -2: /* Same string */ + case -2: /* It's the same string. */ #ifdef HAVE_REGEX_H - if (ISSET(USE_REGEXP)) - /* If answer is "", use last_search! */ - if (regexp_init(last_search) == 0) { - statusbar(regex_error, last_search); - reset_cursor(); - return -3; - } + /* Since answer is "", use last_search! */ + if (ISSET(USE_REGEXP) && regexp_init(last_search) == 0) { + statusbar(_("Invalid regex \"%s\""), last_search); + reset_cursor(); + return -1; + } #endif break; - case 0: /* They entered something new */ + case 0: /* They entered something new. */ last_replace[0] = '\0'; #ifdef HAVE_REGEX_H - if (ISSET(USE_REGEXP)) - if (regexp_init(answer) == 0) { - statusbar(regex_error, answer); - reset_cursor(); -#ifndef NANO_SMALL - search_history.current = search_history.next; -#endif - return -3; - } + if (ISSET(USE_REGEXP) && regexp_init(answer) == 0) { + statusbar(_("Invalid regex \"%s\""), answer); + reset_cursor(); + return -1; + } #endif break; #ifndef NANO_SMALL @@ -216,226 +219,194 @@ int search_init(int replacing) #endif /* !NANO_SMALL */ case NANO_OTHERSEARCH_KEY: backupstring = mallocstrcpy(backupstring, answer); - return -2; /* Call the opposite search function */ + return -2; /* Call the opposite search function. */ case NANO_FROMSEARCHTOGOTO_KEY: #ifndef NANO_SMALL search_history.current = search_history.next; #endif - i = (int)strtol(answer, &buf, 10); /* Just testing answer here */ + i = (int)strtol(answer, &buf, 10); /* Just testing answer here. */ if (!(errno == ERANGE || *answer == '\0' || *buf != '\0')) do_gotoline(-1, 0); else do_gotoline_void(); - return -3; + /* Fall through. */ default: - do_early_abort(); - return -3; + return -1; } } return 0; } -int is_whole_word(int curr_pos, const char *datastr, const char *searchword) +int is_whole_word(int curr_pos, const char *datastr, const char + *searchword) { size_t sln = curr_pos + strlen(searchword); - /* start of line or previous character not a letter and end of line - or next character not a letter */ + /* Start of line or previous character is not a letter and end of + * line or next character is not a letter. */ return (curr_pos < 1 || !isalpha((int)datastr[curr_pos - 1])) && (sln == strlen(datastr) || !isalpha((int)datastr[sln])); } -filestruct *findnextstr(int quiet, int bracket_mode, - const filestruct *begin, int beginx, - const char *needle, int no_sameline) +/* Look for needle, starting at current, column current_x. If + * no_sameline is nonzero, skip over begin when looking for needle. + * begin is the line where we first started searching, at column beginx. + * If can_display_wrap is nonzero, we put messages on the statusbar, and + * wrap around the file boundaries. The return value specifies whether + * we found anything. */ +int findnextstr(int can_display_wrap, int wholeword, const filestruct + *begin, size_t beginx, const char *needle, int no_sameline) { filestruct *fileptr = current; - const char *searchstr, *rev_start = NULL, *found = NULL; - int current_x_find = 0; - - search_offscreen = 0; - - if (!ISSET(REVERSE_SEARCH)) { /* forward search */ - /* Argh, current_x is set to -1 by nano.c:do_int_spell_fix(), and - * strlen returns size_t, which is unsigned. */ - assert(current_x < 0 || current_x <= strlen(fileptr->data)); - current_x_find = current_x; - if (current_x_find < 0 || fileptr->data[current_x_find] != '\0') - current_x_find++; - - searchstr = &fileptr->data[current_x_find]; - - /* Look for needle in searchstr. Keep going until we find it - * and, if no_sameline is set, until it isn't on the current - * line. If we don't find it, we'll end up at - * current[current_x] regardless of whether no_sameline is - * set. */ - while ((found = strstrwrapper(searchstr, needle, rev_start, current_x_find)) == NULL || (no_sameline && fileptr == current)) { - - /* finished processing file, get out */ - if (search_last_line) { - if (!quiet) - not_found_msg(needle); - update_line(fileptr, current_x); - return NULL; - } - - update_line(fileptr, 0); - - /* reset current_x_find between lines */ - current_x_find = 0; - - fileptr = fileptr->next; - - if (fileptr == editbot) - search_offscreen = 1; - - /* EOF reached?, wrap around once */ - if (fileptr == NULL) { - /* don't wrap if looking for bracket match */ - if (bracket_mode) - return NULL; - fileptr = fileage; - search_offscreen = 1; - if (!quiet) - statusbar(_("Search Wrapped")); - } + const char *rev_start = NULL, *found = NULL; + size_t current_x_find = 0; + /* Where needle was found. */ + + /* rev_start might end up 1 character before the start or after the + * end of the line. This won't be a problem because strstrwrapper() + * will return immediately and say that no match was found, and + * rev_start will be properly set when the search continues on the + * previous or next line. */ +#ifndef NANO_SMALL + if (ISSET(REVERSE_SEARCH)) + rev_start = fileptr->data + (current_x - 1); + else +#endif + rev_start = fileptr->data + (current_x + 1); - /* Original start line reached */ - if (fileptr == begin) - search_last_line = 1; + /* Look for needle in searchstr. */ + while (1) { + found = strstrwrapper(fileptr->data, needle, rev_start); - searchstr = fileptr->data; + if (found != NULL && (!wholeword || is_whole_word(found - + fileptr->data, fileptr->data, needle))) { + if (!no_sameline || fileptr != current) + break; } - /* We found an instance */ - current_x_find = found - fileptr->data; - /* Ensure we haven't wrapped around again! */ - if (search_last_line && current_x_find > beginx) { - if (!quiet) + /* Finished processing file, get out. */ + if (search_last_line) { + if (can_display_wrap) not_found_msg(needle); - return NULL; + return 0; } - } + fileptr = #ifndef NANO_SMALL - else { /* reverse search */ - current_x_find = current_x - 1; - /* Make sure we haven't passed the beginning of the string */ - rev_start = &fileptr->data[current_x_find]; - searchstr = fileptr->data; - - /* Look for needle in searchstr. Keep going until we find it - * and, if no_sameline is set, until it isn't on the current - * line. If we don't find it, we'll end up at - * current[current_x] regardless of whether no_sameline is - * set. */ - while ((found = strstrwrapper(searchstr, needle, rev_start, current_x_find)) == NULL || (no_sameline && fileptr == current)) { - - /* finished processing file, get out */ - if (search_last_line) { - if (!quiet) - not_found_msg(needle); - return NULL; - } - - update_line(fileptr, 0); - - /* reset current_x_find between lines */ - current_x_find = 0; + ISSET(REVERSE_SEARCH) ? fileptr->prev : +#endif + fileptr->next; - fileptr = fileptr->prev; + /* Start or end of buffer reached; wrap around. */ + if (fileptr == NULL) { + if (!can_display_wrap) + return 0; + fileptr = +#ifndef NANO_SMALL + ISSET(REVERSE_SEARCH) ? filebot : +#endif + fileage; + if (can_display_wrap) + statusbar(_("Search Wrapped")); + } - if (fileptr == edittop->prev) - search_offscreen = 1; + /* Original start line reached. */ + if (fileptr == begin) + search_last_line = 1; + rev_start = fileptr->data; +#ifndef NANO_SMALL + if (ISSET(REVERSE_SEARCH)) + rev_start += strlen(fileptr->data); +#endif + } - /* SOF reached?, wrap around once */ -/* ? */ if (fileptr == NULL) { - if (bracket_mode) - return NULL; - fileptr = filebot; - search_offscreen = 1; - if (!quiet) - statusbar(_("Search Wrapped")); - } - /* Original start line reached */ - if (fileptr == begin) - search_last_line = 1; + /* We found an instance. */ + current_x_find = found - fileptr->data; - searchstr = fileptr->data; - rev_start = fileptr->data + strlen(fileptr->data); - } + /* Ensure we haven't wrapped around again! */ + if (search_last_line && +#ifndef NANO_SMALL + ((!ISSET(REVERSE_SEARCH) && current_x_find > beginx) || + (ISSET(REVERSE_SEARCH) && current_x_find < beginx)) +#else + current_x_find > beginx +#endif + ) { - /* We found an instance */ - current_x_find = found - fileptr->data; - /* Ensure we haven't wrapped around again! */ - if ((search_last_line) && (current_x_find < beginx)) { - if (!quiet) - not_found_msg(needle); - return NULL; - } + if (can_display_wrap) + not_found_msg(needle); + return 0; } -#endif /* !NANO_SMALL */ - /* Set globals now that we are sure we found something */ + /* Set globals now that we are sure we found something. */ current = fileptr; current_x = current_x_find; - if (!bracket_mode) { - update_line(current, current_x); - placewewant = xplustabs(); - reset_cursor(); - } - return fileptr; + return 1; } /* Search for a string. */ int do_search(void) { int i; - filestruct *fileptr = current, *didfind; - int fileptr_x = current_x; + filestruct *fileptr = current; + int fileptr_x = current_x, didfind; #ifndef DISABLE_WRAPPING wrap_reset(); #endif i = search_init(0); - switch (i) { - case -1: - current = fileptr; - search_abort(); - return 0; - case -3: + if (i == -1) /* Cancel, Go to Line, blank search string, or + * regcomp() failed. */ search_abort(); - return 0; - case -2: + else if (i == -2) /* Replace. */ do_replace(); - return 0; - case 1: +#ifndef NANO_SMALL + else if (i == 1) /* Case Sensitive, Backwards, or Regexp search + * toggle. */ do_search(); - search_abort(); - return 1; - } +#endif - /* If answer is now "", copy last_search into answer... */ + if (i != 0) + return 0; + + /* If answer is now "", copy last_search into answer. */ if (answer[0] == '\0') answer = mallocstrcpy(answer, last_search); else last_search = mallocstrcpy(last_search, answer); #ifndef NANO_SMALL - /* add this search string to the search history list */ + /* If answer is not "", add this search string to the search history + * list. */ if (answer[0] != '\0') update_history(&search_history, answer); -#endif /* !NANO_SMALL */ +#endif search_last_line = 0; - didfind = findnextstr(FALSE, FALSE, current, current_x, answer, 0); + didfind = findnextstr(TRUE, FALSE, current, current_x, answer, FALSE); + edit_refresh(); + placewewant = xplustabs(); - if (fileptr == current && fileptr_x == current_x && didfind != NULL) - statusbar(_("This is the only occurrence")); - else if (current->lineno <= edittop->lineno - || current->lineno >= editbot->lineno) - edit_update(current, CENTER); + /* Check to see if there's only one occurrence of the string and + * we're on it now. */ + if (fileptr == current && fileptr_x == current_x && didfind) { +#ifdef HAVE_REGEX_H + /* Do the search again, skipping over the current line, if we're + * doing a bol and/or eol regex search ("^", "$", or "^$"), so + * that we find one only once per line. We should only end up + * back at the same position if the string isn't found again, in + * which case it's the only occurrence. */ + if (ISSET(USE_REGEXP) && regexp_bol_or_eol(&search_regexp, last_search)) { + didfind = findnextstr(TRUE, FALSE, current, current_x, answer, TRUE); + if (fileptr == current && fileptr_x == current_x && !didfind) + statusbar(_("This is the only occurrence")); + } else { +#endif + statusbar(_("This is the only occurrence")); +#ifdef HAVE_REGEX_H + } +#endif + } search_abort(); @@ -445,11 +416,8 @@ int do_search(void) /* Search for the next string without prompting. */ int do_research(void) { - filestruct *fileptr = current, *didfind; - int fileptr_x = current_x; -#ifdef HAVE_REGEX_H - const char *regex_error = _("Invalid regex \"%s\""); -#endif /* HAVE_REGEX_H */ + filestruct *fileptr = current; + int fileptr_x = current_x, didfind; #ifndef DISABLE_WRAPPING wrap_reset(); @@ -459,23 +427,39 @@ int do_research(void) if (last_search[0] != '\0') { #ifdef HAVE_REGEX_H - if (ISSET(USE_REGEXP)) - if (regexp_init(last_search) == 0) { - statusbar(regex_error, last_search); + /* Since answer is "", use last_search! */ + if (ISSET(USE_REGEXP) && regexp_init(last_search) == 0) { + statusbar(_("Invalid regex \"%s\""), last_search); reset_cursor(); - return -3; + return -1; } #endif search_last_line = 0; - didfind = findnextstr(FALSE, FALSE, current, current_x, last_search, 0); - - if (fileptr == current && fileptr_x == current_x && didfind != NULL) - statusbar(_("This is the only occurrence")); - else if (current->lineno <= edittop->lineno - || current->lineno >= editbot->lineno) - edit_update(current, CENTER); + didfind = findnextstr(TRUE, FALSE, current, current_x, last_search, FALSE); + edit_refresh(); + placewewant = xplustabs(); + /* Check to see if there's only one occurrence of the string and + * we're on it now. */ + if (fileptr == current && fileptr_x == current_x && didfind) { +#ifdef HAVE_REGEX_H + /* Do the search again, skipping over the current line, if + * we're doing a bol and/or eol regex search ("^", "$", or + * "^$"), so that we find one only once per line. We should + * only end up back at the same position if the string isn't + * found again, in which case it's the only occurrence. */ + if (ISSET(USE_REGEXP) && regexp_bol_or_eol(&search_regexp, last_search)) { + didfind = findnextstr(TRUE, FALSE, current, current_x, answer, TRUE); + if (fileptr == current && fileptr_x == current_x && !didfind) + statusbar(_("This is the only occurrence")); + } else { +#endif + statusbar(_("This is the only occurrence")); +#ifdef HAVE_REGEX_H + } +#endif + } } else statusbar(_("No current search pattern")); @@ -486,9 +470,9 @@ int do_research(void) void replace_abort(void) { - /* Identical to search_abort, so we'll call it here. If it - does something different later, we can change it back. For now - it's just a waste to duplicate code */ + /* Identical to search_abort(), so we'll call it here. If it does + * something different later, we can change it back. For now, it's + * just a waste to duplicate code. */ search_abort(); placewewant = xplustabs(); } @@ -496,57 +480,39 @@ void replace_abort(void) #ifdef HAVE_REGEX_H int replace_regexp(char *string, int create_flag) { - /* Split personality here - if create_flag is NULL, just calculate + /* Split personality here - if create_flag is zero, just calculate * the size of the replacement line (necessary because of - * subexpressions like \1 \2 \3 in the replaced text). */ + * subexpressions \1 to \9 in the replaced text). */ - char *c; - int new_size = strlen(current->data) + 1; + const char *c = last_replace; int search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so; - - new_size -= search_match_count; + int new_size = strlen(current->data) + 1 - search_match_count; /* Iterate through the replacement text to handle subexpression * replacement using \1, \2, \3, etc. */ - - c = last_replace; while (*c != '\0') { - if (*c != '\\') { + int num = (int)(*(c + 1) - '0'); + + if (*c != '\\' || num < 1 || num > 9 || num > search_regexp.re_nsub) { if (create_flag) *string++ = *c; c++; new_size++; } else { - int num = (int) *(c + 1) - (int) '0'; - if (num >= 1 && num <= 9) { - - int i = regmatches[num].rm_eo - regmatches[num].rm_so; - - if (num > search_regexp.re_nsub) { - /* Ugh, they specified a subexpression that doesn't - * exist. */ - return -1; - } - - /* Skip over the replacement expression */ - c += 2; + int i = regmatches[num].rm_eo - regmatches[num].rm_so; - /* But add the length of the subexpression to new_size */ - new_size += i; + /* Skip over the replacement expression. */ + c += 2; - /* And if create_flag is set, append the result of the - * subexpression match to the new line */ - if (create_flag) { - strncpy(string, current->data + current_x + - regmatches[num].rm_so, i); - string += i; - } + /* But add the length of the subexpression to new_size. */ + new_size += i; - } else { - if (create_flag) - *string++ = *c; - c++; - new_size++; + /* And if create_flag is nonzero, append the result of the + * subexpression match to the new line. */ + if (create_flag) { + strncpy(string, current->data + current_x + + regmatches[num].rm_so, i); + string += i; } } } @@ -558,146 +524,116 @@ int replace_regexp(char *string, int create_flag) } #endif -char *replace_line(void) +char *replace_line(const char *needle) { - char *copy, *tmp; + char *copy; int new_line_size; int search_match_count; - /* Calculate size of new line */ + /* Calculate the size of the new line. */ #ifdef HAVE_REGEX_H if (ISSET(USE_REGEXP)) { - search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so; + search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so; new_line_size = replace_regexp(NULL, 0); - /* If they specified an invalid subexpression in the replace - * text, return NULL, indicating an error */ - if (new_line_size < 0) - return NULL; } else { -#else - { #endif - search_match_count = strlen(last_search); - new_line_size = strlen(current->data) - strlen(last_search) + - strlen(last_replace) + 1; + search_match_count = strlen(needle); + new_line_size = strlen(current->data) - search_match_count + + strlen(answer) + 1; +#ifdef HAVE_REGEX_H } +#endif - /* Create buffer */ + /* Create the buffer. */ copy = charalloc(new_line_size); - /* Head of Original Line */ + /* The head of the original line. */ strncpy(copy, current->data, current_x); - copy[current_x] = '\0'; - /* Replacement Text */ - if (!ISSET(USE_REGEXP)) - strcat(copy, last_replace); + /* The replacement text. */ #ifdef HAVE_REGEX_H + if (ISSET(USE_REGEXP)) + replace_regexp(copy + current_x, TRUE); else - replace_regexp(copy + current_x, 1); #endif + strcpy(copy + current_x, answer); - /* The tail of the original line */ - - /* This may expose other bugs, because it no longer goes through - * each character in the string and tests for string goodness. But - * because we can assume the invariant that current->data is less - * than current_x + strlen(last_search) long, this should be safe. - * Or it will expose bugs ;-) */ - tmp = current->data + current_x + search_match_count; - strcat(copy, tmp); + /* The tail of the original line. */ + assert(current_x + search_match_count <= strlen(current->data)); + strcat(copy, current->data + current_x + search_match_count); return copy; } -/* Step through each replace word and prompt user before replacing - * word. Return -1 if the string to replace isn't found at all. - * Otherwise, return the number of replacements made. */ -int do_replace_loop(const char *prevanswer, const filestruct *begin, - int *beginx, int wholewords, int *i) +/* Step through each replace word and prompt user before replacing. + * Parameters real_current and real_current_x are needed by the internal + * speller, to allow the cursor position to be updated when a word + * before the cursor is replaced by a shorter word. + * + * needle is the string to seek. We replace it with answer. Return -1 + * if needle isn't found, else the number of replacements performed. */ +int do_replace_loop(const char *needle, const filestruct *real_current, + size_t *real_current_x, int wholewords) { int replaceall = 0, numreplaced = -1; + const filestruct *current_save = current; + size_t current_x_save = current_x; #ifdef HAVE_REGEX_H /* The starting-line match and bol/eol regex flags. */ - int beginline = 0, bol_eol = 0; + int begin_line = 0, bol_or_eol = 0; #endif - filestruct *fileptr = NULL; - - switch (*i) { - case -1: /* Aborted enter. */ - if (last_replace[0] != '\0') - answer = mallocstrcpy(answer, last_replace); - statusbar(_("Replace Cancelled")); - replace_abort(); - return 0; - case 0: /* They actually entered something. */ - break; - default: - if (*i != -2) { /* First page, last page, for example, could - * get here. */ - do_early_abort(); - replace_abort(); - return 0; - } - } +#ifndef NANO_SMALL + int mark_set = ISSET(MARK_ISSET); - last_replace = mallocstrcpy(last_replace, answer); - while (1) { - size_t match_len; + UNSET(MARK_ISSET); + edit_refresh(); +#endif - /* Sweet optimization by Rocco here. */ - fileptr = findnextstr(fileptr || replaceall || search_last_line, - FALSE, begin, *beginx, prevanswer, + while (findnextstr(TRUE, wholewords, current_save, current_x_save, + needle, #ifdef HAVE_REGEX_H - /* We should find a bol and/or eol regex only once per - * line. If the bol_eol flag is set, it means that the - * last search found one on the beginning line, so we - * should skip over the beginning line when doing this - * search. */ - bol_eol + /* We should find a bol and/or eol regex only once per line. If + * the bol_or_eol flag is set, it means that the last search + * found one on the beginning line, so we should skip over the + * beginning line when doing this search. */ + bol_or_eol #else - 0 + FALSE #endif - ); + ) != 0) { + + int i = 0; + size_t match_len; #ifdef HAVE_REGEX_H - /* If the bol_eol flag is set, we've found a match on the + /* If the bol_or_eol flag is set, we've found a match on the * beginning line already, and we're still on the beginning line * after the search, it means that we've wrapped around, so * we're done. */ - if (bol_eol && beginline && fileptr == begin) - fileptr = NULL; - /* Otherwise, set the beginline flag if we've found a match on - * the beginning line, reset the bol_eol flag, and continue. */ + if (bol_or_eol && begin_line && current == real_current) + break; + /* Otherwise, set the begin_line flag if we've found a match on + * the beginning line, reset the bol_or_eol flag, and + * continue. */ else { - if (fileptr == begin) - beginline = 1; - bol_eol = 0; + if (current == real_current) + begin_line = 1; + bol_or_eol = 0; } #endif - if (current->lineno <= edittop->lineno - || current->lineno >= editbot->lineno) - edit_update(current, CENTER); - - /* No more matches. Done! */ - if (fileptr == NULL) - break; - - /* Make sure only whole words are found. */ - if (wholewords && !is_whole_word(current_x, fileptr->data, prevanswer)) - continue; - - /* If we're here, we've found the search string. */ - if (numreplaced == -1) - numreplaced = 0; + edit_refresh(); #ifdef HAVE_REGEX_H if (ISSET(USE_REGEXP)) match_len = regmatches[0].rm_eo - regmatches[0].rm_so; else #endif - match_len = strlen(prevanswer); + match_len = strlen(needle); + + /* Record for the return value that we found the search string. */ + if (numreplaced == -1) + numreplaced = 0; if (!replaceall) { char *exp_word; @@ -709,36 +645,32 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin, curs_set(0); do_replace_highlight(TRUE, exp_word); - *i = do_yesno(1, _("Replace this instance?")); + i = do_yesno(1, _("Replace this instance?")); do_replace_highlight(FALSE, exp_word); free(exp_word); curs_set(1); - if (*i == -1) /* We canceled the replace. */ + if (i == -1) /* We canceled the replace. */ break; } #ifdef HAVE_REGEX_H - /* Set the bol_eol flag if we're doing a bol and/or eol regex + /* Set the bol_or_eol flag if we're doing a bol and/or eol regex * replace ("^", "$", or "^$"). */ - if (ISSET(USE_REGEXP) && regexec(&search_regexp, prevanswer, 0, NULL, REG_NOTBOL | REG_NOTEOL) == REG_NOMATCH) - bol_eol = 1; + if (ISSET(USE_REGEXP) && regexp_bol_or_eol(&search_regexp, + needle)) + bol_or_eol = 1; #endif - if (*i > 0 || replaceall) { /* Yes, replace it!!!! */ + if (i > 0 || replaceall) { /* Yes, replace it!!!! */ char *copy; int length_change; - if (*i == 2) + if (i == 2) replaceall = 1; - copy = replace_line(); - if (copy == NULL) { - statusbar(_("Replace failed: unknown subexpression!")); - replace_abort(); - return 0; - } + copy = replace_line(needle); length_change = strlen(copy) - strlen(current->data); @@ -752,10 +684,10 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin, #endif assert(0 <= match_len + length_change); - if (current == begin && current_x <= *beginx) { - if (*beginx < current_x + match_len) - *beginx = current_x + match_len; - *beginx += length_change; + if (current == real_current && current_x <= *real_current_x) { + if (*real_current_x < current_x + match_len) + *real_current_x = current_x + match_len; + *real_current_x += length_change; } /* Set the cursor at the last character of the replacement @@ -781,15 +713,20 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin, if (filebot->data[0] != '\0') new_magicline(); +#ifndef NANO_SMALL + if (mark_set) + SET(MARK_ISSET); +#endif + return numreplaced; } /* Replace a string. */ int do_replace(void) { - int i, numreplaced, beginx; - filestruct *begin; - char *prevanswer = NULL; + int i, numreplaced; + filestruct *edittop_save, *begin; + size_t beginx; if (ISSET(VIEW_MODE)) { print_view_warning(); @@ -798,35 +735,28 @@ int do_replace(void) } i = search_init(1); - switch (i) { - case -1: - statusbar(_("Replace Cancelled")); + if (i == -1) { /* Cancel, Go to Line, blank search + * string, or regcomp() failed. */ replace_abort(); return 0; - case 1: - do_replace(); - return 1; - case -2: + } else if (i == -2) { /* No Replace. */ do_search(); return 0; - case -3: - replace_abort(); + } else if (i == 1) /* Case Sensitive, Backwards, or Regexp + * search toggle. */ + do_replace(); + + if (i != 0) return 0; - } + /* If answer is not "", add answer to the search history list and + * copy answer into last_search. */ + if (answer[0] != '\0') { #ifndef NANO_SMALL - if (answer[0] != '\0') update_history(&search_history, answer); -#endif /* !NANO_SMALL */ - - /* If answer is now == "", copy last_search into answer - (and prevanswer)... */ - if (answer[0] == '\0') - answer = mallocstrcpy(answer, last_search); - else +#endif last_search = mallocstrcpy(last_search, answer); - - prevanswer = mallocstrcpy(prevanswer, last_search); + } #ifndef NANO_SMALL replace_history.current = (historytype *)&replace_history.next; @@ -840,29 +770,42 @@ int do_replace(void) _("Replace with")); #ifndef NANO_SMALL - if (i == 0 && answer[0] != '\0') + /* Add this replace string to the replace history list. i == 0 + * means that the string is not "". */ + if (i == 0) update_history(&replace_history, answer); -#endif /* !NANO_SMALL */ +#endif + + if (i != 0 && i != -2) { + if (i == -1) { /* Cancel. */ + if (last_replace[0] != '\0') + answer = mallocstrcpy(answer, last_replace); + statusbar(_("Replace Cancelled")); + } + replace_abort(); + return 0; + } + + last_replace = mallocstrcpy(last_replace, answer); + /* Save where we are. */ begin = current; beginx = current_x; - search_last_line = 0; + edittop_save = edittop; + search_last_line = FALSE; - numreplaced = do_replace_loop(prevanswer, begin, &beginx, FALSE, &i); + numreplaced = do_replace_loop(last_search, begin, &beginx, FALSE); - /* restore where we were */ + /* Restore where we were. */ current = begin; current_x = beginx; renumber_all(); - edit_update(current, CENTER); + edit_update(edittop_save, TOP); if (numreplaced >= 0) statusbar(P_("Replaced %d occurrence", "Replaced %d occurrences", numreplaced), numreplaced); - else - not_found_msg(prevanswer); - free(prevanswer); replace_abort(); return 1; } @@ -940,65 +883,56 @@ int do_find_bracket(void) char ch_under_cursor, wanted_ch; const char *pos, *brackets = "([{<>}])"; char regexp_pat[] = "[ ]"; - int offset, have_search_offscreen = 0, flagsave, current_x_save, count = 1; + int flagsave, current_x_save, count = 1; filestruct *current_save; ch_under_cursor = current->data[current_x]; -/* if ((!(pos = strchr(brackets, ch_under_cursor))) || (!((offset = pos - brackets) < 8))) { */ - - if (((pos = strchr(brackets, ch_under_cursor)) == NULL) || (((offset = pos - brackets) < 8) == 0)) { + pos = strchr(brackets, ch_under_cursor); + if (ch_under_cursor == '\0' || pos == NULL) { statusbar(_("Not a bracket")); return 1; } - blank_statusbar_refresh(); - - wanted_ch = *(brackets + ((strlen(brackets) - (offset + 1)))); + assert(strlen(brackets) % 2 == 0); + wanted_ch = brackets[(strlen(brackets) - 1) - (pos - brackets)]; current_x_save = current_x; current_save = current; flagsave = flags; SET(USE_REGEXP); -/* apparent near redundancy with regexp_pat[] here is needed, [][] works, [[]] doesn't */ + /* Apparent near redundancy with regexp_pat[] here is needed. + * "[][]" works, "[[]]" doesn't. */ - if (offset < (strlen(brackets) / 2)) { /* on a left bracket */ + if (pos < brackets + (strlen(brackets) / 2)) { /* On a left bracket. */ regexp_pat[1] = wanted_ch; regexp_pat[2] = ch_under_cursor; UNSET(REVERSE_SEARCH); - } else { /* on a right bracket */ + } else { /* On a right bracket. */ regexp_pat[1] = ch_under_cursor; regexp_pat[2] = wanted_ch; SET(REVERSE_SEARCH); } regexp_init(regexp_pat); + /* We constructed regexp_pat to be a valid expression. */ + assert(ISSET(REGEXP_COMPILED)); + search_last_line = 0; while (1) { - search_last_line = 0; - if (findnextstr(TRUE, TRUE, current, current_x, regexp_pat, 0) != NULL) { - have_search_offscreen |= search_offscreen; - - /* found identical bracket */ + if (findnextstr(FALSE, FALSE, current, current_x, regexp_pat, FALSE) != 0) { + /* Found identical bracket. */ if (current->data[current_x] == ch_under_cursor) count++; - else { - - /* found complementary bracket */ - if (!(--count)) { - if (have_search_offscreen) - edit_update(current, CENTER); - else - update_line(current, current_x); - placewewant = xplustabs(); - reset_cursor(); - break; - } + /* Found complementary bracket. */ + else if (--count == 0) { + edit_refresh(); + placewewant = xplustabs(); + break; } } else { - - /* didn't find either left or right bracket */ + /* Didn't find either a left or right bracket. */ statusbar(_("No matching bracket")); current_x = current_x_save; current = current_save; @@ -1007,8 +941,7 @@ int do_find_bracket(void) } } - if (ISSET(REGEXP_COMPILED)) - regexp_cleanup(); + regexp_cleanup(); flags = flagsave; return 0; } diff --git a/src/utils.c b/src/utils.c index af53c2ed..37d0bcff 100644 --- a/src/utils.c +++ b/src/utils.c @@ -30,6 +30,7 @@ #include "proto.h" #include "nano.h" +#ifdef HAVE_REGEX_H #ifdef BROKEN_REGEXEC #undef regexec int regexec_safe(const regex_t *preg, const char *string, size_t nmatch, @@ -40,7 +41,16 @@ int regexec_safe(const regex_t *preg, const char *string, size_t nmatch, return REG_NOMATCH; } #define regexec(preg, string, nmatch, pmatch, eflags) regexec_safe(preg, string, nmatch, pmatch, eflags) -#endif +#endif /* BROKEN_REGEXEC */ + +/* Assume that string will be found by regexec() if the REG_NOTBOL and + * REG_NOTEOL glags are not set. */ +int regexp_bol_or_eol(const regex_t *preg, const char *string) +{ + return (regexec(preg, string, 0, NULL, REG_NOTBOL | REG_NOTEOL) == + REG_NOMATCH); +} +#endif /* HAVE_REGEX_H */ int is_cntrl_char(int c) { @@ -182,29 +192,32 @@ const char *stristr(const char *haystack, const char *needle) return NULL; } -/* If we are searching backwards, we will find the last match - * that starts no later than rev_start. If we are doing a regexp search, - * then line_pos should be 0 if haystack starts at the beginning of a - * line, and positive otherwise. In the regexp case, we fill in the - * global variable regmatches with at most 9 subexpression matches. Also, - * all .rm_so elements are relative to the start of the whole match, so - * regmatches[0].rm_so == 0. */ +/* If we are searching backwards, we will find the last match that + * starts no later than start. Otherwise we find the first match + * starting no earlier than start. If we are doing a regexp search, we + * fill in the global variable regmatches with at most 9 subexpression + * matches. Also, all .rm_so elements are relative to the start of the + * whole match, so regmatches[0].rm_so == 0. */ const char *strstrwrapper(const char *haystack, const char *needle, - const char *rev_start, int line_pos) + const char *start) { + /* start can be 1 character before the start or after the end of the + * line. In either case, we just say there is no match found. */ + if ((start > haystack && *(start - 1) == '\0') || start < haystack) + return NULL; + assert(haystack != NULL && needle != NULL && start != NULL); #ifdef HAVE_REGEX_H if (ISSET(USE_REGEXP)) { #ifndef NANO_SMALL if (ISSET(REVERSE_SEARCH)) { - /* When doing a backwards search, haystack is a whole line. */ - if (regexec(&search_regexp, haystack, 1, regmatches, 0) == 0 && - haystack + regmatches[0].rm_so <= rev_start) { + if (regexec(&search_regexp, haystack, 1, regmatches, 0) == 0 + && haystack + regmatches[0].rm_so <= start) { const char *retval = haystack + regmatches[0].rm_so; /* Search forward until there is no more match. */ while (regexec(&search_regexp, retval + 1, 1, regmatches, - REG_NOTBOL) == 0 && - retval + 1 + regmatches[0].rm_so <= rev_start) + REG_NOTBOL) == 0 && retval + 1 + + regmatches[0].rm_so <= start) retval += 1 + regmatches[0].rm_so; /* Finally, put the subexpression matches in global * variable regmatches. The REG_NOTBOL flag doesn't @@ -214,9 +227,9 @@ const char *strstrwrapper(const char *haystack, const char *needle, } } else #endif /* !NANO_SMALL */ - if (regexec(&search_regexp, haystack, 10, regmatches, - line_pos > 0 ? REG_NOTBOL : 0) == 0) { - const char *retval = haystack + regmatches[0].rm_so; + if (regexec(&search_regexp, start, 10, regmatches, + start > haystack ? REG_NOTBOL : 0) == 0) { + const char *retval = start + regmatches[0].rm_so; regexec(&search_regexp, retval, 10, regmatches, 0); return retval; @@ -224,16 +237,21 @@ const char *strstrwrapper(const char *haystack, const char *needle, return NULL; } #endif /* HAVE_REGEX_H */ -#ifndef NANO_SMALL +#if !defined(DISABLE_SPELLER) || !defined(NANO_SMALL) if (ISSET(CASE_SENSITIVE)) { +#ifndef NANO_SMALL if (ISSET(REVERSE_SEARCH)) - return revstrstr(haystack, needle, rev_start); + return revstrstr(haystack, needle, start); else +#endif return strstr(haystack, needle); - } else if (ISSET(REVERSE_SEARCH)) - return revstristr(haystack, needle, rev_start); + } +#endif /* !DISABLE_SPELLER || !NANO_SMALL */ +#ifndef NANO_SMALL + else if (ISSET(REVERSE_SEARCH)) + return revstristr(haystack, needle, start); #endif - return stristr(haystack, needle); + return stristr(start, needle); } /* This is a wrapper for the perror function. The wrapper takes care of diff --git a/src/winio.c b/src/winio.c index 51c734a4..fc9359b1 100644 --- a/src/winio.c +++ b/src/winio.c @@ -1523,23 +1523,17 @@ size_t get_page_start(size_t column) * cursor at (current_y, current_x). */ void reset_cursor(void) { - const filestruct *ptr = edittop; - size_t x; - /* Yuck. This condition can be true after open_file() when opening * the first file. */ if (edittop == NULL) return; - current_y = 0; - - while (ptr != current && ptr != editbot && ptr->next != NULL) { - ptr = ptr->next; - current_y++; - } + current_y = current->lineno - edittop->lineno; + if (current_y < editwinrows) { + size_t x = xplustabs(); - x = xplustabs(); - wmove(edit, current_y, x - get_page_start(x)); + wmove(edit, current_y, x - get_page_start(x)); + } } /* edit_add() takes care of the job of actually painting a line into the @@ -1878,6 +1872,9 @@ void update_line(const filestruct *fileptr, size_t index) if (line < 0 || line >= editwinrows) return; + /* Don't make the cursor jump around the screen while updating. */ + leaveok(edit, TRUE); + /* First, blank out the line (at a minimum) */ mvwaddstr(edit, line, 0, hblank); @@ -1898,6 +1895,9 @@ void update_line(const filestruct *fileptr, size_t index) mvwaddch(edit, line, 0, '$'); if (strlenpt(fileptr->data) > page_start + COLS) mvwaddch(edit, line, COLS - 1, '$'); + + /* Let the cursor jump around the screen again. */ + leaveok(edit, FALSE); } /* This function updates current, based on where current_y is; @@ -1948,27 +1948,27 @@ void edit_refresh(void) edit_update(current, CENTER); else { int nlines = 0; + const filestruct *foo = edittop; - /* Don't make the cursor jump around the screen whilst - * updating. */ - leaveok(edit, TRUE); +#ifdef DEBUG + fprintf(stderr, "edit_refresh(): edittop->lineno = %ld\n", edittop->lineno); +#endif - editbot = edittop; while (nlines < editwinrows) { - update_line(editbot, current_x); + update_line(foo, current_x); nlines++; - if (editbot->next == NULL) + if (foo->next == NULL) break; - editbot = editbot->next; + foo = foo->next; } while (nlines < editwinrows) { mvwaddstr(edit, nlines, 0, hblank); nlines++; } + reset_cursor(); /* What the hell are we expecting to update the screen if this * isn't here? Luck? */ wrefresh(edit); - leaveok(edit, FALSE); } } -- 2.39.5