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
"", *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 = "";
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"),
_("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);
_("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"),
#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 */
#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
#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
/* 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);
{
int i = 0;
char *buf;
- char *prompt, *reprompt = "";
+ char *prompt;
static char *backupstring = NULL;
search_init_globals();
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])) {
} 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;
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) {
- if (!quiet)
- not_found_msg(needle);
- return NULL;
- }
+ /* 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;
- fileptr = fileptr->next;
+ if (!past_editbot && (fileptr == editbot))
+ past_editbot = 1;
- 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"));
+ }
- /* EOF reached, wrap around once */
- if (fileptr == NULL) {
- fileptr = fileage;
+ /* Original start line reached */
+ if (fileptr == begin)
+ search_last_line = 1;
+
+ searchstr = fileptr->data;
+ }
- past_editbot = 1;
+ /* 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)
- statusbar(_("Search Wrapped"));
+ not_found_msg(needle);
+ return NULL;
}
- /* Original start line reached */
- if (fileptr == begin)
+ } else { /* reverse search */
+
+ current_x_find = current_x - 1;
+
+ /* 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;
- }
- /* We found an instance */
- current_x_find = 0;
- for (tmp = fileptr->data; tmp != found; tmp++)
- current_x_find++;
+ /* 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;
- /* Ensure we haven't wrapped around again! */
- if ((search_last_line) && (current_x_find >= beginx)) {
- if (!quiet)
- not_found_msg(needle);
- return NULL;
+ /* 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;
+ }
}
- /* 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;
}
}
+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). */
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... */