Reverse Search by Ken Tyler
git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@685 35c25a1d-7b9e-4130-9fde-d3aeb78583b8master
parent
a75bc41faf
commit
e4933a393a
|
@ -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
|
||||
|
|
15
global.c
15
global.c
|
@ -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
6
nano.h
|
@ -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
|
||||
|
|
4
proto.h
4
proto.h
|
@ -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
174
search.c
|
@ -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
71
utils.c
|
@ -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... */
|
||||
|
|
Loading…
Reference in New Issue