blob: ee105f8ef7dad979f4718ef93b7ff0d5750ec872 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettabceb1b22000-06-19 04:22:15 +00002/**************************************************************************
3 * search.c *
4 * *
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +00005 * Copyright (C) 2000-2004 Chris Allegretta *
Chris Allegrettabceb1b22000-06-19 04:22:15 +00006 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
Chris Allegretta3a24f3f2001-10-24 11:33:54 +00008 * the Free Software Foundation; either version 2, or (at your option) *
Chris Allegrettabceb1b22000-06-19 04:22:15 +00009 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
Jordi Mallach55381aa2004-11-17 23:17:05 +000022#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
Chris Allegretta6efda542001-04-28 18:03:52 +000025
Chris Allegrettabceb1b22000-06-19 04:22:15 +000026#include <stdlib.h>
27#include <string.h>
28#include <stdio.h>
David Lawrence Ramsey1044d742004-02-24 20:41:39 +000029#include <unistd.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000030#include <ctype.h>
Chris Allegretta5beed502003-01-05 20:41:21 +000031#include <errno.h>
Chris Allegretta6df90f52002-07-19 01:08:59 +000032#include <assert.h>
Chris Allegrettabceb1b22000-06-19 04:22:15 +000033#include "proto.h"
34#include "nano.h"
Chris Allegretta4da1fc62000-06-21 03:00:43 +000035
David Lawrence Ramseye5e88fd2004-10-31 13:20:30 +000036static bool search_last_line = FALSE;
37 /* Have we gone past the last line while searching? */
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
42/* Regular expression helper functions. */
43
44/* Compile the given regular expression. Return value 0 means the
45 * expression was invalid, and we wrote an error message on the status
46 * bar. Return value 1 means success. */
Chris Allegretta5d715142003-01-29 04:18:37 +000047int regexp_init(const char *regexp)
Chris Allegretta9fc8d432000-07-07 01:49:52 +000048{
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +000049 int rc = regcomp(&search_regexp, regexp, REG_EXTENDED
50#ifndef NANO_SMALL
51 | (ISSET(CASE_SENSITIVE) ? 0 : REG_ICASE)
52#endif
53 );
Chris Allegretta5d715142003-01-29 04:18:37 +000054
David Lawrence Ramsey4b741b92004-04-30 19:40:03 +000055 assert(!regexp_compiled);
56 if (rc != 0) {
57 size_t len = regerror(rc, &search_regexp, NULL, 0);
58 char *str = charalloc(len);
59
60 regerror(rc, &search_regexp, str, len);
61 statusbar(_("Bad regex \"%s\": %s"), regexp, str);
62 free(str);
63 return 0;
64 }
65
66 regexp_compiled = TRUE;
Chris Allegretta5d715142003-01-29 04:18:37 +000067 return 1;
Chris Allegretta9fc8d432000-07-07 01:49:52 +000068}
69
Chris Allegrettae3167732001-03-18 16:59:34 +000070void regexp_cleanup(void)
Chris Allegretta9fc8d432000-07-07 01:49:52 +000071{
David Lawrence Ramsey4b741b92004-04-30 19:40:03 +000072 if (regexp_compiled) {
73 regexp_compiled = FALSE;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +000074 regfree(&search_regexp);
75 }
Chris Allegretta9fc8d432000-07-07 01:49:52 +000076}
Chris Allegretta47805612000-07-07 02:35:34 +000077#endif
Chris Allegretta9fc8d432000-07-07 01:49:52 +000078
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;
83
David Lawrence Ramseya3370c42004-04-05 01:08:14 +000084 assert(str != NULL);
David Lawrence Ramsey483ea322004-05-29 16:25:30 +000085
86 disp = display_string(str, 0, (COLS / 2) + 1);
87 numchars = strnlen(disp, COLS / 2);
88
89 statusbar(_("\"%.*s%s\" not found"), numchars, disp,
90 disp[numchars] == '\0' ? "" : "...");
91
92 free(disp);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +000093}
94
95void search_abort(void)
96{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +000097 display_main_list();
David Lawrence Ramsey1044d742004-02-24 20:41:39 +000098#ifndef NANO_SMALL
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +000099 if (ISSET(MARK_ISSET))
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000100 edit_refresh();
101#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000102#ifdef HAVE_REGEX_H
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000103 regexp_cleanup();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000104#endif
105}
106
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000107void search_init_globals(void)
108{
David Lawrence Ramsey6be53392004-10-16 15:41:57 +0000109 if (last_search == NULL)
110 last_search = mallocstrcpy(NULL, "");
111 if (last_replace == NULL)
112 last_replace = mallocstrcpy(NULL, "");
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000113}
114
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000115/* Set up the system variables for a search or replace. If use_answer
116 * is TRUE, only set backupstring to answer. Return -2 to run opposite
117 * program (search -> replace, replace -> search), return -1 if the
118 * search should be canceled (due to Cancel, Go to Line, or a failed
119 * regcomp()), return 0 on success, and return 1 on rerun calling
120 * program.
Chris Allegretta7662c862003-01-13 01:35:15 +0000121 *
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000122 * replacing is TRUE if we call from do_replace(), and FALSE if called
123 * from do_search(). */
124int search_init(bool replacing, bool use_answer)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000125{
Chris Allegrettaf372bd92001-07-15 22:24:24 +0000126 int i = 0;
Chris Allegretta71844ba2000-11-03 14:23:00 +0000127 char *buf;
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000128 static char *backupstring = NULL;
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000129 /* The search string we'll be using. */
130
131 /* If backupstring doesn't exist, initialize it to "". */
132 if (backupstring == NULL)
133 backupstring = mallocstrcpy(NULL, "");
134
135 /* If use_answer is TRUE, set backupstring to answer and get out. */
136 if (use_answer) {
137 backupstring = mallocstrcpy(backupstring, answer);
138 return 0;
139 }
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000140
141 /* We display the search prompt below. If the user types a partial
142 * search string and then Replace or a toggle, we will return to
143 * do_search() or do_replace() and be called again. In that case,
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000144 * we should put the same search string back up. */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000145
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000146 search_init_globals();
Chris Allegretta31925e42000-11-02 04:40:39 +0000147
Chris Allegrettaa65ba512003-01-05 20:57:07 +0000148#ifndef NANO_SMALL
Chris Allegretta15c28f82003-01-05 21:47:06 +0000149 search_history.current = (historytype *)&search_history.next;
Chris Allegrettaa65ba512003-01-05 20:57:07 +0000150#endif
Chris Allegretta15c28f82003-01-05 21:47:06 +0000151
Chris Allegretta15c28f82003-01-05 21:47:06 +0000152 if (last_search[0] != '\0') {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000153 char *disp = display_string(last_search, 0, COLS / 3);
154
Chris Allegrettacf287c82002-07-20 13:57:41 +0000155 buf = charalloc(COLS / 3 + 7);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000156 /* We use COLS / 3 here because we need to see more on the
157 * line. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000158 sprintf(buf, " [%s%s]", disp,
159 strlenpt(last_search) > COLS / 3 ? "..." : "");
160 free(disp);
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000161 } else
162 buf = mallocstrcpy(NULL, "");
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000163
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000164 /* This is now one simple call. It just does a lot. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000165 i = statusq(FALSE, replacing ? replace_list : whereis_list,
166 backupstring,
Chris Allegretta5beed502003-01-05 20:41:21 +0000167#ifndef NANO_SMALL
168 &search_history,
169#endif
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000170 "%s%s%s%s%s%s", _("Search"),
Chris Allegretta759d3522001-09-27 13:04:10 +0000171
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000172#ifndef NANO_SMALL
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000173 /* This string is just a modifier for the search prompt; no
174 * grammar is implied. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000175 ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") :
176#endif
177 "",
Chris Allegretta759d3522001-09-27 13:04:10 +0000178
David Lawrence Ramsey4b741b92004-04-30 19:40:03 +0000179#ifdef HAVE_REGEX_H
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000180 /* This string is just a modifier for the search prompt; no
181 * grammar is implied. */
David Lawrence Ramsey4b741b92004-04-30 19:40:03 +0000182 ISSET(USE_REGEXP) ? _(" [Regexp]") :
183#endif
184 "",
Chris Allegretta759d3522001-09-27 13:04:10 +0000185
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000186#ifndef NANO_SMALL
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000187 /* This string is just a modifier for the search prompt; no
188 * grammar is implied. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000189 ISSET(REVERSE_SEARCH) ? _(" [Backwards]") :
190#endif
191 "",
Chris Allegretta759d3522001-09-27 13:04:10 +0000192
David Lawrence Ramseye1ee22f2004-11-03 23:05:11 +0000193 replacing ?
194#ifndef NANO_SMALL
195 (ISSET(MARK_ISSET) ? _(" (to replace) in selection") :
196#endif
197 _(" (to replace)")
198#ifndef NANO_SMALL
199 )
200#endif
201 : "",
202
Chris Allegrettae4933a32001-06-13 02:35:44 +0000203 buf);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000204
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000205 /* Release buf now that we don't need it anymore. */
Chris Allegretta45329a12002-03-10 01:22:21 +0000206 free(buf);
207
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000208 free(backupstring);
209 backupstring = NULL;
210
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000211 /* Cancel any search, or just return with no previous search. */
212 if (i == -1 || (i < 0 && last_search[0] == '\0') ||
213 (!replacing && i == 0 && answer[0] == '\0')) {
David Lawrence Ramseyd1322102004-08-26 04:22:54 +0000214 statusbar(_("Cancelled"));
Chris Allegretta5beed502003-01-05 20:41:21 +0000215#ifndef NANO_SMALL
216 search_history.current = search_history.next;
217#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000218 return -1;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000219 } else {
220 switch (i) {
David Lawrence Ramsey6be53392004-10-16 15:41:57 +0000221 case -2: /* It's the same string. */
Chris Allegretta805c26d2000-09-06 13:39:17 +0000222#ifdef HAVE_REGEX_H
David Lawrence Ramsey6be53392004-10-16 15:41:57 +0000223 /* Since answer is "", use last_search! */
224 if (ISSET(USE_REGEXP) && regexp_init(last_search) == 0)
225 return -1;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000226#endif
David Lawrence Ramsey6be53392004-10-16 15:41:57 +0000227 break;
228 case 0: /* They entered something new. */
229 last_replace[0] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +0000230#ifdef HAVE_REGEX_H
David Lawrence Ramsey6be53392004-10-16 15:41:57 +0000231 if (ISSET(USE_REGEXP) && regexp_init(answer) == 0)
232 return -1;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000233#endif
David Lawrence Ramsey6be53392004-10-16 15:41:57 +0000234 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000235#ifndef NANO_SMALL
David Lawrence Ramsey6be53392004-10-16 15:41:57 +0000236 case TOGGLE_CASE_KEY:
237 TOGGLE(CASE_SENSITIVE);
238 backupstring = mallocstrcpy(backupstring, answer);
239 return 1;
240 case TOGGLE_BACKWARDS_KEY:
241 TOGGLE(REVERSE_SEARCH);
242 backupstring = mallocstrcpy(backupstring, answer);
243 return 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000244#ifdef HAVE_REGEX_H
David Lawrence Ramsey6be53392004-10-16 15:41:57 +0000245 case TOGGLE_REGEXP_KEY:
246 TOGGLE(USE_REGEXP);
247 backupstring = mallocstrcpy(backupstring, answer);
248 return 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000249#endif
250#endif /* !NANO_SMALL */
David Lawrence Ramsey6be53392004-10-16 15:41:57 +0000251 case NANO_TOOTHERSEARCH_KEY:
252 backupstring = mallocstrcpy(backupstring, answer);
253 return -2; /* Call the opposite search function. */
254 case NANO_TOGOTOLINE_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +0000255#ifndef NANO_SMALL
David Lawrence Ramsey6be53392004-10-16 15:41:57 +0000256 search_history.current = search_history.next;
Chris Allegretta5beed502003-01-05 20:41:21 +0000257#endif
David Lawrence Ramsey6be53392004-10-16 15:41:57 +0000258 /* Put answer up on the statusbar. */
259 do_gotoline(-1, FALSE);
260 /* Fall through. */
261 default:
262 return -1;
Chris Allegretta74bb31b2001-03-14 09:08:14 +0000263 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000264 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000265 return 0;
266}
267
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000268bool is_whole_word(int curr_pos, const char *datastr, const char
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000269 *searchword)
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +0000270{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000271 size_t sln = curr_pos + strlen(searchword);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +0000272
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000273 /* Start of line or previous character is not a letter and end of
274 * line or next character is not a letter. */
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +0000275 return (curr_pos < 1 || !isalpha(datastr[curr_pos - 1])) &&
276 (sln == strlen(datastr) || !isalpha(datastr[sln]));
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +0000277}
278
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000279/* Look for needle, starting at current, column current_x. If
David Lawrence Ramsey4b7e3c32004-10-15 16:25:56 +0000280 * no_sameline is TRUE, skip over begin when looking for needle. begin
281 * is the line where we first started searching, at column beginx. If
David Lawrence Ramsey9819ed02004-10-21 15:32:11 +0000282 * can_display_wrap is TRUE, we put messages on the statusbar, wrap
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +0000283 * around the file boundaries. The return value specifies whether we
284 * found anything. If we did, set needle_len to the length of the
285 * string we found if it isn't NULL. */
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000286bool findnextstr(bool can_display_wrap, bool wholeword, bool
287 no_sameline, const filestruct *begin, size_t beginx, const char
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +0000288 *needle, size_t *needle_len)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000289{
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000290 filestruct *fileptr = current;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000291 const char *rev_start = NULL, *found = NULL;
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000292 size_t found_len;
293 /* The length of the match we found. */
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000294 size_t current_x_find = 0;
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000295 /* The location of the match we found. */
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000296 int current_y_find = current_y;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000297
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000298 /* rev_start might end up 1 character before the start or after the
299 * end of the line. This won't be a problem because strstrwrapper()
300 * will return immediately and say that no match was found, and
301 * rev_start will be properly set when the search continues on the
302 * previous or next line. */
David Lawrence Ramsey4b7e3c32004-10-15 16:25:56 +0000303 rev_start =
Chris Allegrettae10f3892001-10-02 03:54:40 +0000304#ifndef NANO_SMALL
David Lawrence Ramsey4b7e3c32004-10-15 16:25:56 +0000305 ISSET(REVERSE_SEARCH) ? fileptr->data + (current_x - 1) :
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000306#endif
David Lawrence Ramsey4b7e3c32004-10-15 16:25:56 +0000307 fileptr->data + (current_x + 1);
Chris Allegrettae4933a32001-06-13 02:35:44 +0000308
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000309 /* Look for needle in searchstr. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000310 while (TRUE) {
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000311 found = strstrwrapper(fileptr->data, needle, rev_start);
David Lawrence Ramsey45cfbec2003-11-28 16:04:24 +0000312
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000313 /* We've found a potential match. */
314 if (found != NULL) {
315 bool found_whole = FALSE;
316 /* Is this potential match a whole word? */
317
318 /* Set found_len to the length of the potential match. */
319 found_len =
320#ifdef HAVE_REGEX_H
321 ISSET(USE_REGEXP) ?
322 regmatches[0].rm_eo - regmatches[0].rm_so :
323#endif
324 strlen(needle);
325
326 /* If we're searching for whole words, see if this potential
327 * match is a whole word. */
328 if (wholeword) {
David Lawrence Ramsey99869f52004-11-02 20:48:37 +0000329 char *word = mallocstrncpy(NULL, found, found_len + 1);
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000330 word[found_len] = '\0';
331
332 found_whole = is_whole_word(found - fileptr->data,
333 fileptr->data, word);
334 free(word);
335 }
336
337 /* If we're searching for whole words and this potential
338 * match isn't a whole word, or if we're not allowed to find
339 * a match on the same line we started on and this potential
340 * match is on that line, continue searching. */
341 if ((!wholeword || found_whole) && (!no_sameline ||
342 fileptr != current))
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000343 break;
Chris Allegrettae4933a32001-06-13 02:35:44 +0000344 }
345
David Lawrence Ramsey2cc2a572004-10-18 02:06:53 +0000346 /* We've finished processing the file, so get out. */
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000347 if (search_last_line) {
348 if (can_display_wrap)
Chris Allegrettae4933a32001-06-13 02:35:44 +0000349 not_found_msg(needle);
David Lawrence Ramsey4b7e3c32004-10-15 16:25:56 +0000350 return FALSE;
Chris Allegrettae4933a32001-06-13 02:35:44 +0000351 }
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000352
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000353#ifndef NANO_SMALL
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000354 if (ISSET(REVERSE_SEARCH)) {
355 fileptr = fileptr->prev;
356 current_y_find--;
357 } else {
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000358#endif
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000359 fileptr = fileptr->next;
360 current_y_find++;
361#ifndef NANO_SMALL
362 }
363#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000364
David Lawrence Ramsey2cc2a572004-10-18 02:06:53 +0000365 /* Start or end of buffer reached, so wrap around. */
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000366 if (fileptr == NULL) {
367 if (!can_display_wrap)
David Lawrence Ramsey4b7e3c32004-10-15 16:25:56 +0000368 return FALSE;
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000369
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000370#ifndef NANO_SMALL
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000371 if (ISSET(REVERSE_SEARCH)) {
372 fileptr = filebot;
373 current_y_find = editwinrows - 1;
374 } else {
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000375#endif
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000376 fileptr = fileage;
377 current_y_find = 0;
378#ifndef NANO_SMALL
379 }
380#endif
381
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000382 if (can_display_wrap)
383 statusbar(_("Search Wrapped"));
384 }
385
386 /* Original start line reached. */
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +0000387 if (fileptr == begin)
David Lawrence Ramseyc3724882004-05-27 18:39:16 +0000388 search_last_line = TRUE;
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +0000389
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000390 rev_start = fileptr->data;
391#ifndef NANO_SMALL
392 if (ISSET(REVERSE_SEARCH))
393 rev_start += strlen(fileptr->data);
394#endif
395 }
396
397 /* We found an instance. */
398 current_x_find = found - fileptr->data;
399
400 /* Ensure we haven't wrapped around again! */
401 if (search_last_line &&
402#ifndef NANO_SMALL
403 ((!ISSET(REVERSE_SEARCH) && current_x_find > beginx) ||
404 (ISSET(REVERSE_SEARCH) && current_x_find < beginx))
405#else
406 current_x_find > beginx
407#endif
408 ) {
409
410 if (can_display_wrap)
411 not_found_msg(needle);
David Lawrence Ramsey4b7e3c32004-10-15 16:25:56 +0000412 return FALSE;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000413 }
414
415 /* Set globals now that we are sure we found something. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000416 current = fileptr;
417 current_x = current_x_find;
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000418 current_y = current_y_find;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +0000419 placewewant = xplustabs();
David Lawrence Ramsey9819ed02004-10-21 15:32:11 +0000420
421 /* needle_len holds the length of needle. */
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000422 if (needle_len != NULL)
423 *needle_len = found_len;
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000424
David Lawrence Ramsey4b7e3c32004-10-15 16:25:56 +0000425 return TRUE;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000426}
427
David Lawrence Ramseye5e88fd2004-10-31 13:20:30 +0000428void findnextstr_wrap_reset(void)
429{
430 search_last_line = FALSE;
431}
432
Chris Allegretta6df90f52002-07-19 01:08:59 +0000433/* Search for a string. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000434void do_search(void)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000435{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +0000436 size_t old_pww = placewewant, fileptr_x = current_x;
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000437 int i;
438 bool didfind;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000439 filestruct *fileptr = current;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000440
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +0000441#ifndef DISABLE_WRAPPING
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000442 wrap_reset();
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +0000443#endif
David Lawrence Ramseye5d8f322004-09-30 22:07:21 +0000444
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000445 i = search_init(FALSE, FALSE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000446 if (i == -1) /* Cancel, Go to Line, blank search string, or
447 * regcomp() failed. */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000448 search_abort();
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000449 else if (i == -2) /* Replace. */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000450 do_replace();
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000451#ifndef NANO_SMALL
452 else if (i == 1) /* Case Sensitive, Backwards, or Regexp search
453 * toggle. */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000454 do_search();
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000455#endif
Chris Allegretta86f8b3a2000-10-31 05:28:33 +0000456
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000457 if (i != 0)
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000458 return;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000459
460 /* If answer is now "", copy last_search into answer. */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000461 if (answer[0] == '\0')
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000462 answer = mallocstrcpy(answer, last_search);
463 else
464 last_search = mallocstrcpy(last_search, answer);
465
Chris Allegretta5beed502003-01-05 20:41:21 +0000466#ifndef NANO_SMALL
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000467 /* If answer is not "", add this search string to the search history
468 * list. */
Chris Allegretta688c8eb2003-01-14 23:36:11 +0000469 if (answer[0] != '\0')
Chris Allegretta63287922003-01-05 20:43:49 +0000470 update_history(&search_history, answer);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000471#endif
Chris Allegretta5beed502003-01-05 20:41:21 +0000472
David Lawrence Ramseye5e88fd2004-10-31 13:20:30 +0000473 findnextstr_wrap_reset();
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000474 didfind = findnextstr(TRUE, FALSE, FALSE, current, current_x,
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +0000475 answer, NULL);
Chris Allegretta1c2fddc2002-01-21 20:40:14 +0000476
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000477 /* Check to see if there's only one occurrence of the string and
478 * we're on it now. */
479 if (fileptr == current && fileptr_x == current_x && didfind) {
480#ifdef HAVE_REGEX_H
481 /* Do the search again, skipping over the current line, if we're
482 * doing a bol and/or eol regex search ("^", "$", or "^$"), so
483 * that we find one only once per line. We should only end up
484 * back at the same position if the string isn't found again, in
485 * which case it's the only occurrence. */
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +0000486 if (ISSET(USE_REGEXP) && regexp_bol_or_eol(&search_regexp,
487 last_search)) {
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000488 didfind = findnextstr(TRUE, FALSE, TRUE, current, current_x,
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +0000489 answer, NULL);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000490 if (fileptr == current && fileptr_x == current_x && !didfind)
491 statusbar(_("This is the only occurrence"));
492 } else {
493#endif
494 statusbar(_("This is the only occurrence"));
495#ifdef HAVE_REGEX_H
496 }
497#endif
498 }
Chris Allegretta1c2fddc2002-01-21 20:40:14 +0000499
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000500 placewewant = xplustabs();
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +0000501 edit_redraw(fileptr, old_pww);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000502 search_abort();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000503}
504
David Lawrence Ramsey5aa39832004-05-05 21:36:50 +0000505#ifndef NANO_SMALL
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000506/* Search for the next string without prompting. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000507void do_research(void)
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000508{
David Lawrence Ramsey576bf332004-07-12 03:10:30 +0000509 size_t old_pww = placewewant, fileptr_x = current_x;
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000510 bool didfind;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000511 filestruct *fileptr = current;
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000512
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +0000513#ifndef DISABLE_WRAPPING
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000514 wrap_reset();
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +0000515#endif
David Lawrence Ramseyca744152004-10-01 18:47:17 +0000516
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000517 search_init_globals();
518
519 if (last_search[0] != '\0') {
520
521#ifdef HAVE_REGEX_H
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000522 /* Since answer is "", use last_search! */
David Lawrence Ramsey4b741b92004-04-30 19:40:03 +0000523 if (ISSET(USE_REGEXP) && regexp_init(last_search) == 0)
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000524 return;
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000525#endif
526
David Lawrence Ramseye5e88fd2004-10-31 13:20:30 +0000527 findnextstr_wrap_reset();
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000528 didfind = findnextstr(TRUE, FALSE, FALSE, current, current_x,
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +0000529 last_search, NULL);
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000530
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000531 /* Check to see if there's only one occurrence of the string and
532 * we're on it now. */
533 if (fileptr == current && fileptr_x == current_x && didfind) {
534#ifdef HAVE_REGEX_H
535 /* Do the search again, skipping over the current line, if
536 * we're doing a bol and/or eol regex search ("^", "$", or
537 * "^$"), so that we find one only once per line. We should
538 * only end up back at the same position if the string isn't
539 * found again, in which case it's the only occurrence. */
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +0000540 if (ISSET(USE_REGEXP) && regexp_bol_or_eol(&search_regexp,
541 last_search)) {
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000542 didfind = findnextstr(TRUE, FALSE, TRUE, current,
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +0000543 current_x, answer, NULL);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000544 if (fileptr == current && fileptr_x == current_x && !didfind)
545 statusbar(_("This is the only occurrence"));
546 } else {
547#endif
548 statusbar(_("This is the only occurrence"));
549#ifdef HAVE_REGEX_H
550 }
551#endif
552 }
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000553 } else
554 statusbar(_("No current search pattern"));
555
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000556 placewewant = xplustabs();
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +0000557 edit_redraw(fileptr, old_pww);
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000558 search_abort();
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000559}
David Lawrence Ramsey5aa39832004-05-05 21:36:50 +0000560#endif
David Lawrence Ramseye0497062003-08-23 21:11:06 +0000561
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000562void replace_abort(void)
563{
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000564 /* Identical to search_abort(), so we'll call it here. If it does
565 * something different later, we can change it back. For now, it's
566 * just a waste to duplicate code. */
Chris Allegretta18bd0292000-07-28 01:18:10 +0000567 search_abort();
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000568 placewewant = xplustabs();
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000569}
570
Chris Allegretta805c26d2000-09-06 13:39:17 +0000571#ifdef HAVE_REGEX_H
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000572int replace_regexp(char *string, bool create_flag)
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000573{
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000574 /* Split personality here - if create_flag is FALSE, just calculate
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000575 * the size of the replacement line (necessary because of
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000576 * subexpressions \1 to \9 in the replaced text). */
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000577
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000578 const char *c = last_replace;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000579 int search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000580 int new_size = strlen(current->data) + 1 - search_match_count;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000581
Chris Allegretta6df90f52002-07-19 01:08:59 +0000582 /* Iterate through the replacement text to handle subexpression
583 * replacement using \1, \2, \3, etc. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000584 while (*c != '\0') {
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000585 int num = (int)(*(c + 1) - '0');
586
David Lawrence Ramsey40a6c8c2004-11-27 21:10:11 +0000587 if (*c != '\\' || num < 1 || num > 9 ||
588 num > search_regexp.re_nsub) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000589 if (create_flag)
590 *string++ = *c;
591 c++;
592 new_size++;
593 } else {
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000594 int i = regmatches[num].rm_eo - regmatches[num].rm_so;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000595
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000596 /* Skip over the replacement expression. */
597 c += 2;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000598
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000599 /* But add the length of the subexpression to new_size. */
600 new_size += i;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000601
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000602 /* And if create_flag is TRUE, append the result of the
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000603 * subexpression match to the new line. */
604 if (create_flag) {
605 strncpy(string, current->data + current_x +
606 regmatches[num].rm_so, i);
607 string += i;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000608 }
609 }
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000610 }
611
612 if (create_flag)
Chris Allegretta7662c862003-01-13 01:35:15 +0000613 *string = '\0';
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000614
615 return new_size;
616}
Chris Allegretta47805612000-07-07 02:35:34 +0000617#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000618
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000619char *replace_line(const char *needle)
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000620{
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000621 char *copy;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000622 int new_line_size;
623 int search_match_count;
624
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000625 /* Calculate the size of the new line. */
Chris Allegretta805c26d2000-09-06 13:39:17 +0000626#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000627 if (ISSET(USE_REGEXP)) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +0000628 search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000629 new_line_size = replace_regexp(NULL, 0);
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000630 } else {
Chris Allegretta47805612000-07-07 02:35:34 +0000631#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000632 search_match_count = strlen(needle);
633 new_line_size = strlen(current->data) - search_match_count +
634 strlen(answer) + 1;
635#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000636 }
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000637#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000638
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000639 /* Create the buffer. */
Chris Allegretta88b09152001-05-17 11:35:43 +0000640 copy = charalloc(new_line_size);
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000641
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000642 /* The head of the original line. */
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000643 strncpy(copy, current->data, current_x);
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000644
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000645 /* The replacement text. */
Chris Allegretta805c26d2000-09-06 13:39:17 +0000646#ifdef HAVE_REGEX_H
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000647 if (ISSET(USE_REGEXP))
648 replace_regexp(copy + current_x, TRUE);
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000649 else
Chris Allegretta47805612000-07-07 02:35:34 +0000650#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000651 strcpy(copy + current_x, answer);
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000652
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000653 /* The tail of the original line. */
654 assert(current_x + search_match_count <= strlen(current->data));
655 strcat(copy, current->data + current_x + search_match_count);
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000656
657 return copy;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000658}
659
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000660/* Step through each replace word and prompt user before replacing.
David Lawrence Ramsey491cad32004-10-08 23:06:01 +0000661 * Parameters real_current and real_current_x are needed in order to
662 * allow the cursor position to be updated when a word before the cursor
663 * is replaced by a shorter word.
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000664 *
665 * needle is the string to seek. We replace it with answer. Return -1
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +0000666 * if needle isn't found, else the number of replacements performed. If
667 * canceled isn't NULL, set it to TRUE if we canceled. */
David Lawrence Ramsey182b2c92004-11-03 16:02:41 +0000668ssize_t do_replace_loop(const char *needle, const filestruct
669 *real_current, size_t *real_current_x, bool wholewords, bool
670 *canceled)
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000671{
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000672 ssize_t numreplaced = -1;
673 size_t match_len;
David Lawrence Ramsey3de81bc2004-11-22 17:08:41 +0000674 size_t pww_save = placewewant;
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000675 bool replaceall = FALSE;
David Lawrence Ramseyb7cb6a32003-10-31 17:53:38 +0000676#ifdef HAVE_REGEX_H
David Lawrence Ramseye190ff32004-01-03 21:42:25 +0000677 /* The starting-line match and bol/eol regex flags. */
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000678 bool begin_line = FALSE, bol_or_eol = FALSE;
David Lawrence Ramseyb7cb6a32003-10-31 17:53:38 +0000679#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000680#ifndef NANO_SMALL
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +0000681 bool old_mark_set = ISSET(MARK_ISSET);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000682 filestruct *edittop_save = edittop, *top, *bot;
683 size_t top_x, bot_x;
684 bool right_side_up = FALSE;
685 /* TRUE if (mark_beginbuf, mark_beginx) is the top of the mark,
686 * FALSE if (current, current_x) is. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000687
David Lawrence Ramsey491cad32004-10-08 23:06:01 +0000688 if (old_mark_set) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000689 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +0000690 * contains only the marked text, set edittop to the top of the
691 * partition, turn the mark off, and refresh the screen. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000692 mark_order((const filestruct **)&top, &top_x,
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +0000693 (const filestruct **)&bot, &bot_x, &right_side_up);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000694 filepart = partition_filestruct(top, top_x, bot, bot_x);
695 edittop = fileage;
David Lawrence Ramsey491cad32004-10-08 23:06:01 +0000696 UNSET(MARK_ISSET);
697 edit_refresh();
698 }
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000699#endif
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000700
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +0000701 if (canceled != NULL)
702 *canceled = FALSE;
703
David Lawrence Ramseye5e88fd2004-10-31 13:20:30 +0000704 findnextstr_wrap_reset();
David Lawrence Ramseyc5100422004-08-27 20:28:34 +0000705 while (findnextstr(TRUE, wholewords,
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000706#ifdef HAVE_REGEX_H
707 /* We should find a bol and/or eol regex only once per line. If
708 * the bol_or_eol flag is set, it means that the last search
709 * found one on the beginning line, so we should skip over the
710 * beginning line when doing this search. */
711 bol_or_eol
712#else
713 FALSE
714#endif
David Lawrence Ramsey3de81bc2004-11-22 17:08:41 +0000715 , real_current, *real_current_x, needle, &match_len)) {
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000716
717 int i = 0;
David Lawrence Ramsey34976662004-10-09 16:26:32 +0000718
David Lawrence Ramsey32889252004-10-21 15:44:36 +0000719#ifdef HAVE_REGEX_H
720 /* If the bol_or_eol flag is set, we've found a match on the
721 * beginning line already, and we're still on the beginning line
722 * after the search, it means that we've wrapped around, so
723 * we're done. */
724 if (bol_or_eol && begin_line && current == real_current)
725 break;
726 /* Otherwise, set the begin_line flag if we've found a match on
727 * the beginning line, reset the bol_or_eol flag, and
728 * continue. */
729 else {
730 if (current == real_current)
731 begin_line = TRUE;
732 bol_or_eol = FALSE;
733 }
734#endif
735
David Lawrence Ramseyf56cc9e2004-07-29 14:32:17 +0000736 if (!replaceall) {
David Lawrence Ramsey3de81bc2004-11-22 17:08:41 +0000737 edit_redraw(real_current, pww_save);
David Lawrence Ramsey17586402004-10-26 16:29:21 +0000738 pww_save = placewewant;
David Lawrence Ramseyf56cc9e2004-07-29 14:32:17 +0000739 }
Chris Allegretta7662c862003-01-13 01:35:15 +0000740
David Lawrence Ramsey29f03dc2004-11-03 21:11:38 +0000741 /* Record for the return value that we found the search
742 * string. */
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000743 if (numreplaced == -1)
744 numreplaced = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000745
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000746 if (!replaceall) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000747 char *exp_word;
748 size_t xpt = xplustabs();
749
750 exp_word = display_string(current->data, xpt,
751 strnlenpt(current->data, match_len + current_x) - xpt);
752
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000753 curs_set(0);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000754 do_replace_highlight(TRUE, exp_word);
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000755
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000756 i = do_yesno(TRUE, _("Replace this instance?"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000757
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000758 do_replace_highlight(FALSE, exp_word);
759 free(exp_word);
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000760 curs_set(1);
David Lawrence Ramseyafb75f22003-12-29 02:15:23 +0000761
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +0000762 if (i == -1) { /* We canceled the replace. */
763 if (canceled != NULL)
764 *canceled = TRUE;
David Lawrence Ramseyafb75f22003-12-29 02:15:23 +0000765 break;
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +0000766 }
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000767 }
768
David Lawrence Ramsey18394ac2003-12-24 03:13:44 +0000769#ifdef HAVE_REGEX_H
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000770 /* Set the bol_or_eol flag if we're doing a bol and/or eol regex
David Lawrence Ramseye190ff32004-01-03 21:42:25 +0000771 * replace ("^", "$", or "^$"). */
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000772 if (ISSET(USE_REGEXP) && regexp_bol_or_eol(&search_regexp,
773 needle))
David Lawrence Ramseya3370c42004-04-05 01:08:14 +0000774 bol_or_eol = TRUE;
David Lawrence Ramsey18394ac2003-12-24 03:13:44 +0000775#endif
776
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000777 if (i > 0 || replaceall) { /* Yes, replace it!!!! */
David Lawrence Ramseyafb75f22003-12-29 02:15:23 +0000778 char *copy;
David Lawrence Ramsey687776b2004-10-30 01:16:08 +0000779 size_t length_change;
Chris Allegretta1939c352003-01-26 04:26:25 +0000780
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000781 if (i == 2)
David Lawrence Ramsey576bf332004-07-12 03:10:30 +0000782 replaceall = TRUE;
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000783
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000784 copy = replace_line(needle);
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000785
Chris Allegretta1939c352003-01-26 04:26:25 +0000786 length_change = strlen(copy) - strlen(current->data);
787
Chris Allegretta1939c352003-01-26 04:26:25 +0000788#ifndef NANO_SMALL
David Lawrence Ramseydcc201b2004-11-05 14:37:18 +0000789 /* If the mark was on and (mark_beginbuf, mark_begin_x) was
790 * the top of it, don't change mark_beginx. */
791 if (!old_mark_set || !right_side_up) {
792 /* Keep mark_beginx in sync with the text changes. */
David Lawrence Ramsey40a6c8c2004-11-27 21:10:11 +0000793 if (current == mark_beginbuf &&
794 mark_beginx > current_x) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000795 if (mark_beginx < current_x + match_len)
796 mark_beginx = current_x;
797 else
798 mark_beginx += length_change;
799 }
Chris Allegretta1939c352003-01-26 04:26:25 +0000800 }
Chris Allegretta1939c352003-01-26 04:26:25 +0000801
David Lawrence Ramseydcc201b2004-11-05 14:37:18 +0000802 /* If the mark was on and (current, current_x) was the top
803 * of it, don't change real_current_x. */
804 if (!old_mark_set || right_side_up) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000805#endif
David Lawrence Ramseydcc201b2004-11-05 14:37:18 +0000806 /* Keep real_current_x in sync with the text changes. */
David Lawrence Ramsey40a6c8c2004-11-27 21:10:11 +0000807 if (current == real_current &&
808 current_x <= *real_current_x) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000809 if (*real_current_x < current_x + match_len)
810 *real_current_x = current_x + match_len;
811 *real_current_x += length_change;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000812 }
David Lawrence Ramseydcc201b2004-11-05 14:37:18 +0000813#ifndef NANO_SMALL
Chris Allegretta1939c352003-01-26 04:26:25 +0000814 }
David Lawrence Ramseydcc201b2004-11-05 14:37:18 +0000815#endif
Chris Allegretta1939c352003-01-26 04:26:25 +0000816
817 /* Set the cursor at the last character of the replacement
David Lawrence Ramsey45cfbec2003-11-28 16:04:24 +0000818 * text, so searching will resume after the replacement
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +0000819 * text. Note that current_x might be set to (size_t)-1
820 * here. */
Chris Allegretta1939c352003-01-26 04:26:25 +0000821#ifndef NANO_SMALL
David Lawrence Ramsey18394ac2003-12-24 03:13:44 +0000822 if (!ISSET(REVERSE_SEARCH))
Chris Allegretta1939c352003-01-26 04:26:25 +0000823#endif
824 current_x += match_len + length_change - 1;
825
David Lawrence Ramseyb7cb6a32003-10-31 17:53:38 +0000826 /* Cleanup. */
Chris Allegretta1939c352003-01-26 04:26:25 +0000827 totsize += length_change;
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000828 free(current->data);
829 current->data = copy;
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000830
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000831 if (!replaceall) {
832#ifdef ENABLE_COLOR
833 if (ISSET(COLOR_SYNTAX))
834 edit_refresh();
835 else
836#endif
837 update_line(current, current_x);
838 }
839
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000840 set_modified();
841 numreplaced++;
David Lawrence Ramseyafb75f22003-12-29 02:15:23 +0000842 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000843 }
844
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000845#ifndef NANO_SMALL
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000846 if (old_mark_set) {
David Lawrence Ramseyf978f042004-11-04 16:45:48 +0000847 /* If the mark was on, unpartition the filestruct so that it
848 * contains all the text again, set edittop back to what it was
849 * before, turn the mark back on, and refresh the screen. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000850 unpartition_filestruct(&filepart);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000851 edittop = edittop_save;
852 SET(MARK_ISSET);
853 edit_refresh();
854 }
855#endif
856
Chris Allegretta7662c862003-01-13 01:35:15 +0000857 /* If text has been added to the magicline, make a new magicline. */
858 if (filebot->data[0] != '\0')
859 new_magicline();
860
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000861 return numreplaced;
862}
863
Chris Allegretta7662c862003-01-13 01:35:15 +0000864/* Replace a string. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000865void do_replace(void)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000866{
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000867 int i;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000868 filestruct *edittop_save, *begin;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +0000869 size_t beginx, pww_save;
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000870 ssize_t numreplaced;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000871
Chris Allegretta5050aa62001-04-22 07:10:21 +0000872 if (ISSET(VIEW_MODE)) {
873 print_view_warning();
874 replace_abort();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000875 return;
Chris Allegretta5050aa62001-04-22 07:10:21 +0000876 }
877
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000878 i = search_init(TRUE, FALSE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000879 if (i == -1) { /* Cancel, Go to Line, blank search
880 * string, or regcomp() failed. */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000881 replace_abort();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000882 return;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000883 } else if (i == -2) { /* No Replace. */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000884 do_search();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000885 return;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000886 } else if (i == 1) /* Case Sensitive, Backwards, or Regexp
887 * search toggle. */
888 do_replace();
889
890 if (i != 0)
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000891 return;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000892
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000893 /* If answer is not "", add answer to the search history list and
894 * copy answer into last_search. */
895 if (answer[0] != '\0') {
Chris Allegretta5beed502003-01-05 20:41:21 +0000896#ifndef NANO_SMALL
Chris Allegretta63287922003-01-05 20:43:49 +0000897 update_history(&search_history, answer);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000898#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000899 last_search = mallocstrcpy(last_search, answer);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000900 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000901
Chris Allegretta15c28f82003-01-05 21:47:06 +0000902#ifndef NANO_SMALL
903 replace_history.current = (historytype *)&replace_history.next;
904 last_replace = mallocstrcpy(last_replace, "");
905#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000906
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000907 i = statusq(FALSE, replace_list_2, last_replace,
Chris Allegretta5beed502003-01-05 20:41:21 +0000908#ifndef NANO_SMALL
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000909 &replace_history,
Chris Allegretta5beed502003-01-05 20:41:21 +0000910#endif
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000911 _("Replace with"));
Chris Allegretta15c28f82003-01-05 21:47:06 +0000912
Chris Allegretta5beed502003-01-05 20:41:21 +0000913#ifndef NANO_SMALL
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000914 /* Add this replace string to the replace history list. i == 0
915 * means that the string is not "". */
916 if (i == 0)
Chris Allegretta5beed502003-01-05 20:41:21 +0000917 update_history(&replace_history, answer);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000918#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000919
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000920 if (i != 0 && i != -2) {
921 if (i == -1) { /* Cancel. */
922 if (last_replace[0] != '\0')
923 answer = mallocstrcpy(answer, last_replace);
David Lawrence Ramseyd1322102004-08-26 04:22:54 +0000924 statusbar(_("Cancelled"));
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000925 }
926 replace_abort();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000927 return;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000928 }
929
930 last_replace = mallocstrcpy(last_replace, answer);
931
932 /* Save where we are. */
David Lawrence Ramsey27fbc692004-10-19 21:09:37 +0000933 edittop_save = edittop;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000934 begin = current;
Chris Allegrettabc72e362002-02-16 20:03:44 +0000935 beginx = current_x;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +0000936 pww_save = placewewant;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000937
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +0000938 numreplaced = do_replace_loop(last_search, begin, &beginx, FALSE,
939 NULL);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000940
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000941 /* Restore where we were. */
David Lawrence Ramsey90625792004-07-30 20:21:34 +0000942 edittop = edittop_save;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000943 current = begin;
Chris Allegrettabc72e362002-02-16 20:03:44 +0000944 current_x = beginx;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +0000945 placewewant = pww_save;
David Lawrence Ramsey27fbc692004-10-19 21:09:37 +0000946
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000947 renumber_all();
David Lawrence Ramsey90625792004-07-30 20:21:34 +0000948 edit_refresh();
Chris Allegretta7662c862003-01-13 01:35:15 +0000949
950 if (numreplaced >= 0)
David Lawrence Ramsey53752e82004-10-18 22:19:22 +0000951 statusbar(P_("Replaced %ld occurrence", "Replaced %ld occurrences",
952 (long)numreplaced), (long)numreplaced);
Chris Allegretta7662c862003-01-13 01:35:15 +0000953
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000954 replace_abort();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000955}
956
David Lawrence Ramseyc53ab2a2004-08-04 18:24:53 +0000957void do_gotoline(int line, bool save_pos)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000958{
David Lawrence Ramsey90625792004-07-30 20:21:34 +0000959 if (line <= 0) { /* Ask for it. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000960 char *ans = mallocstrcpy(NULL, answer);
David Lawrence Ramseye5d8f322004-09-30 22:07:21 +0000961 int i = statusq(FALSE, gotoline_list, line < 0 ? ans : "",
Chris Allegretta7662c862003-01-13 01:35:15 +0000962#ifndef NANO_SMALL
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000963 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +0000964#endif
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000965 _("Enter line number"));
966
967 free(ans);
Chris Allegrettaa90d0cf2003-02-10 02:55:03 +0000968
969 /* Cancel, or Enter with blank string. */
David Lawrence Ramsey4c9e8f42004-10-04 16:01:37 +0000970 if (i < 0) {
David Lawrence Ramseyb77ec622004-09-28 15:06:15 +0000971 statusbar(_("Cancelled"));
David Lawrence Ramsey4c9e8f42004-10-04 16:01:37 +0000972 display_main_list();
David Lawrence Ramseye5d8f322004-09-30 22:07:21 +0000973 return;
974 }
975
David Lawrence Ramsey4c9e8f42004-10-04 16:01:37 +0000976 if (i == NANO_TOOTHERWHEREIS_KEY) {
David Lawrence Ramseyd532f192004-10-04 22:37:56 +0000977 /* Keep answer up on the statusbar. */
978 search_init(TRUE, TRUE);
979
David Lawrence Ramsey4c9e8f42004-10-04 16:01:37 +0000980 do_search();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000981 return;
Rocco Corsi4dfaf932001-04-20 01:59:55 +0000982 }
983
David Lawrence Ramsey1f204c02004-10-15 01:39:46 +0000984 /* Do a bounds check. Display a warning on an out-of-bounds
985 * line number only if we hit Enter at the statusbar prompt. */
David Lawrence Ramseyc53ab2a2004-08-04 18:24:53 +0000986 if (!parse_num(answer, &line) || line < 0) {
David Lawrence Ramsey1f204c02004-10-15 01:39:46 +0000987 if (i == 0)
988 statusbar(_("Come on, be reasonable"));
Chris Allegrettae1e0fd62003-04-15 01:15:09 +0000989 display_main_list();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000990 return;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000991 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000992 }
993
David Lawrence Ramsey90625792004-07-30 20:21:34 +0000994 if (current->lineno > line) {
995 for (; current->prev != NULL && current->lineno > line;
996 current = current->prev)
997 ;
998 } else {
999 for (; current->next != NULL && current->lineno < line;
1000 current = current->next)
1001 ;
1002 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001003
Rocco Corsi4dfaf932001-04-20 01:59:55 +00001004 current_x = 0;
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001005
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001006 /* If save_pos is TRUE, don't change the cursor position when
David Lawrence Ramseyc6908f22004-03-11 02:20:25 +00001007 * updating the edit window. */
David Lawrence Ramsey20b83502004-08-26 18:07:58 +00001008 edit_update(save_pos ? NONE : CENTER);
David Lawrence Ramseyc6908f22004-03-11 02:20:25 +00001009
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00001010 placewewant = 0;
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00001011 display_main_list();
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001012}
1013
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001014void do_gotoline_void(void)
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001015{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001016 do_gotoline(0, FALSE);
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001017}
Chris Allegrettae1f14522001-09-19 03:19:43 +00001018
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00001019#if defined(ENABLE_MULTIBUFFER) || !defined(DISABLE_SPELLER)
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001020void do_gotopos(int line, size_t pos_x, int pos_y, size_t pos_pww)
Chris Allegrettae1f14522001-09-19 03:19:43 +00001021{
David Lawrence Ramsey90625792004-07-30 20:21:34 +00001022 /* Since do_gotoline() resets the x-coordinate but not the
1023 * y-coordinate, set the coordinates up this way. */
Chris Allegrettae1f14522001-09-19 03:19:43 +00001024 current_y = pos_y;
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001025 do_gotoline(line, TRUE);
Chris Allegretta2084acc2001-11-29 03:43:08 +00001026
David Lawrence Ramsey90625792004-07-30 20:21:34 +00001027 /* Make sure that the x-coordinate is sane here. */
1028 current_x = strlen(current->data);
1029 if (pos_x < current_x)
1030 current_x = pos_x;
Chris Allegretta2084acc2001-11-29 03:43:08 +00001031
David Lawrence Ramsey90625792004-07-30 20:21:34 +00001032 /* Set the rest of the coordinates up. */
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001033 placewewant = pos_pww;
Chris Allegrettae1f14522001-09-19 03:19:43 +00001034 update_line(current, pos_x);
1035}
1036#endif
Chris Allegretta8d990b52001-09-22 22:14:25 +00001037
1038#if !defined(NANO_SMALL) && defined(HAVE_REGEX_H)
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001039void do_find_bracket(void)
Chris Allegretta8d990b52001-09-22 22:14:25 +00001040{
1041 char ch_under_cursor, wanted_ch;
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00001042 const char *pos, *brackets = "([{<>}])";
Chris Allegretta8d990b52001-09-22 22:14:25 +00001043 char regexp_pat[] = "[ ]";
David Lawrence Ramsey17586402004-10-26 16:29:21 +00001044 size_t current_x_save, pww_save;
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001045 int count = 1;
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00001046 long flags_save;
Chris Allegretta8d990b52001-09-22 22:14:25 +00001047 filestruct *current_save;
1048
1049 ch_under_cursor = current->data[current_x];
Chris Allegretta5beed502003-01-05 20:41:21 +00001050
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001051 pos = strchr(brackets, ch_under_cursor);
1052 if (ch_under_cursor == '\0' || pos == NULL) {
Chris Allegretta8d990b52001-09-22 22:14:25 +00001053 statusbar(_("Not a bracket"));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001054 return;
Chris Allegretta8d990b52001-09-22 22:14:25 +00001055 }
1056
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001057 assert(strlen(brackets) % 2 == 0);
1058 wanted_ch = brackets[(strlen(brackets) - 1) - (pos - brackets)];
Chris Allegretta8d990b52001-09-22 22:14:25 +00001059
Chris Allegretta8d990b52001-09-22 22:14:25 +00001060 current_save = current;
David Lawrence Ramseyb6377c92004-10-09 20:10:55 +00001061 current_x_save = current_x;
David Lawrence Ramsey17586402004-10-26 16:29:21 +00001062 pww_save = placewewant;
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00001063 flags_save = flags;
Chris Allegretta8d990b52001-09-22 22:14:25 +00001064 SET(USE_REGEXP);
1065
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001066 /* Apparent near redundancy with regexp_pat[] here is needed.
1067 * "[][]" works, "[[]]" doesn't. */
Chris Allegretta8d990b52001-09-22 22:14:25 +00001068
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001069 if (pos < brackets + (strlen(brackets) / 2)) {
1070 /* On a left bracket. */
Chris Allegretta8d990b52001-09-22 22:14:25 +00001071 regexp_pat[1] = wanted_ch;
1072 regexp_pat[2] = ch_under_cursor;
1073 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001074 } else {
1075 /* On a right bracket. */
Chris Allegretta8d990b52001-09-22 22:14:25 +00001076 regexp_pat[1] = ch_under_cursor;
1077 regexp_pat[2] = wanted_ch;
1078 SET(REVERSE_SEARCH);
1079 }
1080
1081 regexp_init(regexp_pat);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001082 /* We constructed regexp_pat to be a valid expression. */
David Lawrence Ramsey4b741b92004-04-30 19:40:03 +00001083 assert(regexp_compiled);
Chris Allegretta8d990b52001-09-22 22:14:25 +00001084
David Lawrence Ramseye5e88fd2004-10-31 13:20:30 +00001085 findnextstr_wrap_reset();
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001086 while (TRUE) {
David Lawrence Ramseyc5100422004-08-27 20:28:34 +00001087 if (findnextstr(FALSE, FALSE, FALSE, current, current_x,
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +00001088 regexp_pat, NULL)) {
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001089 /* Found identical bracket. */
Chris Allegretta7662c862003-01-13 01:35:15 +00001090 if (current->data[current_x] == ch_under_cursor)
Chris Allegretta8d990b52001-09-22 22:14:25 +00001091 count++;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001092 /* Found complementary bracket. */
1093 else if (--count == 0) {
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001094 placewewant = xplustabs();
David Lawrence Ramsey17586402004-10-26 16:29:21 +00001095 edit_redraw(current_save, pww_save);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001096 break;
Chris Allegretta8d990b52001-09-22 22:14:25 +00001097 }
Chris Allegretta7662c862003-01-13 01:35:15 +00001098 } else {
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001099 /* Didn't find either a left or right bracket. */
Chris Allegretta8d990b52001-09-22 22:14:25 +00001100 statusbar(_("No matching bracket"));
Chris Allegretta8d990b52001-09-22 22:14:25 +00001101 current = current_save;
David Lawrence Ramseyb6377c92004-10-09 20:10:55 +00001102 current_x = current_x_save;
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00001103 update_line(current, current_x);
Chris Allegretta8d990b52001-09-22 22:14:25 +00001104 break;
1105 }
1106 }
1107
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001108 regexp_cleanup();
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00001109 flags = flags_save;
Chris Allegretta8d990b52001-09-22 22:14:25 +00001110}
1111#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001112
1113#ifndef NANO_SMALL
1114/*
1115 * search and replace history list support functions
1116 */
1117
1118/* initialize search and replace history lists */
1119void history_init(void)
1120{
1121 search_history.next = (historytype *)&search_history.prev;
1122 search_history.prev = NULL;
1123 search_history.tail = (historytype *)&search_history.next;
1124 search_history.current = search_history.next;
1125 search_history.count = 0;
1126 search_history.len = 0;
1127
1128 replace_history.next = (historytype *)&replace_history.prev;
1129 replace_history.prev = NULL;
1130 replace_history.tail = (historytype *)&replace_history.next;
1131 replace_history.current = replace_history.next;
1132 replace_history.count = 0;
1133 replace_history.len = 0;
1134}
1135
1136/* find first node containing string *s in history list *h */
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00001137historytype *find_node(historytype *h, const char *s)
Chris Allegretta5beed502003-01-05 20:41:21 +00001138{
Chris Allegretta09fc4302003-01-16 22:16:38 +00001139 for (; h->next != NULL; h = h->next)
Chris Allegretta5beed502003-01-05 20:41:21 +00001140 if (strcmp(s, h->data) == 0)
1141 return h;
1142 return NULL;
1143}
1144
1145/* remove node *r */
1146void remove_node(historytype *r)
1147{
1148 r->prev->next = r->next;
1149 r->next->prev = r->prev;
1150 free(r->data);
1151 free(r);
1152}
1153
1154/* add a node after node *h */
1155void insert_node(historytype *h, const char *s)
1156{
1157 historytype *a;
1158
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001159 a = (historytype *)nmalloc(sizeof(historytype));
Chris Allegretta5beed502003-01-05 20:41:21 +00001160 a->next = h->next;
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00001161 a->prev = h;
Chris Allegretta5beed502003-01-05 20:41:21 +00001162 h->next->prev = a;
1163 h->next = a;
1164 a->data = mallocstrcpy(NULL, s);
1165}
1166
1167/* update history list */
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00001168void update_history(historyheadtype *h, const char *s)
Chris Allegretta5beed502003-01-05 20:41:21 +00001169{
1170 historytype *p;
1171
Chris Allegretta09fc4302003-01-16 22:16:38 +00001172 if ((p = find_node(h->next, s)) != NULL) {
1173 if (p == h->next) /* catch delete and re-insert of
1174 same string in 1st node */
Chris Allegretta5beed502003-01-05 20:41:21 +00001175 goto up_hs;
Chris Allegretta09fc4302003-01-16 22:16:38 +00001176 remove_node(p); /* delete identical older string */
Chris Allegretta5beed502003-01-05 20:41:21 +00001177 h->count--;
1178 }
1179 if (h->count == MAX_SEARCH_HISTORY) { /* list 'full', delete oldest */
1180 remove_node(h->tail);
1181 h->count--;
1182 }
1183 insert_node((historytype *)h, s);
1184 h->count++;
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00001185 SET(HISTORY_CHANGED);
Chris Allegretta09fc4302003-01-16 22:16:38 +00001186 up_hs:
Chris Allegretta5beed502003-01-05 20:41:21 +00001187 h->current = h->next;
1188}
1189
1190/* return a pointer to either the next older history or NULL if no more */
1191char *get_history_older(historyheadtype *h)
1192{
Chris Allegretta09fc4302003-01-16 22:16:38 +00001193 if (h->current->next != NULL) { /* any older entries? */
Chris Allegretta5beed502003-01-05 20:41:21 +00001194 h->current = h->current->next; /* yes */
1195 return h->current->data; /* return it */
1196 }
1197 return NULL; /* end of list */
1198}
1199
1200char *get_history_newer(historyheadtype *h)
1201{
Chris Allegretta09fc4302003-01-16 22:16:38 +00001202 if (h->current->prev != NULL) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001203 h->current = h->current->prev;
Chris Allegretta09fc4302003-01-16 22:16:38 +00001204 if (h->current->prev != NULL)
Chris Allegretta5beed502003-01-05 20:41:21 +00001205 return h->current->data;
1206 }
1207 return NULL;
1208}
1209
1210/* get a completion */
1211char *get_history_completion(historyheadtype *h, char *s)
1212{
1213 historytype *p;
1214
Chris Allegretta09fc4302003-01-16 22:16:38 +00001215 for (p = h->current->next; p->next != NULL; p = p->next) {
1216 if (strncmp(s, p->data, h->len) == 0 && strlen(p->data) != h->len) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001217 h->current = p;
1218 return p->data;
1219 }
1220 }
1221 h->current = (historytype*)h;
1222 null_at(&s, h->len);
1223 return s;
1224}
1225
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00001226#ifdef DEBUG
Chris Allegretta5beed502003-01-05 20:41:21 +00001227/* free a history list */
1228void free_history(historyheadtype *h)
1229{
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00001230 historytype *p;
Chris Allegretta5beed502003-01-05 20:41:21 +00001231
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00001232 for (p = h->next; p->next != NULL; p = p->next)
Chris Allegretta5beed502003-01-05 20:41:21 +00001233 remove_node(p);
1234}
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00001235#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001236
1237/* end of history support functions */
1238#endif /* !NANO_SMALL */