Reverse Search by Ken Tyler

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@685 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
master
Chris Allegretta 2001-06-13 02:35:44 +00:00
parent a75bc41faf
commit e4933a393a
6 changed files with 202 additions and 73 deletions

View File

@ -35,6 +35,11 @@ Cvs code -
insert and write routines can't share shortcut lists anymore),
new args to do_writeout and write_file called append, and of source
code changes to those functions.
- Allow backwards searching. Drastic rewrite of the search prompt
string by Chris. All other code by Ken Tyler. New globals
nano_reverse_msg, new functions revstrstr and revstrcasestr,
many changes to search functions. Not too big a code size
increase!
- configure.in:
- New option, --enable-nanorc, which allows people to have a .nanorc
initialization file and set options normally used on the command

View File

@ -194,7 +194,7 @@ void shortcut_init(int unjustify)
"", *nano_backspace_msg = "", *nano_tab_msg =
"", *nano_enter_msg = "", *nano_case_msg =
"", *nano_cancel_msg = "", *nano_unjustify_msg =
"", *nano_append_msg = "";
"", *nano_append_msg = "", *nano_reverse_msg = "";
#ifndef NANO_SMALL
char *nano_tofiles_msg = "";
@ -236,6 +236,7 @@ void shortcut_init(int unjustify)
nano_gotodir_msg = _("Goto Directory");
nano_cancel_msg = _("Cancel the current function");
nano_append_msg = _("Append to the current file");
nano_reverse_msg = _("Search Backwards");
#endif
sc_init_one(&main_list[0], NANO_HELP_KEY, _("Get Help"),
@ -369,9 +370,11 @@ void shortcut_init(int unjustify)
_("Goto Line"), nano_goto_msg, 0, 0, 0, VIEW,
do_gotoline_void);
sc_init_one(&whereis_list[5], NANO_CANCEL_KEY, _("Cancel"),
nano_cancel_msg, 0, 0, 0, VIEW, 0);
sc_init_one(&whereis_list[5], NANO_REVERSESEARCH_KEY, _("Backward"),
nano_reverse_msg, 0, 0, 0, VIEW, 0);
sc_init_one(&whereis_list[6], NANO_CANCEL_KEY, _("Cancel"),
nano_cancel_msg, 0, 0, 0, VIEW, 0);
sc_init_one(&replace_list[0], NANO_FIRSTLINE_KEY, _("First Line"),
nano_firstline_msg, 0, 0, 0, VIEW, do_first_line);
@ -389,9 +392,11 @@ void shortcut_init(int unjustify)
_("Goto Line"), nano_goto_msg, 0, 0, 0, VIEW,
do_gotoline_void);
sc_init_one(&replace_list[5], NANO_CANCEL_KEY, _("Cancel"),
nano_cancel_msg, 0, 0, 0, VIEW, 0);
sc_init_one(&replace_list[5], NANO_REVERSESEARCH_KEY, _("Backward"),
nano_reverse_msg, 0, 0, 0, VIEW, 0);
sc_init_one(&replace_list[6], NANO_CANCEL_KEY, _("Cancel"),
nano_cancel_msg, 0, 0, 0, VIEW, 0);
sc_init_one(&replace_list_2[0], NANO_FIRSTLINE_KEY, _("First Line"),

6
nano.h
View File

@ -123,6 +123,7 @@ typedef struct rcoption {
#define TEMP_OPT (1<<16)
#define CUT_TO_END (1<<17)
#define DISABLE_CURPOS (1<<18)
#define REVERSE_SEARCH (1<<19)
/* Control key sequences, changing these would be very very bad */
@ -205,6 +206,7 @@ know what you're doing */
#define NANO_REPLACE_FKEY KEY_F(14)
#define NANO_ALT_REPLACE_KEY NANO_ALT_R
#define NANO_OTHERSEARCH_KEY NANO_CONTROL_R
#define NANO_REVERSESEARCH_KEY NANO_CONTROL_B
#define NANO_PREVPAGE_KEY NANO_CONTROL_Y
#define NANO_PREVPAGE_FKEY KEY_F(7)
#define NANO_NEXTPAGE_KEY NANO_CONTROL_V
@ -253,8 +255,8 @@ know what you're doing */
#define MAIN_LIST_LEN 26
#define MAIN_VISIBLE 12
#define WHEREIS_LIST_LEN 6
#define REPLACE_LIST_LEN 6
#define WHEREIS_LIST_LEN 7
#define REPLACE_LIST_LEN 7
#define REPLACE_LIST_2_LEN 3
#define GOTO_LIST_LEN 3
#define GOTODIR_LIST_LEN 1

View File

@ -71,8 +71,10 @@ extern toggle toggles[TOGGLE_LEN];
/* Programs we want available */
char *revstrstr(char *haystack, char *needle, char *rev_start);
char *strcasestr(char *haystack, char *needle);
char *strstrwrapper(char *haystack, char *needle);
char *revstrcasestr(char *haystack, char *needle, char *rev_start);
char *strstrwrapper(char *haystack, char *needle, char *rev_start);
int search_init(int replacing);
int renumber(filestruct * fileptr);
int free_filestruct(filestruct * src);

174
search.c
View File

@ -74,7 +74,7 @@ int search_init(int replacing)
{
int i = 0;
char *buf;
char *prompt, *reprompt = "";
char *prompt;
static char *backupstring = NULL;
search_init_globals();
@ -114,22 +114,21 @@ int search_init(int replacing)
else
strcpy(buf, "");
if (ISSET(USE_REGEXP) && ISSET(CASE_SENSITIVE))
prompt = _("Case Sensitive Regexp Search%s%s");
else if (ISSET(USE_REGEXP))
prompt = _("Regexp Search%s%s");
else if (ISSET(CASE_SENSITIVE))
prompt = _("Case Sensitive Search%s%s");
else
prompt = _("Search%s%s");
if (replacing)
reprompt = _(" (to replace)");
/* Instead of having a million if statements here to determine
the prompt, we instead just have a hundred "? :" calls in
the statusq call. I hope no one ever has to modify this :-) */
prompt = "%s%s%s%s%s%s";
/* This is now one simple call. It just does a lot */
i = statusq(0, replacing ? replace_list : whereis_list,
replacing ? REPLACE_LIST_LEN : WHEREIS_LIST_LEN, backupstring,
prompt, reprompt, buf);
prompt,
ISSET(CASE_SENSITIVE) ? _("Case Sensitive ") : "",
ISSET(USE_REGEXP) ? _("Regexp ") : "",
_("Search"),
ISSET(REVERSE_SEARCH) ? _(" Backwards") : "",
replacing ? _(" (to replace)") : "",
buf);
/* Cancel any search, or just return with no previous search */
if ((i == -1) || (i < 0 && !last_search[0])) {
@ -173,6 +172,17 @@ int search_init(int replacing)
} else if (i == NANO_OTHERSEARCH_KEY) {
backupstring = mallocstrcpy(backupstring, answer);
return -2; /* Call the opposite search function */
} else if (i == NANO_REVERSESEARCH_KEY) {
free(backupstring);
backupstring = NULL;
backupstring = mallocstrcpy(backupstring, answer);
if (ISSET(REVERSE_SEARCH))
UNSET(REVERSE_SEARCH);
else
SET(REVERSE_SEARCH);
return 1;
} else if (i == NANO_FROMSEARCHTOGOTO_KEY) {
free(backupstring);
backupstring = NULL;
@ -207,68 +217,124 @@ filestruct *findnextstr(int quiet, filestruct * begin, int beginx,
char *needle)
{
filestruct *fileptr;
char *searchstr, *found = NULL, *tmp;
char *searchstr, *rev_start = NULL, *found = NULL;
int past_editbot = 0, current_x_find;
fileptr = current;
current_x_find = current_x + 1;
if (!ISSET(REVERSE_SEARCH)) { /* forward search */
/* Are we searching the last line? (i.e. the line where search started) */
if ((fileptr == begin) && (current_x_find < beginx))
search_last_line = 1;
current_x_find = current_x + 1;
/* Make sure we haven't passed the end of the string */
if (strlen(fileptr->data) < current_x_find)
current_x_find--;
/* Are we now back to the line where the search started) */
if ((fileptr == begin) && (current_x_find < beginx))
search_last_line = 1;
searchstr = &fileptr->data[current_x_find];
/* Make sure we haven't passed the end of the string */
if (strlen(fileptr->data) < current_x_find)
current_x_find--;
/* Look for needle in searchstr */
while ((found = strstrwrapper(searchstr, needle)) == NULL) {
searchstr = &fileptr->data[current_x_find];
/* finished processing file, get out */
if (search_last_line) {
/* Look for needle in searchstr */
while ((found = strstrwrapper(searchstr, needle, rev_start)) == NULL) {
/* finished processing file, get out */
if (search_last_line) {
if (!quiet)
not_found_msg(needle);
return NULL;
}
fileptr = fileptr->next;
if (!past_editbot && (fileptr == editbot))
past_editbot = 1;
/* EOF reached ?, wrap around once */
if (fileptr == NULL) {
fileptr = fileage;
past_editbot = 1;
if (!quiet)
statusbar(_("Search Wrapped"));
}
/* Original start line reached */
if (fileptr == begin)
search_last_line = 1;
searchstr = fileptr->data;
}
/* 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;
}
fileptr = fileptr->next;
} else { /* reverse search */
if (!past_editbot && (fileptr == editbot))
past_editbot = 1;
current_x_find = current_x - 1;
/* EOF reached, wrap around once */
if (fileptr == NULL) {
fileptr = fileage;
past_editbot = 1;
if (!quiet)
statusbar(_("Search Wrapped"));
}
/* Original start line reached */
if (fileptr == begin)
/* Are we now back to the line where the search started) */
if ((fileptr == begin) && (current_x_find > beginx))
search_last_line = 1;
/* Make sure we haven't passed the begining of the string */
#if 0 /* Is this required here ? */
if (!(&fileptr->data[current_x_find] - fileptr->data))
current_x_find++;
#endif
rev_start = &fileptr->data[current_x_find];
searchstr = fileptr->data;
/* Look for needle in searchstr */
while ((found = strstrwrapper(searchstr, needle, rev_start)) == NULL) {
/* finished processing file, get out */
if (search_last_line) {
if (!quiet)
not_found_msg(needle);
return NULL;
}
fileptr = fileptr->prev;
/* ? */ if (!past_editbot && (fileptr == edittop->prev))
past_editbot = 1;
/* SOF reached ?, wrap around once */
/* ? */ if (fileptr == NULL) {
fileptr = filebot;
past_editbot = 1;
if (!quiet)
statusbar(_("Search Wrapped"));
}
/* Original start line reached */
if (fileptr == begin)
search_last_line = 1;
searchstr = fileptr->data;
rev_start = fileptr->data + strlen(fileptr->data);
}
/* 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;
}
}
/* We found an instance */
current_x_find = 0;
for (tmp = fileptr->data; tmp != found; tmp++)
current_x_find++;
/* Ensure we haven't wrapped around again! */
if ((search_last_line) && (current_x_find >= beginx)) {
if (!quiet)
not_found_msg(needle);
return NULL;
}
/* 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;

71
utils.c
View File

@ -47,6 +47,31 @@ void lowercase(char *src)
}
}
char *revstrstr(char *haystack, char *needle, char *rev_start)
{
char *p, *q, *r;
for(p = rev_start ; p >= haystack ; --p) {
for (r = p, q = needle ; (*q == *r) && (*q != '\0') ; r++, q++)
;
if (*q == '\0')
return p;
}
return 0;
}
char *revstrcasestr(char *haystack, char *needle, char *rev_start)
{
char *p, *q, *r;
for(p = rev_start ; p >= haystack ; --p) {
for (r = p, q = needle ; (tolower(*q) == tolower(*r)) && (*q != '\0') ; r++, q++)
;
if (*q == '\0')
return p;
}
return 0;
}
/* This is now mutt's version (called mutt_stristr) because it doesn't
use memory allocation to do a simple search (yuck). */
@ -59,31 +84,55 @@ char *strcasestr(char *haystack, char *needle)
if (!needle)
return (haystack);
while (*(p = haystack))
{
while (*(p = haystack)) {
for (q = needle; *p && *q && tolower (*p) == tolower (*q); p++, q++)
;
if (!*q)
return (haystack);
haystack++;
haystack++;
}
return NULL;
}
char *strstrwrapper(char *haystack, char *needle)
char *strstrwrapper(char *haystack, char *needle, char *rev_start)
{
#ifdef HAVE_REGEX_H
int result;
char *i, *j;
if (ISSET(USE_REGEXP)) {
int result = regexec(&search_regexp, haystack, 10, regmatches, 0);
if (!result)
return haystack + regmatches[0].rm_so;
if (!ISSET(REVERSE_SEARCH)) {
result = regexec(&search_regexp, haystack, 10, regmatches, 0);
if (!result)
return haystack + regmatches[0].rm_so;
} else {
/* do quick check first */
if (!(regexec(&search_regexp, haystack, 10, regmatches, 0))) {
/* there is a match */
for(i = rev_start ; i >= haystack ; --i)
if (!(result = regexec(&search_regexp, i, 10, regmatches, 0))) {
j = i + regmatches[0].rm_so;
if (j <= rev_start)
return j;
}
}
}
return 0;
}
#endif
if (ISSET(CASE_SENSITIVE))
return strstr(haystack, needle);
else
return strcasestr(haystack, needle);
if (ISSET(CASE_SENSITIVE)) {
if (!ISSET(REVERSE_SEARCH))
return strstr(haystack,needle);
else
return revstrstr(haystack, needle, rev_start);
} else {
if (!ISSET(REVERSE_SEARCH))
return strcasestr(haystack, needle);
else
return revstrcasestr(haystack, needle, rev_start);
}
}
/* Thanks BG, many ppl have been asking for this... */