From: David Lawrence Ramsey Date: Tue, 15 Nov 2005 23:45:29 +0000 (+0000) Subject: overhaul the bracket searching code so that it no longer requires regex X-Git-Tag: v1.3.10~63 X-Git-Url: https://git.wh0rd.org/?a=commitdiff_plain;h=c5c5230b9d246621adc53b68a3795a2a12303efd;p=nano.git overhaul the bracket searching code so that it no longer requires regex support to work, and add some miscellaneous search code cleanups git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@3183 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- diff --git a/ChangeLog b/ChangeLog index 323a1a45..a3521b1c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -101,6 +101,10 @@ CVS code - nano is built with --disable-nls. Changes to Makefile.am and doc/man/Makefile.am. (Mike Frysinger) - Rename the NANO_SMALL #define to NANO_TINY. (DLR) + - Overhaul the bracket searching code so that it no longer + requires regex support to work. New functions revstrpbrk() + and find_bracket_match(); changes to sc_init_one() and + do_find_bracket(). (DLR) - chars.c: mbwidth() - If wcwidth() returns -1 for the character passed in, treat the @@ -132,6 +136,15 @@ CVS code - - rcfile.c: do_rcfile() - Remove unneeded assert. (DLR) +- search.c: + findnextstr() + - Remove parameter can_display_wrap, as it's always set to TRUE + now, and rename parameter wholeword to whole_word for + consistency. (DLR) + do_replace_loop() + - Change order of parameters to more closely match those of + findnextstr(), and rename parameter wholewords to whole_word + for consistency. (DLR) - text.c: begpar() - Return FALSE if foo is NULL, as inpar() does. (DLR) diff --git a/src/chars.c b/src/chars.c index 90808a91..09b2b9b1 100644 --- a/src/chars.c +++ b/src/chars.c @@ -814,6 +814,26 @@ size_t mbstrnlen(const char *s, size_t maxlen) return strnlen(s, maxlen); } +#ifndef NANO_TINY +/* This function is equivalent to strpbrk(), except in that it scans the + * string in reverse, starting at rev_start. */ +char *revstrpbrk(const char *s, const char *accept, const char + *rev_start) +{ + assert(s != NULL && accept != NULL && rev_start != NULL); + + for (; rev_start >= s; rev_start--) { + const char *q = (*rev_start == '\0') ? NULL : strchr(accept, + *rev_start); + + if (q != NULL) + return (char *)rev_start; + } + + return NULL; +} +#endif /* !NANO_TINY */ + #ifndef DISABLE_JUSTIFY /* This function is equivalent to strchr() for multibyte strings. */ char *mbstrchr(const char *s, char *c) diff --git a/src/global.c b/src/global.c index 960112ea..984c13a4 100644 --- a/src/global.c +++ b/src/global.c @@ -313,7 +313,7 @@ void shortcut_init(bool unjustify) #ifndef DISABLE_JUSTIFY const char *nano_fulljustify_msg = N_("Justify the entire file"); #endif -#if !defined(NANO_TINY) && defined(HAVE_REGEX_H) +#ifndef NANO_TINY const char *nano_bracket_msg = N_("Find other bracket"); #endif const char *nano_cancel_msg = N_("Cancel the current function"); @@ -594,7 +594,7 @@ void shortcut_init(bool unjustify) NANO_NO_KEY, NANO_NO_KEY, NOVIEW, do_full_justify); #endif -#if !defined(NANO_TINY) && defined(HAVE_REGEX_H) +#ifndef NANO_TINY sc_init_one(&main_list, NANO_NO_KEY, N_("Find Other Bracket"), IFHELP(nano_bracket_msg, NANO_BRACKET_KEY), NANO_NO_KEY, NANO_NO_KEY, VIEW, do_find_bracket); diff --git a/src/proto.h b/src/proto.h index e9872176..8e93bdc0 100644 --- a/src/proto.h +++ b/src/proto.h @@ -196,6 +196,10 @@ size_t mbstrlen(const char *s); size_t nstrnlen(const char *s, size_t maxlen); #endif size_t mbstrnlen(const char *s, size_t maxlen); +#ifndef NANO_TINY +char *revstrpbrk(const char *s, const char *accept, const char + *rev_start); +#endif #ifndef DISABLE_JUSTIFY char *mbstrchr(const char *s, char *c); #ifdef ENABLE_NANORC @@ -489,9 +493,8 @@ void not_found_msg(const char *str); void search_abort(void); void search_init_globals(void); int search_init(bool replacing, bool use_answer); -bool findnextstr(bool can_display_wrap, bool wholeword, bool - no_sameline, const filestruct *begin, size_t begin_x, const char - *needle, size_t *needle_len); +bool findnextstr(bool whole_word, bool no_sameline, const filestruct + *begin, size_t begin_x, const char *needle, size_t *needle_len); void findnextstr_wrap_reset(void); void do_search(void); #ifndef NANO_TINY @@ -502,9 +505,9 @@ void replace_abort(void); int replace_regexp(char *string, bool create); #endif char *replace_line(const char *needle); -ssize_t do_replace_loop(const char *needle, const filestruct - *real_current, size_t *real_current_x, bool wholewords, bool - *canceled); +ssize_t do_replace_loop(bool whole_word, bool *canceled, const + filestruct *real_current, size_t *real_current_x, const char + *needle); void do_replace(void); void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer, bool interactive, bool save_pos, bool allow_update); @@ -514,9 +517,8 @@ void do_gotopos(ssize_t line, size_t pos_x, ssize_t pos_y, size_t pos_pww); #endif #ifndef NANO_TINY -#ifdef HAVE_REGEX_H +bool find_bracket_match(bool reverse, const char *bracket_set); void do_find_bracket(void); -#endif #ifdef ENABLE_NANORC bool history_has_changed(void); #endif diff --git a/src/search.c b/src/search.c index 3ee62e62..8b49bd33 100644 --- a/src/search.c +++ b/src/search.c @@ -256,21 +256,18 @@ int search_init(bool replacing, bool use_answer) /* Look for needle, starting at (current, current_x). If no_sameline is * TRUE, skip over begin when looking for needle. begin is the line - * where we first started searching, at column begin_x. If - * can_display_wrap is TRUE, we put messages on the statusbar and wrap - * around the file boundaries. The return value specifies whether we - * found anything. If we did, set needle_len to the length of the - * string we found if it isn't NULL. */ -bool findnextstr(bool can_display_wrap, bool wholeword, bool - no_sameline, const filestruct *begin, size_t begin_x, const char - *needle, size_t *needle_len) + * where we first started searching, at column begin_x. The return + * value specifies whether we found anything. If we did, set needle_len + * to the length of the string we found if it isn't NULL. */ +bool findnextstr(bool whole_word, bool no_sameline, const filestruct + *begin, size_t begin_x, const char *needle, size_t *needle_len) { filestruct *fileptr = openfile->current; const char *rev_start = NULL, *found = NULL; size_t found_len; /* The length of the match we found. */ size_t current_x_find = 0; - /* The location of the match we found. */ + /* The location in the current line of the match we found. */ ssize_t current_y_find = openfile->current_y; /* rev_start might end up 1 character before the start or after the @@ -304,7 +301,7 @@ bool findnextstr(bool can_display_wrap, bool wholeword, bool /* If we're searching for whole words, see if this potential * match is a whole word. */ - if (wholeword) { + if (whole_word) { char *word = mallocstrncpy(NULL, found, found_len + 1); word[found_len] = '\0'; @@ -317,15 +314,14 @@ bool findnextstr(bool can_display_wrap, bool wholeword, bool * match isn't a whole word, or if we're not allowed to find * a match on the same line we started on and this potential * match is on that line, continue searching. */ - if ((!wholeword || found_whole) && (!no_sameline || + if ((!whole_word || found_whole) && (!no_sameline || fileptr != openfile->current)) break; } /* We've finished processing the file, so get out. */ if (search_last_line) { - if (can_display_wrap) - not_found_msg(needle); + not_found_msg(needle); return FALSE; } @@ -343,9 +339,6 @@ bool findnextstr(bool can_display_wrap, bool wholeword, bool /* Start or end of buffer reached, so wrap around. */ if (fileptr == NULL) { - if (!can_display_wrap) - return FALSE; - #ifndef NANO_TINY if (ISSET(BACKWARDS_SEARCH)) { fileptr = openfile->filebot; @@ -358,8 +351,7 @@ bool findnextstr(bool can_display_wrap, bool wholeword, bool } #endif - if (can_display_wrap) - statusbar(_("Search Wrapped")); + statusbar(_("Search Wrapped")); } /* Original start line reached. */ @@ -385,8 +377,7 @@ bool findnextstr(bool can_display_wrap, bool wholeword, bool current_x_find > begin_x #endif ) { - if (can_display_wrap) - not_found_msg(needle); + not_found_msg(needle); return FALSE; } @@ -450,7 +441,7 @@ void do_search(void) #endif findnextstr_wrap_reset(); - didfind = findnextstr(TRUE, FALSE, FALSE, openfile->current, + didfind = findnextstr(FALSE, FALSE, openfile->current, openfile->current_x, answer, NULL); /* Check to see if there's only one occurrence of the string and @@ -465,7 +456,7 @@ void do_search(void) * which case it's the only occurrence. */ if (ISSET(USE_REGEXP) && regexp_bol_or_eol(&search_regexp, last_search)) { - didfind = findnextstr(TRUE, FALSE, TRUE, openfile->current, + didfind = findnextstr(FALSE, TRUE, openfile->current, openfile->current_x, answer, NULL); if (fileptr == openfile->current && fileptr_x == openfile->current_x && !didfind) @@ -506,7 +497,7 @@ void do_research(void) #endif findnextstr_wrap_reset(); - didfind = findnextstr(TRUE, FALSE, FALSE, openfile->current, + didfind = findnextstr(FALSE, FALSE, openfile->current, openfile->current_x, last_search, NULL); /* Check to see if there's only one occurrence of the string and @@ -521,9 +512,8 @@ void do_research(void) * 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, TRUE, - openfile->current, openfile->current_x, answer, - NULL); + didfind = findnextstr(FALSE, TRUE, openfile->current, + openfile->current_x, answer, NULL); if (fileptr == openfile->current && fileptr_x == openfile->current_x && !didfind) statusbar(_("This is the only occurrence")); @@ -649,9 +639,9 @@ char *replace_line(const char *needle) * needle is the string to seek. We replace it with answer. Return -1 * if needle isn't found, else the number of replacements performed. If * canceled isn't NULL, set it to TRUE if we canceled. */ -ssize_t do_replace_loop(const char *needle, const filestruct - *real_current, size_t *real_current_x, bool wholewords, bool - *canceled) +ssize_t do_replace_loop(bool whole_word, bool *canceled, const + filestruct *real_current, size_t *real_current_x, const char + *needle) { ssize_t numreplaced = -1; size_t match_len; @@ -685,7 +675,7 @@ ssize_t do_replace_loop(const char *needle, const filestruct *canceled = FALSE; findnextstr_wrap_reset(); - while (findnextstr(TRUE, wholewords, + while (findnextstr(whole_word, #ifdef HAVE_REGEX_H /* 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 @@ -922,8 +912,8 @@ void do_replace(void) begin_x = openfile->current_x; pww_save = openfile->placewewant; - numreplaced = do_replace_loop(last_search, begin, &begin_x, FALSE, - NULL); + numreplaced = do_replace_loop(FALSE, NULL, begin, &begin_x, + last_search); /* Restore where we were. */ openfile->edittop = edittop_save; @@ -1034,22 +1024,95 @@ void do_gotopos(ssize_t line, size_t pos_x, ssize_t pos_y, size_t #endif #ifndef NANO_TINY -#ifdef HAVE_REGEX_H +/* Search for a match to one of the two characters in bracket_set. If + * reverse is TRUE, search backwards. Otherwise, search forwards. */ +bool find_bracket_match(bool reverse, const char *bracket_set) +{ + filestruct *fileptr = openfile->current; + const char *rev_start = NULL, *found = NULL; + size_t current_x_find = 0; + /* The location in the current line of the match we found. */ + ssize_t current_y_find = openfile->current_y; + + assert(strlen(bracket_set) == 2); + + /* rev_start might end up 1 character before the start or after the + * end of the line. This won't be a problem because we'll skip over + * it below in that case, and rev_start will be properly set when + * the search continues on the previous or next line. */ + rev_start = reverse ? fileptr->data + (openfile->current_x - 1) : + fileptr->data + (openfile->current_x + 1); + + /* Look for either of the two characters in bracket_set. rev_start + * can be 1 character before the start or after the end of the line. + * In either case, just act as though no match is found. */ + while (TRUE) { + found = ((rev_start > fileptr->data && *(rev_start - 1) == + '\0') || rev_start < fileptr->data) ? NULL : (reverse ? + revstrpbrk(fileptr->data, bracket_set, rev_start) : + strpbrk(rev_start, bracket_set)); + + /* We've found a potential match. */ + if (found != NULL) + break; + + if (reverse) { + fileptr = fileptr->prev; + current_y_find--; + } else { + fileptr = fileptr->next; + current_y_find++; + } + + /* Start or end of buffer reached, so get out. */ + if (fileptr == NULL) + return FALSE; + + rev_start = fileptr->data; + if (reverse) + rev_start += strlen(fileptr->data); + } + + /* We found an instance. */ + current_x_find = found - fileptr->data; + + /* We've definitely found something. */ + openfile->current = fileptr; + openfile->current_x = current_x_find; + openfile->placewewant = xplustabs(); + openfile->current_y = current_y_find; + + return TRUE; +} + +/* Search for a match to the bracket at the current cursor position, if + * there is one. */ void do_find_bracket(void) { - const char *bracket_pat = "()<>[]{}", *pos; - char regex_pat[] = "[ ]", ch, wanted_ch; filestruct *current_save; size_t current_x_save, pww_save; - bool regexp_set = ISSET(USE_REGEXP); - bool backwards_search_set = ISSET(BACKWARDS_SEARCH); - int count = 1; - - assert(strlen(bracket_pat) % 2 == 0); + const char *bracket_list = "()<>[]{}"; + /* The list of brackets we can find matches to. */ + const char *pos; + /* The location in bracket_list of the bracket at the current + * cursor position. */ + char ch; + /* The bracket at the current cursor position. */ + char wanted_ch; + /* The bracket complementing the bracket at the current cursor + * position. */ + char bracket_set[3]; + /* The pair of characters in ch and wanted_ch. */ + size_t count = 1; + /* The initial bracket count. */ + bool reverse; + /* The direction we search. */ + + assert(strlen(bracket_list) % 2 == 0); ch = openfile->current->data[openfile->current_x]; - if (ch == '\0' || (pos = strchr(bracket_pat, ch)) == NULL) { + if (ch == '\0' || (pos = strchr(bracket_list, ch)) == NULL) { statusbar(_("Not a bracket")); return; } @@ -1059,40 +1122,17 @@ void do_find_bracket(void) current_x_save = openfile->current_x; pww_save = openfile->placewewant; - /* Turn regular expression searches on. */ - SET(USE_REGEXP); - /* If we're on an opening bracket, we want to search forwards for a * closing bracket, and if we're on a closing bracket, we want to - * search backwards for an opening bracket. - * - * We replace the spaces in regex_pat with the opening and closing - * brackets, and then do a regular expression search using it. We - * have to put the closing bracket first when we do the latter, - * since "[[]]" won't work properly, but "[][]" will. */ - if ((pos - bracket_pat) % 2 == 0) { - wanted_ch = *(pos + 1); - regex_pat[1] = wanted_ch; - regex_pat[2] = ch; - UNSET(BACKWARDS_SEARCH); - } else { - wanted_ch = *(pos - 1); - regex_pat[1] = ch; - regex_pat[2] = wanted_ch; - SET(BACKWARDS_SEARCH); - } - - /* Compile the regular expression in regex_pat. */ - regexp_init(regex_pat); - - /* The regular expression in regex_pat should always be valid. */ - assert(regexp_compiled); - - findnextstr_wrap_reset(); + * search backwards for an opening bracket. */ + reverse = ((pos - bracket_list) % 2 != 0); + wanted_ch = reverse ? *(pos - 1) : *(pos + 1); + bracket_set[0] = ch; + bracket_set[1] = wanted_ch; + bracket_set[2] = '\0'; while (TRUE) { - if (findnextstr(FALSE, FALSE, FALSE, openfile->current, - openfile->current_x, regex_pat, NULL)) { + if (find_bracket_match(reverse, bracket_set)) { /* If we found an identical bracket, increment count. If we * found a complementary bracket, decrement it. */ count += (openfile->current->data[openfile->current_x] == @@ -1114,21 +1154,7 @@ void do_find_bracket(void) break; } } - - /* Decompile the regular expression in regex_pat. */ - regexp_cleanup(); - - /* Restore search/replace direction. */ - if (backwards_search_set) - SET(BACKWARDS_SEARCH); - else - UNSET(BACKWARDS_SEARCH); - - /* Restore regular expression usage setting. */ - if (!regexp_set) - UNSET(USE_REGEXP); } -#endif /* HAVE_REGEX_H */ #ifdef ENABLE_NANORC /* Indicate whether any of the history lists have changed. */ diff --git a/src/text.c b/src/text.c index 03135775..6724ea17 100644 --- a/src/text.c +++ b/src/text.c @@ -1589,9 +1589,9 @@ bool do_int_spell_fix(const char *word) openfile->current_x = (size_t)-1; openfile->placewewant = 0; - /* Find the first whole-word occurrence of word. */ + /* Find the first whole occurrence of word. */ findnextstr_wrap_reset(); - while (findnextstr(TRUE, TRUE, FALSE, openfile->fileage, 0, word, + while (findnextstr(TRUE, FALSE, openfile->fileage, 0, word, &match_len)) { if (is_whole_word(openfile->current_x, openfile->current->data, word)) { @@ -1617,8 +1617,8 @@ bool do_int_spell_fix(const char *word) if (!canceled && strcmp(word, answer) != 0) { openfile->current_x--; - do_replace_loop(word, openfile->current, - &openfile->current_x, TRUE, &canceled); + do_replace_loop(TRUE, &canceled, openfile->current, + &openfile->current_x, word); } break;