2000-08-06 21:13:45 +00:00
|
|
|
/* $Id$ */
|
2000-06-19 04:22:15 +00:00
|
|
|
/**************************************************************************
|
|
|
|
* search.c *
|
|
|
|
* *
|
2004-01-09 23:04:55 +00:00
|
|
|
* Copyright (C) 2000-2004 Chris Allegretta *
|
2000-06-19 04:22:15 +00:00
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
2001-10-24 11:33:54 +00:00
|
|
|
* the Free Software Foundation; either version 2, or (at your option) *
|
2000-06-19 04:22:15 +00:00
|
|
|
* any later version. *
|
|
|
|
* *
|
|
|
|
* This program is distributed in the hope that it will be useful, *
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
* GNU General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the Free Software *
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
|
|
|
|
* *
|
|
|
|
**************************************************************************/
|
|
|
|
|
2004-11-17 23:17:05 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
2001-04-28 18:03:52 +00:00
|
|
|
|
2000-06-19 04:22:15 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
2004-02-24 20:41:39 +00:00
|
|
|
#include <unistd.h>
|
2000-11-05 16:52:21 +00:00
|
|
|
#include <ctype.h>
|
2003-01-05 20:41:21 +00:00
|
|
|
#include <errno.h>
|
2002-07-19 01:08:59 +00:00
|
|
|
#include <assert.h>
|
2000-06-19 04:22:15 +00:00
|
|
|
#include "proto.h"
|
|
|
|
#include "nano.h"
|
2000-06-21 03:00:43 +00:00
|
|
|
|
2004-10-31 13:20:30 +00:00
|
|
|
static bool search_last_line = FALSE;
|
|
|
|
/* Have we gone past the last line while searching? */
|
2000-09-06 13:39:17 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
2004-10-19 21:09:37 +00:00
|
|
|
static bool regexp_compiled = FALSE;
|
|
|
|
/* Have we compiled any regular expressions? */
|
2004-04-30 19:40:03 +00:00
|
|
|
|
|
|
|
/* Regular expression helper functions. */
|
|
|
|
|
|
|
|
/* Compile the given regular expression. Return value 0 means the
|
|
|
|
* expression was invalid, and we wrote an error message on the status
|
|
|
|
* bar. Return value 1 means success. */
|
2003-01-29 04:18:37 +00:00
|
|
|
int regexp_init(const char *regexp)
|
2000-07-07 01:49:52 +00:00
|
|
|
{
|
2004-10-11 13:55:33 +00:00
|
|
|
int rc = regcomp(&search_regexp, regexp, REG_EXTENDED
|
|
|
|
#ifndef NANO_SMALL
|
|
|
|
| (ISSET(CASE_SENSITIVE) ? 0 : REG_ICASE)
|
|
|
|
#endif
|
|
|
|
);
|
2004-04-30 19:40:03 +00:00
|
|
|
|
|
|
|
assert(!regexp_compiled);
|
|
|
|
if (rc != 0) {
|
|
|
|
size_t len = regerror(rc, &search_regexp, NULL, 0);
|
|
|
|
char *str = charalloc(len);
|
|
|
|
|
|
|
|
regerror(rc, &search_regexp, str, len);
|
|
|
|
statusbar(_("Bad regex \"%s\": %s"), regexp, str);
|
|
|
|
free(str);
|
2003-01-29 04:18:37 +00:00
|
|
|
return 0;
|
2004-04-30 19:40:03 +00:00
|
|
|
}
|
2003-01-29 04:18:37 +00:00
|
|
|
|
2004-04-30 19:40:03 +00:00
|
|
|
regexp_compiled = TRUE;
|
2003-01-29 04:18:37 +00:00
|
|
|
return 1;
|
2000-07-07 01:49:52 +00:00
|
|
|
}
|
|
|
|
|
2001-03-18 16:59:34 +00:00
|
|
|
void regexp_cleanup(void)
|
2000-07-07 01:49:52 +00:00
|
|
|
{
|
2004-04-30 19:40:03 +00:00
|
|
|
if (regexp_compiled) {
|
|
|
|
regexp_compiled = FALSE;
|
2004-02-24 20:41:39 +00:00
|
|
|
regfree(&search_regexp);
|
|
|
|
}
|
2000-07-07 01:49:52 +00:00
|
|
|
}
|
2000-07-07 02:35:34 +00:00
|
|
|
#endif
|
2000-07-07 01:49:52 +00:00
|
|
|
|
2002-09-06 20:35:28 +00:00
|
|
|
void not_found_msg(const char *str)
|
|
|
|
{
|
2004-05-29 16:25:30 +00:00
|
|
|
char *disp;
|
|
|
|
int numchars;
|
|
|
|
|
2004-04-05 01:08:14 +00:00
|
|
|
assert(str != NULL);
|
2004-05-29 16:25:30 +00:00
|
|
|
|
2004-12-23 17:43:27 +00:00
|
|
|
disp = display_string(str, 0, (COLS / 2) + 1, FALSE);
|
2004-05-29 16:25:30 +00:00
|
|
|
numchars = strnlen(disp, COLS / 2);
|
|
|
|
|
|
|
|
statusbar(_("\"%.*s%s\" not found"), numchars, disp,
|
2004-12-22 21:38:43 +00:00
|
|
|
(disp[numchars] == '\0') ? "" : "...");
|
2004-05-29 16:25:30 +00:00
|
|
|
|
|
|
|
free(disp);
|
2002-09-06 20:35:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void search_abort(void)
|
|
|
|
{
|
|
|
|
display_main_list();
|
2004-02-24 20:41:39 +00:00
|
|
|
#ifndef NANO_SMALL
|
2002-09-06 20:35:28 +00:00
|
|
|
if (ISSET(MARK_ISSET))
|
2004-02-24 20:41:39 +00:00
|
|
|
edit_refresh();
|
|
|
|
#endif
|
2002-09-06 20:35:28 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
2004-02-24 20:41:39 +00:00
|
|
|
regexp_cleanup();
|
2002-09-06 20:35:28 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2000-11-05 16:52:21 +00:00
|
|
|
void search_init_globals(void)
|
|
|
|
{
|
2004-10-16 15:41:57 +00:00
|
|
|
if (last_search == NULL)
|
|
|
|
last_search = mallocstrcpy(NULL, "");
|
|
|
|
if (last_replace == NULL)
|
|
|
|
last_replace = mallocstrcpy(NULL, "");
|
2000-11-05 16:52:21 +00:00
|
|
|
}
|
|
|
|
|
2004-10-04 22:37:56 +00:00
|
|
|
/* Set up the system variables for a search or replace. If use_answer
|
|
|
|
* is TRUE, only set backupstring to answer. Return -2 to run opposite
|
|
|
|
* program (search -> replace, replace -> search), return -1 if the
|
|
|
|
* search should be canceled (due to Cancel, Go to Line, or a failed
|
|
|
|
* regcomp()), return 0 on success, and return 1 on rerun calling
|
|
|
|
* program.
|
2003-01-13 01:35:15 +00:00
|
|
|
*
|
2004-10-04 22:37:56 +00:00
|
|
|
* replacing is TRUE if we call from do_replace(), and FALSE if called
|
|
|
|
* from do_search(). */
|
|
|
|
int search_init(bool replacing, bool use_answer)
|
2000-06-19 04:22:15 +00:00
|
|
|
{
|
2001-07-15 22:24:24 +00:00
|
|
|
int i = 0;
|
2000-11-03 14:23:00 +00:00
|
|
|
char *buf;
|
2000-11-16 06:01:10 +00:00
|
|
|
static char *backupstring = NULL;
|
2004-10-04 22:37:56 +00:00
|
|
|
/* The search string we'll be using. */
|
|
|
|
|
|
|
|
/* If backupstring doesn't exist, initialize it to "". */
|
|
|
|
if (backupstring == NULL)
|
|
|
|
backupstring = mallocstrcpy(NULL, "");
|
|
|
|
|
|
|
|
/* If use_answer is TRUE, set backupstring to answer and get out. */
|
|
|
|
if (use_answer) {
|
|
|
|
backupstring = mallocstrcpy(backupstring, answer);
|
|
|
|
return 0;
|
|
|
|
}
|
2004-02-24 20:41:39 +00:00
|
|
|
|
|
|
|
/* 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,
|
2004-10-04 22:37:56 +00:00
|
|
|
* we should put the same search string back up. */
|
2000-10-26 01:44:42 +00:00
|
|
|
|
2000-11-05 16:52:21 +00:00
|
|
|
search_init_globals();
|
2000-11-02 04:40:39 +00:00
|
|
|
|
2003-01-05 20:57:07 +00:00
|
|
|
#ifndef NANO_SMALL
|
2003-01-05 21:47:06 +00:00
|
|
|
search_history.current = (historytype *)&search_history.next;
|
2003-01-05 20:57:07 +00:00
|
|
|
#endif
|
2003-01-05 21:47:06 +00:00
|
|
|
|
|
|
|
if (last_search[0] != '\0') {
|
2004-12-23 17:43:27 +00:00
|
|
|
char *disp = display_string(last_search, 0, COLS / 3, FALSE);
|
2003-09-16 01:16:49 +00:00
|
|
|
|
2002-07-20 13:57:41 +00:00
|
|
|
buf = charalloc(COLS / 3 + 7);
|
2004-02-24 20:41:39 +00:00
|
|
|
/* We use COLS / 3 here because we need to see more on the
|
|
|
|
* line. */
|
2003-09-16 01:16:49 +00:00
|
|
|
sprintf(buf, " [%s%s]", disp,
|
|
|
|
strlenpt(last_search) > COLS / 3 ? "..." : "");
|
|
|
|
free(disp);
|
2004-10-04 22:37:56 +00:00
|
|
|
} else
|
|
|
|
buf = mallocstrcpy(NULL, "");
|
2000-06-19 04:22:15 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* This is now one simple call. It just does a lot. */
|
2004-03-15 20:26:30 +00:00
|
|
|
i = statusq(FALSE, replacing ? replace_list : whereis_list,
|
|
|
|
backupstring,
|
2003-01-05 20:41:21 +00:00
|
|
|
#ifndef NANO_SMALL
|
|
|
|
&search_history,
|
|
|
|
#endif
|
2004-03-15 20:26:30 +00:00
|
|
|
"%s%s%s%s%s%s", _("Search"),
|
2001-09-27 13:04:10 +00:00
|
|
|
|
2003-09-16 01:16:49 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-02-24 20:41:39 +00:00
|
|
|
/* This string is just a modifier for the search prompt; no
|
|
|
|
* grammar is implied. */
|
2003-09-16 01:16:49 +00:00
|
|
|
ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") :
|
|
|
|
#endif
|
|
|
|
"",
|
2001-09-27 13:04:10 +00:00
|
|
|
|
2004-04-30 19:40:03 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
2004-02-24 20:41:39 +00:00
|
|
|
/* This string is just a modifier for the search prompt; no
|
|
|
|
* grammar is implied. */
|
2004-04-30 19:40:03 +00:00
|
|
|
ISSET(USE_REGEXP) ? _(" [Regexp]") :
|
|
|
|
#endif
|
|
|
|
"",
|
2001-09-27 13:04:10 +00:00
|
|
|
|
2003-09-16 01:16:49 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-02-24 20:41:39 +00:00
|
|
|
/* This string is just a modifier for the search prompt; no
|
|
|
|
* grammar is implied. */
|
2003-09-16 01:16:49 +00:00
|
|
|
ISSET(REVERSE_SEARCH) ? _(" [Backwards]") :
|
|
|
|
#endif
|
|
|
|
"",
|
2001-09-27 13:04:10 +00:00
|
|
|
|
2004-11-03 23:05:11 +00:00
|
|
|
replacing ?
|
|
|
|
#ifndef NANO_SMALL
|
|
|
|
(ISSET(MARK_ISSET) ? _(" (to replace) in selection") :
|
|
|
|
#endif
|
|
|
|
_(" (to replace)")
|
|
|
|
#ifndef NANO_SMALL
|
|
|
|
)
|
|
|
|
#endif
|
|
|
|
: "",
|
|
|
|
|
2001-06-13 02:35:44 +00:00
|
|
|
buf);
|
2000-06-19 04:22:15 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Release buf now that we don't need it anymore. */
|
2002-03-10 01:22:21 +00:00
|
|
|
free(buf);
|
|
|
|
|
2003-09-16 01:16:49 +00:00
|
|
|
free(backupstring);
|
|
|
|
backupstring = NULL;
|
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* 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')) {
|
2004-08-26 04:22:54 +00:00
|
|
|
statusbar(_("Cancelled"));
|
2003-01-05 20:41:21 +00:00
|
|
|
#ifndef NANO_SMALL
|
|
|
|
search_history.current = search_history.next;
|
|
|
|
#endif
|
2000-06-19 04:22:15 +00:00
|
|
|
return -1;
|
2002-07-19 01:08:59 +00:00
|
|
|
} else {
|
|
|
|
switch (i) {
|
2004-10-16 15:41:57 +00:00
|
|
|
case -2: /* It's the same string. */
|
2000-09-06 13:39:17 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
2004-10-16 15:41:57 +00:00
|
|
|
/* Since answer is "", use last_search! */
|
|
|
|
if (ISSET(USE_REGEXP) && regexp_init(last_search) == 0)
|
|
|
|
return -1;
|
2000-07-07 02:35:34 +00:00
|
|
|
#endif
|
2004-10-16 15:41:57 +00:00
|
|
|
break;
|
|
|
|
case 0: /* They entered something new. */
|
|
|
|
last_replace[0] = '\0';
|
2000-09-06 13:39:17 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
2004-10-16 15:41:57 +00:00
|
|
|
if (ISSET(USE_REGEXP) && regexp_init(answer) == 0)
|
|
|
|
return -1;
|
2000-07-07 02:35:34 +00:00
|
|
|
#endif
|
2004-10-16 15:41:57 +00:00
|
|
|
break;
|
2002-07-19 01:08:59 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-10-16 15:41:57 +00:00
|
|
|
case TOGGLE_CASE_KEY:
|
|
|
|
TOGGLE(CASE_SENSITIVE);
|
|
|
|
backupstring = mallocstrcpy(backupstring, answer);
|
|
|
|
return 1;
|
|
|
|
case TOGGLE_BACKWARDS_KEY:
|
|
|
|
TOGGLE(REVERSE_SEARCH);
|
|
|
|
backupstring = mallocstrcpy(backupstring, answer);
|
|
|
|
return 1;
|
2001-06-14 02:54:22 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
2004-10-16 15:41:57 +00:00
|
|
|
case TOGGLE_REGEXP_KEY:
|
|
|
|
TOGGLE(USE_REGEXP);
|
|
|
|
backupstring = mallocstrcpy(backupstring, answer);
|
|
|
|
return 1;
|
2001-06-14 02:54:22 +00:00
|
|
|
#endif
|
2002-07-19 01:08:59 +00:00
|
|
|
#endif /* !NANO_SMALL */
|
2004-10-16 15:41:57 +00:00
|
|
|
case NANO_TOOTHERSEARCH_KEY:
|
|
|
|
backupstring = mallocstrcpy(backupstring, answer);
|
|
|
|
return -2; /* Call the opposite search function. */
|
|
|
|
case NANO_TOGOTOLINE_KEY:
|
2003-01-05 20:41:21 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-10-16 15:41:57 +00:00
|
|
|
search_history.current = search_history.next;
|
2003-01-05 20:41:21 +00:00
|
|
|
#endif
|
2004-10-16 15:41:57 +00:00
|
|
|
/* Put answer up on the statusbar. */
|
|
|
|
do_gotoline(-1, FALSE);
|
|
|
|
/* Fall through. */
|
|
|
|
default:
|
|
|
|
return -1;
|
2002-07-19 01:08:59 +00:00
|
|
|
}
|
2000-06-19 04:22:15 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-08-27 20:28:34 +00:00
|
|
|
bool is_whole_word(int curr_pos, const char *datastr, const char
|
2004-02-24 20:41:39 +00:00
|
|
|
*searchword)
|
2002-01-08 15:00:24 +00:00
|
|
|
{
|
2002-07-19 01:08:59 +00:00
|
|
|
size_t sln = curr_pos + strlen(searchword);
|
2002-01-08 15:00:24 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Start of line or previous character is not a letter and end of
|
|
|
|
* line or next character is not a letter. */
|
2004-10-21 22:49:51 +00:00
|
|
|
return (curr_pos < 1 || !isalpha(datastr[curr_pos - 1])) &&
|
|
|
|
(sln == strlen(datastr) || !isalpha(datastr[sln]));
|
2002-01-08 15:00:24 +00:00
|
|
|
}
|
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Look for needle, starting at current, column current_x. If
|
2004-10-15 16:25:56 +00:00
|
|
|
* no_sameline is TRUE, skip over begin when looking for needle. begin
|
|
|
|
* is the line where we first started searching, at column beginx. If
|
2004-10-21 15:32:11 +00:00
|
|
|
* can_display_wrap is TRUE, we put messages on the statusbar, wrap
|
2004-10-27 02:21:01 +00:00
|
|
|
* 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. */
|
2004-08-27 20:28:34 +00:00
|
|
|
bool findnextstr(bool can_display_wrap, bool wholeword, bool
|
|
|
|
no_sameline, const filestruct *begin, size_t beginx, const char
|
2004-10-27 02:21:01 +00:00
|
|
|
*needle, size_t *needle_len)
|
2000-06-19 04:22:15 +00:00
|
|
|
{
|
2002-05-11 03:04:44 +00:00
|
|
|
filestruct *fileptr = current;
|
2004-02-24 20:41:39 +00:00
|
|
|
const char *rev_start = NULL, *found = NULL;
|
2004-10-18 22:19:22 +00:00
|
|
|
size_t found_len;
|
|
|
|
/* The length of the match we found. */
|
2004-02-24 20:41:39 +00:00
|
|
|
size_t current_x_find = 0;
|
2004-10-18 22:19:22 +00:00
|
|
|
/* The location of the match we found. */
|
2004-08-27 20:28:34 +00:00
|
|
|
int current_y_find = current_y;
|
2004-02-24 20:41:39 +00:00
|
|
|
|
|
|
|
/* 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. */
|
2004-10-15 16:25:56 +00:00
|
|
|
rev_start =
|
2004-02-24 20:41:39 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-10-15 16:25:56 +00:00
|
|
|
ISSET(REVERSE_SEARCH) ? fileptr->data + (current_x - 1) :
|
2004-02-24 20:41:39 +00:00
|
|
|
#endif
|
2004-10-15 16:25:56 +00:00
|
|
|
fileptr->data + (current_x + 1);
|
2001-06-13 02:35:44 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Look for needle in searchstr. */
|
2004-03-15 20:26:30 +00:00
|
|
|
while (TRUE) {
|
2004-02-24 20:41:39 +00:00
|
|
|
found = strstrwrapper(fileptr->data, needle, rev_start);
|
2001-06-13 02:35:44 +00:00
|
|
|
|
2004-10-18 22:19:22 +00:00
|
|
|
/* We've found a potential match. */
|
|
|
|
if (found != NULL) {
|
|
|
|
bool found_whole = FALSE;
|
|
|
|
/* Is this potential match a whole word? */
|
|
|
|
|
|
|
|
/* Set found_len to the length of the potential match. */
|
|
|
|
found_len =
|
|
|
|
#ifdef HAVE_REGEX_H
|
|
|
|
ISSET(USE_REGEXP) ?
|
|
|
|
regmatches[0].rm_eo - regmatches[0].rm_so :
|
|
|
|
#endif
|
|
|
|
strlen(needle);
|
|
|
|
|
|
|
|
/* If we're searching for whole words, see if this potential
|
|
|
|
* match is a whole word. */
|
|
|
|
if (wholeword) {
|
2004-11-02 20:48:37 +00:00
|
|
|
char *word = mallocstrncpy(NULL, found, found_len + 1);
|
2004-10-18 22:19:22 +00:00
|
|
|
word[found_len] = '\0';
|
|
|
|
|
|
|
|
found_whole = is_whole_word(found - fileptr->data,
|
|
|
|
fileptr->data, word);
|
|
|
|
free(word);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we're searching for whole words and this potential
|
|
|
|
* 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 ||
|
|
|
|
fileptr != current))
|
2004-02-24 20:41:39 +00:00
|
|
|
break;
|
2001-06-13 02:35:44 +00:00
|
|
|
}
|
2000-10-24 22:25:36 +00:00
|
|
|
|
2004-10-18 02:06:53 +00:00
|
|
|
/* We've finished processing the file, so get out. */
|
2004-02-24 20:41:39 +00:00
|
|
|
if (search_last_line) {
|
|
|
|
if (can_display_wrap)
|
2001-06-13 02:35:44 +00:00
|
|
|
not_found_msg(needle);
|
2004-10-15 16:25:56 +00:00
|
|
|
return FALSE;
|
2000-10-24 22:25:36 +00:00
|
|
|
}
|
2004-08-27 20:28:34 +00:00
|
|
|
|
|
|
|
#ifndef NANO_SMALL
|
|
|
|
if (ISSET(REVERSE_SEARCH)) {
|
|
|
|
fileptr = fileptr->prev;
|
|
|
|
current_y_find--;
|
|
|
|
} else {
|
|
|
|
#endif
|
|
|
|
fileptr = fileptr->next;
|
|
|
|
current_y_find++;
|
2001-10-02 03:54:40 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-08-27 20:28:34 +00:00
|
|
|
}
|
2004-02-24 20:41:39 +00:00
|
|
|
#endif
|
2002-06-21 03:20:06 +00:00
|
|
|
|
2004-10-18 02:06:53 +00:00
|
|
|
/* Start or end of buffer reached, so wrap around. */
|
2004-02-24 20:41:39 +00:00
|
|
|
if (fileptr == NULL) {
|
|
|
|
if (!can_display_wrap)
|
2004-10-15 16:25:56 +00:00
|
|
|
return FALSE;
|
2004-08-27 20:28:34 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-08-27 20:28:34 +00:00
|
|
|
if (ISSET(REVERSE_SEARCH)) {
|
|
|
|
fileptr = filebot;
|
|
|
|
current_y_find = editwinrows - 1;
|
|
|
|
} else {
|
2004-02-24 20:41:39 +00:00
|
|
|
#endif
|
2004-08-27 20:28:34 +00:00
|
|
|
fileptr = fileage;
|
|
|
|
current_y_find = 0;
|
|
|
|
#ifndef NANO_SMALL
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
if (can_display_wrap)
|
|
|
|
statusbar(_("Search Wrapped"));
|
|
|
|
}
|
2001-06-13 02:35:44 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Original start line reached. */
|
2004-10-27 02:21:01 +00:00
|
|
|
if (fileptr == begin)
|
2004-05-27 18:39:16 +00:00
|
|
|
search_last_line = TRUE;
|
2004-10-27 02:21:01 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
rev_start = fileptr->data;
|
|
|
|
#ifndef NANO_SMALL
|
|
|
|
if (ISSET(REVERSE_SEARCH))
|
|
|
|
rev_start += strlen(fileptr->data);
|
|
|
|
#endif
|
|
|
|
}
|
2000-10-24 22:25:36 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* We found an instance. */
|
|
|
|
current_x_find = found - fileptr->data;
|
2001-06-13 02:35:44 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* 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
|
|
|
|
) {
|
2001-06-13 02:35:44 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
if (can_display_wrap)
|
|
|
|
not_found_msg(needle);
|
2004-10-15 16:25:56 +00:00
|
|
|
return FALSE;
|
2000-06-19 04:22:15 +00:00
|
|
|
}
|
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Set globals now that we are sure we found something. */
|
2000-11-29 04:33:26 +00:00
|
|
|
current = fileptr;
|
|
|
|
current_x = current_x_find;
|
2004-08-27 20:28:34 +00:00
|
|
|
current_y = current_y_find;
|
2004-10-21 16:25:44 +00:00
|
|
|
placewewant = xplustabs();
|
2004-10-21 15:32:11 +00:00
|
|
|
|
|
|
|
/* needle_len holds the length of needle. */
|
2004-10-18 22:19:22 +00:00
|
|
|
if (needle_len != NULL)
|
|
|
|
*needle_len = found_len;
|
2000-11-29 04:33:26 +00:00
|
|
|
|
2004-10-15 16:25:56 +00:00
|
|
|
return TRUE;
|
2000-06-19 04:22:15 +00:00
|
|
|
}
|
|
|
|
|
2004-10-31 13:20:30 +00:00
|
|
|
void findnextstr_wrap_reset(void)
|
|
|
|
{
|
|
|
|
search_last_line = FALSE;
|
|
|
|
}
|
|
|
|
|
2002-07-19 01:08:59 +00:00
|
|
|
/* Search for a string. */
|
2004-07-02 14:31:03 +00:00
|
|
|
void do_search(void)
|
2000-06-19 04:22:15 +00:00
|
|
|
{
|
2004-07-28 20:46:25 +00:00
|
|
|
size_t old_pww = placewewant, fileptr_x = current_x;
|
2004-08-27 20:28:34 +00:00
|
|
|
int i;
|
|
|
|
bool didfind;
|
2004-02-24 20:41:39 +00:00
|
|
|
filestruct *fileptr = current;
|
2000-06-19 04:22:15 +00:00
|
|
|
|
2003-09-10 20:08:00 +00:00
|
|
|
#ifndef DISABLE_WRAPPING
|
2000-06-19 04:22:15 +00:00
|
|
|
wrap_reset();
|
2003-09-10 20:08:00 +00:00
|
|
|
#endif
|
2004-09-30 22:07:21 +00:00
|
|
|
|
2004-10-04 22:37:56 +00:00
|
|
|
i = search_init(FALSE, FALSE);
|
2004-02-24 20:41:39 +00:00
|
|
|
if (i == -1) /* Cancel, Go to Line, blank search string, or
|
|
|
|
* regcomp() failed. */
|
2000-06-19 04:22:15 +00:00
|
|
|
search_abort();
|
2004-02-24 20:41:39 +00:00
|
|
|
else if (i == -2) /* Replace. */
|
2000-06-19 04:22:15 +00:00
|
|
|
do_replace();
|
2004-02-24 20:41:39 +00:00
|
|
|
#ifndef NANO_SMALL
|
|
|
|
else if (i == 1) /* Case Sensitive, Backwards, or Regexp search
|
|
|
|
* toggle. */
|
2000-06-19 04:22:15 +00:00
|
|
|
do_search();
|
2004-02-24 20:41:39 +00:00
|
|
|
#endif
|
2000-10-31 05:28:33 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
if (i != 0)
|
2004-07-02 14:31:03 +00:00
|
|
|
return;
|
2004-02-24 20:41:39 +00:00
|
|
|
|
|
|
|
/* If answer is now "", copy last_search into answer. */
|
2002-05-11 03:04:44 +00:00
|
|
|
if (answer[0] == '\0')
|
2000-11-16 06:01:10 +00:00
|
|
|
answer = mallocstrcpy(answer, last_search);
|
|
|
|
else
|
|
|
|
last_search = mallocstrcpy(last_search, answer);
|
|
|
|
|
2003-01-05 20:41:21 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-02-24 20:41:39 +00:00
|
|
|
/* If answer is not "", add this search string to the search history
|
|
|
|
* list. */
|
2003-01-14 23:36:11 +00:00
|
|
|
if (answer[0] != '\0')
|
2003-01-05 20:43:49 +00:00
|
|
|
update_history(&search_history, answer);
|
2004-02-24 20:41:39 +00:00
|
|
|
#endif
|
2003-01-05 20:41:21 +00:00
|
|
|
|
2004-10-31 13:20:30 +00:00
|
|
|
findnextstr_wrap_reset();
|
2004-10-18 22:19:22 +00:00
|
|
|
didfind = findnextstr(TRUE, FALSE, FALSE, current, current_x,
|
2004-10-27 02:21:01 +00:00
|
|
|
answer, NULL);
|
2002-01-21 20:40:14 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* 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. */
|
2004-07-17 19:49:12 +00:00
|
|
|
if (ISSET(USE_REGEXP) && regexp_bol_or_eol(&search_regexp,
|
|
|
|
last_search)) {
|
2004-08-27 20:28:34 +00:00
|
|
|
didfind = findnextstr(TRUE, FALSE, TRUE, current, current_x,
|
2004-10-27 02:21:01 +00:00
|
|
|
answer, NULL);
|
2004-02-24 20:41:39 +00:00
|
|
|
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
|
|
|
|
}
|
2002-01-21 20:40:14 +00:00
|
|
|
|
2004-05-28 20:44:09 +00:00
|
|
|
placewewant = xplustabs();
|
2004-05-30 03:19:52 +00:00
|
|
|
edit_redraw(fileptr, old_pww);
|
2000-06-19 04:22:15 +00:00
|
|
|
search_abort();
|
|
|
|
}
|
|
|
|
|
2004-05-05 21:36:50 +00:00
|
|
|
#ifndef NANO_SMALL
|
2003-08-23 21:11:06 +00:00
|
|
|
/* Search for the next string without prompting. */
|
2004-07-02 14:31:03 +00:00
|
|
|
void do_research(void)
|
2003-08-23 21:11:06 +00:00
|
|
|
{
|
2004-07-12 03:10:30 +00:00
|
|
|
size_t old_pww = placewewant, fileptr_x = current_x;
|
2004-08-27 20:28:34 +00:00
|
|
|
bool didfind;
|
2004-05-28 20:44:09 +00:00
|
|
|
filestruct *fileptr = current;
|
2003-08-23 21:11:06 +00:00
|
|
|
|
2003-09-10 20:08:00 +00:00
|
|
|
#ifndef DISABLE_WRAPPING
|
2003-08-23 21:11:06 +00:00
|
|
|
wrap_reset();
|
2003-09-10 20:08:00 +00:00
|
|
|
#endif
|
2004-10-01 18:47:17 +00:00
|
|
|
|
2003-08-23 21:11:06 +00:00
|
|
|
search_init_globals();
|
|
|
|
|
|
|
|
if (last_search[0] != '\0') {
|
|
|
|
|
|
|
|
#ifdef HAVE_REGEX_H
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Since answer is "", use last_search! */
|
2004-04-30 19:40:03 +00:00
|
|
|
if (ISSET(USE_REGEXP) && regexp_init(last_search) == 0)
|
2004-07-02 14:31:03 +00:00
|
|
|
return;
|
2003-08-23 21:11:06 +00:00
|
|
|
#endif
|
|
|
|
|
2004-10-31 13:20:30 +00:00
|
|
|
findnextstr_wrap_reset();
|
2004-08-27 20:28:34 +00:00
|
|
|
didfind = findnextstr(TRUE, FALSE, FALSE, current, current_x,
|
2004-10-27 02:21:01 +00:00
|
|
|
last_search, NULL);
|
2003-08-23 21:11:06 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* 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. */
|
2004-07-17 19:49:12 +00:00
|
|
|
if (ISSET(USE_REGEXP) && regexp_bol_or_eol(&search_regexp,
|
|
|
|
last_search)) {
|
2004-08-27 20:28:34 +00:00
|
|
|
didfind = findnextstr(TRUE, FALSE, TRUE, current,
|
2004-10-27 02:21:01 +00:00
|
|
|
current_x, answer, NULL);
|
2004-02-24 20:41:39 +00:00
|
|
|
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
|
|
|
|
}
|
2003-08-23 21:11:06 +00:00
|
|
|
} else
|
|
|
|
statusbar(_("No current search pattern"));
|
|
|
|
|
2004-05-28 20:44:09 +00:00
|
|
|
placewewant = xplustabs();
|
2004-05-30 03:19:52 +00:00
|
|
|
edit_redraw(fileptr, old_pww);
|
2003-08-23 21:11:06 +00:00
|
|
|
search_abort();
|
|
|
|
}
|
2004-05-05 21:36:50 +00:00
|
|
|
#endif
|
2003-08-23 21:11:06 +00:00
|
|
|
|
2000-06-19 04:22:15 +00:00
|
|
|
void replace_abort(void)
|
|
|
|
{
|
2004-02-24 20:41:39 +00:00
|
|
|
/* 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. */
|
2000-07-28 01:18:10 +00:00
|
|
|
search_abort();
|
2000-10-24 22:25:36 +00:00
|
|
|
placewewant = xplustabs();
|
2000-07-07 01:49:52 +00:00
|
|
|
}
|
|
|
|
|
2000-09-06 13:39:17 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
2004-08-27 20:28:34 +00:00
|
|
|
int replace_regexp(char *string, bool create_flag)
|
2000-07-07 01:49:52 +00:00
|
|
|
{
|
2004-08-27 20:28:34 +00:00
|
|
|
/* Split personality here - if create_flag is FALSE, just calculate
|
2000-07-07 01:49:52 +00:00
|
|
|
* the size of the replacement line (necessary because of
|
2004-02-24 20:41:39 +00:00
|
|
|
* subexpressions \1 to \9 in the replaced text). */
|
2000-07-07 01:49:52 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
const char *c = last_replace;
|
2000-10-26 01:44:42 +00:00
|
|
|
int search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
|
2004-02-24 20:41:39 +00:00
|
|
|
int new_size = strlen(current->data) + 1 - search_match_count;
|
2000-07-07 01:49:52 +00:00
|
|
|
|
2002-07-19 01:08:59 +00:00
|
|
|
/* Iterate through the replacement text to handle subexpression
|
|
|
|
* replacement using \1, \2, \3, etc. */
|
2002-12-22 16:30:00 +00:00
|
|
|
while (*c != '\0') {
|
2004-02-24 20:41:39 +00:00
|
|
|
int num = (int)(*(c + 1) - '0');
|
|
|
|
|
2004-11-27 21:10:11 +00:00
|
|
|
if (*c != '\\' || num < 1 || num > 9 ||
|
|
|
|
num > search_regexp.re_nsub) {
|
2000-10-26 01:44:42 +00:00
|
|
|
if (create_flag)
|
|
|
|
*string++ = *c;
|
|
|
|
c++;
|
|
|
|
new_size++;
|
|
|
|
} else {
|
2004-02-24 20:41:39 +00:00
|
|
|
int i = regmatches[num].rm_eo - regmatches[num].rm_so;
|
2000-10-26 01:44:42 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Skip over the replacement expression. */
|
|
|
|
c += 2;
|
2000-10-26 01:44:42 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* But add the length of the subexpression to new_size. */
|
|
|
|
new_size += i;
|
2000-10-26 01:44:42 +00:00
|
|
|
|
2004-08-27 20:28:34 +00:00
|
|
|
/* And if create_flag is TRUE, append the result of the
|
2004-02-24 20:41:39 +00:00
|
|
|
* subexpression match to the new line. */
|
|
|
|
if (create_flag) {
|
|
|
|
strncpy(string, current->data + current_x +
|
|
|
|
regmatches[num].rm_so, i);
|
|
|
|
string += i;
|
2000-10-26 01:44:42 +00:00
|
|
|
}
|
|
|
|
}
|
2000-07-07 01:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (create_flag)
|
2003-01-13 01:35:15 +00:00
|
|
|
*string = '\0';
|
2000-07-07 01:49:52 +00:00
|
|
|
|
|
|
|
return new_size;
|
|
|
|
}
|
2000-07-07 02:35:34 +00:00
|
|
|
#endif
|
2000-10-26 01:44:42 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
char *replace_line(const char *needle)
|
2000-07-07 01:49:52 +00:00
|
|
|
{
|
2004-02-24 20:41:39 +00:00
|
|
|
char *copy;
|
2000-07-07 01:49:52 +00:00
|
|
|
int new_line_size;
|
|
|
|
int search_match_count;
|
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Calculate the size of the new line. */
|
2000-09-06 13:39:17 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
2000-07-07 01:49:52 +00:00
|
|
|
if (ISSET(USE_REGEXP)) {
|
2004-05-23 21:11:14 +00:00
|
|
|
search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
|
2000-10-26 01:44:42 +00:00
|
|
|
new_line_size = replace_regexp(NULL, 0);
|
2000-07-07 01:49:52 +00:00
|
|
|
} else {
|
2000-07-07 02:35:34 +00:00
|
|
|
#endif
|
2004-02-24 20:41:39 +00:00
|
|
|
search_match_count = strlen(needle);
|
|
|
|
new_line_size = strlen(current->data) - search_match_count +
|
|
|
|
strlen(answer) + 1;
|
|
|
|
#ifdef HAVE_REGEX_H
|
2000-07-07 01:49:52 +00:00
|
|
|
}
|
2004-02-24 20:41:39 +00:00
|
|
|
#endif
|
2000-10-26 01:44:42 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Create the buffer. */
|
2001-05-17 11:35:43 +00:00
|
|
|
copy = charalloc(new_line_size);
|
2000-07-07 01:49:52 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* The head of the original line. */
|
2000-07-07 01:49:52 +00:00
|
|
|
strncpy(copy, current->data, current_x);
|
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* The replacement text. */
|
2000-09-06 13:39:17 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
2004-02-24 20:41:39 +00:00
|
|
|
if (ISSET(USE_REGEXP))
|
|
|
|
replace_regexp(copy + current_x, TRUE);
|
2000-07-07 01:49:52 +00:00
|
|
|
else
|
2000-07-07 02:35:34 +00:00
|
|
|
#endif
|
2004-02-24 20:41:39 +00:00
|
|
|
strcpy(copy + current_x, answer);
|
2000-07-07 01:49:52 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* The tail of the original line. */
|
|
|
|
assert(current_x + search_match_count <= strlen(current->data));
|
|
|
|
strcat(copy, current->data + current_x + search_match_count);
|
2000-07-07 01:49:52 +00:00
|
|
|
|
|
|
|
return copy;
|
2000-06-19 04:22:15 +00:00
|
|
|
}
|
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Step through each replace word and prompt user before replacing.
|
2004-10-08 23:06:01 +00:00
|
|
|
* Parameters real_current and real_current_x are needed in order to
|
|
|
|
* allow the cursor position to be updated when a word before the cursor
|
|
|
|
* is replaced by a shorter word.
|
2004-02-24 20:41:39 +00:00
|
|
|
*
|
|
|
|
* needle is the string to seek. We replace it with answer. Return -1
|
2004-10-26 20:58:30 +00:00
|
|
|
* if needle isn't found, else the number of replacements performed. If
|
|
|
|
* canceled isn't NULL, set it to TRUE if we canceled. */
|
2004-11-03 16:02:41 +00:00
|
|
|
ssize_t do_replace_loop(const char *needle, const filestruct
|
|
|
|
*real_current, size_t *real_current_x, bool wholewords, bool
|
|
|
|
*canceled)
|
2000-06-19 04:22:15 +00:00
|
|
|
{
|
2004-10-18 22:19:22 +00:00
|
|
|
ssize_t numreplaced = -1;
|
|
|
|
size_t match_len;
|
2004-11-22 17:08:41 +00:00
|
|
|
size_t pww_save = placewewant;
|
2004-08-27 20:28:34 +00:00
|
|
|
bool replaceall = FALSE;
|
2003-10-31 17:53:38 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
2004-01-03 21:42:25 +00:00
|
|
|
/* The starting-line match and bol/eol regex flags. */
|
2004-08-27 20:28:34 +00:00
|
|
|
bool begin_line = FALSE, bol_or_eol = FALSE;
|
2003-10-31 17:53:38 +00:00
|
|
|
#endif
|
2004-02-24 20:41:39 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-10-27 02:21:01 +00:00
|
|
|
bool old_mark_set = ISSET(MARK_ISSET);
|
2004-11-03 22:03:41 +00:00
|
|
|
filestruct *edittop_save = edittop, *top, *bot;
|
|
|
|
size_t top_x, bot_x;
|
|
|
|
bool right_side_up = FALSE;
|
|
|
|
/* TRUE if (mark_beginbuf, mark_beginx) is the top of the mark,
|
|
|
|
* FALSE if (current, current_x) is. */
|
2000-06-19 04:22:15 +00:00
|
|
|
|
2004-10-08 23:06:01 +00:00
|
|
|
if (old_mark_set) {
|
2004-11-03 22:03:41 +00:00
|
|
|
/* If the mark is on, partition the filestruct so that it
|
2004-11-05 23:03:03 +00:00
|
|
|
* contains only the marked text, set edittop to the top of the
|
|
|
|
* partition, turn the mark off, and refresh the screen. */
|
2004-11-03 22:03:41 +00:00
|
|
|
mark_order((const filestruct **)&top, &top_x,
|
2004-11-05 23:03:03 +00:00
|
|
|
(const filestruct **)&bot, &bot_x, &right_side_up);
|
2004-11-03 22:03:41 +00:00
|
|
|
filepart = partition_filestruct(top, top_x, bot, bot_x);
|
|
|
|
edittop = fileage;
|
2004-10-08 23:06:01 +00:00
|
|
|
UNSET(MARK_ISSET);
|
|
|
|
edit_refresh();
|
|
|
|
}
|
2004-02-24 20:41:39 +00:00
|
|
|
#endif
|
2003-09-16 01:16:49 +00:00
|
|
|
|
2004-10-26 20:58:30 +00:00
|
|
|
if (canceled != NULL)
|
|
|
|
*canceled = FALSE;
|
|
|
|
|
2004-10-31 13:20:30 +00:00
|
|
|
findnextstr_wrap_reset();
|
2004-08-27 20:28:34 +00:00
|
|
|
while (findnextstr(TRUE, wholewords,
|
2003-11-28 16:04:24 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
2004-02-24 20:41:39 +00:00
|
|
|
/* 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
|
2003-11-28 16:04:24 +00:00
|
|
|
#else
|
2004-02-24 20:41:39 +00:00
|
|
|
FALSE
|
2003-11-28 16:04:24 +00:00
|
|
|
#endif
|
2004-11-22 17:08:41 +00:00
|
|
|
, real_current, *real_current_x, needle, &match_len)) {
|
2004-02-24 20:41:39 +00:00
|
|
|
|
|
|
|
int i = 0;
|
2004-10-09 16:26:32 +00:00
|
|
|
|
2004-10-21 15:44:36 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
|
|
|
/* 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_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 (current == real_current)
|
|
|
|
begin_line = TRUE;
|
|
|
|
bol_or_eol = FALSE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-07-29 14:32:17 +00:00
|
|
|
if (!replaceall) {
|
2004-11-22 17:08:41 +00:00
|
|
|
edit_redraw(real_current, pww_save);
|
2004-10-26 16:29:21 +00:00
|
|
|
pww_save = placewewant;
|
2004-07-29 14:32:17 +00:00
|
|
|
}
|
2003-01-13 01:35:15 +00:00
|
|
|
|
2004-11-03 21:11:38 +00:00
|
|
|
/* Record for the return value that we found the search
|
|
|
|
* string. */
|
2004-02-24 20:41:39 +00:00
|
|
|
if (numreplaced == -1)
|
|
|
|
numreplaced = 0;
|
2003-09-16 01:16:49 +00:00
|
|
|
|
2000-11-29 04:33:26 +00:00
|
|
|
if (!replaceall) {
|
2003-09-16 01:16:49 +00:00
|
|
|
char *exp_word;
|
|
|
|
size_t xpt = xplustabs();
|
|
|
|
|
|
|
|
exp_word = display_string(current->data, xpt,
|
2004-12-23 17:43:27 +00:00
|
|
|
strnlenpt(current->data, match_len + current_x) - xpt,
|
|
|
|
FALSE);
|
2003-09-16 01:16:49 +00:00
|
|
|
|
2000-11-29 04:33:26 +00:00
|
|
|
curs_set(0);
|
2003-09-16 01:16:49 +00:00
|
|
|
do_replace_highlight(TRUE, exp_word);
|
2000-11-29 04:33:26 +00:00
|
|
|
|
2004-03-15 20:26:30 +00:00
|
|
|
i = do_yesno(TRUE, _("Replace this instance?"));
|
2000-06-19 04:22:15 +00:00
|
|
|
|
2003-09-16 01:16:49 +00:00
|
|
|
do_replace_highlight(FALSE, exp_word);
|
|
|
|
free(exp_word);
|
2000-11-29 04:33:26 +00:00
|
|
|
curs_set(1);
|
2003-12-29 02:15:23 +00:00
|
|
|
|
2004-10-26 20:58:30 +00:00
|
|
|
if (i == -1) { /* We canceled the replace. */
|
|
|
|
if (canceled != NULL)
|
|
|
|
*canceled = TRUE;
|
2003-12-29 02:15:23 +00:00
|
|
|
break;
|
2004-10-26 20:58:30 +00:00
|
|
|
}
|
2000-11-29 04:33:26 +00:00
|
|
|
}
|
|
|
|
|
2003-12-24 03:13:44 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Set the bol_or_eol flag if we're doing a bol and/or eol regex
|
2004-01-03 21:42:25 +00:00
|
|
|
* replace ("^", "$", or "^$"). */
|
2004-02-24 20:41:39 +00:00
|
|
|
if (ISSET(USE_REGEXP) && regexp_bol_or_eol(&search_regexp,
|
|
|
|
needle))
|
2004-04-05 01:08:14 +00:00
|
|
|
bol_or_eol = TRUE;
|
2003-12-24 03:13:44 +00:00
|
|
|
#endif
|
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
if (i > 0 || replaceall) { /* Yes, replace it!!!! */
|
2003-12-29 02:15:23 +00:00
|
|
|
char *copy;
|
2004-10-30 01:16:08 +00:00
|
|
|
size_t length_change;
|
2003-01-26 04:26:25 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
if (i == 2)
|
2004-07-12 03:10:30 +00:00
|
|
|
replaceall = TRUE;
|
2000-06-19 04:22:15 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
copy = replace_line(needle);
|
2000-06-19 04:22:15 +00:00
|
|
|
|
2003-01-26 04:26:25 +00:00
|
|
|
length_change = strlen(copy) - strlen(current->data);
|
2000-06-19 04:22:15 +00:00
|
|
|
|
2003-01-26 04:26:25 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-11-05 14:37:18 +00:00
|
|
|
/* If the mark was on and (mark_beginbuf, mark_begin_x) was
|
|
|
|
* the top of it, don't change mark_beginx. */
|
|
|
|
if (!old_mark_set || !right_side_up) {
|
|
|
|
/* Keep mark_beginx in sync with the text changes. */
|
2004-11-27 21:10:11 +00:00
|
|
|
if (current == mark_beginbuf &&
|
|
|
|
mark_beginx > current_x) {
|
2004-11-03 22:03:41 +00:00
|
|
|
if (mark_beginx < current_x + match_len)
|
|
|
|
mark_beginx = current_x;
|
|
|
|
else
|
|
|
|
mark_beginx += length_change;
|
|
|
|
}
|
2003-01-26 04:26:25 +00:00
|
|
|
}
|
2002-07-19 01:08:59 +00:00
|
|
|
|
2004-11-05 14:37:18 +00:00
|
|
|
/* If the mark was on and (current, current_x) was the top
|
|
|
|
* of it, don't change real_current_x. */
|
|
|
|
if (!old_mark_set || right_side_up) {
|
2004-11-03 22:03:41 +00:00
|
|
|
#endif
|
2004-11-05 14:37:18 +00:00
|
|
|
/* Keep real_current_x in sync with the text changes. */
|
2004-11-27 21:10:11 +00:00
|
|
|
if (current == real_current &&
|
|
|
|
current_x <= *real_current_x) {
|
2004-11-03 22:03:41 +00:00
|
|
|
if (*real_current_x < current_x + match_len)
|
|
|
|
*real_current_x = current_x + match_len;
|
|
|
|
*real_current_x += length_change;
|
|
|
|
}
|
2004-11-05 14:37:18 +00:00
|
|
|
#ifndef NANO_SMALL
|
2003-01-26 04:26:25 +00:00
|
|
|
}
|
2004-11-05 14:37:18 +00:00
|
|
|
#endif
|
2002-02-16 20:03:44 +00:00
|
|
|
|
2003-01-26 04:26:25 +00:00
|
|
|
/* Set the cursor at the last character of the replacement
|
2003-11-28 16:04:24 +00:00
|
|
|
* text, so searching will resume after the replacement
|
2004-10-30 01:03:15 +00:00
|
|
|
* text. Note that current_x might be set to (size_t)-1
|
|
|
|
* here. */
|
2003-01-26 04:26:25 +00:00
|
|
|
#ifndef NANO_SMALL
|
2003-12-24 03:13:44 +00:00
|
|
|
if (!ISSET(REVERSE_SEARCH))
|
2003-01-26 04:26:25 +00:00
|
|
|
#endif
|
|
|
|
current_x += match_len + length_change - 1;
|
2002-02-16 20:03:44 +00:00
|
|
|
|
2003-10-31 17:53:38 +00:00
|
|
|
/* Cleanup. */
|
2003-01-26 04:26:25 +00:00
|
|
|
totsize += length_change;
|
|
|
|
free(current->data);
|
|
|
|
current->data = copy;
|
2000-10-24 22:25:36 +00:00
|
|
|
|
2004-05-28 20:44:09 +00:00
|
|
|
if (!replaceall) {
|
|
|
|
#ifdef ENABLE_COLOR
|
|
|
|
if (ISSET(COLOR_SYNTAX))
|
|
|
|
edit_refresh();
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
update_line(current, current_x);
|
|
|
|
}
|
|
|
|
|
2000-06-19 04:22:15 +00:00
|
|
|
set_modified();
|
|
|
|
numreplaced++;
|
2003-12-29 02:15:23 +00:00
|
|
|
}
|
2000-06-19 04:22:15 +00:00
|
|
|
}
|
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-11-03 22:03:41 +00:00
|
|
|
if (old_mark_set) {
|
2004-11-04 16:45:48 +00:00
|
|
|
/* If the mark was on, unpartition the filestruct so that it
|
|
|
|
* contains all the text again, set edittop back to what it was
|
|
|
|
* before, turn the mark back on, and refresh the screen. */
|
2004-11-22 00:16:23 +00:00
|
|
|
unpartition_filestruct(&filepart);
|
2004-11-03 22:03:41 +00:00
|
|
|
edittop = edittop_save;
|
2004-02-24 20:41:39 +00:00
|
|
|
SET(MARK_ISSET);
|
2004-11-03 22:03:41 +00:00
|
|
|
edit_refresh();
|
|
|
|
}
|
2004-02-24 20:41:39 +00:00
|
|
|
#endif
|
|
|
|
|
2004-11-03 22:03:41 +00:00
|
|
|
/* If text has been added to the magicline, make a new magicline. */
|
|
|
|
if (filebot->data[0] != '\0')
|
|
|
|
new_magicline();
|
|
|
|
|
2000-11-05 16:52:21 +00:00
|
|
|
return numreplaced;
|
|
|
|
}
|
|
|
|
|
2003-01-13 01:35:15 +00:00
|
|
|
/* Replace a string. */
|
2004-07-02 14:31:03 +00:00
|
|
|
void do_replace(void)
|
2000-11-05 16:52:21 +00:00
|
|
|
{
|
2004-10-18 22:19:22 +00:00
|
|
|
int i;
|
2004-02-24 20:41:39 +00:00
|
|
|
filestruct *edittop_save, *begin;
|
2004-10-21 16:25:44 +00:00
|
|
|
size_t beginx, pww_save;
|
2004-10-18 22:19:22 +00:00
|
|
|
ssize_t numreplaced;
|
2000-11-05 16:52:21 +00:00
|
|
|
|
2001-04-22 07:10:21 +00:00
|
|
|
if (ISSET(VIEW_MODE)) {
|
|
|
|
print_view_warning();
|
|
|
|
replace_abort();
|
2004-07-02 14:31:03 +00:00
|
|
|
return;
|
2001-04-22 07:10:21 +00:00
|
|
|
}
|
|
|
|
|
2004-10-04 22:37:56 +00:00
|
|
|
i = search_init(TRUE, FALSE);
|
2004-02-24 20:41:39 +00:00
|
|
|
if (i == -1) { /* Cancel, Go to Line, blank search
|
|
|
|
* string, or regcomp() failed. */
|
2000-11-05 16:52:21 +00:00
|
|
|
replace_abort();
|
2004-07-02 14:31:03 +00:00
|
|
|
return;
|
2004-02-24 20:41:39 +00:00
|
|
|
} else if (i == -2) { /* No Replace. */
|
2000-11-05 16:52:21 +00:00
|
|
|
do_search();
|
2004-07-02 14:31:03 +00:00
|
|
|
return;
|
2004-02-24 20:41:39 +00:00
|
|
|
} else if (i == 1) /* Case Sensitive, Backwards, or Regexp
|
|
|
|
* search toggle. */
|
|
|
|
do_replace();
|
|
|
|
|
|
|
|
if (i != 0)
|
2004-07-02 14:31:03 +00:00
|
|
|
return;
|
2000-11-05 16:52:21 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* If answer is not "", add answer to the search history list and
|
|
|
|
* copy answer into last_search. */
|
|
|
|
if (answer[0] != '\0') {
|
2003-01-05 20:41:21 +00:00
|
|
|
#ifndef NANO_SMALL
|
2003-01-05 20:43:49 +00:00
|
|
|
update_history(&search_history, answer);
|
2004-02-24 20:41:39 +00:00
|
|
|
#endif
|
2002-07-19 01:08:59 +00:00
|
|
|
last_search = mallocstrcpy(last_search, answer);
|
2004-02-24 20:41:39 +00:00
|
|
|
}
|
2002-07-19 01:08:59 +00:00
|
|
|
|
2003-01-05 20:41:21 +00:00
|
|
|
#ifndef NANO_SMALL
|
2003-01-05 21:47:06 +00:00
|
|
|
replace_history.current = (historytype *)&replace_history.next;
|
|
|
|
last_replace = mallocstrcpy(last_replace, "");
|
2003-01-05 20:41:21 +00:00
|
|
|
#endif
|
2003-01-05 21:47:06 +00:00
|
|
|
|
2004-03-15 20:26:30 +00:00
|
|
|
i = statusq(FALSE, replace_list_2, last_replace,
|
2003-01-05 20:41:21 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-03-15 20:26:30 +00:00
|
|
|
&replace_history,
|
2003-01-05 20:41:21 +00:00
|
|
|
#endif
|
2004-03-15 20:26:30 +00:00
|
|
|
_("Replace with"));
|
2003-01-05 21:47:06 +00:00
|
|
|
|
2003-01-05 20:41:21 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Add this replace string to the replace history list. i == 0
|
|
|
|
* means that the string is not "". */
|
|
|
|
if (i == 0)
|
2003-01-05 20:41:21 +00:00
|
|
|
update_history(&replace_history, answer);
|
2004-02-24 20:41:39 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (i != 0 && i != -2) {
|
|
|
|
if (i == -1) { /* Cancel. */
|
|
|
|
if (last_replace[0] != '\0')
|
|
|
|
answer = mallocstrcpy(answer, last_replace);
|
2004-08-26 04:22:54 +00:00
|
|
|
statusbar(_("Cancelled"));
|
2004-02-24 20:41:39 +00:00
|
|
|
}
|
|
|
|
replace_abort();
|
2004-07-02 14:31:03 +00:00
|
|
|
return;
|
2004-02-24 20:41:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
last_replace = mallocstrcpy(last_replace, answer);
|
2000-11-05 16:52:21 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Save where we are. */
|
2004-10-19 21:09:37 +00:00
|
|
|
edittop_save = edittop;
|
2000-11-05 16:52:21 +00:00
|
|
|
begin = current;
|
2002-02-16 20:03:44 +00:00
|
|
|
beginx = current_x;
|
2004-10-21 16:25:44 +00:00
|
|
|
pww_save = placewewant;
|
2000-11-05 16:52:21 +00:00
|
|
|
|
2004-10-26 20:58:30 +00:00
|
|
|
numreplaced = do_replace_loop(last_search, begin, &beginx, FALSE,
|
|
|
|
NULL);
|
2000-11-05 16:52:21 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Restore where we were. */
|
2004-07-30 20:21:34 +00:00
|
|
|
edittop = edittop_save;
|
2000-06-19 04:22:15 +00:00
|
|
|
current = begin;
|
2002-02-16 20:03:44 +00:00
|
|
|
current_x = beginx;
|
2004-10-21 16:25:44 +00:00
|
|
|
placewewant = pww_save;
|
2004-10-19 21:09:37 +00:00
|
|
|
|
2000-06-19 04:22:15 +00:00
|
|
|
renumber_all();
|
2004-07-30 20:21:34 +00:00
|
|
|
edit_refresh();
|
2003-01-13 01:35:15 +00:00
|
|
|
|
|
|
|
if (numreplaced >= 0)
|
2004-10-18 22:19:22 +00:00
|
|
|
statusbar(P_("Replaced %ld occurrence", "Replaced %ld occurrences",
|
|
|
|
(long)numreplaced), (long)numreplaced);
|
2003-01-13 01:35:15 +00:00
|
|
|
|
2000-06-19 04:22:15 +00:00
|
|
|
replace_abort();
|
|
|
|
}
|
|
|
|
|
2004-08-04 18:24:53 +00:00
|
|
|
void do_gotoline(int line, bool save_pos)
|
2000-06-19 04:22:15 +00:00
|
|
|
{
|
2004-07-30 20:21:34 +00:00
|
|
|
if (line <= 0) { /* Ask for it. */
|
2004-03-15 20:26:30 +00:00
|
|
|
char *ans = mallocstrcpy(NULL, answer);
|
2004-09-30 22:07:21 +00:00
|
|
|
int i = statusq(FALSE, gotoline_list, line < 0 ? ans : "",
|
2003-01-13 01:35:15 +00:00
|
|
|
#ifndef NANO_SMALL
|
2004-03-15 20:26:30 +00:00
|
|
|
NULL,
|
2003-01-13 01:35:15 +00:00
|
|
|
#endif
|
2004-03-15 20:26:30 +00:00
|
|
|
_("Enter line number"));
|
|
|
|
|
|
|
|
free(ans);
|
2003-02-10 02:55:03 +00:00
|
|
|
|
|
|
|
/* Cancel, or Enter with blank string. */
|
2004-10-04 16:01:37 +00:00
|
|
|
if (i < 0) {
|
2004-09-28 15:06:15 +00:00
|
|
|
statusbar(_("Cancelled"));
|
2004-10-04 16:01:37 +00:00
|
|
|
display_main_list();
|
2004-09-30 22:07:21 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-10-04 16:01:37 +00:00
|
|
|
if (i == NANO_TOOTHERWHEREIS_KEY) {
|
2004-10-04 22:37:56 +00:00
|
|
|
/* Keep answer up on the statusbar. */
|
|
|
|
search_init(TRUE, TRUE);
|
|
|
|
|
2004-10-04 16:01:37 +00:00
|
|
|
do_search();
|
2004-07-02 14:31:03 +00:00
|
|
|
return;
|
2000-06-19 04:22:15 +00:00
|
|
|
}
|
2001-04-20 01:59:55 +00:00
|
|
|
|
2004-10-15 01:39:46 +00:00
|
|
|
/* Do a bounds check. Display a warning on an out-of-bounds
|
|
|
|
* line number only if we hit Enter at the statusbar prompt. */
|
2004-08-04 18:24:53 +00:00
|
|
|
if (!parse_num(answer, &line) || line < 0) {
|
2004-10-15 01:39:46 +00:00
|
|
|
if (i == 0)
|
|
|
|
statusbar(_("Come on, be reasonable"));
|
2003-04-15 01:15:09 +00:00
|
|
|
display_main_list();
|
2004-07-02 14:31:03 +00:00
|
|
|
return;
|
2000-06-19 04:22:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-30 20:21:34 +00:00
|
|
|
if (current->lineno > line) {
|
|
|
|
for (; current->prev != NULL && current->lineno > line;
|
|
|
|
current = current->prev)
|
|
|
|
;
|
|
|
|
} else {
|
|
|
|
for (; current->next != NULL && current->lineno < line;
|
|
|
|
current = current->next)
|
|
|
|
;
|
|
|
|
}
|
2000-06-19 04:22:15 +00:00
|
|
|
|
2001-04-20 01:59:55 +00:00
|
|
|
current_x = 0;
|
2001-07-11 02:08:33 +00:00
|
|
|
|
2004-07-02 14:31:03 +00:00
|
|
|
/* If save_pos is TRUE, don't change the cursor position when
|
2004-03-11 02:20:25 +00:00
|
|
|
* updating the edit window. */
|
2004-08-26 18:07:58 +00:00
|
|
|
edit_update(save_pos ? NONE : CENTER);
|
2004-03-11 02:20:25 +00:00
|
|
|
|
2002-06-21 03:20:06 +00:00
|
|
|
placewewant = 0;
|
2003-04-15 01:15:09 +00:00
|
|
|
display_main_list();
|
2000-06-19 04:22:15 +00:00
|
|
|
}
|
|
|
|
|
2004-07-02 14:31:03 +00:00
|
|
|
void do_gotoline_void(void)
|
2000-06-19 04:22:15 +00:00
|
|
|
{
|
2004-07-02 14:31:03 +00:00
|
|
|
do_gotoline(0, FALSE);
|
2000-06-19 04:22:15 +00:00
|
|
|
}
|
2001-09-19 03:19:43 +00:00
|
|
|
|
2002-06-28 22:45:14 +00:00
|
|
|
#if defined(ENABLE_MULTIBUFFER) || !defined(DISABLE_SPELLER)
|
2004-10-30 01:03:15 +00:00
|
|
|
void do_gotopos(int line, size_t pos_x, int pos_y, size_t pos_pww)
|
2001-09-19 03:19:43 +00:00
|
|
|
{
|
2004-07-30 20:21:34 +00:00
|
|
|
/* Since do_gotoline() resets the x-coordinate but not the
|
|
|
|
* y-coordinate, set the coordinates up this way. */
|
2001-09-19 03:19:43 +00:00
|
|
|
current_y = pos_y;
|
2004-07-02 14:31:03 +00:00
|
|
|
do_gotoline(line, TRUE);
|
2001-11-29 03:43:08 +00:00
|
|
|
|
2004-07-30 20:21:34 +00:00
|
|
|
/* Make sure that the x-coordinate is sane here. */
|
|
|
|
current_x = strlen(current->data);
|
|
|
|
if (pos_x < current_x)
|
|
|
|
current_x = pos_x;
|
2001-11-29 03:43:08 +00:00
|
|
|
|
2004-07-30 20:21:34 +00:00
|
|
|
/* Set the rest of the coordinates up. */
|
2004-07-28 20:46:25 +00:00
|
|
|
placewewant = pos_pww;
|
2001-09-19 03:19:43 +00:00
|
|
|
update_line(current, pos_x);
|
|
|
|
}
|
|
|
|
#endif
|
2001-09-22 22:14:25 +00:00
|
|
|
|
|
|
|
#if !defined(NANO_SMALL) && defined(HAVE_REGEX_H)
|
2004-07-02 14:31:03 +00:00
|
|
|
void do_find_bracket(void)
|
2001-09-22 22:14:25 +00:00
|
|
|
{
|
|
|
|
char ch_under_cursor, wanted_ch;
|
2002-09-13 18:14:04 +00:00
|
|
|
const char *pos, *brackets = "([{<>}])";
|
2001-09-22 22:14:25 +00:00
|
|
|
char regexp_pat[] = "[ ]";
|
2004-10-26 16:29:21 +00:00
|
|
|
size_t current_x_save, pww_save;
|
2004-07-28 20:46:25 +00:00
|
|
|
int count = 1;
|
2004-07-03 03:09:12 +00:00
|
|
|
long flags_save;
|
2001-09-22 22:14:25 +00:00
|
|
|
filestruct *current_save;
|
|
|
|
|
|
|
|
ch_under_cursor = current->data[current_x];
|
2003-01-05 20:41:21 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
pos = strchr(brackets, ch_under_cursor);
|
|
|
|
if (ch_under_cursor == '\0' || pos == NULL) {
|
2001-09-22 22:14:25 +00:00
|
|
|
statusbar(_("Not a bracket"));
|
2004-07-02 14:31:03 +00:00
|
|
|
return;
|
2001-09-22 22:14:25 +00:00
|
|
|
}
|
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
assert(strlen(brackets) % 2 == 0);
|
|
|
|
wanted_ch = brackets[(strlen(brackets) - 1) - (pos - brackets)];
|
2001-09-22 22:14:25 +00:00
|
|
|
|
|
|
|
current_save = current;
|
2004-10-09 20:10:55 +00:00
|
|
|
current_x_save = current_x;
|
2004-10-26 16:29:21 +00:00
|
|
|
pww_save = placewewant;
|
2004-07-03 03:09:12 +00:00
|
|
|
flags_save = flags;
|
2001-09-22 22:14:25 +00:00
|
|
|
SET(USE_REGEXP);
|
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Apparent near redundancy with regexp_pat[] here is needed.
|
|
|
|
* "[][]" works, "[[]]" doesn't. */
|
2001-09-22 22:14:25 +00:00
|
|
|
|
2004-07-17 19:49:12 +00:00
|
|
|
if (pos < brackets + (strlen(brackets) / 2)) {
|
|
|
|
/* On a left bracket. */
|
2001-09-22 22:14:25 +00:00
|
|
|
regexp_pat[1] = wanted_ch;
|
|
|
|
regexp_pat[2] = ch_under_cursor;
|
|
|
|
UNSET(REVERSE_SEARCH);
|
2004-07-17 19:49:12 +00:00
|
|
|
} else {
|
|
|
|
/* On a right bracket. */
|
2001-09-22 22:14:25 +00:00
|
|
|
regexp_pat[1] = ch_under_cursor;
|
|
|
|
regexp_pat[2] = wanted_ch;
|
|
|
|
SET(REVERSE_SEARCH);
|
|
|
|
}
|
|
|
|
|
|
|
|
regexp_init(regexp_pat);
|
2004-02-24 20:41:39 +00:00
|
|
|
/* We constructed regexp_pat to be a valid expression. */
|
2004-04-30 19:40:03 +00:00
|
|
|
assert(regexp_compiled);
|
2001-09-22 22:14:25 +00:00
|
|
|
|
2004-10-31 13:20:30 +00:00
|
|
|
findnextstr_wrap_reset();
|
2004-03-15 20:26:30 +00:00
|
|
|
while (TRUE) {
|
2004-08-27 20:28:34 +00:00
|
|
|
if (findnextstr(FALSE, FALSE, FALSE, current, current_x,
|
2004-10-27 02:21:01 +00:00
|
|
|
regexp_pat, NULL)) {
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Found identical bracket. */
|
2003-01-13 01:35:15 +00:00
|
|
|
if (current->data[current_x] == ch_under_cursor)
|
2001-09-22 22:14:25 +00:00
|
|
|
count++;
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Found complementary bracket. */
|
|
|
|
else if (--count == 0) {
|
|
|
|
placewewant = xplustabs();
|
2004-10-26 16:29:21 +00:00
|
|
|
edit_redraw(current_save, pww_save);
|
2004-02-24 20:41:39 +00:00
|
|
|
break;
|
2001-09-22 22:14:25 +00:00
|
|
|
}
|
2003-01-13 01:35:15 +00:00
|
|
|
} else {
|
2004-02-24 20:41:39 +00:00
|
|
|
/* Didn't find either a left or right bracket. */
|
2001-09-22 22:14:25 +00:00
|
|
|
statusbar(_("No matching bracket"));
|
|
|
|
current = current_save;
|
2004-10-09 20:10:55 +00:00
|
|
|
current_x = current_x_save;
|
2003-04-15 01:15:09 +00:00
|
|
|
update_line(current, current_x);
|
2001-09-22 22:14:25 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
regexp_cleanup();
|
2004-07-03 03:09:12 +00:00
|
|
|
flags = flags_save;
|
2001-09-22 22:14:25 +00:00
|
|
|
}
|
|
|
|
#endif
|
2003-01-05 20:41:21 +00:00
|
|
|
|
|
|
|
#ifndef NANO_SMALL
|
|
|
|
/*
|
|
|
|
* search and replace history list support functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* initialize search and replace history lists */
|
|
|
|
void history_init(void)
|
|
|
|
{
|
|
|
|
search_history.next = (historytype *)&search_history.prev;
|
|
|
|
search_history.prev = NULL;
|
|
|
|
search_history.tail = (historytype *)&search_history.next;
|
|
|
|
search_history.current = search_history.next;
|
|
|
|
search_history.count = 0;
|
|
|
|
search_history.len = 0;
|
|
|
|
|
|
|
|
replace_history.next = (historytype *)&replace_history.prev;
|
|
|
|
replace_history.prev = NULL;
|
|
|
|
replace_history.tail = (historytype *)&replace_history.next;
|
|
|
|
replace_history.current = replace_history.next;
|
|
|
|
replace_history.count = 0;
|
|
|
|
replace_history.len = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find first node containing string *s in history list *h */
|
2004-08-11 05:13:08 +00:00
|
|
|
historytype *find_node(historytype *h, const char *s)
|
2003-01-05 20:41:21 +00:00
|
|
|
{
|
2003-01-16 22:16:38 +00:00
|
|
|
for (; h->next != NULL; h = h->next)
|
2003-01-05 20:41:21 +00:00
|
|
|
if (strcmp(s, h->data) == 0)
|
|
|
|
return h;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove node *r */
|
|
|
|
void remove_node(historytype *r)
|
|
|
|
{
|
|
|
|
r->prev->next = r->next;
|
|
|
|
r->next->prev = r->prev;
|
|
|
|
free(r->data);
|
|
|
|
free(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add a node after node *h */
|
|
|
|
void insert_node(historytype *h, const char *s)
|
|
|
|
{
|
|
|
|
historytype *a;
|
|
|
|
|
2003-06-14 20:41:34 +00:00
|
|
|
a = (historytype *)nmalloc(sizeof(historytype));
|
2003-01-05 20:41:21 +00:00
|
|
|
a->next = h->next;
|
2004-08-11 05:13:08 +00:00
|
|
|
a->prev = h;
|
2003-01-05 20:41:21 +00:00
|
|
|
h->next->prev = a;
|
|
|
|
h->next = a;
|
|
|
|
a->data = mallocstrcpy(NULL, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update history list */
|
2004-08-11 05:13:08 +00:00
|
|
|
void update_history(historyheadtype *h, const char *s)
|
2003-01-05 20:41:21 +00:00
|
|
|
{
|
|
|
|
historytype *p;
|
|
|
|
|
2003-01-16 22:16:38 +00:00
|
|
|
if ((p = find_node(h->next, s)) != NULL) {
|
|
|
|
if (p == h->next) /* catch delete and re-insert of
|
|
|
|
same string in 1st node */
|
2003-01-05 20:41:21 +00:00
|
|
|
goto up_hs;
|
2003-01-16 22:16:38 +00:00
|
|
|
remove_node(p); /* delete identical older string */
|
2003-01-05 20:41:21 +00:00
|
|
|
h->count--;
|
|
|
|
}
|
|
|
|
if (h->count == MAX_SEARCH_HISTORY) { /* list 'full', delete oldest */
|
|
|
|
remove_node(h->tail);
|
|
|
|
h->count--;
|
|
|
|
}
|
|
|
|
insert_node((historytype *)h, s);
|
|
|
|
h->count++;
|
2003-01-16 23:44:46 +00:00
|
|
|
SET(HISTORY_CHANGED);
|
2003-01-16 22:16:38 +00:00
|
|
|
up_hs:
|
2003-01-05 20:41:21 +00:00
|
|
|
h->current = h->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return a pointer to either the next older history or NULL if no more */
|
|
|
|
char *get_history_older(historyheadtype *h)
|
|
|
|
{
|
2003-01-16 22:16:38 +00:00
|
|
|
if (h->current->next != NULL) { /* any older entries? */
|
2003-01-05 20:41:21 +00:00
|
|
|
h->current = h->current->next; /* yes */
|
|
|
|
return h->current->data; /* return it */
|
|
|
|
}
|
|
|
|
return NULL; /* end of list */
|
|
|
|
}
|
|
|
|
|
|
|
|
char *get_history_newer(historyheadtype *h)
|
|
|
|
{
|
2003-01-16 22:16:38 +00:00
|
|
|
if (h->current->prev != NULL) {
|
2003-01-05 20:41:21 +00:00
|
|
|
h->current = h->current->prev;
|
2003-01-16 22:16:38 +00:00
|
|
|
if (h->current->prev != NULL)
|
2003-01-05 20:41:21 +00:00
|
|
|
return h->current->data;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get a completion */
|
|
|
|
char *get_history_completion(historyheadtype *h, char *s)
|
|
|
|
{
|
|
|
|
historytype *p;
|
|
|
|
|
2003-01-16 22:16:38 +00:00
|
|
|
for (p = h->current->next; p->next != NULL; p = p->next) {
|
|
|
|
if (strncmp(s, p->data, h->len) == 0 && strlen(p->data) != h->len) {
|
2003-01-05 20:41:21 +00:00
|
|
|
h->current = p;
|
|
|
|
return p->data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
h->current = (historytype*)h;
|
|
|
|
null_at(&s, h->len);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2004-08-11 05:13:08 +00:00
|
|
|
#ifdef DEBUG
|
2003-01-05 20:41:21 +00:00
|
|
|
/* free a history list */
|
|
|
|
void free_history(historyheadtype *h)
|
|
|
|
{
|
2004-08-11 05:13:08 +00:00
|
|
|
historytype *p;
|
2003-01-05 20:41:21 +00:00
|
|
|
|
2004-08-11 05:13:08 +00:00
|
|
|
for (p = h->next; p->next != NULL; p = p->next)
|
2003-01-05 20:41:21 +00:00
|
|
|
remove_node(p);
|
|
|
|
}
|
2004-08-11 05:13:08 +00:00
|
|
|
#endif
|
2003-01-05 20:41:21 +00:00
|
|
|
|
|
|
|
/* end of history support functions */
|
|
|
|
#endif /* !NANO_SMALL */
|