blob: 7e04041ae83628f807781d6c77642dc0cd55fd2f [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettabceb1b22000-06-19 04:22:15 +00002/**************************************************************************
3 * search.c *
4 * *
5 * Copyright (C) 2000 Chris Allegretta *
6 * 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 *
8 * the Free Software Foundation; either version 1, or (at your option) *
9 * 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
22#include <stdlib.h>
23#include <string.h>
Chris Allegretta47805612000-07-07 02:35:34 +000024#include <unistd.h>
Chris Allegrettabceb1b22000-06-19 04:22:15 +000025#include <stdio.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000026#include <ctype.h>
Chris Allegrettabceb1b22000-06-19 04:22:15 +000027#include "config.h"
28#include "proto.h"
29#include "nano.h"
Chris Allegretta4da1fc62000-06-21 03:00:43 +000030
Chris Allegrettabceb1b22000-06-19 04:22:15 +000031#ifndef NANO_SMALL
32#include <libintl.h>
33#define _(string) gettext(string)
34#else
35#define _(string) (string)
36#endif
37
Chris Allegretta9fc8d432000-07-07 01:49:52 +000038/* Regular expression helper functions */
39
Chris Allegretta805c26d2000-09-06 13:39:17 +000040#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +000041void regexp_init(const char *regexp)
42{
43 regcomp(&search_regexp, regexp, ISSET(CASE_SENSITIVE) ? 0 : REG_ICASE);
44 SET(REGEXP_COMPILED);
45}
46
Chris Allegrettae3167732001-03-18 16:59:34 +000047void regexp_cleanup(void)
Chris Allegretta9fc8d432000-07-07 01:49:52 +000048{
49 UNSET(REGEXP_COMPILED);
50 regfree(&search_regexp);
51}
Chris Allegretta47805612000-07-07 02:35:34 +000052#endif
Chris Allegretta9fc8d432000-07-07 01:49:52 +000053
Chris Allegretta27eb13f2000-11-05 16:52:21 +000054void search_init_globals(void)
55{
56 if (last_search == NULL) {
57 last_search = nmalloc(1);
58 last_search[0] = 0;
59 }
60 if (last_replace == NULL) {
61 last_replace = nmalloc(1);
62 last_replace[0] = 0;
63 }
64}
65
Chris Allegrettabceb1b22000-06-19 04:22:15 +000066/* Set up the system variables for a search or replace. Returns -1 on
67 abort, 0 on success, and 1 on rerun calling program
68 Return -2 to run opposite program (searchg -> replace, replace -> search)
69
70 replacing = 1 if we call from do_replace, 0 if called from do_search func.
71*/
72int search_init(int replacing)
73{
Chris Allegretta71844ba2000-11-03 14:23:00 +000074 int i = 0;
75 char *buf;
Chris Allegrettaa4d21622000-07-08 23:57:03 +000076 char *prompt, *reprompt = "";
Chris Allegretta5bf51d32000-11-16 06:01:10 +000077 static char *backupstring = NULL;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +000078
Chris Allegretta27eb13f2000-11-05 16:52:21 +000079 search_init_globals();
Chris Allegretta31925e42000-11-02 04:40:39 +000080
Chris Allegretta27eb13f2000-11-05 16:52:21 +000081 buf = nmalloc(strlen(last_search) + 5);
82 buf[0] = 0;
Chris Allegretta71844ba2000-11-03 14:23:00 +000083
Chris Allegretta5bf51d32000-11-16 06:01:10 +000084 /* Okay, fun time. backupstring is our holder for what is being
85 returned from the statusq call. Using answer for this would be tricky.
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +000086 Here, if we're using PICO_MODE, we only want nano to put the
Chris Allegretta5bf51d32000-11-16 06:01:10 +000087 old string back up as editable if it's not the same as last_search.
88
89 Otherwise, if we don't already have a backupstring, set it to
90 last_search. */
91
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +000092 if (ISSET(PICO_MODE)) {
Chris Allegretta5bf51d32000-11-16 06:01:10 +000093 if (backupstring == NULL || !strcmp(backupstring, last_search))
94 backupstring = mallocstrcpy(backupstring, "");
95 }
96 else if (backupstring == NULL)
97 backupstring = mallocstrcpy(backupstring, last_search);
98
Chris Allegretta27eb13f2000-11-05 16:52:21 +000099 /* If using Pico messages, we do things the old fashioned way... */
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +0000100 if (ISSET(PICO_MODE)) {
Chris Allegretta71844ba2000-11-03 14:23:00 +0000101 if (last_search[0]) {
102
103 /* We use COLS / 3 here because we need to see more on the line */
104 if (strlen(last_search) > COLS / 3) {
105 snprintf(buf, COLS / 3 + 3, " [%s", last_search);
106 sprintf(&buf[COLS / 3 + 2], "...]");
107 } else
108 sprintf(buf, " [%s]", last_search);
109 } else {
110 buf[0] = '\0';
111 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000112 }
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000113 else
114 strcpy(buf, "");
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000115
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000116 if (ISSET(USE_REGEXP) && ISSET(CASE_SENSITIVE))
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000117 prompt = _("Case Sensitive Regexp Search%s%s");
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000118 else if (ISSET(USE_REGEXP))
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000119 prompt = _("Regexp Search%s%s");
120 else if (ISSET(CASE_SENSITIVE))
121 prompt = _("Case Sensitive Search%s%s");
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000122 else
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000123 prompt = _("Search%s%s");
Chris Allegrettaa4d21622000-07-08 23:57:03 +0000124
125 if (replacing)
126 reprompt = _(" (to replace)");
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000127
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000128 /* This is now one simple call. It just does a lot */
129 i = statusq(0, replacing ? replace_list : whereis_list,
130 replacing ? REPLACE_LIST_LEN : WHEREIS_LIST_LEN, backupstring,
Chris Allegrettaef601bb2000-11-19 19:15:03 +0000131 prompt, reprompt, buf);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000132
133 /* Cancel any search, or just return with no previous search */
134 if ((i == -1) || (i < 0 && !last_search[0])) {
135 statusbar(_("Search Cancelled"));
136 reset_cursor();
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000137 free(backupstring);
138 backupstring = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000139 return -1;
140 } else if (i == -2) { /* Same string */
Chris Allegretta805c26d2000-09-06 13:39:17 +0000141#ifdef HAVE_REGEX_H
Chris Allegretta74bb31b2001-03-14 09:08:14 +0000142 if (ISSET(USE_REGEXP)) {
143
144 /* If we're in pico mode, answer is "", use last_search! */
145 if (ISSET(PICO_MODE))
146 regexp_init(last_search);
147 else
148 regexp_init(answer);
149 }
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000150#else
151 ;
Chris Allegretta47805612000-07-07 02:35:34 +0000152#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000153 } else if (i == 0) { /* They entered something new */
Chris Allegretta805c26d2000-09-06 13:39:17 +0000154#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000155 if (ISSET(USE_REGEXP))
156 regexp_init(answer);
Chris Allegretta47805612000-07-07 02:35:34 +0000157#endif
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000158 free(backupstring);
159 backupstring = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000160 last_replace[0] = '\0';
161 } else if (i == NANO_CASE_KEY) { /* They want it case sensitive */
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000162 free(backupstring);
163 backupstring = NULL;
164 backupstring = mallocstrcpy(backupstring, answer);
165
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000166 if (ISSET(CASE_SENSITIVE))
167 UNSET(CASE_SENSITIVE);
168 else
169 SET(CASE_SENSITIVE);
170
171 return 1;
172 } else if (i == NANO_OTHERSEARCH_KEY) {
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000173 backupstring = mallocstrcpy(backupstring, answer);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000174 return -2; /* Call the opposite search function */
Chris Allegretta8c2b40f2000-06-29 01:30:04 +0000175 } else if (i == NANO_FROMSEARCHTOGOTO_KEY) {
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000176 free(backupstring);
177 backupstring = NULL;
Chris Allegretta8c2b40f2000-06-29 01:30:04 +0000178 do_gotoline_void();
179 return -3;
Chris Allegretta105da332000-10-31 05:10:10 +0000180 } else { /* First line key, etc. */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000181 do_early_abort();
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000182 free(backupstring);
183 backupstring = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000184 return -3;
185 }
186
187 return 0;
188}
189
Chris Allegretta31925e42000-11-02 04:40:39 +0000190void not_found_msg(char *str)
191{
Chris Allegrettacbb0f8b2000-11-15 03:50:02 +0000192 if (strlen(str) <= COLS / 2)
Chris Allegretta31925e42000-11-02 04:40:39 +0000193 statusbar(_("\"%s\" not found"), str);
194 else {
Chris Allegrettacbb0f8b2000-11-15 03:50:02 +0000195 char *foo = NULL;
196
197 foo = mallocstrcpy(foo, str);
Chris Allegretta31925e42000-11-02 04:40:39 +0000198 foo[COLS / 2] = 0;
199 statusbar(_("\"%s...\" not found"), foo);
Chris Allegrettacbb0f8b2000-11-15 03:50:02 +0000200
201 free(foo);
Chris Allegretta31925e42000-11-02 04:40:39 +0000202 }
203}
204
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000205filestruct *findnextstr(int quiet, filestruct * begin, int beginx,
206 char *needle)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000207{
208 filestruct *fileptr;
209 char *searchstr, *found = NULL, *tmp;
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000210 int past_editbot = 0, current_x_find;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000211
Chris Allegrettab9bfc9b2000-09-10 05:06:09 +0000212 fileptr = current;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000213
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000214 current_x_find = current_x + 1;
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000215
216 /* Are we searching the last line? (i.e. the line where search started) */
Chris Allegretta1cc29f62000-11-20 01:29:37 +0000217 if ((fileptr == begin) && (current_x_find < beginx))
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000218 search_last_line = 1;
219
220 /* Make sure we haven't passed the end of the string */
Chris Allegretta1cc29f62000-11-20 01:29:37 +0000221 if (strlen(fileptr->data) < current_x_find)
222 current_x_find--;
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000223
Chris Allegretta1cc29f62000-11-20 01:29:37 +0000224 searchstr = &fileptr->data[current_x_find];
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000225
226 /* Look for needle in searchstr */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000227 while ((found = strstrwrapper(searchstr, needle)) == NULL) {
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000228
229 /* finished processing file, get out */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000230 if (search_last_line) {
Chris Allegretta1cc29f62000-11-20 01:29:37 +0000231 if (!quiet)
Chris Allegretta31925e42000-11-02 04:40:39 +0000232 not_found_msg(needle);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000233 return NULL;
234 }
Adam Rogoyski2a4ef922000-07-09 00:15:11 +0000235
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000236 fileptr = fileptr->next;
237
Adam Rogoyskia966d992000-07-09 18:42:53 +0000238 if (!past_editbot && (fileptr == editbot))
239 past_editbot = 1;
Adam Rogoyski2a4ef922000-07-09 00:15:11 +0000240
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000241 /* EOF reached, wrap around once */
242 if (fileptr == NULL) {
243 fileptr = fileage;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000244
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000245 past_editbot = 1;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000246
247 if (!quiet)
248 statusbar(_("Search Wrapped"));
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000249 }
250
251 /* Original start line reached */
252 if (fileptr == begin)
253 search_last_line = 1;
254
255 searchstr = fileptr->data;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000256 }
257
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000258 /* We found an instance */
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000259 current_x_find = 0;
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000260 for (tmp = fileptr->data; tmp != found; tmp++)
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000261 current_x_find++;
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000262
263 /* Ensure we haven't wrap around again! */
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000264 if ((search_last_line) && (current_x_find >= beginx)) {
Chris Allegretta1cc29f62000-11-20 01:29:37 +0000265 if (!quiet)
Chris Allegretta31925e42000-11-02 04:40:39 +0000266 not_found_msg(needle);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000267 return NULL;
268 }
269
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000270 /* Set globals now that we are sure we found something */
271 current = fileptr;
272 current_x = current_x_find;
273
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000274 if (past_editbot)
275 edit_update(fileptr, CENTER);
276 else
277 update_line(current, current_x);
278
279 placewewant = xplustabs();
280 reset_cursor();
281
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000282 return fileptr;
283}
284
285void search_abort(void)
286{
287 UNSET(KEEP_CUTBUFFER);
288 display_main_list();
289 wrefresh(bottomwin);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000290 if (ISSET(MARK_ISSET))
Chris Allegrettaf1d33d32000-08-19 03:53:39 +0000291 edit_refresh_clearok();
Chris Allegretta47805612000-07-07 02:35:34 +0000292
Chris Allegretta805c26d2000-09-06 13:39:17 +0000293#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000294 if (ISSET(REGEXP_COMPILED))
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000295 regexp_cleanup();
Chris Allegretta47805612000-07-07 02:35:34 +0000296#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000297}
298
299/* Search for a string */
300int do_search(void)
301{
302 int i;
303 filestruct *fileptr = current;
304
305 wrap_reset();
Chris Allegretta9c371a22000-10-27 05:48:05 +0000306 i = search_init(0);
307 switch (i) {
308 case -1:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000309 current = fileptr;
310 search_abort();
311 return 0;
Chris Allegretta9c371a22000-10-27 05:48:05 +0000312 case -3:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000313 search_abort();
314 return 0;
Chris Allegretta9c371a22000-10-27 05:48:05 +0000315 case -2:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000316 do_replace();
317 return 0;
Chris Allegretta9c371a22000-10-27 05:48:05 +0000318 case 1:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000319 do_search();
320 search_abort();
321 return 1;
322 }
Chris Allegretta86f8b3a2000-10-31 05:28:33 +0000323
324 /* The sneaky user deleted the previous search string */
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +0000325 if (!ISSET(PICO_MODE) && !strcmp(answer, "")) {
Jordi Mallache7a647c2000-11-01 18:43:21 +0000326 statusbar(_("Search Cancelled"));
Chris Allegretta86f8b3a2000-10-31 05:28:33 +0000327 search_abort();
328 return 0;
329 }
330
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +0000331 /* If answer is now == "", then PICO_MODE is set. So, copy
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000332 last_search into answer... */
333
334 if (!strcmp(answer, ""))
335 answer = mallocstrcpy(answer, last_search);
336 else
337 last_search = mallocstrcpy(last_search, answer);
338
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000339 search_last_line = 0;
340 findnextstr(0, current, current_x, answer);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000341 search_abort();
342 return 1;
343}
344
345void print_replaced(int num)
346{
347 if (num > 1)
Jordi Mallach5b387d72001-02-20 12:45:47 +0000348 statusbar(_("Replaced %d occurrences"), num);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000349 else if (num == 1)
Jordi Mallach5b387d72001-02-20 12:45:47 +0000350 statusbar(_("Replaced 1 occurrence"));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000351}
352
353void replace_abort(void)
354{
Chris Allegretta18bd0292000-07-28 01:18:10 +0000355 /* Identicle to search_abort, so we'll call it here. If it
356 does something different later, we can change it back. For now
357 it's just a waste to duplicat code */
358 search_abort();
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000359 placewewant = xplustabs();
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000360}
361
Chris Allegretta805c26d2000-09-06 13:39:17 +0000362#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000363int replace_regexp(char *string, int create_flag)
364{
365 /* split personality here - if create_flag is null, just calculate
366 * the size of the replacement line (necessary because of
367 * subexpressions like \1 \2 \3 in the replaced text) */
368
369 char *c;
370 int new_size = strlen(current->data) + 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000371 int search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000372
373 new_size -= search_match_count;
374
375 /* Iterate through the replacement text to handle
376 * subexpression replacement using \1, \2, \3, etc */
377
378 c = last_replace;
379 while (*c) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000380 if (*c != '\\') {
381 if (create_flag)
382 *string++ = *c;
383 c++;
384 new_size++;
385 } else {
386 int num = (int) *(c + 1) - (int) '0';
387 if (num >= 1 && num <= 9) {
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000388
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000389 int i = regmatches[num].rm_so;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000390
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000391 if (num > search_regexp.re_nsub) {
392 /* Ugh, they specified a subexpression that doesn't
393 exist. */
394 return -1;
395 }
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000396
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000397 /* Skip over the replacement expression */
398 c += 2;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000399
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000400 /* But add the length of the subexpression to new_size */
401 new_size += regmatches[num].rm_eo - regmatches[num].rm_so;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000402
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000403 /* And if create_flag is set, append the result of the
404 * subexpression match to the new line */
405 while (create_flag && i < regmatches[num].rm_eo)
406 *string++ = *(current->data + i++);
407
408 } else {
409 if (create_flag)
410 *string++ = *c;
411 c++;
412 new_size++;
413 }
414 }
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000415 }
416
417 if (create_flag)
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000418 *string = 0;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000419
420 return new_size;
421}
Chris Allegretta47805612000-07-07 02:35:34 +0000422#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000423
Chris Allegrettab46df992000-11-01 02:12:13 +0000424char *replace_line(void)
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000425{
426 char *copy, *tmp;
427 int new_line_size;
428 int search_match_count;
429
430 /* Calculate size of new line */
Chris Allegretta805c26d2000-09-06 13:39:17 +0000431#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000432 if (ISSET(USE_REGEXP)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000433 search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
434 new_line_size = replace_regexp(NULL, 0);
435 /* If they specified an invalid subexpression in the replace
436 * text, return NULL indicating an error */
437 if (new_line_size < 0)
438 return NULL;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000439 } else {
Chris Allegretta47805612000-07-07 02:35:34 +0000440#else
441 {
442#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000443 search_match_count = strlen(last_search);
444 new_line_size = strlen(current->data) - strlen(last_search) +
445 strlen(last_replace) + 1;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000446 }
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000447
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000448 /* Create buffer */
449 copy = nmalloc(new_line_size);
450
451 /* Head of Original Line */
452 strncpy(copy, current->data, current_x);
453 copy[current_x] = 0;
454
455 /* Replacement Text */
456 if (!ISSET(USE_REGEXP))
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000457 strcat(copy, last_replace);
Chris Allegretta805c26d2000-09-06 13:39:17 +0000458#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000459 else
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000460 (void) replace_regexp(copy + current_x, 1);
Chris Allegretta47805612000-07-07 02:35:34 +0000461#endif
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000462
463 /* The tail of the original line */
464 /* This may expose other bugs, because it no longer
465 goes through each character on the string
466 and tests for string goodness. But because
467 we can assume the invariant that current->data
468 is less than current_x + strlen(last_search) long,
469 this should be safe. Or it will expose bugs ;-) */
470 tmp = current->data + current_x + search_match_count;
471 strcat(copy, tmp);
472
473 return copy;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000474}
475
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000476/* step through each replace word and prompt user before replacing word */
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000477int do_replace_loop(char *prevanswer, filestruct *begin, int *beginx,
478 int wholewords, int *i)
479{
480 int replaceall = 0, numreplaced = 0;
481 filestruct *fileptr;
482 char *copy;
483
484 switch (*i) {
485 case -1: /* Aborted enter */
486 if (strcmp(last_replace, ""))
487 answer = mallocstrcpy(answer, last_replace);
488 statusbar(_("Replace Cancelled"));
489 replace_abort();
490 return 0;
491 case 0: /* They actually entered something */
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000492 break;
493 default:
494 if (*i != -2) { /* First page, last page, for example
495 could get here */
496 do_early_abort();
497 replace_abort();
498 return 0;
499 }
500 }
501
Chris Allegrettac793c432000-11-21 12:52:55 +0000502 if (ISSET(PICO_MODE) && !strcmp(answer, ""))
503 answer = mallocstrcpy(answer, last_replace);
504
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000505 last_replace = mallocstrcpy(last_replace, answer);
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000506 while (1) {
507
508 /* Sweet optimization by Rocco here */
509 fileptr = findnextstr(replaceall, begin, *beginx, prevanswer);
510
511 /* No more matches. Done! */
Chris Allegretta022b96f2000-11-14 17:47:58 +0000512 if (!fileptr)
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000513 break;
514
515 /* Make sure only wholewords are found */
516 if (wholewords)
517 {
518 /* start of line or previous character not a letter */
Chris Allegretta63a89d32000-11-18 03:05:50 +0000519 if ((current_x == 0) || (!isalpha((int) fileptr->data[current_x-1])))
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000520 {
521 /* end of line or next character not a letter */
522 if (((current_x + strlen(prevanswer)) == strlen(fileptr->data))
Chris Allegretta63a89d32000-11-18 03:05:50 +0000523 || (!isalpha((int) fileptr->data[current_x + strlen(prevanswer)])))
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000524 ;
525 else
526 continue;
527 }
528 else
529 continue;
530 }
531
532 /* If we're here, we've found the search string */
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000533 if (!replaceall) {
534
535 curs_set(0);
536 do_replace_highlight(TRUE, prevanswer);
537
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000538 *i = do_yesno(1, 1, _("Replace this instance?"));
539
Chris Allegrettad00e6df2000-11-29 04:33:26 +0000540 do_replace_highlight(FALSE, prevanswer);
541 curs_set(1);
542 }
543
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000544 if (*i > 0 || replaceall) { /* Yes, replace it!!!! */
545 if (*i == 2)
546 replaceall = 1;
547
548 copy = replace_line();
549 if (!copy) {
550 statusbar(_("Replace failed: unknown subexpression!"));
551 replace_abort();
552 return 0;
553 }
554
555 /* Cleanup */
556 free(current->data);
557 current->data = copy;
558
559 /* Stop bug where we replace a substring of the replacement text */
560 current_x += strlen(last_replace) - 1;
561
562 /* Adjust the original cursor position - COULD BE IMPROVED */
563 if (search_last_line) {
564 *beginx += strlen(last_replace) - strlen(last_search);
565
566 /* For strings that cross the search start/end boundary */
567 /* Don't go outside of allocated memory */
568 if (*beginx < 1)
569 *beginx = 1;
570 }
571
572 edit_refresh();
573 set_modified();
574 numreplaced++;
575 } else if (*i == -1) /* Abort, else do nothing and continue loop */
576 break;
577 }
578
579 return numreplaced;
580}
581
Chris Allegretta47805612000-07-07 02:35:34 +0000582/* Replace a string */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000583int do_replace(void)
584{
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000585 int i, numreplaced, beginx;
586 filestruct *begin;
587 char *prevanswer = NULL, *buf = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000588
Chris Allegretta5050aa62001-04-22 07:10:21 +0000589 if (ISSET(VIEW_MODE)) {
590 print_view_warning();
591 replace_abort();
592 return 0;
593 }
594
Chris Allegretta9c371a22000-10-27 05:48:05 +0000595 i = search_init(1);
596 switch (i) {
597 case -1:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000598 statusbar(_("Replace Cancelled"));
599 replace_abort();
600 return 0;
Chris Allegretta9c371a22000-10-27 05:48:05 +0000601 case 1:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000602 do_replace();
603 return 1;
Chris Allegretta9c371a22000-10-27 05:48:05 +0000604 case -2:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000605 do_search();
606 return 0;
Chris Allegretta9c371a22000-10-27 05:48:05 +0000607 case -3:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000608 replace_abort();
609 return 0;
610 }
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000611
Chris Allegretta86f8b3a2000-10-31 05:28:33 +0000612 /* Again, there was a previous string but they deleted it and hit enter */
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +0000613 if (!ISSET(PICO_MODE) && !strcmp(answer, "")) {
Chris Allegretta86f8b3a2000-10-31 05:28:33 +0000614 statusbar(_("Replace Cancelled"));
615 replace_abort();
616 return 0;
617 }
618
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +0000619 /* If answer is now == "", then PICO_MODE is set. So, copy
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000620 last_search into answer (and prevanswer)... */
621 if (!strcmp(answer, "")) {
622 answer = mallocstrcpy(answer, last_search);
623 prevanswer = mallocstrcpy(prevanswer, last_search);
624 } else {
625 last_search = mallocstrcpy(last_search, answer);
626 prevanswer = mallocstrcpy(prevanswer, answer);
627 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000628
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +0000629 if (ISSET(PICO_MODE)) {
Chris Allegretta71844ba2000-11-03 14:23:00 +0000630 buf = nmalloc(strlen(last_replace) + 5);
631 if (strcmp(last_replace, "")) {
632 if (strlen(last_replace) > (COLS / 3)) {
633 strncpy(buf, last_replace, COLS / 3);
634 sprintf(&buf[COLS / 3 - 1], "...");
635 } else
636 sprintf(buf, "%s", last_replace);
637
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000638 i = statusq(0, replace_list_2, REPLACE_LIST_2_LEN, "",
Chris Allegretta71844ba2000-11-03 14:23:00 +0000639 _("Replace with [%s]"), buf);
640 }
641 else
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000642 i = statusq(0, replace_list_2, REPLACE_LIST_2_LEN, "",
Chris Allegretta71844ba2000-11-03 14:23:00 +0000643 _("Replace with"));
644 }
645 else
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000646 i = statusq(0, replace_list_2, REPLACE_LIST_2_LEN, last_replace,
Chris Allegretta105da332000-10-31 05:10:10 +0000647 _("Replace with"));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000648
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000649 /* save where we are */
650 begin = current;
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000651 beginx = current_x + 1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000652
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000653 search_last_line = 0;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000654
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000655 numreplaced = do_replace_loop(prevanswer, begin, &beginx, FALSE, &i);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000656
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000657 /* restore where we were */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000658 current = begin;
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000659 current_x = beginx - 1;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000660 renumber_all();
Chris Allegretta234a34d2000-07-29 04:33:38 +0000661 edit_update(current, CENTER);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000662 print_replaced(numreplaced);
663 replace_abort();
664 return 1;
665}
666
667void goto_abort(void)
668{
669 UNSET(KEEP_CUTBUFFER);
670 display_main_list();
671}
672
Rocco Corsi4dfaf932001-04-20 01:59:55 +0000673int do_gotoline(long line)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000674{
Rocco Corsi4dfaf932001-04-20 01:59:55 +0000675 long i = 1;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000676
Rocco Corsi4dfaf932001-04-20 01:59:55 +0000677 if (line <= 0) { /* Ask for it */
678
679 long j = 0;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000680
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000681 j = statusq(0, goto_list, GOTO_LIST_LEN, "", _("Enter line number"));
Rocco Corsi4dfaf932001-04-20 01:59:55 +0000682 if (j != 0) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000683 statusbar(_("Aborted"));
684 goto_abort();
685 return 0;
Rocco Corsi4dfaf932001-04-20 01:59:55 +0000686 }
687
688 line = atoi(answer);
689
690 /* Bounds check */
691 if (line <= 0) {
692 statusbar(_("Come on, be reasonable"));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000693 goto_abort();
694 return 0;
695 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000696 }
697
Rocco Corsi4dfaf932001-04-20 01:59:55 +0000698 for (current = fileage; ((current->next != NULL) && (i < line)); i++)
699 current = current->next;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000700
Rocco Corsi4dfaf932001-04-20 01:59:55 +0000701 current_x = 0;
702 edit_update(current, CENTER);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000703
704 goto_abort();
705 return 1;
706}
707
708int do_gotoline_void(void)
709{
710 return do_gotoline(0);
711}