search.c 18.9 KB
Newer Older
Chris Allegretta's avatar
Chris Allegretta committed
1
/* $Id$ */
Chris Allegretta's avatar
Chris Allegretta committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**************************************************************************
 *   search.c                                                             *
 *                                                                        *
 *   Copyright (C) 2000 Chris Allegretta                                  *
 *   This program is free software; you can redistribute it and/or modify *
 *   it under the terms of the GNU General Public License as published by *
 *   the Free Software Foundation; either version 1, or (at your option)  *
 *   any later version.                                                   *
 *                                                                        *
 *   This program is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of       *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
 *   GNU General Public License for more details.                         *
 *                                                                        *
 *   You should have received a copy of the GNU General Public License    *
 *   along with this program; if not, write to the Free Software          *
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
 *                                                                        *
 **************************************************************************/

22
23
#include "config.h"

Chris Allegretta's avatar
Chris Allegretta committed
24
25
#include <stdlib.h>
#include <string.h>
26
#include <unistd.h>
Chris Allegretta's avatar
Chris Allegretta committed
27
#include <stdio.h>
Chris Allegretta's avatar
Chris Allegretta committed
28
#include <ctype.h>
Chris Allegretta's avatar
Chris Allegretta committed
29
30
#include "proto.h"
#include "nano.h"
Chris Allegretta's avatar
Chris Allegretta committed
31

Chris Allegretta's avatar
Chris Allegretta committed
32
33
34
35
36
37
38
#ifndef NANO_SMALL
#include <libintl.h>
#define _(string) gettext(string)
#else
#define _(string) (string)
#endif

39
40
/* Regular expression helper functions */

41
#ifdef HAVE_REGEX_H
42
43
44
45
46
47
void regexp_init(const char *regexp)
{
    regcomp(&search_regexp, regexp, ISSET(CASE_SENSITIVE) ? 0 : REG_ICASE);
    SET(REGEXP_COMPILED);
}

48
void regexp_cleanup(void)
49
50
51
52
{
    UNSET(REGEXP_COMPILED);
    regfree(&search_regexp);
}
53
#endif
54

Chris Allegretta's avatar
Chris Allegretta committed
55
56
57
void search_init_globals(void)
{
    if (last_search == NULL) {
58
	last_search = charalloc(1);
Chris Allegretta's avatar
Chris Allegretta committed
59
60
61
	last_search[0] = 0;
    }
    if (last_replace == NULL) {
62
	last_replace = charalloc(1);
Chris Allegretta's avatar
Chris Allegretta committed
63
64
65
66
	last_replace[0] = 0;
    }
}

Chris Allegretta's avatar
Chris Allegretta committed
67
68
/* Set up the system variables for a search or replace.  Returns -1 on
   abort, 0 on success, and 1 on rerun calling program 
69
   Return -2 to run opposite program (search -> replace, replace -> search)
Chris Allegretta's avatar
Chris Allegretta committed
70
71
72
73
74

   replacing = 1 if we call from do_replace, 0 if called from do_search func.
*/
int search_init(int replacing)
{
75
76
    int i = 0;
    char *buf;
Chris Allegretta's avatar
Chris Allegretta committed
77
    char *prompt;
78
    static char *backupstring = NULL;
79

Chris Allegretta's avatar
Chris Allegretta committed
80
    search_init_globals();
81

82
    buf = charalloc(strlen(last_search) + 5);
Chris Allegretta's avatar
Chris Allegretta committed
83
    buf[0] = 0;
84

85
86
     /* Okay, fun time.  backupstring is our holder for what is being 
	returned from the statusq call.  Using answer for this would be tricky.
87
	Here, if we're using PICO_MODE, we only want nano to put the
88
89
90
91
92
	old string back up as editable if it's not the same as last_search.

	Otherwise, if we don't already have a backupstring, set it to
	last_search.  */

93
    if (ISSET(PICO_MODE)) {
94
95
96
97
98
99
	if (backupstring == NULL || !strcmp(backupstring, last_search))
	    backupstring = mallocstrcpy(backupstring, "");
    }
    else if (backupstring == NULL)
	backupstring = mallocstrcpy(backupstring, last_search);

Chris Allegretta's avatar
Chris Allegretta committed
100
    /* If using Pico messages, we do things the old fashioned way... */
101
    if (ISSET(PICO_MODE)) {
102
103
104
105
106
107
108
109
110
111
112
	if (last_search[0]) {

	    /* We use COLS / 3 here because we need to see more on the line */
	    if (strlen(last_search) > COLS / 3) {
		snprintf(buf, COLS / 3 + 3, " [%s", last_search);
		sprintf(&buf[COLS / 3 + 2], "...]");
	    } else
		sprintf(buf, " [%s]", last_search);
	} else {
	    buf[0] = '\0';
	}
Chris Allegretta's avatar
Chris Allegretta committed
113
    }
114
115
    else
	strcpy(buf, "");
Chris Allegretta's avatar
Chris Allegretta committed
116

Chris Allegretta's avatar
Chris Allegretta committed
117
118
119
120
     /* Instead of having a million if statements here to determine
	the prompt, we instead just have a hundred "? :" calls in
	the statusq call.  I hope no one ever has to modify this :-) */
    prompt = "%s%s%s%s%s%s";
121

122
123
124
    /* This is now one simple call.  It just does a lot */
    i = statusq(0, replacing ? replace_list : whereis_list,
	replacing ? REPLACE_LIST_LEN : WHEREIS_LIST_LEN, backupstring,
Chris Allegretta's avatar
Chris Allegretta committed
125
126
127
128
129
130
131
	prompt, 
	ISSET(CASE_SENSITIVE) ? _("Case Sensitive ") : "",
	ISSET(USE_REGEXP) ? _("Regexp ") : "",
	_("Search"),
	ISSET(REVERSE_SEARCH) ? _(" Backwards") : "",
	replacing ? _(" (to replace)") : "",
	buf);
Chris Allegretta's avatar
Chris Allegretta committed
132
133
134
135
136

    /* Cancel any search, or just return with no previous search */
    if ((i == -1) || (i < 0 && !last_search[0])) {
	statusbar(_("Search Cancelled"));
	reset_cursor();
137
138
	free(backupstring);
	backupstring = NULL;
Chris Allegretta's avatar
Chris Allegretta committed
139
140
	return -1;
    } else if (i == -2) {	/* Same string */
141
#ifdef HAVE_REGEX_H
142
143
144
145
146
147
148
149
	if (ISSET(USE_REGEXP)) {

	    /* If we're in pico mode, answer is "", use last_search! */
	    if (ISSET(PICO_MODE))
		regexp_init(last_search);
	    else
		regexp_init(answer);
	}
150
151
#else
	;
152
#endif
Chris Allegretta's avatar
Chris Allegretta committed
153
    } else if (i == 0) {	/* They entered something new */
154
#ifdef HAVE_REGEX_H
155
156
	if (ISSET(USE_REGEXP))
	    regexp_init(answer);
157
#endif
158
159
	free(backupstring);
	backupstring = NULL;
Chris Allegretta's avatar
Chris Allegretta committed
160
161
	last_replace[0] = '\0';
    } else if (i == NANO_CASE_KEY) {	/* They want it case sensitive */
162
163
164
165
	free(backupstring);
	backupstring = NULL;
	backupstring = mallocstrcpy(backupstring, answer);

Chris Allegretta's avatar
Chris Allegretta committed
166
167
168
169
170
171
172
	if (ISSET(CASE_SENSITIVE))
	    UNSET(CASE_SENSITIVE);
	else
	    SET(CASE_SENSITIVE);

	return 1;
    } else if (i == NANO_OTHERSEARCH_KEY) {
173
	backupstring = mallocstrcpy(backupstring, answer);
Chris Allegretta's avatar
Chris Allegretta committed
174
	return -2;		/* Call the opposite search function */
Chris Allegretta's avatar
Chris Allegretta committed
175
176
177
178
179
180
181
182
183
184
185
    } else if (i == NANO_REVERSESEARCH_KEY) {
	free(backupstring);
	backupstring = NULL;
	backupstring = mallocstrcpy(backupstring, answer);

	if (ISSET(REVERSE_SEARCH))
	    UNSET(REVERSE_SEARCH);
	else
	    SET(REVERSE_SEARCH);

	return 1;
186
    } else if (i == NANO_FROMSEARCHTOGOTO_KEY) {
187
188
	free(backupstring);
	backupstring = NULL;
189
190
	do_gotoline_void();
	return -3;
191
    } else {			/* First line key, etc. */
Chris Allegretta's avatar
Chris Allegretta committed
192
	do_early_abort();
193
194
	free(backupstring);
	backupstring = NULL;
Chris Allegretta's avatar
Chris Allegretta committed
195
196
197
198
199
200
	return -3;
    }

    return 0;
}

201
202
void not_found_msg(char *str)
{
203
    if (strlen(str) <= COLS / 2)
204
205
	statusbar(_("\"%s\" not found"), str);
    else {
206
207
208
	char *foo = NULL;

	foo = mallocstrcpy(foo, str);
209
210
	foo[COLS / 2] = 0;
	statusbar(_("\"%s...\" not found"), foo);
211
212

	free(foo);
213
214
215
    }
}

216
217
filestruct *findnextstr(int quiet, filestruct * begin, int beginx,
			char *needle)
Chris Allegretta's avatar
Chris Allegretta committed
218
219
{
    filestruct *fileptr;
Chris Allegretta's avatar
Chris Allegretta committed
220
    char *searchstr, *rev_start = NULL, *found = NULL;
221
    int past_editbot = 0, current_x_find;
Chris Allegretta's avatar
Chris Allegretta committed
222

223
    fileptr = current;
Chris Allegretta's avatar
Chris Allegretta committed
224

Chris Allegretta's avatar
Chris Allegretta committed
225
    if (!ISSET(REVERSE_SEARCH)) {		/* forward search */
Chris Allegretta's avatar
Chris Allegretta committed
226

Chris Allegretta's avatar
Chris Allegretta committed
227
	current_x_find = current_x + 1;
Chris Allegretta's avatar
Chris Allegretta committed
228

Chris Allegretta's avatar
Chris Allegretta committed
229
230
231
	/* Are we now back to the line where the search started) */
	if ((fileptr == begin) && (current_x_find < beginx))
	    search_last_line = 1;
Chris Allegretta's avatar
Chris Allegretta committed
232

Chris Allegretta's avatar
Chris Allegretta committed
233
234
235
	/* Make sure we haven't passed the end of the string */
	if (strlen(fileptr->data) < current_x_find)
	    current_x_find--;
Chris Allegretta's avatar
Chris Allegretta committed
236

Chris Allegretta's avatar
Chris Allegretta committed
237
	searchstr = &fileptr->data[current_x_find];
Chris Allegretta's avatar
Chris Allegretta committed
238

Chris Allegretta's avatar
Chris Allegretta committed
239
240
	/* Look for needle in searchstr */
	while ((found = strstrwrapper(searchstr, needle, rev_start)) == NULL) {
Chris Allegretta's avatar
Chris Allegretta committed
241

Chris Allegretta's avatar
Chris Allegretta committed
242
243
244
245
246
247
	    /* finished processing file, get out */
	    if (search_last_line) {
		if (!quiet)
		    not_found_msg(needle);
	        return NULL;
	    }
248

Chris Allegretta's avatar
Chris Allegretta committed
249
	    fileptr = fileptr->next;
250

Chris Allegretta's avatar
Chris Allegretta committed
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
	    if (!past_editbot && (fileptr == editbot))
		past_editbot = 1;

	    /* EOF reached ?, wrap around once */
	    if (fileptr == NULL) {
		fileptr = fileage;
		past_editbot = 1;
		if (!quiet)
		    statusbar(_("Search Wrapped"));
	    }

	    /* Original start line reached */
	    if (fileptr == begin)
		search_last_line = 1;

	    searchstr = fileptr->data;
	}
268

Chris Allegretta's avatar
Chris Allegretta committed
269
270
	/* We found an instance */
	current_x_find = found - fileptr->data;
Chris Allegretta's avatar
Chris Allegretta committed
271

Chris Allegretta's avatar
Chris Allegretta committed
272
273
	/* Ensure we haven't wrapped around again! */
	if ((search_last_line) && (current_x_find >= beginx)) {
Chris Allegretta's avatar
Chris Allegretta committed
274
	    if (!quiet)
Chris Allegretta's avatar
Chris Allegretta committed
275
276
		not_found_msg(needle);
	    return NULL;
277
278
	}

Chris Allegretta's avatar
Chris Allegretta committed
279
280
281
282
283
284
    } else {	/* reverse search */

	current_x_find = current_x - 1;

	/* Are we now back to the line where the search started) */
	if ((fileptr == begin) && (current_x_find > beginx))
285
286
	    search_last_line = 1;

Chris Allegretta's avatar
Chris Allegretta committed
287
288
289
290
291
292
	/* Make sure we haven't passed the begining of the string */
#if 0	/* Is this required here ? */
	if (!(&fileptr->data[current_x_find] - fileptr->data))      
	    current_x_find++;
#endif
	rev_start = &fileptr->data[current_x_find];
293
294
	searchstr = fileptr->data;

Chris Allegretta's avatar
Chris Allegretta committed
295
296
297
298
299
300
301
302
303
304
305
306
307
308
	/* Look for needle in searchstr */
	while ((found = strstrwrapper(searchstr, needle, rev_start)) == NULL) {

	    /* finished processing file, get out */
	    if (search_last_line) {
		if (!quiet)
		    not_found_msg(needle);
		return NULL;
	    }

	    fileptr = fileptr->prev;

/* ? */	    if (!past_editbot && (fileptr == edittop->prev))
		past_editbot = 1;
309

Chris Allegretta's avatar
Chris Allegretta committed
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
	    /* SOF reached ?, wrap around once */
/* ? */	    if (fileptr == NULL) {
		fileptr = filebot;
		past_editbot = 1;
		if (!quiet)
		    statusbar(_("Search Wrapped"));
	    }

	    /* Original start line reached */
	    if (fileptr == begin)
		search_last_line = 1;

	    searchstr = fileptr->data;
	    rev_start = fileptr->data + strlen(fileptr->data);
	}

	/* We found an instance */
	current_x_find = found - fileptr->data;

	/* Ensure we haven't wrapped around again! */
	if ((search_last_line) && (current_x_find < beginx)) {
	    if (!quiet)
		not_found_msg(needle);
	    return NULL;
	}
Chris Allegretta's avatar
Chris Allegretta committed
335
336
    }

Chris Allegretta's avatar
Chris Allegretta committed
337
    /* Set globals now that we are sure we found something */
338
339
340
    current = fileptr;
    current_x = current_x_find;

341
342
343
344
345
346
347
348
    if (past_editbot)
	edit_update(fileptr, CENTER);
    else
	update_line(current, current_x);

    placewewant = xplustabs();
    reset_cursor();

Chris Allegretta's avatar
Chris Allegretta committed
349
350
351
352
353
354
355
356
    return fileptr;
}

void search_abort(void)
{
    UNSET(KEEP_CUTBUFFER);
    display_main_list();
    wrefresh(bottomwin);
357
    if (ISSET(MARK_ISSET))
358
	edit_refresh_clearok();
359

360
#ifdef HAVE_REGEX_H
361
    if (ISSET(REGEXP_COMPILED))
362
	regexp_cleanup();
363
#endif
Chris Allegretta's avatar
Chris Allegretta committed
364
365
366
367
368
369
370
371
372
}

/* Search for a string */
int do_search(void)
{
    int i;
    filestruct *fileptr = current;

    wrap_reset();
373
374
375
    i = search_init(0);
    switch (i) {
    case -1:
Chris Allegretta's avatar
Chris Allegretta committed
376
377
378
	current = fileptr;
	search_abort();
	return 0;
379
    case -3:
Chris Allegretta's avatar
Chris Allegretta committed
380
381
	search_abort();
	return 0;
382
    case -2:
Chris Allegretta's avatar
Chris Allegretta committed
383
384
	do_replace();
	return 0;
385
    case 1:
Chris Allegretta's avatar
Chris Allegretta committed
386
387
388
389
	do_search();
	search_abort();
	return 1;
    }
390
391

    /* The sneaky user deleted the previous search string */
392
    if (!ISSET(PICO_MODE) && !strcmp(answer, "")) {
Jordi Mallach's avatar
   
Jordi Mallach committed
393
	statusbar(_("Search Cancelled"));
394
395
396
397
	search_abort();
	return 0;
    }

398
     /* If answer is now == "", then PICO_MODE is set.  So, copy
399
400
401
402
403
404
405
	last_search into answer... */

    if (!strcmp(answer, ""))
	answer = mallocstrcpy(answer, last_search);
    else
	last_search = mallocstrcpy(last_search, answer);

406
407
    search_last_line = 0;
    findnextstr(0, current, current_x, answer);
Chris Allegretta's avatar
Chris Allegretta committed
408
409
410
411
412
413
414
    search_abort();
    return 1;
}

void print_replaced(int num)
{
    if (num > 1)
Jordi Mallach's avatar
   
Jordi Mallach committed
415
	statusbar(_("Replaced %d occurrences"), num);
Chris Allegretta's avatar
Chris Allegretta committed
416
    else if (num == 1)
Jordi Mallach's avatar
   
Jordi Mallach committed
417
	statusbar(_("Replaced 1 occurrence"));
Chris Allegretta's avatar
Chris Allegretta committed
418
419
420
421
}

void replace_abort(void)
{
422
    /* Identical to search_abort, so we'll call it here.  If it
423
       does something different later, we can change it back.  For now
424
       it's just a waste to duplicate code */
425
    search_abort();
426
    placewewant = xplustabs();
427
428
}

429
#ifdef HAVE_REGEX_H
430
431
432
433
434
435
436
437
int replace_regexp(char *string, int create_flag)
{
    /* split personality here - if create_flag is null, just calculate
     * the size of the replacement line (necessary because of
     * subexpressions like \1 \2 \3 in the replaced text) */

    char *c;
    int new_size = strlen(current->data) + 1;
438
    int search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
439
440
441
442
443
444
445
446

    new_size -= search_match_count;

    /* Iterate through the replacement text to handle
     * subexpression replacement using \1, \2, \3, etc */

    c = last_replace;
    while (*c) {
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
	if (*c != '\\') {
	    if (create_flag)
		*string++ = *c;
	    c++;
	    new_size++;
	} else {
	    int num = (int) *(c + 1) - (int) '0';
	    if (num >= 1 && num <= 9) {

		int i = regmatches[num].rm_so;

		if (num > search_regexp.re_nsub) {
		    /* Ugh, they specified a subexpression that doesn't
		       exist.  */
		    return -1;
		}

		/* Skip over the replacement expression */
		c += 2;

		/* But add the length of the subexpression to new_size */
		new_size += regmatches[num].rm_eo - regmatches[num].rm_so;

		/* And if create_flag is set, append the result of the
		 * subexpression match to the new line */
		while (create_flag && i < regmatches[num].rm_eo)
		    *string++ = *(current->data + i++);

	    } else {
		if (create_flag)
		    *string++ = *c;
		c++;
		new_size++;
	    }
	}
482
483
484
    }

    if (create_flag)
485
	*string = 0;
486
487
488

    return new_size;
}
489
#endif
490

Chris Allegretta's avatar
Chris Allegretta committed
491
char *replace_line(void)
492
493
494
495
496
497
{
    char *copy, *tmp;
    int new_line_size;
    int search_match_count;

    /* Calculate size of new line */
498
#ifdef HAVE_REGEX_H
499
    if (ISSET(USE_REGEXP)) {
500
501
502
	search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
	new_line_size = replace_regexp(NULL, 0);
	/* If they specified an invalid subexpression in the replace
503
	 * text, return NULL, indicating an error */
504
505
	if (new_line_size < 0)
	    return NULL;
506
    } else {
507
508
509
#else
    {
#endif
510
511
512
	search_match_count = strlen(last_search);
	new_line_size = strlen(current->data) - strlen(last_search) +
	    strlen(last_replace) + 1;
513
    }
514

515
    /* Create buffer */
516
    copy = charalloc(new_line_size);
517
518
519
520
521
522
523

    /* Head of Original Line */
    strncpy(copy, current->data, current_x);
    copy[current_x] = 0;

    /* Replacement Text */
    if (!ISSET(USE_REGEXP))
524
	strcat(copy, last_replace);
525
#ifdef HAVE_REGEX_H
526
    else
527
	(void) replace_regexp(copy + current_x, 1);
528
#endif
529
530
531

    /* The tail of the original line */
    /* This may expose other bugs, because it no longer
532
       goes through each character in the string
533
534
535
536
537
538
539
540
       and tests for string goodness.  But because
       we can assume the invariant that current->data
       is less than current_x + strlen(last_search) long,
       this should be safe.  Or it will expose bugs ;-) */
    tmp = current->data + current_x + search_match_count;
    strcat(copy, tmp);

    return copy;
Chris Allegretta's avatar
Chris Allegretta committed
541
542
}

543
/* step through each replace word and prompt user before replacing word */
Chris Allegretta's avatar
Chris Allegretta committed
544
545
int do_replace_loop(char *prevanswer, filestruct *begin, int *beginx,
			int wholewords, int *i)
Chris Allegretta's avatar
Chris Allegretta committed
546
{
Chris Allegretta's avatar
Chris Allegretta committed
547
548
549
    int replaceall = 0, numreplaced = 0;
    filestruct *fileptr;
    char *copy;
Chris Allegretta's avatar
Chris Allegretta committed
550

Chris Allegretta's avatar
Chris Allegretta committed
551
    switch (*i) {
552
    case -1:				/* Aborted enter */
553
	if (strcmp(last_replace, ""))
554
	    answer = mallocstrcpy(answer, last_replace);
555
556
557
	statusbar(_("Replace Cancelled"));
	replace_abort();
	return 0;
558
559
560
    case 0:		/* They actually entered something */
	break;
    default:
Chris Allegretta's avatar
Chris Allegretta committed
561
        if (*i != -2) {	/* First page, last page, for example 
562
				   could get here */
Chris Allegretta's avatar
Chris Allegretta committed
563
564
565
	    do_early_abort();
	    replace_abort();
	    return 0;
566
        }
Chris Allegretta's avatar
Chris Allegretta committed
567
568
    }

569
570
571
    if (ISSET(PICO_MODE) && !strcmp(answer, ""))
	answer = mallocstrcpy(answer, last_replace);

572
    last_replace = mallocstrcpy(last_replace, answer);
Chris Allegretta's avatar
Chris Allegretta committed
573
574
    while (1) {

575
	/* Sweet optimization by Rocco here */
Chris Allegretta's avatar
Chris Allegretta committed
576
	fileptr = findnextstr(replaceall, begin, *beginx, prevanswer);
Chris Allegretta's avatar
Chris Allegretta committed
577
578

	/* No more matches.  Done! */
579
	if (!fileptr)
Chris Allegretta's avatar
Chris Allegretta committed
580
581
	    break;

582
	/* Make sure only whole words are found */
Chris Allegretta's avatar
Chris Allegretta committed
583
584
585
	if (wholewords)
	{
	    /* start of line or previous character not a letter */
586
	    if ((current_x == 0) || (!isalpha((int) fileptr->data[current_x-1])))
Chris Allegretta's avatar
Chris Allegretta committed
587
588
589
	    {
		/* end of line or next character not a letter */
		if (((current_x + strlen(prevanswer)) == strlen(fileptr->data))
590
			|| (!isalpha((int) fileptr->data[current_x + strlen(prevanswer)])))
Chris Allegretta's avatar
Chris Allegretta committed
591
592
593
594
595
596
597
598
		    ;
		else
		    continue;
	    }
	    else
		continue;
	}

Chris Allegretta's avatar
Chris Allegretta committed
599
	/* If we're here, we've found the search string */
600
601
602
603
604
	if (!replaceall) {

	    curs_set(0);
	    do_replace_highlight(TRUE, prevanswer);

Chris Allegretta's avatar
Chris Allegretta committed
605
	    *i = do_yesno(1, 1, _("Replace this instance?"));
Chris Allegretta's avatar
Chris Allegretta committed
606

607
608
609
610
	    do_replace_highlight(FALSE, prevanswer);
	    curs_set(1);
	}

Chris Allegretta's avatar
Chris Allegretta committed
611
612
	if (*i > 0 || replaceall) {	/* Yes, replace it!!!! */
	    if (*i == 2)
Chris Allegretta's avatar
Chris Allegretta committed
613
614
		replaceall = 1;

615
616
	    copy = replace_line();
	    if (!copy) {
Jordi Mallach's avatar
   
Jordi Mallach committed
617
		statusbar(_("Replace failed: unknown subexpression!"));
618
		replace_abort();
Chris Allegretta's avatar
Chris Allegretta committed
619
		return 0;
620
	    }
Chris Allegretta's avatar
Chris Allegretta committed
621
622
623
624
625
626

	    /* Cleanup */
	    free(current->data);
	    current->data = copy;

	    /* Stop bug where we replace a substring of the replacement text */
627
	    current_x += strlen(last_replace) - 1;
Chris Allegretta's avatar
Chris Allegretta committed
628

629
630
	    /* Adjust the original cursor position - COULD BE IMPROVED */
	    if (search_last_line) {
Chris Allegretta's avatar
Chris Allegretta committed
631
		*beginx += strlen(last_replace) - strlen(last_search);
632
633
634

		/* For strings that cross the search start/end boundary */
		/* Don't go outside of allocated memory */
Chris Allegretta's avatar
Chris Allegretta committed
635
636
		if (*beginx < 1)
		    *beginx = 1;
637
638
	    }

Chris Allegretta's avatar
Chris Allegretta committed
639
640
641
	    edit_refresh();
	    set_modified();
	    numreplaced++;
Chris Allegretta's avatar
Chris Allegretta committed
642
	} else if (*i == -1)	/* Abort, else do nothing and continue loop */
Chris Allegretta's avatar
Chris Allegretta committed
643
644
645
	    break;
    }

Chris Allegretta's avatar
Chris Allegretta committed
646
647
648
649
650
651
652
653
654
655
    return numreplaced;
}

/* Replace a string */
int do_replace(void)
{
    int i, numreplaced, beginx;
    filestruct *begin;
    char *prevanswer = NULL, *buf = NULL;

Chris Allegretta's avatar
Chris Allegretta committed
656
657
658
659
660
661
    if (ISSET(VIEW_MODE)) {
	print_view_warning();
	replace_abort();
	return 0;
    }

Chris Allegretta's avatar
Chris Allegretta committed
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
    i = search_init(1);
    switch (i) {
    case -1:
	statusbar(_("Replace Cancelled"));
	replace_abort();
	return 0;
    case 1:
	do_replace();
	return 1;
    case -2:
	do_search();
	return 0;
    case -3:
	replace_abort();
	return 0;
    }

679
    /* Again, there was a previous string, but they deleted it and hit enter */
680
    if (!ISSET(PICO_MODE) && !strcmp(answer, "")) {
Chris Allegretta's avatar
Chris Allegretta committed
681
682
683
684
685
	statusbar(_("Replace Cancelled"));
	replace_abort();
	return 0;
    }

686
     /* If answer is now == "", then PICO_MODE is set.  So, copy
687
688
689
690
691
692
693
694
	last_search into answer (and prevanswer)... */
    if (!strcmp(answer, "")) {
	answer = mallocstrcpy(answer, last_search);
	prevanswer = mallocstrcpy(prevanswer, last_search);
    } else {
	last_search = mallocstrcpy(last_search, answer);
	prevanswer = mallocstrcpy(prevanswer, answer);
    }
Chris Allegretta's avatar
Chris Allegretta committed
695

696
    if (ISSET(PICO_MODE)) {
697
	buf = charalloc(strlen(last_replace) + 5);
Chris Allegretta's avatar
Chris Allegretta committed
698
699
700
701
702
703
704
	if (strcmp(last_replace, "")) {
	    if (strlen(last_replace) > (COLS / 3)) {
		strncpy(buf, last_replace, COLS / 3);
		sprintf(&buf[COLS / 3 - 1], "...");
	    } else
		sprintf(buf, "%s", last_replace);

705
	    i = statusq(0, replace_list_2, REPLACE_LIST_2_LEN, "",
Chris Allegretta's avatar
Chris Allegretta committed
706
707
708
			_("Replace with [%s]"), buf);
	}
	else
709
	    i = statusq(0, replace_list_2, REPLACE_LIST_2_LEN, "",
Chris Allegretta's avatar
Chris Allegretta committed
710
711
712
			_("Replace with"));
    }
    else
713
	i = statusq(0, replace_list_2, REPLACE_LIST_2_LEN, last_replace, 
Chris Allegretta's avatar
Chris Allegretta committed
714
715
716
717
718
719
720
721
722
723
724
			_("Replace with"));

    /* save where we are */
    begin = current;
    beginx = current_x + 1;

    search_last_line = 0;

    numreplaced = do_replace_loop(prevanswer, begin, &beginx, FALSE, &i);

    /* restore where we were */
Chris Allegretta's avatar
Chris Allegretta committed
725
    current = begin;
726
    current_x = beginx - 1;
Chris Allegretta's avatar
Chris Allegretta committed
727
    renumber_all();
728
    edit_update(current, CENTER);
Chris Allegretta's avatar
Chris Allegretta committed
729
730
731
732
733
734
735
736
737
738
739
    print_replaced(numreplaced);
    replace_abort();
    return 1;
}

void goto_abort(void)
{
    UNSET(KEEP_CUTBUFFER);
    display_main_list();
}

740
int do_gotoline(long line)
Chris Allegretta's avatar
Chris Allegretta committed
741
{
742
743
744
    long i = 1;

    if (line <= 0) {		/* Ask for it */
Chris Allegretta's avatar
Chris Allegretta committed
745

746
	long j = 0;
Chris Allegretta's avatar
Chris Allegretta committed
747

748
	j = statusq(0, goto_list, GOTO_LIST_LEN, "", _("Enter line number"));
749
	if (j != 0) {
Chris Allegretta's avatar
Chris Allegretta committed
750
751
752
753
	    statusbar(_("Aborted"));
	    goto_abort();
	    return 0;
	}
754
755
756
757
758
759

	line = atoi(answer);

	/* Bounds check */
	if (line <= 0) {
	    statusbar(_("Come on, be reasonable"));
Chris Allegretta's avatar
Chris Allegretta committed
760
	    goto_abort();
761
	    return 0;
Chris Allegretta's avatar
Chris Allegretta committed
762
763
764
	}
    }

765
766
    for (current = fileage; ((current->next != NULL) && (i < line)); i++)
	current = current->next;
Chris Allegretta's avatar
Chris Allegretta committed
767

768
769
    current_x = 0;
    edit_update(current, CENTER);
Chris Allegretta's avatar
Chris Allegretta committed
770
771
772
773
774
775
776
777
778

    goto_abort();
    return 1;
}

int do_gotoline_void(void)
{
    return do_gotoline(0);
}