blob: 68ed79da141dedc49a48e9e383b2ef2b7bb6c052 [file] [log] [blame]
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001/**************************************************************************
Benno Schulenberg514cd9a2016-08-29 17:10:49 +02002 * search.c -- This file is part of GNU nano. *
Chris Allegrettabceb1b22000-06-19 04:22:15 +00003 * *
Chris Allegretta8a07a962009-12-02 03:36:22 +00004 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
Benno Schulenberg7a9f4a42014-04-30 20:18:26 +00005 * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. *
Benno Schulenbergc1183972017-02-21 20:27:49 +01006 * Copyright (C) 2015, 2016, 2017 Benno Schulenberg *
Benno Schulenberg406e5242016-08-29 15:14:18 +02007 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +02008 * GNU nano is free software: you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published *
10 * by the Free Software Foundation, either version 3 of the License, *
11 * or (at your option) any later version. *
Chris Allegrettabceb1b22000-06-19 04:22:15 +000012 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020013 * GNU nano is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty *
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
16 * See the GNU General Public License for more details. *
Chris Allegrettabceb1b22000-06-19 04:22:15 +000017 * *
18 * You should have received a copy of the GNU General Public License *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020019 * along with this program. If not, see http://www.gnu.org/licenses/. *
Chris Allegrettabceb1b22000-06-19 04:22:15 +000020 * *
21 **************************************************************************/
22
David Lawrence Ramsey034b9942005-12-08 02:47:10 +000023#include "proto.h"
Chris Allegretta6efda542001-04-28 18:03:52 +000024
Chris Allegrettabceb1b22000-06-19 04:22:15 +000025#include <string.h>
26#include <stdio.h>
David Lawrence Ramsey1044d742004-02-24 20:41:39 +000027#include <unistd.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000028#include <ctype.h>
Chris Allegretta5beed502003-01-05 20:41:21 +000029#include <errno.h>
Chris Allegretta0dc26dc2009-01-24 22:40:41 +000030#include <time.h>
Chris Allegretta4da1fc62000-06-21 03:00:43 +000031
Benno Schulenbergae8df002016-05-01 12:59:32 +020032static bool came_full_circle = FALSE;
33 /* Have we reached the starting line again while searching? */
Benno Schulenbergb341f292014-06-19 20:05:24 +000034#ifndef DISABLE_HISTORIES
David Lawrence Ramsey934f9682005-05-23 16:30:06 +000035static bool history_changed = FALSE;
36 /* Have any of the history lists changed? */
37#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +000038#ifdef HAVE_REGEX_H
David Lawrence Ramsey27fbc692004-10-19 21:09:37 +000039static bool regexp_compiled = FALSE;
40 /* Have we compiled any regular expressions? */
David Lawrence Ramsey4b741b92004-04-30 19:40:03 +000041
Benno Schulenberg0b0ddb12017-01-02 20:25:24 +010042/* Compile the given regular expression and store it in search_regexp.
43 * Return TRUE if the expression is valid, and FALSE otherwise. */
David Lawrence Ramsey61848f12007-01-09 23:40:24 +000044bool regexp_init(const char *regexp)
Chris Allegretta9fc8d432000-07-07 01:49:52 +000045{
Benno Schulenberg0b0ddb12017-01-02 20:25:24 +010046 int value = regcomp(&search_regexp, fixbounds(regexp),
Benno Schulenberg08cd1972016-09-08 21:00:51 +020047 NANO_REG_EXTENDED | (ISSET(CASE_SENSITIVE) ? 0 : REG_ICASE));
Chris Allegretta5d715142003-01-29 04:18:37 +000048
Benno Schulenberg0b0ddb12017-01-02 20:25:24 +010049 /* If regex compilation failed, show the error message. */
50 if (value != 0) {
51 size_t len = regerror(value, &search_regexp, NULL, 0);
David Lawrence Ramsey4b741b92004-04-30 19:40:03 +000052 char *str = charalloc(len);
53
Benno Schulenberg0b0ddb12017-01-02 20:25:24 +010054 regerror(value, &search_regexp, str, len);
Benno Schulenberg2535f512016-04-30 17:31:43 +020055 statusline(ALERT, _("Bad regex \"%s\": %s"), regexp, str);
David Lawrence Ramsey4b741b92004-04-30 19:40:03 +000056 free(str);
David Lawrence Ramsey0ec34ac2007-01-09 23:35:02 +000057
58 return FALSE;
David Lawrence Ramsey4b741b92004-04-30 19:40:03 +000059 }
60
61 regexp_compiled = TRUE;
David Lawrence Ramsey0ec34ac2007-01-09 23:35:02 +000062
63 return TRUE;
Chris Allegretta9fc8d432000-07-07 01:49:52 +000064}
65
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +000066/* Decompile the compiled regular expression we used in the last
67 * search, if any. */
Chris Allegrettae3167732001-03-18 16:59:34 +000068void regexp_cleanup(void)
Chris Allegretta9fc8d432000-07-07 01:49:52 +000069{
David Lawrence Ramsey4b741b92004-04-30 19:40:03 +000070 if (regexp_compiled) {
71 regexp_compiled = FALSE;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +000072 regfree(&search_regexp);
73 }
Chris Allegretta9fc8d432000-07-07 01:49:52 +000074}
Chris Allegretta47805612000-07-07 02:35:34 +000075#endif
Chris Allegretta9fc8d432000-07-07 01:49:52 +000076
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +000077/* Indicate on the statusbar that the string at str was not found by the
78 * last search. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +000079void not_found_msg(const char *str)
80{
David Lawrence Ramsey483ea322004-05-29 16:25:30 +000081 char *disp;
82 int numchars;
David Lawrence Ramseyb94d51a2007-04-19 03:15:04 +000083
David Lawrence Ramseya3370c42004-04-05 01:08:14 +000084 assert(str != NULL);
David Lawrence Ramsey483ea322004-05-29 16:25:30 +000085
David Lawrence Ramseyfc693212004-12-23 17:43:27 +000086 disp = display_string(str, 0, (COLS / 2) + 1, FALSE);
David Lawrence Ramsey65658ef2005-01-16 20:05:36 +000087 numchars = actual_x(disp, mbstrnlen(disp, COLS / 2));
David Lawrence Ramsey483ea322004-05-29 16:25:30 +000088
Benno Schulenberg2535f512016-04-30 17:31:43 +020089 statusline(HUSH, _("\"%.*s%s\" not found"), numchars, disp,
Benno Schulenberge753cd12016-03-17 19:30:29 +000090 (disp[numchars] == '\0') ? "" : "...");
David Lawrence Ramsey483ea322004-05-29 16:25:30 +000091
92 free(disp);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +000093}
94
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +000095/* Abort the current search or replace. Clean up by displaying the main
96 * shortcut list, updating the screen if the mark was on before, and
97 * decompiling the compiled regular expression we used in the last
98 * search, if any. */
99void search_replace_abort(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000100{
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000101#ifndef NANO_TINY
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000102 if (openfile->mark_set)
Benno Schulenbergf920e0d2016-12-03 17:00:28 +0100103 refresh_needed = TRUE;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000104#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000105#ifdef HAVE_REGEX_H
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000106 regexp_cleanup();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000107#endif
108}
109
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000110/* Set up the system variables for a search or replace. If use_answer
David Lawrence Ramsey20323a82006-03-23 22:14:40 +0000111 * is TRUE, only set backupstring to answer. Return -2 to run the
112 * opposite program (search -> replace, replace -> search), return -1 if
113 * the search should be canceled (due to Cancel, a blank search string,
114 * Go to Line, or a failed regcomp()), return 0 on success, and return 1
115 * on rerun calling program.
Chris Allegretta7662c862003-01-13 01:35:15 +0000116 *
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000117 * replacing is TRUE if we call from do_replace(), and FALSE if called
118 * from do_search(). */
119int search_init(bool replacing, bool use_answer)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000120{
Chris Allegrettaf372bd92001-07-15 22:24:24 +0000121 int i = 0;
Chris Allegretta71844ba2000-11-03 14:23:00 +0000122 char *buf;
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000123 static char *backupstring = NULL;
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000124 /* The search string we'll be using. */
Benno Schulenberg9f93b332016-03-19 18:51:46 +0000125 functionptrtype func;
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000126
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000127 /* If use_answer is TRUE, set backupstring to answer and get out. */
128 if (use_answer) {
129 backupstring = mallocstrcpy(backupstring, answer);
130 return 0;
131 }
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000132
133 /* We display the search prompt below. If the user types a partial
134 * search string and then Replace or a toggle, we will return to
135 * do_search() or do_replace() and be called again. In that case,
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000136 * we should put the same search string back up. */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000137
Benno Schulenberg1d3d3072016-05-27 21:31:55 +0200138 if (*last_search != '\0') {
David Lawrence Ramseyfc693212004-12-23 17:43:27 +0000139 char *disp = display_string(last_search, 0, COLS / 3, FALSE);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000140
David Lawrence Ramsey08cd7ef2005-01-02 20:30:15 +0000141 buf = charalloc(strlen(disp) + 7);
Benno Schulenbergcb776fa2015-03-21 21:40:56 +0000142 /* We use (COLS / 3) here because we need to see more on the line. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000143 sprintf(buf, " [%s%s]", disp,
David Lawrence Ramsey3d12f0f2005-10-26 23:14:59 +0000144 (strlenpt(last_search) > COLS / 3) ? "..." : "");
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000145 free(disp);
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000146 } else
147 buf = mallocstrcpy(NULL, "");
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000148
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000149 /* This is now one simple call. It just does a lot. */
Benno Schulenbergfd0589d2017-01-02 21:12:44 +0100150 i = do_prompt(FALSE, FALSE,
Benno Schulenbergb77b1392016-08-26 12:18:04 +0200151 replacing ? MREPLACE : MWHEREIS, backupstring,
Benno Schulenbergb341f292014-06-19 20:05:24 +0000152#ifndef DISABLE_HISTORIES
Benno Schulenbergb77b1392016-08-26 12:18:04 +0200153 &search_history,
Chris Allegretta5beed502003-01-05 20:41:21 +0000154#endif
Benno Schulenbergb77b1392016-08-26 12:18:04 +0200155 /* TRANSLATORS: This is the main search prompt. */
156 edit_refresh, "%s%s%s%s%s%s", _("Search"),
Benno Schulenbergb77b1392016-08-26 12:18:04 +0200157 /* TRANSLATORS: The next three modify the search prompt. */
Benno Schulenberg08cd1972016-09-08 21:00:51 +0200158 ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") : "",
David Lawrence Ramsey4b741b92004-04-30 19:40:03 +0000159#ifdef HAVE_REGEX_H
Benno Schulenbergb77b1392016-08-26 12:18:04 +0200160 ISSET(USE_REGEXP) ? _(" [Regexp]") :
David Lawrence Ramsey4b741b92004-04-30 19:40:03 +0000161#endif
Benno Schulenbergb77b1392016-08-26 12:18:04 +0200162 "",
Benno Schulenberg08cd1972016-09-08 21:00:51 +0200163 ISSET(BACKWARDS_SEARCH) ? _(" [Backwards]") : "", replacing ?
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000164#ifndef NANO_TINY
Benno Schulenbergb77b1392016-08-26 12:18:04 +0200165 /* TRANSLATORS: The next two modify the search prompt. */
166 openfile->mark_set ? _(" (to replace) in selection") :
David Lawrence Ramseye1ee22f2004-11-03 23:05:11 +0000167#endif
Benno Schulenbergb77b1392016-08-26 12:18:04 +0200168 _(" (to replace)") : "", buf);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000169
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000170 /* Release buf now that we don't need it anymore. */
Chris Allegretta45329a12002-03-10 01:22:21 +0000171 free(buf);
172
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000173 free(backupstring);
174 backupstring = NULL;
175
Benno Schulenberge2911312016-03-19 18:23:37 +0000176 /* If the search was cancelled, or we have a blank answer and
177 * nothing was searched for yet during this session, get out. */
178 if (i == -1 || (i == -2 && *last_search == '\0')) {
David Lawrence Ramseyd1322102004-08-26 04:22:54 +0000179 statusbar(_("Cancelled"));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000180 return -1;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000181 }
David Lawrence Ramseye0b55132005-05-31 17:35:11 +0000182
Benno Schulenberg9f93b332016-03-19 18:51:46 +0000183 /* If Enter was pressed, see what we got. */
184 if (i == 0 || i == -2) {
185 /* If an answer was given, remember it. */
186 if (*answer != '\0') {
187 last_search = mallocstrcpy(last_search, answer);
188#ifndef DISABLE_HISTORIES
189 update_history(&search_history, answer);
190#endif
191 }
192#ifdef HAVE_REGEX_H
193 if (ISSET(USE_REGEXP) && !regexp_init(last_search))
194 return -1;
195 else
196#endif
197 return 0; /* We have a valid string or regex. */
198 }
199
200 func = func_from_key(&i);
201
Benno Schulenberg9f93b332016-03-19 18:51:46 +0000202 if (func == case_sens_void) {
203 TOGGLE(CASE_SENSITIVE);
204 backupstring = mallocstrcpy(backupstring, answer);
205 return 1;
206 } else if (func == backwards_void) {
207 TOGGLE(BACKWARDS_SEARCH);
208 backupstring = mallocstrcpy(backupstring, answer);
209 return 1;
Benno Schulenberg28487712016-04-04 19:38:57 +0200210 } else
Benno Schulenberg9f93b332016-03-19 18:51:46 +0000211#ifdef HAVE_REGEX_H
Benno Schulenberg28487712016-04-04 19:38:57 +0200212 if (func == regexp_void) {
Benno Schulenberg9f93b332016-03-19 18:51:46 +0000213 TOGGLE(USE_REGEXP);
214 backupstring = mallocstrcpy(backupstring, answer);
215 return 1;
Benno Schulenberg28487712016-04-04 19:38:57 +0200216 } else
Benno Schulenberg9f93b332016-03-19 18:51:46 +0000217#endif
Benno Schulenberg28487712016-04-04 19:38:57 +0200218 if (func == do_replace || func == flip_replace_void) {
Benno Schulenberg9f93b332016-03-19 18:51:46 +0000219 backupstring = mallocstrcpy(backupstring, answer);
220 return -2; /* Call the opposite search function. */
221 } else if (func == do_gotolinecolumn_void) {
222 do_gotolinecolumn(openfile->current->lineno,
223 openfile->placewewant + 1, TRUE, TRUE);
224 return 3;
225 }
226
227 return -1;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000228}
229
Benno Schulenbergb454d9c2015-04-25 15:17:22 +0000230/* Look for needle, starting at (current, current_x). begin is the line
Benno Schulenberg400e7ce2016-03-30 12:00:48 +0000231 * where we first started searching, at column begin_x. Return 1 when we
232 * found something, 0 when nothing, and -2 on cancel. When match_len is
233 * not NULL, set it to the length of the found string, if any. */
Benno Schulenberg8f10e362017-02-10 13:51:51 +0100234int findnextstr(const char *needle, bool whole_word_only, bool have_region,
235 size_t *match_len, bool skipone, const filestruct *begin, size_t begin_x)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000236{
Benno Schulenberge36e8292017-01-05 21:25:30 +0100237 size_t found_len = strlen(needle);
238 /* The length of a match -- will be recomputed for a regex. */
Benno Schulenberg108fe332016-03-28 19:00:19 +0000239 int feedback = 0;
240 /* When bigger than zero, show and wipe the "Searching..." message. */
Benno Schulenberg4a1302e2017-01-05 22:40:49 +0100241 filestruct *line = openfile->current;
Benno Schulenbergc88d7ce2017-01-13 16:11:47 +0100242 /* The line that we will search through now. */
243 const char *from = line->data + openfile->current_x;
244 /* The point in the line from where we start searching. */
245 const char *found = NULL;
246 /* A pointer to the location of the match, if any. */
Benno Schulenberg9f1a44d2016-05-01 12:35:47 +0200247 size_t found_x;
248 /* The x coordinate of a found occurrence. */
Chris Allegretta0dc26dc2009-01-24 22:40:41 +0000249 time_t lastkbcheck = time(NULL);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000250
Chris Allegretta0dc26dc2009-01-24 22:40:41 +0000251 enable_nodelay();
Benno Schulenberg4b2751c2016-03-23 10:19:01 +0000252
Benno Schulenberg433c7e52016-05-04 17:49:37 +0200253 if (begin == NULL)
254 came_full_circle = FALSE;
255
Benno Schulenberg4b2751c2016-03-23 10:19:01 +0000256 /* Start searching through the lines, looking for the needle. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000257 while (TRUE) {
Benno Schulenberg3660c622016-03-23 10:27:54 +0000258 /* Glance at the keyboard once every second. */
259 if (time(NULL) - lastkbcheck > 0) {
Benno Schulenberg6c86ee12014-07-02 19:12:38 +0000260 int input = parse_kbinput(edit);
261
Benno Schulenberg8f615112014-04-14 09:57:06 +0000262 lastkbcheck = time(NULL);
Benno Schulenberg6c86ee12014-07-02 19:12:38 +0000263
Benno Schulenberg9cbe6a62016-05-05 22:12:24 +0200264 /* Consume all waiting keystrokes until a Cancel. */
265 while (input) {
266 if (func_from_key(&input) == do_cancel) {
267 statusbar(_("Cancelled"));
268 disable_nodelay();
269 return -2;
270 }
271 input = parse_kbinput(NULL);
Chris Allegretta0dc26dc2009-01-24 22:40:41 +0000272 }
Benno Schulenberg108fe332016-03-28 19:00:19 +0000273
274 if (++feedback > 0)
Benno Schulenberg6bb30972016-06-24 09:40:31 +0200275 /* TRANSLATORS: This is shown when searching takes
276 * more than half a second. */
Benno Schulenberg108fe332016-03-28 19:00:19 +0000277 statusbar(_("Searching..."));
Chris Allegretta0dc26dc2009-01-24 22:40:41 +0000278 }
279
Benno Schulenberg4b2751c2016-03-23 10:19:01 +0000280 /* Search for the needle in the current line. */
Benno Schulenbergef7a7c52017-01-24 22:37:37 +0100281 if (!skipone)
282 found = strstrwrapper(line->data, needle, from);
David Lawrence Ramsey45cfbec2003-11-28 16:04:24 +0000283
Benno Schulenbergc88d7ce2017-01-13 16:11:47 +0100284 /* Ignore the initial match at the starting position: continue
285 * searching from the next character, or invalidate the match. */
Benno Schulenberg94e56322017-01-26 20:05:21 +0100286 if (skipone || (!whole_word_only && !came_full_circle &&
287 found == begin->data + begin_x)) {
Benno Schulenbergef7a7c52017-01-24 22:37:37 +0100288 skipone = FALSE;
Benno Schulenbergc88d7ce2017-01-13 16:11:47 +0100289 if (ISSET(BACKWARDS_SEARCH) && from != line->data) {
290 from = line->data + move_mbleft(line->data, from - line->data);
291 continue;
292 } else if (!ISSET(BACKWARDS_SEARCH) && *from != '\0') {
293 from += move_mbright(from, 0);
294 continue;
295 }
296 found = NULL;
297 }
298
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000299 if (found != NULL) {
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000300#ifdef HAVE_REGEX_H
Benno Schulenberge36e8292017-01-05 21:25:30 +0100301 /* When doing a regex search, compute the length of the match. */
Benno Schulenberg64aa8752017-01-26 16:24:18 +0100302 if (ISSET(USE_REGEXP))
Benno Schulenberge36e8292017-01-05 21:25:30 +0100303 found_len = regmatches[0].rm_eo - regmatches[0].rm_so;
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000304#endif
David Lawrence Ramseycf9c34a2005-11-16 05:59:06 +0000305#ifndef DISABLE_SPELLER
Benno Schulenberg4223b832017-01-06 10:56:39 +0100306 /* When we're spell checking, a match should be a separate word;
307 * if it's not, continue looking in the rest of the line. */
308 if (whole_word_only && !is_separate_word(found - line->data,
309 found_len, line->data)) {
310 from = found + move_mbright(found, 0);
311 continue;
312 }
David Lawrence Ramseycf9c34a2005-11-16 05:59:06 +0000313#endif
Benno Schulenberg4223b832017-01-06 10:56:39 +0100314 /* The match is valid. */
315 break;
Chris Allegrettae4933a32001-06-13 02:35:44 +0000316 }
317
Benno Schulenberg4b2751c2016-03-23 10:19:01 +0000318 /* If we're back at the beginning, then there is no needle. */
Benno Schulenberg433c7e52016-05-04 17:49:37 +0200319 if (came_full_circle) {
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000320 not_found_msg(needle);
Benno Schulenberg8f615112014-04-14 09:57:06 +0000321 disable_nodelay();
Benno Schulenberg400e7ce2016-03-30 12:00:48 +0000322 return 0;
Chris Allegrettae4933a32001-06-13 02:35:44 +0000323 }
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000324
David Lawrence Ramseye6958d52006-03-23 21:25:04 +0000325 /* Move to the previous or next line in the file. */
Benno Schulenberg7ba356a2016-04-08 18:11:22 +0200326 if (ISSET(BACKWARDS_SEARCH))
Benno Schulenberg4a1302e2017-01-05 22:40:49 +0100327 line = line->prev;
Benno Schulenberg7ba356a2016-04-08 18:11:22 +0200328 else
Benno Schulenberg4a1302e2017-01-05 22:40:49 +0100329 line = line->next;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000330
Benno Schulenberg8f10e362017-02-10 13:51:51 +0100331 /* If we've reached the start or end of the buffer, wrap around;
332 * but stop when spell-checking or replacing in a region. */
Benno Schulenberg4a1302e2017-01-05 22:40:49 +0100333 if (line == NULL) {
Benno Schulenberg8f10e362017-02-10 13:51:51 +0100334 if (whole_word_only || have_region) {
Benno Schulenberg3c8647e2016-05-01 11:18:20 +0200335 disable_nodelay();
336 return 0;
337 }
Benno Schulenberg8f10e362017-02-10 13:51:51 +0100338
Benno Schulenberg7ba356a2016-04-08 18:11:22 +0200339 if (ISSET(BACKWARDS_SEARCH))
Benno Schulenberg4a1302e2017-01-05 22:40:49 +0100340 line = openfile->filebot;
Benno Schulenberg7ba356a2016-04-08 18:11:22 +0200341 else
Benno Schulenberg4a1302e2017-01-05 22:40:49 +0100342 line = openfile->fileage;
Benno Schulenberg3c8647e2016-05-01 11:18:20 +0200343
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000344 statusbar(_("Search Wrapped"));
Benno Schulenberg108fe332016-03-28 19:00:19 +0000345 /* Delay the "Searching..." message for at least two seconds. */
346 feedback = -2;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000347 }
348
Benno Schulenberg4b2751c2016-03-23 10:19:01 +0000349 /* If we've reached the original starting line, take note. */
Benno Schulenberg4a1302e2017-01-05 22:40:49 +0100350 if (line == begin)
Benno Schulenbergae8df002016-05-01 12:59:32 +0200351 came_full_circle = TRUE;
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +0000352
Benno Schulenberg4b2751c2016-03-23 10:19:01 +0000353 /* Set the starting x to the start or end of the line. */
Benno Schulenberg4a1302e2017-01-05 22:40:49 +0100354 from = line->data;
David Lawrence Ramseyf3ecffd2005-06-16 18:48:30 +0000355 if (ISSET(BACKWARDS_SEARCH))
Benno Schulenberg4a1302e2017-01-05 22:40:49 +0100356 from += strlen(line->data);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000357 }
358
Benno Schulenberg4a1302e2017-01-05 22:40:49 +0100359 found_x = found - line->data;
Benno Schulenberg9f1a44d2016-05-01 12:35:47 +0200360
361 /* Ensure that the found occurrence is not beyond the starting x. */
Benno Schulenberg08cd1972016-09-08 21:00:51 +0200362 if (came_full_circle && ((!ISSET(BACKWARDS_SEARCH) && found_x > begin_x) ||
363 (ISSET(BACKWARDS_SEARCH) && found_x < begin_x))) {
Benno Schulenberg9f1a44d2016-05-01 12:35:47 +0200364 not_found_msg(needle);
365 disable_nodelay();
366 return 0;
367 }
368
Chris Allegretta0dc26dc2009-01-24 22:40:41 +0000369 disable_nodelay();
Benno Schulenberg8704dde2016-03-23 09:52:34 +0000370
Benno Schulenberg4b2751c2016-03-23 10:19:01 +0000371 /* Set the current position to point at what we found. */
Benno Schulenberg4a1302e2017-01-05 22:40:49 +0100372 openfile->current = line;
Benno Schulenberg9f1a44d2016-05-01 12:35:47 +0200373 openfile->current_x = found_x;
David Lawrence Ramsey9819ed02004-10-21 15:32:11 +0000374
Benno Schulenberg4b2751c2016-03-23 10:19:01 +0000375 /* When requested, pass back the length of the match. */
376 if (match_len != NULL)
377 *match_len = found_len;
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000378
Benno Schulenberg108fe332016-03-28 19:00:19 +0000379 if (feedback > 0)
380 blank_statusbar();
381
Benno Schulenberg400e7ce2016-03-30 12:00:48 +0000382 return 1;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000383}
384
Benno Schulenbergf1508942016-03-20 16:57:15 +0000385/* Ask what to search for and then go looking for it. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000386void do_search(void)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000387{
Benno Schulenbergf1508942016-03-20 16:57:15 +0000388 int i = search_init(FALSE, FALSE);
David Lawrence Ramseyef0d5a72006-05-22 02:08:49 +0000389
Benno Schulenberg988274b2016-03-17 10:06:15 +0000390 if (i == -1) /* Cancelled, or some other exit reason. */
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000391 search_replace_abort();
Benno Schulenberg988274b2016-03-17 10:06:15 +0000392 else if (i == -2) /* Do a replace instead. */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000393 do_replace();
Benno Schulenberg988274b2016-03-17 10:06:15 +0000394 else if (i == 1) /* Toggled something. */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000395 do_search();
Chris Allegretta86f8b3a2000-10-31 05:28:33 +0000396
Benno Schulenbergf1508942016-03-20 16:57:15 +0000397 if (i == 0)
398 go_looking();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000399}
400
Benno Schulenberg4990f742015-07-26 09:23:24 +0000401#ifndef NANO_TINY
402/* Search in the backward direction for the next occurrence. */
403void do_findprevious(void)
404{
405 if ISSET(BACKWARDS_SEARCH)
406 do_research();
407 else {
408 SET(BACKWARDS_SEARCH);
409 do_research();
410 UNSET(BACKWARDS_SEARCH);
411 }
412}
413
414/* Search in the forward direction for the next occurrence. */
415void do_findnext(void)
416{
417 if ISSET(BACKWARDS_SEARCH) {
418 UNSET(BACKWARDS_SEARCH);
419 do_research();
420 SET(BACKWARDS_SEARCH);
421 } else
422 do_research();
423}
Benno Schulenberg7098dd02016-03-17 18:51:46 +0000424#endif /* !NANO_TINY */
Benno Schulenberg4990f742015-07-26 09:23:24 +0000425
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000426/* Search for the last string without prompting. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000427void do_research(void)
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000428{
Benno Schulenberga2676992015-06-20 08:10:25 +0000429#ifndef DISABLE_HISTORIES
430 /* If nothing was searched for yet during this run of nano, but
431 * there is a search history, take the most recent item. */
Benno Schulenberg1d3d3072016-05-27 21:31:55 +0200432 if (*last_search == '\0' && searchbot->prev != NULL)
Benno Schulenberga2676992015-06-20 08:10:25 +0000433 last_search = mallocstrcpy(last_search, searchbot->prev->data);
434#endif
435
Benno Schulenberg1d3d3072016-05-27 21:31:55 +0200436 if (*last_search == '\0') {
Benno Schulenberg65c7c812016-01-26 09:16:09 +0000437 statusbar(_("No current search pattern"));
Benno Schulenbergb3b2fa82016-03-20 16:03:20 +0000438 return;
439 }
440
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000441#ifdef HAVE_REGEX_H
Benno Schulenbergb3b2fa82016-03-20 16:03:20 +0000442 if (ISSET(USE_REGEXP) && !regexp_init(last_search))
443 return;
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000444#endif
445
Benno Schulenbergb3b2fa82016-03-20 16:03:20 +0000446 /* Use the search-menu key bindings, to allow cancelling. */
447 currmenu = MWHEREIS;
Benno Schulenberg19bc63d2016-03-17 09:12:30 +0000448
Benno Schulenbergf1508942016-03-20 16:57:15 +0000449 go_looking();
450}
Benno Schulenbergf1508942016-03-20 16:57:15 +0000451
452/* Search for the global string 'last_search'. Inform the user when
453 * the string occurs only once. */
454void go_looking(void)
455{
456 filestruct *was_current = openfile->current;
457 size_t was_current_x = openfile->current_x;
Benno Schulenberg400e7ce2016-03-30 12:00:48 +0000458 int didfind;
Benno Schulenbergee57cbf2016-08-06 14:39:08 +0200459#ifdef DEBUG
460 clock_t start = clock();
461#endif
Benno Schulenbergf1508942016-03-20 16:57:15 +0000462
Benno Schulenberg05238f32016-05-01 13:38:54 +0200463 came_full_circle = FALSE;
Benno Schulenbergae8df002016-05-01 12:59:32 +0200464
Benno Schulenberg8f10e362017-02-10 13:51:51 +0100465 didfind = findnextstr(last_search, FALSE, FALSE, NULL, FALSE,
Benno Schulenberg2cd8ca42016-10-23 17:59:26 +0200466 openfile->current, openfile->current_x);
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000467
Benno Schulenbergb3b2fa82016-03-20 16:03:20 +0000468 /* If we found something, and we're back at the exact same spot
469 * where we started searching, then this is the only occurrence. */
Benno Schulenberg400e7ce2016-03-30 12:00:48 +0000470 if (didfind == 1 && openfile->current == was_current &&
Benno Schulenbergf1508942016-03-20 16:57:15 +0000471 openfile->current_x == was_current_x)
Benno Schulenbergb3b2fa82016-03-20 16:03:20 +0000472 statusbar(_("This is the only occurrence"));
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000473
Benno Schulenbergee57cbf2016-08-06 14:39:08 +0200474#ifdef DEBUG
475 statusline(HUSH, "Took: %.2f", (double)(clock() - start) / CLOCKS_PER_SEC);
476#endif
477
Benno Schulenbergaa1ae0a2016-04-10 21:16:19 +0200478 edit_redraw(was_current);
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000479 search_replace_abort();
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000480}
481
Chris Allegretta805c26d2000-09-06 13:39:17 +0000482#ifdef HAVE_REGEX_H
Benno Schulenbergc7f56912015-07-26 17:29:34 +0000483/* Calculate the size of the replacement text, taking possible
Benno Schulenberg17ab9a22015-07-26 17:04:29 +0000484 * subexpressions \1 to \9 into account. Return the replacement
485 * text in the passed string only when create is TRUE. */
David Lawrence Ramseye3970f52005-05-26 03:47:24 +0000486int replace_regexp(char *string, bool create)
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000487{
Benno Schulenberg51743232016-03-28 19:14:33 +0000488 const char *c = answer;
Benno Schulenbergc7f56912015-07-26 17:29:34 +0000489 size_t replacement_size = 0;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000490
Chris Allegretta6df90f52002-07-19 01:08:59 +0000491 /* Iterate through the replacement text to handle subexpression
492 * replacement using \1, \2, \3, etc. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000493 while (*c != '\0') {
David Lawrence Ramseyf968a182006-07-13 13:27:16 +0000494 int num = (*(c + 1) - '0');
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000495
Benno Schulenberge753cd12016-03-17 19:30:29 +0000496 if (*c != '\\' || num < 1 || num > 9 || num > search_regexp.re_nsub) {
David Lawrence Ramseye3970f52005-05-26 03:47:24 +0000497 if (create)
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000498 *string++ = *c;
499 c++;
Benno Schulenbergc7f56912015-07-26 17:29:34 +0000500 replacement_size++;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000501 } else {
David Lawrence Ramsey16799ba2005-06-21 22:32:50 +0000502 size_t i = regmatches[num].rm_eo - regmatches[num].rm_so;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000503
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000504 /* Skip over the replacement expression. */
505 c += 2;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000506
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000507 /* But add the length of the subexpression to new_size. */
Benno Schulenbergc7f56912015-07-26 17:29:34 +0000508 replacement_size += i;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000509
David Lawrence Ramseye3970f52005-05-26 03:47:24 +0000510 /* And if create is TRUE, append the result of the
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000511 * subexpression match to the new line. */
David Lawrence Ramseye3970f52005-05-26 03:47:24 +0000512 if (create) {
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000513 strncpy(string, openfile->current->data +
Benno Schulenberg64aa8752017-01-26 16:24:18 +0100514 regmatches[num].rm_so, i);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000515 string += i;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000516 }
517 }
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000518 }
519
David Lawrence Ramseye3970f52005-05-26 03:47:24 +0000520 if (create)
Chris Allegretta7662c862003-01-13 01:35:15 +0000521 *string = '\0';
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000522
Benno Schulenbergc7f56912015-07-26 17:29:34 +0000523 return replacement_size;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000524}
Benno Schulenberge4c34c32014-03-17 14:15:57 +0000525#endif /* HAVE_REGEX_H */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000526
Benno Schulenberg17ab9a22015-07-26 17:04:29 +0000527/* Return a copy of the current line with one needle replaced. */
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000528char *replace_line(const char *needle)
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000529{
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000530 char *copy;
Benno Schulenbergc7f56912015-07-26 17:29:34 +0000531 size_t match_len;
532 size_t new_line_size = strlen(openfile->current->data) + 1;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000533
Benno Schulenbergc7f56912015-07-26 17:29:34 +0000534 /* First adjust the size of the new line for the change. */
Chris Allegretta805c26d2000-09-06 13:39:17 +0000535#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000536 if (ISSET(USE_REGEXP)) {
Benno Schulenbergc7f56912015-07-26 17:29:34 +0000537 match_len = regmatches[0].rm_eo - regmatches[0].rm_so;
538 new_line_size += replace_regexp(NULL, FALSE) - match_len;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000539 } else {
Chris Allegretta47805612000-07-07 02:35:34 +0000540#endif
Benno Schulenbergc7f56912015-07-26 17:29:34 +0000541 match_len = strlen(needle);
542 new_line_size += strlen(answer) - match_len;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000543#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000544 }
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000545#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000546
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000547 /* Create the buffer. */
Chris Allegretta88b09152001-05-17 11:35:43 +0000548 copy = charalloc(new_line_size);
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000549
Benno Schulenberg17ab9a22015-07-26 17:04:29 +0000550 /* Copy the head of the original line. */
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000551 strncpy(copy, openfile->current->data, openfile->current_x);
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000552
Benno Schulenberg17ab9a22015-07-26 17:04:29 +0000553 /* Add the replacement text. */
Chris Allegretta805c26d2000-09-06 13:39:17 +0000554#ifdef HAVE_REGEX_H
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000555 if (ISSET(USE_REGEXP))
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000556 replace_regexp(copy + openfile->current_x, TRUE);
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000557 else
Chris Allegretta47805612000-07-07 02:35:34 +0000558#endif
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000559 strcpy(copy + openfile->current_x, answer);
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000560
Benno Schulenbergc7f56912015-07-26 17:29:34 +0000561 assert(openfile->current_x + match_len <= strlen(openfile->current->data));
David Lawrence Ramsey16f88132005-05-26 03:32:41 +0000562
Benno Schulenberg17ab9a22015-07-26 17:04:29 +0000563 /* Copy the tail of the original line. */
Benno Schulenbergc7f56912015-07-26 17:29:34 +0000564 strcat(copy, openfile->current->data + openfile->current_x + match_len);
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000565
566 return copy;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000567}
568
Benno Schulenbergf311c0a2016-07-27 09:23:49 +0200569/* Step through each occurrence of the search string and prompt the user
570 * before replacing it. We seek for needle, and replace it with answer.
571 * The parameters real_current and real_current_x are needed in order to
David Lawrence Ramsey491cad32004-10-08 23:06:01 +0000572 * allow the cursor position to be updated when a word before the cursor
Benno Schulenbergf311c0a2016-07-27 09:23:49 +0200573 * is replaced by a shorter word. Return -1 if needle isn't found, -2 if
574 * the seeking is aborted, else the number of replacements performed. */
Benno Schulenberg2cd8ca42016-10-23 17:59:26 +0200575ssize_t do_replace_loop(const char *needle, bool whole_word_only,
576 const filestruct *real_current, size_t *real_current_x)
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000577{
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000578 ssize_t numreplaced = -1;
579 size_t match_len;
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000580 bool replaceall = FALSE;
Benno Schulenbergef7a7c52017-01-24 22:37:37 +0100581 bool skipone = FALSE;
David Lawrence Ramseyefdb5432017-02-12 12:12:08 -0600582 bool mark_was_set = FALSE;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000583#ifndef NANO_TINY
Benno Schulenberg08a52c12015-04-11 15:21:08 +0000584 filestruct *top, *bot;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000585 size_t top_x, bot_x;
586 bool right_side_up = FALSE;
David Lawrence Ramsey5128de82005-07-12 17:40:16 +0000587 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000588 * FALSE if (current, current_x) is. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000589
David Lawrence Ramseyefdb5432017-02-12 12:12:08 -0600590 mark_was_set = openfile->mark_set;
591
Benno Schulenbergf311c0a2016-07-27 09:23:49 +0200592 /* If the mark is on, frame the region, and turn the mark off. */
Benno Schulenberg5c3d5292017-02-10 14:07:42 +0100593 if (mark_was_set) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000594 mark_order((const filestruct **)&top, &top_x,
Benno Schulenberg95f417f2016-06-14 11:06:04 +0200595 (const filestruct **)&bot, &bot_x, &right_side_up);
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000596 openfile->mark_set = FALSE;
Benno Schulenberg08a52c12015-04-11 15:21:08 +0000597
598 /* Start either at the top or the bottom of the marked region. */
599 if (!ISSET(BACKWARDS_SEARCH)) {
600 openfile->current = top;
Benno Schulenbergda564382017-01-26 21:36:13 +0100601 openfile->current_x = top_x;
Benno Schulenberg08a52c12015-04-11 15:21:08 +0000602 } else {
603 openfile->current = bot;
604 openfile->current_x = bot_x;
605 }
David Lawrence Ramsey491cad32004-10-08 23:06:01 +0000606 }
Benno Schulenberge4c34c32014-03-17 14:15:57 +0000607#endif /* !NANO_TINY */
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000608
Benno Schulenberg05238f32016-05-01 13:38:54 +0200609 came_full_circle = FALSE;
Benno Schulenbergae8df002016-05-01 12:59:32 +0200610
Benno Schulenberg400e7ce2016-03-30 12:00:48 +0000611 while (TRUE) {
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000612 int i = 0;
Benno Schulenberg5c3d5292017-02-10 14:07:42 +0100613 int result = findnextstr(needle, whole_word_only, mark_was_set,
Benno Schulenberg8f10e362017-02-10 13:51:51 +0100614 &match_len, skipone, real_current, *real_current_x);
Benno Schulenberg400e7ce2016-03-30 12:00:48 +0000615
616 /* If nothing more was found, or the user aborted, stop looping. */
617 if (result < 1) {
618 if (result < 0)
619 numreplaced = -2; /* It's a Cancel instead of Not found. */
620 break;
621 }
David Lawrence Ramsey34976662004-10-09 16:26:32 +0000622
Benno Schulenberg08a52c12015-04-11 15:21:08 +0000623#ifndef NANO_TINY
Benno Schulenberg5c3d5292017-02-10 14:07:42 +0100624 /* An occurrence outside of the marked region means we're done. */
625 if (mark_was_set && (openfile->current->lineno > bot->lineno ||
626 openfile->current->lineno < top->lineno ||
627 (openfile->current == bot &&
628 openfile->current_x + match_len > bot_x) ||
629 (openfile->current == top &&
630 openfile->current_x < top_x)))
631 break;
Benno Schulenberg08a52c12015-04-11 15:21:08 +0000632#endif
633
David Lawrence Ramsey8b698f42005-06-13 05:16:55 +0000634 /* Indicate that we found the search string. */
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000635 if (numreplaced == -1)
636 numreplaced = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000637
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000638 if (!replaceall) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000639 size_t xpt = xplustabs();
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000640 char *exp_word = display_string(openfile->current->data,
Benno Schulenberge753cd12016-03-17 19:30:29 +0000641 xpt, strnlenpt(openfile->current->data,
642 openfile->current_x + match_len) - xpt, FALSE);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000643
Benno Schulenberg56cfab32016-02-18 16:31:02 +0000644 /* Refresh the edit window, scrolling it if necessary. */
Benno Schulenberg0a79c782015-03-27 11:29:23 +0000645 edit_refresh();
646
Benno Schulenberg568d2a32016-02-13 19:41:12 +0000647 /* Don't show cursor, to not distract from highlighted match. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000648 curs_set(0);
David Lawrence Ramseyda724532005-06-15 19:15:14 +0000649
Benno Schulenbergc98afde2016-03-30 12:09:39 +0000650 spotlight(TRUE, exp_word);
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000651
Benno Schulenberga2d74f72014-05-28 14:34:11 +0000652 /* TRANSLATORS: This is a prompt. */
David Lawrence Ramseye19449e2005-11-07 21:45:44 +0000653 i = do_yesno_prompt(TRUE, _("Replace this instance?"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000654
Benno Schulenbergc98afde2016-03-30 12:09:39 +0000655 spotlight(FALSE, exp_word);
David Lawrence Ramseyda724532005-06-15 19:15:14 +0000656
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000657 free(exp_word);
David Lawrence Ramseyda724532005-06-15 19:15:14 +0000658
Benno Schulenbergb834ed32016-03-29 15:05:47 +0000659 if (i == -1) /* The replacing was cancelled. */
David Lawrence Ramseyafb75f22003-12-29 02:15:23 +0000660 break;
Benno Schulenberg4edc83c2016-12-22 17:08:10 +0100661 else if (i == 2)
662 replaceall = TRUE;
Benno Schulenbergef7a7c52017-01-24 22:37:37 +0100663
664 /* When "No" or moving backwards, the search routine should
665 * first move one character further before continuing. */
666 skipone = (i == 0 || ISSET(BACKWARDS_SEARCH));
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000667 }
668
Benno Schulenberg4edc83c2016-12-22 17:08:10 +0100669 if (i == 1 || replaceall) { /* Yes, replace it. */
David Lawrence Ramsey91d468d2005-07-18 19:29:27 +0000670 char *copy;
David Lawrence Ramsey687776b2004-10-30 01:16:08 +0000671 size_t length_change;
Chris Allegretta1939c352003-01-26 04:26:25 +0000672
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000673#ifndef NANO_TINY
Benno Schulenberg08a52c12015-04-11 15:21:08 +0000674 add_undo(REPLACE);
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000675#endif
David Lawrence Ramsey91d468d2005-07-18 19:29:27 +0000676 copy = replace_line(needle);
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000677
Benno Schulenbergad827a62015-03-27 10:49:19 +0000678 length_change = strlen(copy) - strlen(openfile->current->data);
Chris Allegretta1939c352003-01-26 04:26:25 +0000679
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000680#ifndef NANO_TINY
Benno Schulenberga1c03ed2015-11-07 09:49:34 +0000681 /* If the mark was on and it was located after the cursor,
682 * then adjust its x position for any text length changes. */
Benno Schulenberg5c3d5292017-02-10 14:07:42 +0100683 if (mark_was_set && !right_side_up) {
David Lawrence Ramsey5128de82005-07-12 17:40:16 +0000684 if (openfile->current == openfile->mark_begin &&
685 openfile->mark_begin_x > openfile->current_x) {
Benno Schulenberga1c03ed2015-11-07 09:49:34 +0000686 if (openfile->mark_begin_x < openfile->current_x + match_len)
David Lawrence Ramsey5128de82005-07-12 17:40:16 +0000687 openfile->mark_begin_x = openfile->current_x;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000688 else
David Lawrence Ramsey5128de82005-07-12 17:40:16 +0000689 openfile->mark_begin_x += length_change;
Benno Schulenberg08a52c12015-04-11 15:21:08 +0000690 bot_x = openfile->mark_begin_x;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000691 }
Chris Allegretta1939c352003-01-26 04:26:25 +0000692 }
Chris Allegretta1939c352003-01-26 04:26:25 +0000693
Benno Schulenberga1c03ed2015-11-07 09:49:34 +0000694 /* If the mark was not on or it was before the cursor, then
695 * adjust the cursor's x position for any text length changes. */
Benno Schulenberg5c3d5292017-02-10 14:07:42 +0100696 if (!mark_was_set || right_side_up) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000697#endif
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000698 if (openfile->current == real_current &&
Benno Schulenberg3534d8f2017-01-24 16:42:42 +0100699 openfile->current_x < *real_current_x) {
Benno Schulenbergad827a62015-03-27 10:49:19 +0000700 if (*real_current_x < openfile->current_x + match_len)
701 *real_current_x = openfile->current_x + match_len;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000702 *real_current_x += length_change;
Benno Schulenbergfd759d52015-04-13 10:59:12 +0000703#ifndef NANO_TINY
Benno Schulenberg08a52c12015-04-11 15:21:08 +0000704 bot_x = *real_current_x;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000705 }
David Lawrence Ramseydcc201b2004-11-05 14:37:18 +0000706#endif
Benno Schulenbergfd759d52015-04-13 10:59:12 +0000707 }
Chris Allegretta1939c352003-01-26 04:26:25 +0000708
Benno Schulenberg8ffc33c2015-07-26 08:20:28 +0000709#ifdef HAVE_REGEX_H
Benno Schulenbergc88fae32016-07-27 09:04:06 +0200710 /* Don't find the same zero-length or BOL match again. */
711 if (match_len == 0 || (*needle == '^' && ISSET(USE_REGEXP)))
Benno Schulenbergef7a7c52017-01-24 22:37:37 +0100712 skipone = TRUE;
Benno Schulenberg8ffc33c2015-07-26 08:20:28 +0000713#endif
Benno Schulenbergef7a7c52017-01-24 22:37:37 +0100714 /* When moving forward, put the cursor just after the replacement
715 * text, so that searching will continue there. */
David Lawrence Ramseyf3ecffd2005-06-16 18:48:30 +0000716 if (!ISSET(BACKWARDS_SEARCH))
Benno Schulenbergef7a7c52017-01-24 22:37:37 +0100717 openfile->current_x += match_len + length_change;
Chris Allegretta1939c352003-01-26 04:26:25 +0000718
Benno Schulenberg17ab9a22015-07-26 17:04:29 +0000719 /* Update the file size, and put the changed line into place. */
720 openfile->totsize += mbstrlen(copy) - mbstrlen(openfile->current->data);
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000721 free(openfile->current->data);
722 openfile->current->data = copy;
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000723
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000724 if (!replaceall) {
Benno Schulenberg00389922014-04-04 11:59:03 +0000725#ifndef DISABLE_COLOR
Benno Schulenberg0f3e3032016-12-02 17:37:11 +0100726 /* When doing syntax coloring, the replacement might require
727 * a change of colors, so refresh the whole edit window. */
Benno Schulenberg65c7c812016-01-26 09:16:09 +0000728 if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX))
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000729 edit_refresh();
730 else
731#endif
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000732 update_line(openfile->current, openfile->current_x);
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000733 }
734
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000735 set_modified();
Benno Schulenbergeef7d102016-12-20 19:27:41 +0100736 as_an_at = TRUE;
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000737 numreplaced++;
David Lawrence Ramseyafb75f22003-12-29 02:15:23 +0000738 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000739 }
740
Benno Schulenberg08a52c12015-04-11 15:21:08 +0000741 if (numreplaced == -1)
742 not_found_msg(needle);
Benno Schulenberg9ec546d2017-02-13 19:11:04 +0100743#ifndef DISABLE_COLOR
744 else if (numreplaced > 0)
745 refresh_needed = TRUE;
746#endif
Benno Schulenberg08a52c12015-04-11 15:21:08 +0000747
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000748#ifndef NANO_TINY
Benno Schulenberg5c3d5292017-02-10 14:07:42 +0100749 if (mark_was_set)
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000750 openfile->mark_set = TRUE;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000751#endif
752
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +0000753 /* If the NO_NEWLINES flag isn't set, and text has been added to the
754 * magicline, make a new magicline. */
755 if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
Chris Allegretta7662c862003-01-13 01:35:15 +0000756 new_magicline();
757
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000758 return numreplaced;
759}
760
Chris Allegretta7662c862003-01-13 01:35:15 +0000761/* Replace a string. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000762void do_replace(void)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000763{
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000764 filestruct *edittop_save, *begin;
Benno Schulenbergea4e9b32016-04-10 09:33:49 +0200765 size_t begin_x;
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000766 ssize_t numreplaced;
David Lawrence Ramsey8f4762a2005-07-16 22:35:11 +0000767 int i;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000768
Chris Allegretta5050aa62001-04-22 07:10:21 +0000769 if (ISSET(VIEW_MODE)) {
770 print_view_warning();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000771 return;
Chris Allegretta5050aa62001-04-22 07:10:21 +0000772 }
773
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000774 i = search_init(TRUE, FALSE);
Benno Schulenberg988274b2016-03-17 10:06:15 +0000775
776 if (i == -1) /* Cancelled, or some other exit reason. */
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000777 search_replace_abort();
Benno Schulenberg988274b2016-03-17 10:06:15 +0000778 else if (i == -2) /* Do a search instead. */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000779 do_search();
Benno Schulenberg988274b2016-03-17 10:06:15 +0000780 else if (i == 1) /* Toggled something. */
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000781 do_replace();
782
783 if (i != 0)
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000784 return;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000785
Benno Schulenbergfd0589d2017-01-02 21:12:44 +0100786 i = do_prompt(FALSE, FALSE, MREPLACEWITH, NULL,
Benno Schulenbergb341f292014-06-19 20:05:24 +0000787#ifndef DISABLE_HISTORIES
Benno Schulenbergb77b1392016-08-26 12:18:04 +0200788 &replace_history,
Chris Allegretta5beed502003-01-05 20:41:21 +0000789#endif
Benno Schulenbergb77b1392016-08-26 12:18:04 +0200790 /* TRANSLATORS: This is a prompt. */
791 edit_refresh, _("Replace with"));
Chris Allegretta15c28f82003-01-05 21:47:06 +0000792
Benno Schulenbergb341f292014-06-19 20:05:24 +0000793#ifndef DISABLE_HISTORIES
Benno Schulenbergcb776fa2015-03-21 21:40:56 +0000794 /* If the replace string is not "", add it to the replace history list. */
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000795 if (i == 0)
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +0000796 update_history(&replace_history, answer);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000797#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000798
Benno Schulenberg311f0e82016-03-19 20:19:49 +0000799 /* When cancelled, or when a function was run, get out. */
800 if (i == -1 || i > 0) {
801 if (i == -1)
David Lawrence Ramseyd1322102004-08-26 04:22:54 +0000802 statusbar(_("Cancelled"));
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000803 search_replace_abort();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000804 return;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000805 }
806
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000807 /* Save where we are. */
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000808 edittop_save = openfile->edittop;
809 begin = openfile->current;
David Lawrence Ramsey5128de82005-07-12 17:40:16 +0000810 begin_x = openfile->current_x;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000811
Benno Schulenberg2cd8ca42016-10-23 17:59:26 +0200812 numreplaced = do_replace_loop(last_search, FALSE, begin, &begin_x);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000813
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000814 /* Restore where we were. */
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000815 openfile->edittop = edittop_save;
816 openfile->current = begin;
David Lawrence Ramsey5128de82005-07-12 17:40:16 +0000817 openfile->current_x = begin_x;
Benno Schulenbergf920e0d2016-12-03 17:00:28 +0100818 refresh_needed = TRUE;
Chris Allegretta7662c862003-01-13 01:35:15 +0000819
820 if (numreplaced >= 0)
Benno Schulenberg2535f512016-04-30 17:31:43 +0200821 statusline(HUSH, P_("Replaced %lu occurrence",
David Lawrence Ramseybdfa9272005-06-14 23:36:13 +0000822 "Replaced %lu occurrences", (unsigned long)numreplaced),
823 (unsigned long)numreplaced);
Chris Allegretta7662c862003-01-13 01:35:15 +0000824
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000825 search_replace_abort();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000826}
827
Benno Schulenberg60815462014-05-15 20:00:46 +0000828/* Go to the specified line and x position. */
829void goto_line_posx(ssize_t line, size_t pos_x)
830{
Benno Schulenberg58346382015-12-08 18:54:13 +0000831 for (openfile->current = openfile->fileage; line > 1 &&
832 openfile->current != openfile->filebot; line--)
Benno Schulenberg60815462014-05-15 20:00:46 +0000833 openfile->current = openfile->current->next;
834
835 openfile->current_x = pos_x;
836 openfile->placewewant = xplustabs();
837
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +0200838 refresh_needed = TRUE;
Benno Schulenberg60815462014-05-15 20:00:46 +0000839}
840
David Lawrence Ramsey0a8ec172005-05-25 18:44:37 +0000841/* Go to the specified line and column, or ask for them if interactive
Benno Schulenberg46db6382015-12-31 19:20:40 +0000842 * is TRUE. In the latter case also update the screen afterwards.
Benno Schulenberg1592ca02015-12-31 17:20:46 +0000843 * Note that both the line and column number should be one-based. */
David Lawrence Ramsey5beae582005-06-29 00:17:18 +0000844void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer,
Benno Schulenberg46db6382015-12-31 19:20:40 +0000845 bool interactive)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000846{
David Lawrence Ramsey8f1afee2005-07-16 07:06:36 +0000847 if (interactive) {
Benno Schulenberg6c86ee12014-07-02 19:12:38 +0000848 functionptrtype func;
David Lawrence Ramsey8f1afee2005-07-16 07:06:36 +0000849
David Lawrence Ramsey6335fb52007-01-01 05:15:32 +0000850 /* Ask for the line and column. */
Benno Schulenbergfd0589d2017-01-02 21:12:44 +0100851 int i = do_prompt(FALSE, FALSE, MGOTOLINE,
852 use_answer ? answer : NULL,
Benno Schulenbergb341f292014-06-19 20:05:24 +0000853#ifndef DISABLE_HISTORIES
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000854 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +0000855#endif
Benno Schulenberga2d74f72014-05-28 14:34:11 +0000856 /* TRANSLATORS: This is a prompt. */
David Lawrence Ramsey68160072006-02-18 21:32:29 +0000857 edit_refresh, _("Enter line number, column number"));
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000858
Benno Schulenberg59b9b222016-06-21 16:47:11 +0200859 /* If the user cancelled or gave a blank answer, get out. */
David Lawrence Ramsey4c9e8f42004-10-04 16:01:37 +0000860 if (i < 0) {
David Lawrence Ramseyb77ec622004-09-28 15:06:15 +0000861 statusbar(_("Cancelled"));
David Lawrence Ramseye5d8f322004-09-30 22:07:21 +0000862 return;
863 }
864
Benno Schulenberg6c86ee12014-07-02 19:12:38 +0000865 func = func_from_key(&i);
Chris Allegretta0018d8e2008-03-13 08:23:52 +0000866
Benno Schulenberg6c86ee12014-07-02 19:12:38 +0000867 if (func == gototext_void) {
Benno Schulenberg59b9b222016-06-21 16:47:11 +0200868 /* Retain what the user typed so far and switch to searching. */
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000869 search_init(TRUE, TRUE);
David Lawrence Ramsey4c9e8f42004-10-04 16:01:37 +0000870 do_search();
Rocco Corsi4dfaf932001-04-20 01:59:55 +0000871 }
872
Benno Schulenberg59b9b222016-06-21 16:47:11 +0200873 /* If a function was executed, we're done here. */
874 if (i > 0)
875 return;
876
Benno Schulenberg1a4ec6c2016-06-20 22:13:14 +0200877 /* Try to extract one or two numbers from the user's response. */
878 if (!parse_line_column(answer, &line, &column)) {
Benno Schulenberge8c7cf22017-01-17 14:17:42 +0100879 statusline(ALERT, _("Invalid line or column number"));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000880 return;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000881 }
David Lawrence Ramsey9245f972005-05-17 18:06:26 +0000882 } else {
883 if (line < 1)
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000884 line = openfile->current->lineno;
David Lawrence Ramsey9245f972005-05-17 18:06:26 +0000885
David Lawrence Ramsey0a8ec172005-05-25 18:44:37 +0000886 if (column < 1)
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000887 column = openfile->placewewant + 1;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000888 }
889
Benno Schulenberg1a4ec6c2016-06-20 22:13:14 +0200890 /* Take a negative line number to mean: from the end of the file. */
891 if (line < 0)
892 line = openfile->filebot->lineno + line + 1;
893 if (line < 1)
894 line = 1;
895
896 /* Iterate to the requested line. */
Benno Schulenberg34fbb1f2016-01-13 20:32:40 +0000897 for (openfile->current = openfile->fileage; line > 1 &&
898 openfile->current != openfile->filebot; line--)
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000899 openfile->current = openfile->current->next;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000900
Benno Schulenberg1a4ec6c2016-06-20 22:13:14 +0200901 /* Take a negative column number to mean: from the end of the line. */
902 if (column < 0)
903 column = strlenpt(openfile->current->data) + column + 2;
904 if (column < 1)
905 column = 1;
906
907 /* Set the x position that corresponds to the requested column. */
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000908 openfile->current_x = actual_x(openfile->current->data, column - 1);
909 openfile->placewewant = column - 1;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000910
Benno Schulenbergaaab6e52016-05-06 21:57:25 +0200911 /* When the position was manually given, center the target line. */
Benno Schulenbergd7168092016-10-10 13:16:32 +0200912 if (interactive || ISSET(SOFTWRAP)) {
Benno Schulenberg01bbf7e2016-10-20 21:11:11 +0200913 adjust_viewport(CENTERING);
914 refresh_needed = TRUE;
Benno Schulenbergaaab6e52016-05-06 21:57:25 +0200915 } else {
916 /* If the target line is close to the tail of the file, put the last
917 * line of the file on the bottom line of the screen; otherwise, just
918 * center the target line. */
919 if (openfile->filebot->lineno - openfile->current->lineno <
920 editwinrows / 2) {
921 openfile->current_y = editwinrows - openfile->filebot->lineno +
922 openfile->current->lineno - 1;
Benno Schulenberg01bbf7e2016-10-20 21:11:11 +0200923 adjust_viewport(STATIONARY);
Benno Schulenbergaaab6e52016-05-06 21:57:25 +0200924 } else
Benno Schulenberg01bbf7e2016-10-20 21:11:11 +0200925 adjust_viewport(CENTERING);
Chris Allegretta5575bfa2014-02-24 10:18:15 +0000926 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000927}
928
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000929/* Go to the specified line and column, asking for them beforehand. */
David Lawrence Ramsey9245f972005-05-17 18:06:26 +0000930void do_gotolinecolumn_void(void)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000931{
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000932 do_gotolinecolumn(openfile->current->lineno,
Benno Schulenberg46db6382015-12-31 19:20:40 +0000933 openfile->placewewant + 1, FALSE, TRUE);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000934}
Chris Allegrettae1f14522001-09-19 03:19:43 +0000935
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000936#ifndef NANO_TINY
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000937/* Search for a match to one of the two characters in bracket_set. If
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000938 * reverse is TRUE, search backwards for the leftmost bracket.
939 * Otherwise, search forwards for the rightmost bracket. Return TRUE if
940 * we found a match, and FALSE otherwise. */
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000941bool find_bracket_match(bool reverse, const char *bracket_set)
942{
943 filestruct *fileptr = openfile->current;
944 const char *rev_start = NULL, *found = NULL;
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000945
David Lawrence Ramseya2488632006-01-06 07:10:30 +0000946 assert(mbstrlen(bracket_set) == 2);
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000947
948 /* rev_start might end up 1 character before the start or after the
949 * end of the line. This won't be a problem because we'll skip over
950 * it below in that case, and rev_start will be properly set when
951 * the search continues on the previous or next line. */
Benno Schulenberg04013fb2016-04-16 12:44:52 +0200952 if (reverse)
953 rev_start = fileptr->data + (openfile->current_x - 1);
954 else
955 rev_start = fileptr->data + (openfile->current_x + 1);
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000956
957 /* Look for either of the two characters in bracket_set. rev_start
958 * can be 1 character before the start or after the end of the line.
959 * In either case, just act as though no match is found. */
960 while (TRUE) {
Benno Schulenberg04013fb2016-04-16 12:44:52 +0200961 if ((rev_start > fileptr->data && *(rev_start - 1) == '\0') ||
962 rev_start < fileptr->data)
963 found = NULL;
964 else if (reverse)
965 found = mbrevstrpbrk(fileptr->data, bracket_set, rev_start);
966 else
967 found = mbstrpbrk(rev_start, bracket_set);
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000968
Benno Schulenberg04013fb2016-04-16 12:44:52 +0200969 if (found)
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000970 break;
971
Benno Schulenberg7ba356a2016-04-08 18:11:22 +0200972 if (reverse)
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000973 fileptr = fileptr->prev;
Benno Schulenberg7ba356a2016-04-08 18:11:22 +0200974 else
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000975 fileptr = fileptr->next;
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000976
Benno Schulenberg04013fb2016-04-16 12:44:52 +0200977 /* If we've reached the start or end of the buffer, get out. */
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000978 if (fileptr == NULL)
979 return FALSE;
980
981 rev_start = fileptr->data;
982 if (reverse)
983 rev_start += strlen(fileptr->data);
984 }
985
Benno Schulenberg04013fb2016-04-16 12:44:52 +0200986 /* Set the current position to the found matching bracket. */
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000987 openfile->current = fileptr;
David Lawrence Ramseyebe4b3b2005-11-16 03:54:22 +0000988 openfile->current_x = found - fileptr->data;
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +0000989
990 return TRUE;
991}
992
993/* Search for a match to the bracket at the current cursor position, if
994 * there is one. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000995void do_find_bracket(void)
Chris Allegretta8d990b52001-09-22 22:14:25 +0000996{
David Lawrence Ramsey3a9a3292005-07-21 02:20:01 +0000997 filestruct *current_save;
Benno Schulenberg023fccb2016-04-10 11:14:03 +0200998 size_t current_x_save;
David Lawrence Ramseya2488632006-01-06 07:10:30 +0000999 const char *ch;
David Lawrence Ramseyd89617f2006-01-06 21:51:10 +00001000 /* The location in matchbrackets of the bracket at the current
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001001 * cursor position. */
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001002 int ch_len;
1003 /* The length of ch in bytes. */
1004 const char *wanted_ch;
David Lawrence Ramseyd89617f2006-01-06 21:51:10 +00001005 /* The location in matchbrackets of the bracket complementing
1006 * the bracket at the current cursor position. */
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001007 int wanted_ch_len;
1008 /* The length of wanted_ch in bytes. */
1009 char *bracket_set;
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001010 /* The pair of characters in ch and wanted_ch. */
David Lawrence Ramseydb2dc812006-01-06 22:35:52 +00001011 size_t i;
1012 /* Generic loop variable. */
David Lawrence Ramseyd89617f2006-01-06 21:51:10 +00001013 size_t matchhalf;
David Lawrence Ramseydb2dc812006-01-06 22:35:52 +00001014 /* The number of single-byte characters in one half of
1015 * matchbrackets. */
1016 size_t mbmatchhalf;
1017 /* The number of multibyte characters in one half of
1018 * matchbrackets. */
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001019 size_t count = 1;
1020 /* The initial bracket count. */
1021 bool reverse;
1022 /* The direction we search. */
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001023 char *found_ch;
1024 /* The character we find. */
Chris Allegretta8d990b52001-09-22 22:14:25 +00001025
David Lawrence Ramseyd89617f2006-01-06 21:51:10 +00001026 assert(mbstrlen(matchbrackets) % 2 == 0);
Chris Allegretta5beed502003-01-05 20:41:21 +00001027
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001028 ch = openfile->current->data + openfile->current_x;
David Lawrence Ramsey3a9a3292005-07-21 02:20:01 +00001029
Benno Schulenberg677e9472015-08-13 17:46:19 +00001030 if ((ch = mbstrchr(matchbrackets, ch)) == NULL) {
Chris Allegretta8d990b52001-09-22 22:14:25 +00001031 statusbar(_("Not a bracket"));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001032 return;
Chris Allegretta8d990b52001-09-22 22:14:25 +00001033 }
1034
David Lawrence Ramsey3a9a3292005-07-21 02:20:01 +00001035 /* Save where we are. */
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +00001036 current_save = openfile->current;
1037 current_x_save = openfile->current_x;
David Lawrence Ramsey3a9a3292005-07-21 02:20:01 +00001038
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001039 /* If we're on an opening bracket, which must be in the first half
David Lawrence Ramseyd89617f2006-01-06 21:51:10 +00001040 * of matchbrackets, we want to search forwards for a closing
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001041 * bracket. If we're on a closing bracket, which must be in the
David Lawrence Ramseyd89617f2006-01-06 21:51:10 +00001042 * second half of matchbrackets, we want to search backwards for an
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001043 * opening bracket. */
David Lawrence Ramseydb2dc812006-01-06 22:35:52 +00001044 matchhalf = 0;
1045 mbmatchhalf = mbstrlen(matchbrackets) / 2;
1046
1047 for (i = 0; i < mbmatchhalf; i++)
Benno Schulenberge753cd12016-03-17 19:30:29 +00001048 matchhalf += parse_mbchar(matchbrackets + matchhalf, NULL, NULL);
David Lawrence Ramseydb2dc812006-01-06 22:35:52 +00001049
David Lawrence Ramsey4a2e0002006-01-28 06:04:59 +00001050 reverse = ((ch - matchbrackets) >= matchhalf);
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001051
1052 /* If we're on an opening bracket, set wanted_ch to the character
David Lawrence Ramseyd89617f2006-01-06 21:51:10 +00001053 * that's matchhalf characters after ch. If we're on a closing
1054 * bracket, set wanted_ch to the character that's matchhalf
1055 * characters before ch. */
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001056 wanted_ch = ch;
1057
David Lawrence Ramseydb2dc812006-01-06 22:35:52 +00001058 while (mbmatchhalf > 0) {
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001059 if (reverse)
David Lawrence Ramseyd89617f2006-01-06 21:51:10 +00001060 wanted_ch = matchbrackets + move_mbleft(matchbrackets,
Benno Schulenberge753cd12016-03-17 19:30:29 +00001061 wanted_ch - matchbrackets);
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001062 else
1063 wanted_ch += move_mbright(wanted_ch, 0);
1064
David Lawrence Ramseydb2dc812006-01-06 22:35:52 +00001065 mbmatchhalf--;
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001066 }
1067
1068 ch_len = parse_mbchar(ch, NULL, NULL);
1069 wanted_ch_len = parse_mbchar(wanted_ch, NULL, NULL);
1070
1071 /* Fill bracket_set in with the values of ch and wanted_ch. */
1072 bracket_set = charalloc((mb_cur_max() * 2) + 1);
1073 strncpy(bracket_set, ch, ch_len);
1074 strncpy(bracket_set + ch_len, wanted_ch, wanted_ch_len);
1075 null_at(&bracket_set, ch_len + wanted_ch_len);
1076
1077 found_ch = charalloc(mb_cur_max() + 1);
David Lawrence Ramsey3a9a3292005-07-21 02:20:01 +00001078
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001079 while (TRUE) {
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001080 if (find_bracket_match(reverse, bracket_set)) {
David Lawrence Ramsey3a9a3292005-07-21 02:20:01 +00001081 /* If we found an identical bracket, increment count. If we
1082 * found a complementary bracket, decrement it. */
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001083 parse_mbchar(openfile->current->data + openfile->current_x,
Benno Schulenberge753cd12016-03-17 19:30:29 +00001084 found_ch, NULL);
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001085 count += (strncmp(found_ch, ch, ch_len) == 0) ? 1 : -1;
David Lawrence Ramsey3a9a3292005-07-21 02:20:01 +00001086
1087 /* If count is zero, we've found a matching bracket. Update
1088 * the screen and get out. */
1089 if (count == 0) {
Benno Schulenberg318ed6b2016-04-12 10:24:57 +02001090 focusing = FALSE;
Benno Schulenbergaa1ae0a2016-04-10 21:16:19 +02001091 edit_redraw(current_save);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001092 break;
Chris Allegretta8d990b52001-09-22 22:14:25 +00001093 }
Chris Allegretta7662c862003-01-13 01:35:15 +00001094 } else {
David Lawrence Ramsey3a9a3292005-07-21 02:20:01 +00001095 /* We didn't find either an opening or closing bracket.
1096 * Indicate this, restore where we were, and get out. */
Chris Allegretta8d990b52001-09-22 22:14:25 +00001097 statusbar(_("No matching bracket"));
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +00001098 openfile->current = current_save;
1099 openfile->current_x = current_x_save;
Chris Allegretta8d990b52001-09-22 22:14:25 +00001100 break;
1101 }
1102 }
David Lawrence Ramseya2488632006-01-06 07:10:30 +00001103
1104 /* Clean up. */
1105 free(bracket_set);
1106 free(found_ch);
Chris Allegretta8d990b52001-09-22 22:14:25 +00001107}
Benno Schulenbergb341f292014-06-19 20:05:24 +00001108#endif /* !NANO_TINY */
Chris Allegretta5beed502003-01-05 20:41:21 +00001109
Benno Schulenbergb341f292014-06-19 20:05:24 +00001110#ifndef DISABLE_HISTORIES
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001111/* Indicate whether any of the history lists have changed. */
1112bool history_has_changed(void)
Chris Allegretta5beed502003-01-05 20:41:21 +00001113{
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001114 return history_changed;
Chris Allegretta5beed502003-01-05 20:41:21 +00001115}
1116
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001117/* Initialize the search and replace history lists. */
1118void history_init(void)
Chris Allegretta5beed502003-01-05 20:41:21 +00001119{
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001120 search_history = make_new_node(NULL);
1121 search_history->data = mallocstrcpy(NULL, "");
1122 searchage = search_history;
1123 searchbot = search_history;
1124
1125 replace_history = make_new_node(NULL);
1126 replace_history->data = mallocstrcpy(NULL, "");
1127 replaceage = replace_history;
1128 replacebot = replace_history;
1129}
1130
David Lawrence Ramsey0e581b32005-07-18 07:48:50 +00001131/* Set the current position in the history list h to the bottom. */
1132void history_reset(const filestruct *h)
1133{
1134 if (h == search_history)
1135 search_history = searchbot;
1136 else if (h == replace_history)
1137 replace_history = replacebot;
1138}
1139
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001140/* Return the first node containing the first len characters of the
1141 * string s in the history list, starting at h_start and ending at
1142 * h_end, or NULL if there isn't one. */
David Lawrence Ramsey96e6d562005-07-19 04:53:45 +00001143filestruct *find_history(const filestruct *h_start, const filestruct
1144 *h_end, const char *s, size_t len)
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001145{
David Lawrence Ramsey96e6d562005-07-19 04:53:45 +00001146 const filestruct *p;
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001147
Benno Schulenberg036c5f92016-03-20 13:38:09 +00001148 for (p = h_start; p != h_end->prev && p != NULL; p = p->prev) {
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001149 if (strncmp(s, p->data, len) == 0)
David Lawrence Ramsey96e6d562005-07-19 04:53:45 +00001150 return (filestruct *)p;
David Lawrence Ramsey7f4dd352005-05-08 17:08:51 +00001151 }
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001152
Chris Allegretta5beed502003-01-05 20:41:21 +00001153 return NULL;
1154}
1155
Benno Schulenberg0172cb02016-06-02 12:07:08 +02001156/* Update a history list (the one in which h is the current position)
1157 * with a fresh string s. That is: add s, or move it to the end. */
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001158void update_history(filestruct **h, const char *s)
Chris Allegretta5beed502003-01-05 20:41:21 +00001159{
Benno Schulenberge198c852016-06-01 17:58:16 +02001160 filestruct **hage = NULL, **hbot = NULL, *thesame;
Chris Allegretta5beed502003-01-05 20:41:21 +00001161
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001162 assert(h != NULL && s != NULL);
1163
1164 if (*h == search_history) {
1165 hage = &searchage;
1166 hbot = &searchbot;
1167 } else if (*h == replace_history) {
1168 hage = &replaceage;
1169 hbot = &replacebot;
1170 }
1171
1172 assert(hage != NULL && hbot != NULL);
Chris Allegretta5beed502003-01-05 20:41:21 +00001173
Benno Schulenberg0172cb02016-06-02 12:07:08 +02001174 /* See if the string is already in the history. */
Benno Schulenberg660584c2016-06-01 21:29:44 +02001175 thesame = find_history(*hbot, *hage, s, HIGHEST_POSITIVE);
Chris Allegretta5beed502003-01-05 20:41:21 +00001176
Benno Schulenberge198c852016-06-01 17:58:16 +02001177 /* If an identical string was found, delete that item. */
1178 if (thesame != NULL) {
1179 filestruct *after = thesame->next;
Chris Allegretta5beed502003-01-05 20:41:21 +00001180
Benno Schulenberge198c852016-06-01 17:58:16 +02001181 /* If the string is at the head of the list, move the head. */
1182 if (thesame == *hage)
1183 *hage = after;
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001184
Benno Schulenberge198c852016-06-01 17:58:16 +02001185 unlink_node(thesame);
1186 renumber(after);
Chris Allegretta5beed502003-01-05 20:41:21 +00001187 }
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001188
Benno Schulenberg0172cb02016-06-02 12:07:08 +02001189 /* If the history is full, delete the oldest item (the one at the
1190 * head of the list), to make room for a new item at the end. */
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001191 if ((*hbot)->lineno == MAX_SEARCH_HISTORY + 1) {
Benno Schulenbergc92b9be2016-12-23 12:51:04 +01001192 filestruct *oldest = *hage;
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001193
1194 *hage = (*hage)->next;
Benno Schulenbergc92b9be2016-12-23 12:51:04 +01001195 unlink_node(oldest);
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001196 renumber(*hage);
Chris Allegretta5beed502003-01-05 20:41:21 +00001197 }
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001198
Benno Schulenberg0172cb02016-06-02 12:07:08 +02001199 /* Store the fresh string in the last item, then create a new item. */
David Lawrence Ramseyb5137782006-12-13 00:27:45 +00001200 (*hbot)->data = mallocstrcpy((*hbot)->data, s);
Benno Schulenbergfbe43762015-11-24 13:24:01 +00001201 splice_node(*hbot, make_new_node(*hbot));
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001202 *hbot = (*hbot)->next;
1203 (*hbot)->data = mallocstrcpy(NULL, "");
1204
Benno Schulenberg0172cb02016-06-02 12:07:08 +02001205 /* Indicate that the history needs to be saved on exit. */
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001206 history_changed = TRUE;
1207
1208 /* Set the current position in the list to the bottom. */
1209 *h = *hbot;
Chris Allegretta5beed502003-01-05 20:41:21 +00001210}
1211
David Lawrence Ramsey8b3266e2005-05-26 02:46:42 +00001212/* Move h to the string in the history list just before it, and return
1213 * that string. If there isn't one, don't move h and return NULL. */
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001214char *get_history_older(filestruct **h)
Chris Allegretta5beed502003-01-05 20:41:21 +00001215{
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001216 assert(h != NULL);
1217
1218 if ((*h)->prev == NULL)
Chris Allegretta1b6ed072008-06-03 08:09:05 +00001219 return NULL;
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001220
1221 *h = (*h)->prev;
1222
1223 return (*h)->data;
Chris Allegretta5beed502003-01-05 20:41:21 +00001224}
1225
David Lawrence Ramsey8b3266e2005-05-26 02:46:42 +00001226/* Move h to the string in the history list just after it, and return
1227 * that string. If there isn't one, don't move h and return NULL. */
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001228char *get_history_newer(filestruct **h)
Chris Allegretta5beed502003-01-05 20:41:21 +00001229{
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001230 assert(h != NULL);
1231
1232 if ((*h)->next == NULL)
Chris Allegretta1b6ed072008-06-03 08:09:05 +00001233 return NULL;
David Lawrence Ramsey934f9682005-05-23 16:30:06 +00001234
1235 *h = (*h)->next;
1236
1237 return (*h)->data;
Chris Allegretta5beed502003-01-05 20:41:21 +00001238}
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001239
Benno Schulenbergd19be5a2014-04-08 18:38:45 +00001240/* More placeholders. */
Chris Allegretta637daa82011-02-07 14:45:56 +00001241void get_history_newer_void(void)
1242{
1243 ;
1244}
1245void get_history_older_void(void)
1246{
1247 ;
1248}
1249
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001250#ifndef DISABLE_TABCOMP
1251/* Move h to the next string that's a tab completion of the string s,
1252 * looking at only the first len characters of s, and return that
David Lawrence Ramsey47ae0d72005-06-03 14:30:52 +00001253 * string. If there isn't one, or if len is 0, don't move h and return
1254 * s. */
Benno Schulenberge86dc032016-02-20 12:16:43 +00001255char *get_history_completion(filestruct **h, char *s, size_t len)
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001256{
1257 assert(s != NULL);
1258
1259 if (len > 0) {
1260 filestruct *hage = NULL, *hbot = NULL, *p;
1261
1262 assert(h != NULL);
1263
1264 if (*h == search_history) {
1265 hage = searchage;
1266 hbot = searchbot;
1267 } else if (*h == replace_history) {
1268 hage = replaceage;
1269 hbot = replacebot;
1270 }
1271
1272 assert(hage != NULL && hbot != NULL);
1273
Benno Schulenberg036c5f92016-03-20 13:38:09 +00001274 /* Search the history list from the current position to the top
1275 * for a match of len characters. Skip over an exact match. */
1276 p = find_history((*h)->prev, hage, s, len);
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001277
David Lawrence Ramseyd2edb8a2005-06-13 03:52:33 +00001278 while (p != NULL && strcmp(p->data, s) == 0)
Benno Schulenberg036c5f92016-03-20 13:38:09 +00001279 p = find_history(p->prev, hage, s, len);
David Lawrence Ramseyd2edb8a2005-06-13 03:52:33 +00001280
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001281 if (p != NULL) {
1282 *h = p;
Benno Schulenberge86dc032016-02-20 12:16:43 +00001283 return mallocstrcpy(s, (*h)->data);
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001284 }
1285
Benno Schulenberg036c5f92016-03-20 13:38:09 +00001286 /* Search the history list from the bottom to the current position
David Lawrence Ramseyd2edb8a2005-06-13 03:52:33 +00001287 * for a match of len characters. Skip over an exact match. */
Benno Schulenberg036c5f92016-03-20 13:38:09 +00001288 p = find_history(hbot, *h, s, len);
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001289
David Lawrence Ramseyd2edb8a2005-06-13 03:52:33 +00001290 while (p != NULL && strcmp(p->data, s) == 0)
Benno Schulenberg036c5f92016-03-20 13:38:09 +00001291 p = find_history(p->prev, *h, s, len);
David Lawrence Ramseyd2edb8a2005-06-13 03:52:33 +00001292
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001293 if (p != NULL) {
1294 *h = p;
Benno Schulenberge86dc032016-02-20 12:16:43 +00001295 return mallocstrcpy(s, (*h)->data);
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001296 }
1297 }
1298
David Lawrence Ramseyd2edb8a2005-06-13 03:52:33 +00001299 /* If we're here, we didn't find a match, we didn't find an inexact
1300 * match, or len is 0. Return s. */
David Lawrence Ramsey96e6d562005-07-19 04:53:45 +00001301 return (char *)s;
David Lawrence Ramsey34bdc352005-06-02 18:41:31 +00001302}
David Lawrence Ramsey4cf22462005-08-11 18:30:47 +00001303#endif /* !DISABLE_TABCOMP */
Benno Schulenbergb341f292014-06-19 20:05:24 +00001304#endif /* !DISABLE_HISTORIES */