blob: 569e063798c171a881b751c070a5b01bc540c4f3 [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
47void regexp_cleanup()
48{
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 Allegrettabd9e7c32000-10-26 01:44:42 +000077
Chris Allegretta27eb13f2000-11-05 16:52:21 +000078 search_init_globals();
Chris Allegretta31925e42000-11-02 04:40:39 +000079
Chris Allegretta27eb13f2000-11-05 16:52:21 +000080 buf = nmalloc(strlen(last_search) + 5);
81 buf[0] = 0;
Chris Allegretta71844ba2000-11-03 14:23:00 +000082
Chris Allegretta27eb13f2000-11-05 16:52:21 +000083 /* If using Pico messages, we do things the old fashioned way... */
84 if (ISSET(PICO_MSGS)) {
Chris Allegretta71844ba2000-11-03 14:23:00 +000085 if (last_search[0]) {
86
87 /* We use COLS / 3 here because we need to see more on the line */
88 if (strlen(last_search) > COLS / 3) {
89 snprintf(buf, COLS / 3 + 3, " [%s", last_search);
90 sprintf(&buf[COLS / 3 + 2], "...]");
91 } else
92 sprintf(buf, " [%s]", last_search);
93 } else {
94 buf[0] = '\0';
95 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +000096 }
97
Chris Allegretta9fc8d432000-07-07 01:49:52 +000098 if (ISSET(USE_REGEXP) && ISSET(CASE_SENSITIVE))
Chris Allegrettabd9e7c32000-10-26 01:44:42 +000099 prompt = _("Case Sensitive Regexp Search%s%s");
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000100 else if (ISSET(USE_REGEXP))
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000101 prompt = _("Regexp Search%s%s");
102 else if (ISSET(CASE_SENSITIVE))
103 prompt = _("Case Sensitive Search%s%s");
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000104 else
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000105 prompt = _("Search%s%s");
Chris Allegrettaa4d21622000-07-08 23:57:03 +0000106
107 if (replacing)
108 reprompt = _(" (to replace)");
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000109
Chris Allegretta71844ba2000-11-03 14:23:00 +0000110 if (ISSET(PICO_MSGS))
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000111 i = statusq(0, replacing ? replace_list : whereis_list,
Chris Allegretta71844ba2000-11-03 14:23:00 +0000112 replacing ? REPLACE_LIST_LEN : WHEREIS_LIST_LEN, "",
113 prompt, reprompt, buf);
114 else
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000115 i = statusq(0, replacing ? replace_list : whereis_list,
Chris Allegretta105da332000-10-31 05:10:10 +0000116 replacing ? REPLACE_LIST_LEN : WHEREIS_LIST_LEN, last_search,
117 prompt, reprompt, "");
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000118
119 /* Cancel any search, or just return with no previous search */
120 if ((i == -1) || (i < 0 && !last_search[0])) {
121 statusbar(_("Search Cancelled"));
122 reset_cursor();
123 return -1;
124 } else if (i == -2) { /* Same string */
Chris Allegretta31925e42000-11-02 04:40:39 +0000125 answer = mallocstrcpy(answer, last_search);
Chris Allegretta805c26d2000-09-06 13:39:17 +0000126#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000127 if (ISSET(USE_REGEXP))
128 regexp_init(answer);
Chris Allegretta47805612000-07-07 02:35:34 +0000129#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000130 } else if (i == 0) { /* They entered something new */
Chris Allegretta31925e42000-11-02 04:40:39 +0000131 last_search = mallocstrcpy(last_search, answer);
Chris Allegretta805c26d2000-09-06 13:39:17 +0000132#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000133 if (ISSET(USE_REGEXP))
134 regexp_init(answer);
Chris Allegretta47805612000-07-07 02:35:34 +0000135#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000136 /* Blow away last_replace because they entered a new search
137 string....uh, right? =) */
138 last_replace[0] = '\0';
139 } else if (i == NANO_CASE_KEY) { /* They want it case sensitive */
140 if (ISSET(CASE_SENSITIVE))
141 UNSET(CASE_SENSITIVE);
142 else
143 SET(CASE_SENSITIVE);
144
145 return 1;
146 } else if (i == NANO_OTHERSEARCH_KEY) {
147 return -2; /* Call the opposite search function */
Chris Allegretta8c2b40f2000-06-29 01:30:04 +0000148 } else if (i == NANO_FROMSEARCHTOGOTO_KEY) {
149 do_gotoline_void();
150 return -3;
Chris Allegretta105da332000-10-31 05:10:10 +0000151 } else { /* First line key, etc. */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000152 do_early_abort();
153 return -3;
154 }
155
156 return 0;
157}
158
Chris Allegretta31925e42000-11-02 04:40:39 +0000159void not_found_msg(char *str)
160{
161 char foo[COLS];
162
163 if (strlen(str) < COLS / 2)
164 statusbar(_("\"%s\" not found"), str);
165 else {
166 strncpy(foo, str, COLS / 2);
167 foo[COLS / 2] = 0;
168 statusbar(_("\"%s...\" not found"), foo);
169 }
170}
171
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000172filestruct *findnextstr(int quiet, filestruct * begin, int beginx,
173 char *needle)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000174{
175 filestruct *fileptr;
176 char *searchstr, *found = NULL, *tmp;
Adam Rogoyski2a4ef922000-07-09 00:15:11 +0000177 int past_editbot = 0;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000178
Chris Allegrettab9bfc9b2000-09-10 05:06:09 +0000179 fileptr = current;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000180
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000181 current_x++;
182
183 /* Are we searching the last line? (i.e. the line where search started) */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000184 if ((fileptr == begin) && (current_x < beginx))
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000185 search_last_line = 1;
186
187 /* Make sure we haven't passed the end of the string */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000188 if (strlen(fileptr->data) < current_x)
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000189 current_x--;
190
191 searchstr = &fileptr->data[current_x];
192
193 /* Look for needle in searchstr */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000194 while ((found = strstrwrapper(searchstr, needle)) == NULL) {
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000195
196 /* finished processing file, get out */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000197 if (search_last_line) {
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000198 if (!quiet)
Chris Allegretta31925e42000-11-02 04:40:39 +0000199 not_found_msg(needle);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000200 return NULL;
201 }
Adam Rogoyski2a4ef922000-07-09 00:15:11 +0000202
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000203 fileptr = fileptr->next;
204
Adam Rogoyskia966d992000-07-09 18:42:53 +0000205 if (!past_editbot && (fileptr == editbot))
206 past_editbot = 1;
Adam Rogoyski2a4ef922000-07-09 00:15:11 +0000207
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000208 /* EOF reached, wrap around once */
209 if (fileptr == NULL) {
210 fileptr = fileage;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000211
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000212 past_editbot = 1;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000213
214 if (!quiet)
215 statusbar(_("Search Wrapped"));
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000216 }
217
218 /* Original start line reached */
219 if (fileptr == begin)
220 search_last_line = 1;
221
222 searchstr = fileptr->data;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000223 }
224
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000225 /* We found an instance */
226 current = fileptr;
227 current_x = 0;
228 for (tmp = fileptr->data; tmp != found; tmp++)
229 current_x++;
230
231 /* Ensure we haven't wrap around again! */
232 if ((search_last_line) && (current_x >= beginx)) {
233 if (!quiet)
Chris Allegretta31925e42000-11-02 04:40:39 +0000234 not_found_msg(needle);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000235 return NULL;
236 }
237
238 if (past_editbot)
239 edit_update(fileptr, CENTER);
240 else
241 update_line(current, current_x);
242
243 placewewant = xplustabs();
244 reset_cursor();
245
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000246 return fileptr;
247}
248
249void search_abort(void)
250{
251 UNSET(KEEP_CUTBUFFER);
252 display_main_list();
253 wrefresh(bottomwin);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000254 if (ISSET(MARK_ISSET))
Chris Allegrettaf1d33d32000-08-19 03:53:39 +0000255 edit_refresh_clearok();
Chris Allegretta47805612000-07-07 02:35:34 +0000256
Chris Allegretta805c26d2000-09-06 13:39:17 +0000257#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000258 if (ISSET(REGEXP_COMPILED))
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000259 regexp_cleanup();
Chris Allegretta47805612000-07-07 02:35:34 +0000260#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000261}
262
263/* Search for a string */
264int do_search(void)
265{
266 int i;
267 filestruct *fileptr = current;
268
269 wrap_reset();
Chris Allegretta9c371a22000-10-27 05:48:05 +0000270 i = search_init(0);
271 switch (i) {
272 case -1:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000273 current = fileptr;
274 search_abort();
275 return 0;
Chris Allegretta9c371a22000-10-27 05:48:05 +0000276 case -3:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000277 search_abort();
278 return 0;
Chris Allegretta9c371a22000-10-27 05:48:05 +0000279 case -2:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000280 do_replace();
281 return 0;
Chris Allegretta9c371a22000-10-27 05:48:05 +0000282 case 1:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000283 do_search();
284 search_abort();
285 return 1;
286 }
Chris Allegretta86f8b3a2000-10-31 05:28:33 +0000287
288 /* The sneaky user deleted the previous search string */
289 if (!strcmp(answer, "")) {
Jordi Mallache7a647c2000-11-01 18:43:21 +0000290 statusbar(_("Search Cancelled"));
Chris Allegretta86f8b3a2000-10-31 05:28:33 +0000291 search_abort();
292 return 0;
293 }
294
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000295 search_last_line = 0;
296 findnextstr(0, current, current_x, answer);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000297 search_abort();
298 return 1;
299}
300
301void print_replaced(int num)
302{
303 if (num > 1)
304 statusbar(_("Replaced %d occurences"), num);
305 else if (num == 1)
306 statusbar(_("Replaced 1 occurence"));
307}
308
309void replace_abort(void)
310{
Chris Allegretta18bd0292000-07-28 01:18:10 +0000311 /* Identicle to search_abort, so we'll call it here. If it
312 does something different later, we can change it back. For now
313 it's just a waste to duplicat code */
314 search_abort();
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000315 placewewant = xplustabs();
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000316}
317
Chris Allegretta805c26d2000-09-06 13:39:17 +0000318#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000319int replace_regexp(char *string, int create_flag)
320{
321 /* split personality here - if create_flag is null, just calculate
322 * the size of the replacement line (necessary because of
323 * subexpressions like \1 \2 \3 in the replaced text) */
324
325 char *c;
326 int new_size = strlen(current->data) + 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000327 int search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000328
329 new_size -= search_match_count;
330
331 /* Iterate through the replacement text to handle
332 * subexpression replacement using \1, \2, \3, etc */
333
334 c = last_replace;
335 while (*c) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000336 if (*c != '\\') {
337 if (create_flag)
338 *string++ = *c;
339 c++;
340 new_size++;
341 } else {
342 int num = (int) *(c + 1) - (int) '0';
343 if (num >= 1 && num <= 9) {
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000344
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000345 int i = regmatches[num].rm_so;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000346
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000347 if (num > search_regexp.re_nsub) {
348 /* Ugh, they specified a subexpression that doesn't
349 exist. */
350 return -1;
351 }
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000352
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000353 /* Skip over the replacement expression */
354 c += 2;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000355
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000356 /* But add the length of the subexpression to new_size */
357 new_size += regmatches[num].rm_eo - regmatches[num].rm_so;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000358
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000359 /* And if create_flag is set, append the result of the
360 * subexpression match to the new line */
361 while (create_flag && i < regmatches[num].rm_eo)
362 *string++ = *(current->data + i++);
363
364 } else {
365 if (create_flag)
366 *string++ = *c;
367 c++;
368 new_size++;
369 }
370 }
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000371 }
372
373 if (create_flag)
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000374 *string = 0;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000375
376 return new_size;
377}
Chris Allegretta47805612000-07-07 02:35:34 +0000378#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000379
Chris Allegrettab46df992000-11-01 02:12:13 +0000380char *replace_line(void)
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000381{
382 char *copy, *tmp;
383 int new_line_size;
384 int search_match_count;
385
386 /* Calculate size of new line */
Chris Allegretta805c26d2000-09-06 13:39:17 +0000387#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000388 if (ISSET(USE_REGEXP)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000389 search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
390 new_line_size = replace_regexp(NULL, 0);
391 /* If they specified an invalid subexpression in the replace
392 * text, return NULL indicating an error */
393 if (new_line_size < 0)
394 return NULL;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000395 } else {
Chris Allegretta47805612000-07-07 02:35:34 +0000396#else
397 {
398#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000399 search_match_count = strlen(last_search);
400 new_line_size = strlen(current->data) - strlen(last_search) +
401 strlen(last_replace) + 1;
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000402 }
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000403
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000404 /* Create buffer */
405 copy = nmalloc(new_line_size);
406
407 /* Head of Original Line */
408 strncpy(copy, current->data, current_x);
409 copy[current_x] = 0;
410
411 /* Replacement Text */
412 if (!ISSET(USE_REGEXP))
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000413 strcat(copy, last_replace);
Chris Allegretta805c26d2000-09-06 13:39:17 +0000414#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000415 else
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000416 (void) replace_regexp(copy + current_x, 1);
Chris Allegretta47805612000-07-07 02:35:34 +0000417#endif
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000418
419 /* The tail of the original line */
420 /* This may expose other bugs, because it no longer
421 goes through each character on the string
422 and tests for string goodness. But because
423 we can assume the invariant that current->data
424 is less than current_x + strlen(last_search) long,
425 this should be safe. Or it will expose bugs ;-) */
426 tmp = current->data + current_x + search_match_count;
427 strcat(copy, tmp);
428
429 return copy;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000430}
431
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000432int do_replace_loop(char *prevanswer, filestruct *begin, int *beginx,
433 int wholewords, int *i)
434{
435 int replaceall = 0, numreplaced = 0;
436 filestruct *fileptr;
437 char *copy;
438
439 switch (*i) {
440 case -1: /* Aborted enter */
441 if (strcmp(last_replace, ""))
442 answer = mallocstrcpy(answer, last_replace);
443 statusbar(_("Replace Cancelled"));
444 replace_abort();
445 return 0;
446 case 0: /* They actually entered something */
447 last_replace = mallocstrcpy(last_replace, answer);
448 break;
449 default:
450 if (*i != -2) { /* First page, last page, for example
451 could get here */
452 do_early_abort();
453 replace_abort();
454 return 0;
455 }
456 }
457
458 while (1) {
459
460 /* Sweet optimization by Rocco here */
461 fileptr = findnextstr(replaceall, begin, *beginx, prevanswer);
462
463 /* No more matches. Done! */
464 if (!fileptr)
465 break;
466
467 /* Make sure only wholewords are found */
468 if (wholewords)
469 {
470 /* start of line or previous character not a letter */
471 if ((current_x == 0) || (!isalpha(fileptr->data[current_x-1])))
472 {
473 /* end of line or next character not a letter */
474 if (((current_x + strlen(prevanswer)) == strlen(fileptr->data))
475 || (!isalpha(fileptr->data[current_x + strlen(prevanswer)])))
476 ;
477 else
478 continue;
479 }
480 else
481 continue;
482 }
483
484 /* If we're here, we've found the search string */
485 if (!replaceall)
486 *i = do_yesno(1, 1, _("Replace this instance?"));
487
488 if (*i > 0 || replaceall) { /* Yes, replace it!!!! */
489 if (*i == 2)
490 replaceall = 1;
491
492 copy = replace_line();
493 if (!copy) {
494 statusbar(_("Replace failed: unknown subexpression!"));
495 replace_abort();
496 return 0;
497 }
498
499 /* Cleanup */
500 free(current->data);
501 current->data = copy;
502
503 /* Stop bug where we replace a substring of the replacement text */
504 current_x += strlen(last_replace) - 1;
505
506 /* Adjust the original cursor position - COULD BE IMPROVED */
507 if (search_last_line) {
508 *beginx += strlen(last_replace) - strlen(last_search);
509
510 /* For strings that cross the search start/end boundary */
511 /* Don't go outside of allocated memory */
512 if (*beginx < 1)
513 *beginx = 1;
514 }
515
516 edit_refresh();
517 set_modified();
518 numreplaced++;
519 } else if (*i == -1) /* Abort, else do nothing and continue loop */
520 break;
521 }
522
523 return numreplaced;
524}
525
Chris Allegretta47805612000-07-07 02:35:34 +0000526/* Replace a string */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000527int do_replace(void)
528{
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000529 int i, numreplaced, beginx;
530 filestruct *begin;
531 char *prevanswer = NULL, *buf = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000532
Chris Allegretta9c371a22000-10-27 05:48:05 +0000533 i = search_init(1);
534 switch (i) {
535 case -1:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000536 statusbar(_("Replace Cancelled"));
537 replace_abort();
538 return 0;
Chris Allegretta9c371a22000-10-27 05:48:05 +0000539 case 1:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000540 do_replace();
541 return 1;
Chris Allegretta9c371a22000-10-27 05:48:05 +0000542 case -2:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000543 do_search();
544 return 0;
Chris Allegretta9c371a22000-10-27 05:48:05 +0000545 case -3:
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000546 replace_abort();
547 return 0;
548 }
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000549
Chris Allegretta86f8b3a2000-10-31 05:28:33 +0000550 /* Again, there was a previous string but they deleted it and hit enter */
551 if (!strcmp(answer, "")) {
552 statusbar(_("Replace Cancelled"));
553 replace_abort();
554 return 0;
555 }
556
Chris Allegretta31925e42000-11-02 04:40:39 +0000557 prevanswer = mallocstrcpy(prevanswer, answer);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000558
Chris Allegretta71844ba2000-11-03 14:23:00 +0000559 if (ISSET(PICO_MSGS)) {
560 buf = nmalloc(strlen(last_replace) + 5);
561 if (strcmp(last_replace, "")) {
562 if (strlen(last_replace) > (COLS / 3)) {
563 strncpy(buf, last_replace, COLS / 3);
564 sprintf(&buf[COLS / 3 - 1], "...");
565 } else
566 sprintf(buf, "%s", last_replace);
567
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000568 i = statusq(0, replace_list_2, REPLACE_LIST_2_LEN, "",
Chris Allegretta71844ba2000-11-03 14:23:00 +0000569 _("Replace with [%s]"), buf);
570 }
571 else
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000572 i = statusq(0, replace_list_2, REPLACE_LIST_2_LEN, "",
Chris Allegretta71844ba2000-11-03 14:23:00 +0000573 _("Replace with"));
574 }
575 else
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000576 i = statusq(0, replace_list_2, REPLACE_LIST_2_LEN, last_replace,
Chris Allegretta105da332000-10-31 05:10:10 +0000577 _("Replace with"));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000578
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000579 /* save where we are */
580 begin = current;
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000581 beginx = current_x + 1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000582
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000583 search_last_line = 0;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000584
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000585 numreplaced = do_replace_loop(prevanswer, begin, &beginx, FALSE, &i);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000586
Chris Allegretta27eb13f2000-11-05 16:52:21 +0000587 /* restore where we were */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000588 current = begin;
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000589 current_x = beginx - 1;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000590 renumber_all();
Chris Allegretta234a34d2000-07-29 04:33:38 +0000591 edit_update(current, CENTER);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000592 print_replaced(numreplaced);
593 replace_abort();
594 return 1;
595}
596
597void goto_abort(void)
598{
599 UNSET(KEEP_CUTBUFFER);
600 display_main_list();
601}
602
603int do_gotoline(long defline)
604{
605 long line, i = 1, j = 0;
606 filestruct *fileptr;
607
608 if (defline > 0) /* We already know what line we want to go to */
609 line = defline;
610 else { /* Ask for it */
611
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000612 j = statusq(0, goto_list, GOTO_LIST_LEN, "", _("Enter line number"));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000613 if (j == -1) {
614 statusbar(_("Aborted"));
615 goto_abort();
616 return 0;
617 } else if (j != 0) {
618 do_early_abort();
619 goto_abort();
620 return 0;
621 }
622 if (!strcmp(answer, "$")) {
623 current = filebot;
624 current_x = 0;
Chris Allegretta234a34d2000-07-29 04:33:38 +0000625 edit_update(current, CENTER);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000626 goto_abort();
627 return 1;
628 }
629 line = atoi(answer);
630 }
631
632 /* Bounds check */
633 if (line <= 0) {
634 statusbar(_("Come on, be reasonable"));
635 goto_abort();
636 return 0;
637 }
638 if (line > totlines) {
639 statusbar(_("Only %d lines available, skipping to last line"),
640 filebot->lineno);
641 current = filebot;
642 current_x = 0;
Chris Allegretta234a34d2000-07-29 04:33:38 +0000643 edit_update(current, CENTER);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000644 } else {
645 for (fileptr = fileage; fileptr != NULL && i < line; i++)
646 fileptr = fileptr->next;
647
648 current = fileptr;
649 current_x = 0;
Chris Allegretta234a34d2000-07-29 04:33:38 +0000650 edit_update(current, CENTER);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000651 }
652
653 goto_abort();
654 return 1;
655}
656
657int do_gotoline_void(void)
658{
659 return do_gotoline(0);
660}