2000-08-06 21:13:45 +00:00
|
|
|
/* $Id$ */
|
2000-06-19 04:22:15 +00:00
|
|
|
/**************************************************************************
|
|
|
|
* search.c *
|
|
|
|
* *
|
2005-01-02 20:30:15 +00:00
|
|
|
* Copyright (C) 2000-2005 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. *
|
|
|
|
* *
|
2005-05-15 19:57:17 +00:00
|
|
|
* 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. *
|
2000-06-19 04:22:15 +00:00
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the Free Software *
|
2005-05-15 19:57:17 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
|
|
|
|
* 02110-1301, USA. *
|
2000-06-19 04:22:15 +00:00
|
|
|
* *
|
|
|
|
**************************************************************************/
|
|
|
|
|
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"
|
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? */
|
2005-06-03 19:28:30 +00:00
|
|
|
#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
|
2005-05-23 16:30:06 +00:00
|
|
|
static bool history_changed = FALSE;
|
|
|
|
/* Have any of the history lists changed? */
|
|
|
|
#endif
|
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);
|
2005-01-16 20:05:36 +00:00
|
|
|
numchars = actual_x(disp, mbstrnlen(disp, COLS / 2));
|
2004-05-29 16:25:30 +00:00
|
|
|
|
|
|
|
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 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
|
|
|
|
2005-01-02 20:30:15 +00:00
|
|
|
buf = charalloc(strlen(disp) + 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
|
2005-06-02 18:41:31 +00:00
|
|
|
&search_history,
|
2003-01-05 20:41:21 +00:00
|
|
|
#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. */
|
2005-06-16 18:48:30 +00:00
|
|
|
ISSET(BACKWARDS_SEARCH) ? _(" [Backwards]") :
|
2003-09-16 01:16:49 +00:00
|
|
|
#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"));
|
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:
|
2005-06-16 18:48:30 +00:00
|
|
|
TOGGLE(BACKWARDS_SEARCH);
|
2004-10-16 15:41:57 +00:00
|
|
|
backupstring = mallocstrcpy(backupstring, answer);
|
|
|
|
return 1;
|
2005-06-03 20:51:39 +00:00
|
|
|
#endif
|
2001-06-14 02:54:22 +00:00
|
|
|
#ifdef HAVE_REGEX_H
|
2005-06-03 20:51:39 +00:00
|
|
|
case NANO_REGEXP_KEY:
|
2004-10-16 15:41:57 +00:00
|
|
|
TOGGLE(USE_REGEXP);
|
|
|
|
backupstring = mallocstrcpy(backupstring, answer);
|
|
|
|
return 1;
|
2001-06-14 02:54:22 +00:00
|
|
|
#endif
|
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:
|
2005-05-25 18:44:37 +00:00
|
|
|
do_gotolinecolumn(current->lineno, placewewant + 1,
|
|
|
|
TRUE, TRUE, FALSE);
|
2005-05-17 18:06:26 +00:00
|
|
|
/* Put answer up on the statusbar and
|
|
|
|
* fall through. */
|
2004-10-16 15:41:57 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
2002-07-19 01:08:59 +00:00
|
|
|
}
|
2000-06-19 04:22:15 +00:00
|
|
|
}
|
2005-05-31 17:35:11 +00:00
|
|
|
|
2000-06-19 04:22:15 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-02-12 23:09:27 +00:00
|
|
|
bool is_whole_word(size_t pos, const char *buf, const char *word)
|
2002-01-08 15:00:24 +00:00
|
|
|
{
|
2005-02-12 23:09:27 +00:00
|
|
|
char *p = charalloc(mb_cur_max()), *r = charalloc(mb_cur_max());
|
|
|
|
size_t word_end = pos + strlen(word);
|
|
|
|
bool retval;
|
2002-01-08 15:00:24 +00:00
|
|
|
|
2005-02-12 23:09:27 +00:00
|
|
|
assert(buf != NULL && pos <= strlen(buf) && word != NULL);
|
|
|
|
|
|
|
|
parse_mbchar(buf + move_mbleft(buf, pos), p, NULL, NULL);
|
|
|
|
parse_mbchar(buf + word_end, r, NULL, NULL);
|
|
|
|
|
|
|
|
/* If we're at the beginning of the line or the character before the
|
2005-06-15 03:03:45 +00:00
|
|
|
* word isn't a non-punctuation "word" character, and if we're at
|
|
|
|
* the end of the line or the character after the word isn't a
|
|
|
|
* non-punctuation "word" character, we have a whole word. */
|
|
|
|
retval = (pos == 0 || !is_word_mbchar(p, FALSE)) &&
|
|
|
|
(word_end == strlen(buf) || !is_word_mbchar(r, FALSE));
|
2005-02-12 23:09:27 +00:00
|
|
|
|
|
|
|
free(p);
|
|
|
|
free(r);
|
|
|
|
|
|
|
|
return retval;
|
2002-01-08 15:00:24 +00:00
|
|
|
}
|
|
|
|
|
2005-02-12 23:09:27 +00:00
|
|
|
/* Look for needle, starting at (current, current_x). If no_sameline is
|
|
|
|
* TRUE, skip over begin when looking for needle. begin is the line
|
|
|
|
* where we first started searching, at column 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
|
2005-06-16 18:48:30 +00:00
|
|
|
ISSET(BACKWARDS_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
|
2005-06-16 18:48:30 +00:00
|
|
|
if (ISSET(BACKWARDS_SEARCH)) {
|
2004-08-27 20:28:34 +00:00
|
|
|
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
|
2005-06-16 18:48:30 +00:00
|
|
|
if (ISSET(BACKWARDS_SEARCH)) {
|
2004-08-27 20:28:34 +00:00
|
|
|
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
|
2005-06-16 18:48:30 +00:00
|
|
|
if (ISSET(BACKWARDS_SEARCH))
|
2004-02-24 20:41:39 +00:00
|
|
|
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
|
2005-06-16 18:48:30 +00:00
|
|
|
((!ISSET(BACKWARDS_SEARCH) && current_x_find > beginx) ||
|
|
|
|
(ISSET(BACKWARDS_SEARCH) && current_x_find < beginx))
|
2004-02-24 20:41:39 +00:00
|
|
|
#else
|
|
|
|
current_x_find > beginx
|
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
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();
|
2005-06-03 21:00:55 +00:00
|
|
|
#if !defined(NANO_SMALL) || defined(HAVE_REGEX_H)
|
2004-02-24 20:41:39 +00:00
|
|
|
else if (i == 1) /* Case Sensitive, Backwards, or Regexp search
|
|
|
|
* toggle. */
|
2000-06-19 04:22:15 +00:00
|
|
|
do_search();
|
2005-06-03 21:00:55 +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')
|
2005-06-02 18:41:31 +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);
|
2005-05-17 16:54:34 +00:00
|
|
|
if (fileptr == current && fileptr_x == current_x &&
|
|
|
|
!didfind)
|
2004-02-24 20:41:39 +00:00
|
|
|
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
|
2005-05-26 03:47:24 +00:00
|
|
|
int replace_regexp(char *string, bool create)
|
2000-07-07 01:49:52 +00:00
|
|
|
{
|
2005-05-26 03:47:24 +00:00
|
|
|
/* We have a split personality here. If create is FALSE, just
|
|
|
|
* calculate 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;
|
2005-06-21 22:32:50 +00:00
|
|
|
size_t search_match_count =
|
|
|
|
regmatches[0].rm_eo - regmatches[0].rm_so;
|
|
|
|
size_t new_line_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) {
|
2005-05-26 03:47:24 +00:00
|
|
|
if (create)
|
2000-10-26 01:44:42 +00:00
|
|
|
*string++ = *c;
|
|
|
|
c++;
|
2005-06-21 22:37:47 +00:00
|
|
|
new_line_size++;
|
2000-10-26 01:44:42 +00:00
|
|
|
} else {
|
2005-06-21 22:32:50 +00:00
|
|
|
size_t 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. */
|
2005-06-21 22:37:47 +00:00
|
|
|
new_line_size += i;
|
2000-10-26 01:44:42 +00:00
|
|
|
|
2005-05-26 03:47:24 +00:00
|
|
|
/* And if create is TRUE, append the result of the
|
2004-02-24 20:41:39 +00:00
|
|
|
* subexpression match to the new line. */
|
2005-05-26 03:47:24 +00:00
|
|
|
if (create) {
|
2005-06-22 00:24:11 +00:00
|
|
|
strncpy(string, current->data + current_x +
|
2004-02-24 20:41:39 +00:00
|
|
|
regmatches[num].rm_so, i);
|
|
|
|
string += i;
|
2000-10-26 01:44:42 +00:00
|
|
|
}
|
|
|
|
}
|
2000-07-07 01:49:52 +00:00
|
|
|
}
|
|
|
|
|
2005-05-26 03:47:24 +00:00
|
|
|
if (create)
|
2003-01-13 01:35:15 +00:00
|
|
|
*string = '\0';
|
2000-07-07 01:49:52 +00:00
|
|
|
|
2005-06-21 22:32:50 +00:00
|
|
|
return new_line_size;
|
2000-07-07 01:49:52 +00:00
|
|
|
}
|
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;
|
2005-05-26 03:32:41 +00:00
|
|
|
size_t new_line_size, search_match_count;
|
2000-07-07 01:49:52 +00:00
|
|
|
|
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;
|
2005-05-26 03:47:24 +00:00
|
|
|
new_line_size = replace_regexp(NULL, FALSE);
|
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. */
|
2005-06-22 00:24:11 +00:00
|
|
|
strncpy(copy, current->data, current_x);
|
2000-07-07 01:49:52 +00:00
|
|
|
|
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));
|
2005-05-26 03:32:41 +00:00
|
|
|
|
2004-02-24 20:41:39 +00:00
|
|
|
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-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
|
|
|
|
|
2005-06-06 03:46:32 +00:00
|
|
|
if (!replaceall)
|
|
|
|
edit_refresh();
|
2003-01-13 01:35:15 +00:00
|
|
|
|
2005-06-13 05:16:55 +00:00
|
|
|
/* Indicate 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
|
|
|
size_t xpt = xplustabs();
|
2005-06-13 04:37:28 +00:00
|
|
|
char *exp_word = display_string(current->data, xpt,
|
|
|
|
strnlenpt(current->data, current_x + match_len) - xpt,
|
2004-12-23 17:43:27 +00:00
|
|
|
FALSE);
|
2003-09-16 01:16:49 +00:00
|
|
|
|
2000-11-29 04:33:26 +00:00
|
|
|
curs_set(0);
|
2005-06-15 19:15:14 +00:00
|
|
|
|
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);
|
2005-06-15 19:15:14 +00:00
|
|
|
|
2003-09-16 01:16:49 +00:00
|
|
|
free(exp_word);
|
2005-06-15 19:15:14 +00:00
|
|
|
|
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
|
2005-06-16 18:48:30 +00:00
|
|
|
if (!ISSET(BACKWARDS_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
|
2005-03-10 20:55:11 +00:00
|
|
|
if (!ISSET(NO_COLOR_SYNTAX))
|
2004-05-28 20:44:09 +00:00
|
|
|
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
|
2005-06-02 18:41:31 +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
|
|
|
|
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
|
2005-06-02 18:41:31 +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)
|
2005-06-02 18:41:31 +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)
|
2005-06-14 23:36:13 +00:00
|
|
|
statusbar(P_("Replaced %lu occurrence",
|
|
|
|
"Replaced %lu occurrences", (unsigned long)numreplaced),
|
|
|
|
(unsigned long)numreplaced);
|
2003-01-13 01:35:15 +00:00
|
|
|
|
2000-06-19 04:22:15 +00:00
|
|
|
replace_abort();
|
|
|
|
}
|
|
|
|
|
2005-05-25 18:44:37 +00:00
|
|
|
/* Go to the specified line and column, or ask for them if interactive
|
|
|
|
* is TRUE. Save the x-coordinate and y-coordinate if save_pos is TRUE.
|
|
|
|
* Note that both the line and column numbers should be one-based. */
|
2005-05-17 18:06:26 +00:00
|
|
|
void do_gotolinecolumn(int line, ssize_t column, bool use_answer, bool
|
|
|
|
interactive, bool save_pos)
|
2000-06-19 04:22:15 +00:00
|
|
|
{
|
2005-05-17 18:06:26 +00:00
|
|
|
if (interactive) { /* Ask for it. */
|
2004-03-15 20:26:30 +00:00
|
|
|
char *ans = mallocstrcpy(NULL, answer);
|
2005-05-17 18:06:26 +00:00
|
|
|
int i = statusq(FALSE, gotoline_list, use_answer ? 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
|
2005-05-17 21:49:19 +00:00
|
|
|
_("Enter line number, column number"));
|
2004-03-15 20:26:30 +00:00
|
|
|
|
|
|
|
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
|
2005-05-25 18:44:37 +00:00
|
|
|
* line or column number only if we hit Enter at the statusbar
|
|
|
|
* prompt. */
|
2005-05-17 18:06:26 +00:00
|
|
|
if (!parse_line_column(answer, &line, &column) || line < 1 ||
|
2005-05-25 18:44:37 +00:00
|
|
|
column < 1) {
|
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
|
|
|
}
|
2005-05-17 18:06:26 +00:00
|
|
|
} else {
|
|
|
|
if (line < 1)
|
2005-05-17 22:27:15 +00:00
|
|
|
line = current->lineno;
|
2005-05-17 18:06:26 +00:00
|
|
|
|
2005-05-25 18:44:37 +00:00
|
|
|
if (column < 1)
|
|
|
|
column = placewewant + 1;
|
2000-06-19 04:22:15 +00:00
|
|
|
}
|
|
|
|
|
2005-05-17 22:01:55 +00:00
|
|
|
for (current = fileage; current->next != NULL && line > 1; line--)
|
|
|
|
current = current->next;
|
2000-06-19 04:22:15 +00:00
|
|
|
|
2005-05-25 18:44:37 +00:00
|
|
|
current_x = actual_x(current->data, column - 1);
|
|
|
|
placewewant = column - 1;
|
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
|
|
|
|
2003-04-15 01:15:09 +00:00
|
|
|
display_main_list();
|
2000-06-19 04:22:15 +00:00
|
|
|
}
|
|
|
|
|
2005-05-17 18:06:26 +00:00
|
|
|
void do_gotolinecolumn_void(void)
|
2000-06-19 04:22:15 +00:00
|
|
|
{
|
2005-05-25 18:44:37 +00:00
|
|
|
do_gotolinecolumn(current->lineno, placewewant + 1, FALSE, TRUE,
|
|
|
|
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
|
|
|
{
|
2005-05-17 18:06:26 +00:00
|
|
|
/* Since do_gotolinecolumn() resets the x-coordinate but not the
|
2004-07-30 20:21:34 +00:00
|
|
|
* y-coordinate, set the coordinates up this way. */
|
2001-09-19 03:19:43 +00:00
|
|
|
current_y = pos_y;
|
2005-05-25 18:44:37 +00:00
|
|
|
do_gotolinecolumn(line, pos_x + 1, FALSE, FALSE, TRUE);
|
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
|
|
|
|
2005-06-16 20:58:19 +00:00
|
|
|
#ifndef NANO_SMALL
|
|
|
|
#ifdef HAVE_REGEX_H
|
2004-07-02 14:31:03 +00:00
|
|
|
void do_find_bracket(void)
|
2001-09-22 22:14:25 +00:00
|
|
|
{
|
2005-06-16 20:41:20 +00:00
|
|
|
const char *pos, *bracket_pat = "([{<>}])";
|
|
|
|
char cursor_ch, wanted_ch, 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;
|
2005-06-16 20:41:20 +00:00
|
|
|
bool regexp_set = ISSET(USE_REGEXP);
|
|
|
|
bool backwards_search_set = ISSET(BACKWARDS_SEARCH);
|
2001-09-22 22:14:25 +00:00
|
|
|
filestruct *current_save;
|
|
|
|
|
2005-06-16 20:41:20 +00:00
|
|
|
cursor_ch = current->data[current_x];
|
|
|
|
pos = strchr(bracket_pat, cursor_ch);
|
2003-01-05 20:41:21 +00:00
|
|
|
|
2005-06-16 20:41:20 +00:00
|
|
|
if (cursor_ch == '\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
|
|
|
}
|
|
|
|
|
2005-06-16 20:41:20 +00:00
|
|
|
assert(strlen(bracket_pat) % 2 == 0);
|
2005-03-14 19:17:27 +00:00
|
|
|
|
2005-06-16 20:41:20 +00:00
|
|
|
wanted_ch =
|
|
|
|
bracket_pat[(strlen(bracket_pat) - 1) - (pos - bracket_pat)];
|
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;
|
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. */
|
2005-06-16 20:41:20 +00:00
|
|
|
if (pos < bracket_pat + (strlen(bracket_pat) / 2)) {
|
2004-07-17 19:49:12 +00:00
|
|
|
/* On a left bracket. */
|
2001-09-22 22:14:25 +00:00
|
|
|
regexp_pat[1] = wanted_ch;
|
2005-06-16 20:41:20 +00:00
|
|
|
regexp_pat[2] = cursor_ch;
|
2005-06-16 18:48:30 +00:00
|
|
|
UNSET(BACKWARDS_SEARCH);
|
2004-07-17 19:49:12 +00:00
|
|
|
} else {
|
|
|
|
/* On a right bracket. */
|
2005-06-16 20:41:20 +00:00
|
|
|
regexp_pat[1] = cursor_ch;
|
2001-09-22 22:14:25 +00:00
|
|
|
regexp_pat[2] = wanted_ch;
|
2005-06-16 18:48:30 +00:00
|
|
|
SET(BACKWARDS_SEARCH);
|
2001-09-22 22:14:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
regexp_init(regexp_pat);
|
2005-03-14 19:17:27 +00:00
|
|
|
|
2005-06-16 20:41:20 +00:00
|
|
|
/* We constructed regexp_pat to be a valid regular 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. */
|
2005-06-16 20:41:20 +00:00
|
|
|
if (current->data[current_x] == cursor_ch)
|
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();
|
2005-06-16 20:41:20 +00:00
|
|
|
|
|
|
|
/* Restore search direction. */
|
|
|
|
if (backwards_search_set)
|
|
|
|
SET(BACKWARDS_SEARCH);
|
|
|
|
else
|
|
|
|
UNSET(BACKWARDS_SEARCH);
|
|
|
|
|
|
|
|
/* Restore regular expression usage setting. */
|
|
|
|
if (!regexp_set)
|
|
|
|
UNSET(USE_REGEXP);
|
2001-09-22 22:14:25 +00:00
|
|
|
}
|
2005-06-16 20:58:19 +00:00
|
|
|
#endif /* HAVE_REGEX_H */
|
2003-01-05 20:41:21 +00:00
|
|
|
|
2005-06-03 19:28:30 +00:00
|
|
|
#ifdef ENABLE_NANORC
|
2005-05-23 16:30:06 +00:00
|
|
|
/* Indicate whether any of the history lists have changed. */
|
|
|
|
bool history_has_changed(void)
|
|
|
|
{
|
|
|
|
return history_changed;
|
|
|
|
}
|
2005-06-03 19:28:30 +00:00
|
|
|
#endif
|
2003-01-05 20:41:21 +00:00
|
|
|
|
2005-05-23 16:30:06 +00:00
|
|
|
/* Initialize the search and replace history lists. */
|
2003-01-05 20:41:21 +00:00
|
|
|
void history_init(void)
|
|
|
|
{
|
2005-05-23 16:30:06 +00:00
|
|
|
search_history = make_new_node(NULL);
|
|
|
|
search_history->data = mallocstrcpy(NULL, "");
|
|
|
|
searchage = search_history;
|
|
|
|
searchbot = search_history;
|
|
|
|
|
|
|
|
replace_history = make_new_node(NULL);
|
|
|
|
replace_history->data = mallocstrcpy(NULL, "");
|
|
|
|
replaceage = replace_history;
|
|
|
|
replacebot = replace_history;
|
2003-01-05 20:41:21 +00:00
|
|
|
}
|
|
|
|
|
2005-06-02 18:41:31 +00:00
|
|
|
/* Return the first node containing the first len characters of the
|
|
|
|
* string s in the history list, starting at h_start and ending at
|
|
|
|
* h_end, or NULL if there isn't one. */
|
|
|
|
filestruct *find_history(filestruct *h_start, filestruct *h_end, const
|
|
|
|
char *s, size_t len)
|
2003-01-05 20:41:21 +00:00
|
|
|
{
|
2005-06-02 18:41:31 +00:00
|
|
|
filestruct *p;
|
2005-05-23 16:30:06 +00:00
|
|
|
|
2005-06-02 18:41:31 +00:00
|
|
|
for (p = h_start; p != h_end->next && p != NULL; p = p->next) {
|
|
|
|
if (strncmp(s, p->data, len) == 0)
|
|
|
|
return p;
|
2005-05-08 17:08:51 +00:00
|
|
|
}
|
2005-05-23 16:30:06 +00:00
|
|
|
|
2003-01-05 20:41:21 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-06-02 18:41:31 +00:00
|
|
|
/* Update a history list. h should be the current position in the
|
|
|
|
* list. */
|
|
|
|
void update_history(filestruct **h, const char *s)
|
2003-01-05 20:41:21 +00:00
|
|
|
{
|
2005-06-02 18:41:31 +00:00
|
|
|
filestruct **hage = NULL, **hbot = NULL, *p;
|
|
|
|
|
|
|
|
assert(h != NULL && s != NULL);
|
|
|
|
|
|
|
|
if (*h == search_history) {
|
|
|
|
hage = &searchage;
|
|
|
|
hbot = &searchbot;
|
|
|
|
} else if (*h == replace_history) {
|
|
|
|
hage = &replaceage;
|
|
|
|
hbot = &replacebot;
|
|
|
|
}
|
2003-01-05 20:41:21 +00:00
|
|
|
|
2005-06-02 18:41:31 +00:00
|
|
|
assert(hage != NULL && hbot != NULL);
|
2003-01-05 20:41:21 +00:00
|
|
|
|
2005-05-23 16:30:06 +00:00
|
|
|
/* If this string is already in the history, delete it. */
|
2005-06-02 18:41:31 +00:00
|
|
|
p = find_history(*hage, *hbot, s, (size_t)-1);
|
2003-01-05 20:41:21 +00:00
|
|
|
|
2005-05-23 16:30:06 +00:00
|
|
|
if (p != NULL) {
|
|
|
|
filestruct *foo, *bar;
|
|
|
|
|
|
|
|
/* If the string is at the beginning, move the beginning down to
|
|
|
|
* the next string. */
|
|
|
|
if (p == *hage)
|
|
|
|
*hage = (*hage)->next;
|
|
|
|
|
|
|
|
/* Delete the string. */
|
|
|
|
foo = p;
|
|
|
|
bar = p->next;
|
|
|
|
unlink_node(foo);
|
|
|
|
delete_node(foo);
|
|
|
|
renumber(bar);
|
2003-01-05 20:41:21 +00:00
|
|
|
}
|
|
|
|
|
2005-05-23 16:30:06 +00:00
|
|
|
/* If the history is full, delete the beginning entry to make room
|
|
|
|
* for the new entry at the end. */
|
|
|
|
if ((*hbot)->lineno == MAX_SEARCH_HISTORY + 1) {
|
|
|
|
filestruct *foo = *hage;
|
|
|
|
|
|
|
|
*hage = (*hage)->next;
|
|
|
|
unlink_node(foo);
|
|
|
|
delete_node(foo);
|
|
|
|
renumber(*hage);
|
2003-01-05 20:41:21 +00:00
|
|
|
}
|
2005-05-23 16:30:06 +00:00
|
|
|
|
|
|
|
/* Add the new entry to the end. */
|
|
|
|
(*hbot)->data = mallocstrcpy(NULL, s);
|
|
|
|
splice_node(*hbot, make_new_node(*hbot), (*hbot)->next);
|
|
|
|
*hbot = (*hbot)->next;
|
|
|
|
(*hbot)->data = mallocstrcpy(NULL, "");
|
|
|
|
|
2005-06-03 19:28:30 +00:00
|
|
|
#ifdef ENABLE_NANORC
|
2005-05-23 16:30:06 +00:00
|
|
|
/* Indicate that the history's been changed. */
|
|
|
|
history_changed = TRUE;
|
2005-06-03 19:28:30 +00:00
|
|
|
#endif
|
2005-05-23 16:30:06 +00:00
|
|
|
|
|
|
|
/* Set the current position in the list to the bottom. */
|
|
|
|
*h = *hbot;
|
2003-01-05 20:41:21 +00:00
|
|
|
}
|
|
|
|
|
2005-05-26 02:46:42 +00:00
|
|
|
/* Move h to the string in the history list just before it, and return
|
|
|
|
* that string. If there isn't one, don't move h and return NULL. */
|
2005-05-23 16:30:06 +00:00
|
|
|
char *get_history_older(filestruct **h)
|
2003-01-05 20:41:21 +00:00
|
|
|
{
|
2005-05-23 16:30:06 +00:00
|
|
|
assert(h != NULL);
|
2003-01-05 20:41:21 +00:00
|
|
|
|
2005-05-23 16:30:06 +00:00
|
|
|
if ((*h)->prev == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
*h = (*h)->prev;
|
|
|
|
|
|
|
|
return (*h)->data;
|
2003-01-05 20:41:21 +00:00
|
|
|
}
|
|
|
|
|
2005-05-26 02:46:42 +00:00
|
|
|
/* Move h to the string in the history list just after it, and return
|
|
|
|
* that string. If there isn't one, don't move h and return NULL. */
|
2005-05-23 16:30:06 +00:00
|
|
|
char *get_history_newer(filestruct **h)
|
2003-01-05 20:41:21 +00:00
|
|
|
{
|
2005-05-23 16:30:06 +00:00
|
|
|
assert(h != NULL);
|
2003-01-05 20:41:21 +00:00
|
|
|
|
2005-05-23 16:30:06 +00:00
|
|
|
if ((*h)->next == NULL)
|
|
|
|
return NULL;
|
2003-01-05 20:41:21 +00:00
|
|
|
|
2005-05-23 16:30:06 +00:00
|
|
|
*h = (*h)->next;
|
|
|
|
|
|
|
|
return (*h)->data;
|
|
|
|
}
|
2005-06-02 18:41:31 +00:00
|
|
|
|
|
|
|
#ifndef DISABLE_TABCOMP
|
|
|
|
/* Move h to the next string that's a tab completion of the string s,
|
|
|
|
* looking at only the first len characters of s, and return that
|
2005-06-03 14:30:52 +00:00
|
|
|
* string. If there isn't one, or if len is 0, don't move h and return
|
|
|
|
* s. */
|
2005-06-02 18:41:31 +00:00
|
|
|
char *get_history_completion(filestruct **h, char *s, size_t len)
|
|
|
|
{
|
|
|
|
assert(s != NULL);
|
|
|
|
|
|
|
|
if (len > 0) {
|
|
|
|
filestruct *hage = NULL, *hbot = NULL, *p;
|
|
|
|
|
|
|
|
assert(h != NULL);
|
|
|
|
|
|
|
|
if (*h == search_history) {
|
|
|
|
hage = searchage;
|
|
|
|
hbot = searchbot;
|
|
|
|
} else if (*h == replace_history) {
|
|
|
|
hage = replaceage;
|
|
|
|
hbot = replacebot;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(hage != NULL && hbot != NULL);
|
|
|
|
|
2005-06-13 03:52:33 +00:00
|
|
|
/* Search the history list from the current position to the
|
|
|
|
* bottom for a match of len characters. Skip over an exact
|
|
|
|
* match. */
|
2005-06-02 18:41:31 +00:00
|
|
|
p = find_history((*h)->next, hbot, s, len);
|
|
|
|
|
2005-06-13 03:52:33 +00:00
|
|
|
while (p != NULL && strcmp(p->data, s) == 0)
|
|
|
|
p = find_history(p->next, hbot, s, len);
|
|
|
|
|
2005-06-02 18:41:31 +00:00
|
|
|
if (p != NULL) {
|
|
|
|
*h = p;
|
|
|
|
return (*h)->data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Search the history list from the top to the current position
|
2005-06-13 03:52:33 +00:00
|
|
|
* for a match of len characters. Skip over an exact match. */
|
2005-06-02 18:41:31 +00:00
|
|
|
p = find_history(hage, *h, s, len);
|
|
|
|
|
2005-06-13 03:52:33 +00:00
|
|
|
while (p != NULL && strcmp(p->data, s) == 0)
|
|
|
|
p = find_history(p->next, *h, s, len);
|
|
|
|
|
2005-06-02 18:41:31 +00:00
|
|
|
if (p != NULL) {
|
|
|
|
*h = p;
|
|
|
|
return (*h)->data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-13 03:52:33 +00:00
|
|
|
/* If we're here, we didn't find a match, we didn't find an inexact
|
|
|
|
* match, or len is 0. Return s. */
|
2005-06-02 18:41:31 +00:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
#endif
|
2005-06-16 20:58:19 +00:00
|
|
|
#endif /* !NANO_SMALL */
|