2 Search & replace engine of MCEditor.
5 Free Software Foundation, Inc.
8 Andrew Borodin <aborodin@vmail.ru>, 2021
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
30 #include "lib/global.h"
31 #include "lib/search.h"
32 #include "lib/mcconfig.h" /* mc_config_history_get */
34 #include "lib/charsets.h" /* cp_source */
37 #include "lib/widget.h"
38 #include "lib/skin.h" /* BOOK_MARK_FOUND_COLOR */
40 #include "src/history.h" /* MC_HISTORY_SHARED_SEARCH */
41 #include "src/setup.h" /* verbose */
43 #include "edit-impl.h"
44 #include "editwidget.h"
46 #include "editsearch.h"
48 /*** global variables ****************************************************************************/
50 edit_search_options_t edit_search_options
= {
51 .type
= MC_SEARCH_T_NORMAL
,
54 .only_in_selection
= FALSE
,
56 .all_codepages
= FALSE
59 /*** file scope macro definitions ****************************************************************/
61 #define B_REPLACE_ALL (B_USER+1)
62 #define B_REPLACE_ONE (B_USER+2)
63 #define B_SKIP_REPLACE (B_USER+3)
65 /*** file scope type declarations ****************************************************************/
67 /*** file scope variables ************************************************************************/
69 /* --------------------------------------------------------------------------------------------- */
70 /*** file scope functions ************************************************************************/
71 /* --------------------------------------------------------------------------------------------- */
74 edit_dialog_search_show (WEdit
* edit
)
77 size_t num_of_types
= 0;
78 gchar
**list_of_types
;
81 list_of_types
= mc_search_get_types_strings_array (&num_of_types
);
84 quick_widget_t quick_widgets
[] = {
86 QUICK_LABELED_INPUT (N_("Enter search string:"), input_label_above
, INPUT_LAST_TEXT
,
87 MC_HISTORY_SHARED_SEARCH
, &search_text
, NULL
, FALSE
, FALSE
,
89 QUICK_SEPARATOR (TRUE
),
91 QUICK_RADIO (num_of_types
, (const char **) list_of_types
,
92 (int *) &edit_search_options
.type
, NULL
),
94 QUICK_CHECKBOX (N_("Cas&e sensitive"), &edit_search_options
.case_sens
, NULL
),
95 QUICK_CHECKBOX (N_("&Backwards"), &edit_search_options
.backwards
, NULL
),
96 QUICK_CHECKBOX (N_("In se&lection"), &edit_search_options
.only_in_selection
, NULL
),
97 QUICK_CHECKBOX (N_("&Whole words"), &edit_search_options
.whole_words
, NULL
),
99 QUICK_CHECKBOX (N_("&All charsets"), &edit_search_options
.all_codepages
, NULL
),
102 QUICK_START_BUTTONS (TRUE
, TRUE
),
103 QUICK_BUTTON (N_("&OK"), B_ENTER
, NULL
, NULL
),
104 QUICK_BUTTON (N_("&Find all"), B_USER
, NULL
, NULL
),
105 QUICK_BUTTON (N_("&Cancel"), B_CANCEL
, NULL
, NULL
),
110 quick_dialog_t qdlg
= {
112 N_("Search"), "[Input Line Keys]",
113 quick_widgets
, NULL
, NULL
116 dialog_result
= quick_dialog (&qdlg
);
119 g_strfreev (list_of_types
);
121 if ((dialog_result
== B_CANCEL
) || (search_text
== NULL
) || (search_text
[0] == '\0'))
123 g_free (search_text
);
127 if (dialog_result
== B_USER
)
128 search_create_bookmark
= TRUE
;
134 tmp
= str_convert_to_input (search_text
);
135 g_free (search_text
);
136 search_text
= g_string_free (tmp
, FALSE
);
140 edit_search_deinit (edit
);
141 edit
->last_search_string
= search_text
;
143 return edit_search_init (edit
, edit
->last_search_string
);
146 /* --------------------------------------------------------------------------------------------- */
149 edit_dialog_replace_show (WEdit
* edit
, const char *search_default
, const char *replace_default
,
150 /*@out@ */ char **search_text
, /*@out@ */ char **replace_text
)
152 size_t num_of_types
= 0;
153 gchar
**list_of_types
;
155 if ((search_default
== NULL
) || (*search_default
== '\0'))
156 search_default
= INPUT_LAST_TEXT
;
158 list_of_types
= mc_search_get_types_strings_array (&num_of_types
);
161 quick_widget_t quick_widgets
[] = {
163 QUICK_LABELED_INPUT (N_("Enter search string:"), input_label_above
, search_default
,
164 MC_HISTORY_SHARED_SEARCH
, search_text
, NULL
, FALSE
, FALSE
,
165 INPUT_COMPLETE_NONE
),
166 QUICK_LABELED_INPUT (N_("Enter replacement string:"), input_label_above
, replace_default
,
167 "replace", replace_text
, NULL
, FALSE
, FALSE
, INPUT_COMPLETE_NONE
),
168 QUICK_SEPARATOR (TRUE
),
170 QUICK_RADIO (num_of_types
, (const char **) list_of_types
,
171 (int *) &edit_search_options
.type
, NULL
),
173 QUICK_CHECKBOX (N_("Cas&e sensitive"), &edit_search_options
.case_sens
, NULL
),
174 QUICK_CHECKBOX (N_("&Backwards"), &edit_search_options
.backwards
, NULL
),
175 QUICK_CHECKBOX (N_("In se&lection"), &edit_search_options
.only_in_selection
, NULL
),
176 QUICK_CHECKBOX (N_("&Whole words"), &edit_search_options
.whole_words
, NULL
),
178 QUICK_CHECKBOX (N_("&All charsets"), &edit_search_options
.all_codepages
, NULL
),
181 QUICK_BUTTONS_OK_CANCEL
,
186 quick_dialog_t qdlg
= {
188 N_("Replace"), "[Input Line Keys]",
189 quick_widgets
, NULL
, NULL
192 if (quick_dialog (&qdlg
) != B_CANCEL
)
193 edit
->replace_mode
= 0;
196 *replace_text
= NULL
;
201 g_strfreev (list_of_types
);
204 /* --------------------------------------------------------------------------------------------- */
207 edit_dialog_replace_prompt_show (WEdit
* edit
, char *from_text
, char *to_text
, int xpos
, int ypos
)
209 Widget
*w
= WIDGET (edit
);
215 char tmp
[BUF_MEDIUM
];
216 char *repl_from
, *repl_to
;
220 xpos
= w
->x
+ option_line_state_width
+ 1;
222 ypos
= w
->y
+ w
->lines
/ 2;
223 /* Sometimes menu can hide replaced text. I don't like it */
224 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ dlg_height
- 1))
227 dlg_width
= WIDGET (w
->owner
)->cols
- xpos
- 1;
229 g_snprintf (tmp
, sizeof (tmp
), "\"%s\"", from_text
);
230 repl_from
= g_strdup (str_trunc (tmp
, dlg_width
- 7));
232 g_snprintf (tmp
, sizeof (tmp
), "\"%s\"", to_text
);
233 repl_to
= g_strdup (str_trunc (tmp
, dlg_width
- 7));
236 quick_widget_t quick_widgets
[] = {
238 QUICK_LABEL (repl_from
, NULL
),
239 QUICK_LABEL (N_("Replace with:"), NULL
),
240 QUICK_LABEL (repl_to
, NULL
),
241 QUICK_START_BUTTONS (TRUE
, TRUE
),
242 QUICK_BUTTON (N_("&Replace"), B_ENTER
, NULL
, NULL
),
243 QUICK_BUTTON (N_("A&ll"), B_REPLACE_ALL
, NULL
, NULL
),
244 QUICK_BUTTON (N_("&Skip"), B_SKIP_REPLACE
, NULL
, NULL
),
245 QUICK_BUTTON (N_("&Cancel"), B_CANCEL
, NULL
, NULL
),
250 quick_dialog_t qdlg
= {
252 N_("Confirm replace"), NULL
,
253 quick_widgets
, NULL
, NULL
256 retval
= quick_dialog (&qdlg
);
265 /* --------------------------------------------------------------------------------------------- */
268 * Get EOL symbol for searching.
270 * @param edit editor object
275 edit_search_get_current_end_line_char (const WEdit
* edit
)
286 /* --------------------------------------------------------------------------------------------- */
288 * Checking if search condition have BOL(^) or EOL ($) regexp special characters.
290 * @param search search object
291 * @return result of checks.
294 static edit_search_line_t
295 edit_get_search_line_type (mc_search_t
* search
)
297 edit_search_line_t search_line_type
= 0;
299 if (search
->search_type
!= MC_SEARCH_T_REGEX
)
300 return search_line_type
;
302 if (*search
->original
== '^')
303 search_line_type
|= AT_START_LINE
;
305 if (search
->original
[search
->original_len
- 1] == '$')
306 search_line_type
|= AT_END_LINE
;
307 return search_line_type
;
310 /* --------------------------------------------------------------------------------------------- */
312 * Calculating the start position of next line.
314 * @param buf editor buffer object
315 * @param current_pos current position
316 * @param max_pos max position
317 * @param end_string_symbol end of line symbol
318 * @return start position of next line
322 edit_calculate_start_of_next_line (const edit_buffer_t
* buf
, off_t current_pos
, off_t max_pos
,
323 char end_string_symbol
)
327 for (i
= current_pos
; i
< max_pos
; i
++)
330 if (edit_buffer_get_byte (buf
, i
) == end_string_symbol
)
337 /* --------------------------------------------------------------------------------------------- */
339 * Calculating the end position of previous line.
341 * @param buf editor buffer object
342 * @param current_pos current position
343 * @param end_string_symbol end of line symbol
344 * @return end position of previous line
348 edit_calculate_end_of_previous_line (const edit_buffer_t
* buf
, off_t current_pos
,
349 char end_string_symbol
)
353 for (i
= current_pos
- 1; i
>= 0; i
--)
354 if (edit_buffer_get_byte (buf
, i
) == end_string_symbol
)
360 /* --------------------------------------------------------------------------------------------- */
362 * Calculating the start position of previous line.
364 * @param buf editor buffer object
365 * @param current_pos current position
366 * @param end_string_symbol end of line symbol
367 * @return start position of previous line
371 edit_calculate_start_of_previous_line (const edit_buffer_t
* buf
, off_t current_pos
,
372 char end_string_symbol
)
374 current_pos
= edit_calculate_end_of_previous_line (buf
, current_pos
, end_string_symbol
);
375 current_pos
= edit_calculate_end_of_previous_line (buf
, current_pos
, end_string_symbol
);
377 return (current_pos
+ 1);
380 /* --------------------------------------------------------------------------------------------- */
382 * Calculating the start position of current line.
384 * @param buf editor buffer object
385 * @param current_pos current position
386 * @param end_string_symbol end of line symbol
387 * @return start position of current line
391 edit_calculate_start_of_current_line (const edit_buffer_t
* buf
, off_t current_pos
,
392 char end_string_symbol
)
394 current_pos
= edit_calculate_end_of_previous_line (buf
, current_pos
, end_string_symbol
);
396 return (current_pos
+ 1);
399 /* --------------------------------------------------------------------------------------------- */
401 * Fixing (if needed) search start position if 'only in selection' option present.
403 * @param edit editor object
407 edit_search_fix_search_start_if_selection (WEdit
* edit
)
409 off_t start_mark
= 0;
412 if (!edit_search_options
.only_in_selection
)
415 if (!eval_marks (edit
, &start_mark
, &end_mark
))
418 if (edit_search_options
.backwards
)
420 if (edit
->search_start
> end_mark
|| edit
->search_start
<= start_mark
)
421 edit
->search_start
= end_mark
;
425 if (edit
->search_start
< start_mark
|| edit
->search_start
>= end_mark
)
426 edit
->search_start
= start_mark
;
430 /* --------------------------------------------------------------------------------------------- */
433 edit_find (edit_search_status_msg_t
* esm
, gsize
* len
)
435 WEdit
*edit
= esm
->edit
;
436 off_t search_start
= edit
->search_start
;
438 off_t start_mark
= 0;
439 off_t end_mark
= edit
->buffer
.size
;
440 char end_string_symbol
;
442 end_string_symbol
= edit_search_get_current_end_line_char (edit
);
444 /* prepare for search */
445 if (edit_search_options
.only_in_selection
)
447 if (!eval_marks (edit
, &start_mark
, &end_mark
))
449 mc_search_set_error (edit
->search
, MC_SEARCH_E_NOTFOUND
, "%s", _(STR_E_NOTFOUND
));
453 /* fix the start and the end of search block positions */
454 if ((edit
->search_line_type
& AT_START_LINE
) != 0
456 || edit_buffer_get_byte (&edit
->buffer
, start_mark
- 1) != end_string_symbol
))
458 edit_calculate_start_of_next_line (&edit
->buffer
, start_mark
, edit
->buffer
.size
,
461 if ((edit
->search_line_type
& AT_END_LINE
) != 0
462 && (end_mark
- 1 != edit
->buffer
.size
463 || edit_buffer_get_byte (&edit
->buffer
, end_mark
) != end_string_symbol
))
465 edit_calculate_end_of_previous_line (&edit
->buffer
, end_mark
, end_string_symbol
);
467 if (start_mark
>= end_mark
)
469 mc_search_set_error (edit
->search
, MC_SEARCH_E_NOTFOUND
, "%s", _(STR_E_NOTFOUND
));
473 else if (edit_search_options
.backwards
)
474 end_mark
= MAX (1, edit
->buffer
.curs1
) - 1;
477 if (edit_search_options
.backwards
)
479 /* backward search */
480 search_end
= end_mark
;
482 if ((edit
->search_line_type
& AT_START_LINE
) != 0)
484 edit_calculate_start_of_current_line (&edit
->buffer
, search_start
,
487 while (search_start
>= start_mark
)
491 if (search_end
> (off_t
) (search_start
+ edit
->search
->original_len
)
492 && mc_search_is_fixed_search_str (edit
->search
))
493 search_end
= search_start
+ edit
->search
->original_len
;
495 ok
= mc_search_run (edit
->search
, (void *) esm
, search_start
, search_end
, len
);
497 if (ok
&& edit
->search
->normal_offset
== search_start
)
500 /* We abort the search in case of a pattern error, or if the user aborts
501 the search. In other words: in all cases except "string not found". */
502 if (!ok
&& edit
->search
->error
!= MC_SEARCH_E_NOTFOUND
)
505 if ((edit
->search_line_type
& AT_START_LINE
) != 0)
507 edit_calculate_start_of_previous_line (&edit
->buffer
, search_start
,
513 mc_search_set_error (edit
->search
, MC_SEARCH_E_NOTFOUND
, "%s", _(STR_E_NOTFOUND
));
518 if ((edit
->search_line_type
& AT_START_LINE
) != 0 && search_start
!= start_mark
)
520 edit_calculate_start_of_next_line (&edit
->buffer
, search_start
, end_mark
,
523 return mc_search_run (edit
->search
, (void *) esm
, search_start
, end_mark
, len
);
526 /* --------------------------------------------------------------------------------------------- */
529 edit_replace_cmd__conv_to_display (const char *str
)
534 tmp
= str_convert_to_display (str
);
538 return g_string_free (tmp
, FALSE
);
539 g_string_free (tmp
, TRUE
);
542 return g_strdup (str
);
545 /* --------------------------------------------------------------------------------------------- */
548 edit_replace_cmd__conv_to_input (char *str
)
553 tmp
= str_convert_to_input (str
);
555 return g_string_free (tmp
, FALSE
);
556 g_string_free (tmp
, TRUE
);
558 return g_strdup (str
);
561 /* --------------------------------------------------------------------------------------------- */
564 edit_show_search_error (const WEdit
* edit
, const char *title
)
566 if (edit
->search
->error
== MC_SEARCH_E_NOTFOUND
)
567 edit_query_dialog (title
, _(STR_E_NOTFOUND
));
568 else if (edit
->search
->error_str
!= NULL
)
569 edit_query_dialog (title
, edit
->search
->error_str
);
572 /* --------------------------------------------------------------------------------------------- */
575 edit_do_search (WEdit
* edit
)
577 edit_search_status_msg_t esm
;
580 /* This shouldn't happen */
581 assert (edit
->search
!= NULL
);
583 edit_push_undo_action (edit
, KEY_PRESS
+ edit
->start_display
);
587 esm
.offset
= edit
->search_start
;
589 status_msg_init (STATUS_MSG (&esm
), _("Search"), 1.0, simple_status_msg_init_cb
,
590 edit_search_status_update_cb
, NULL
);
592 if (search_create_bookmark
)
594 gboolean found
= FALSE
;
595 long l
= 0, l_last
= -1;
598 search_create_bookmark
= FALSE
;
599 book_mark_flush (edit
, -1);
601 while (mc_search_run (edit
->search
, (void *) &esm
, q
, edit
->buffer
.size
, &len
))
604 edit
->search_start
= edit
->search
->normal_offset
;
607 l
+= edit_buffer_count_lines (&edit
->buffer
, q
, edit
->search
->normal_offset
);
609 book_mark_insert (edit
, l
, BOOK_MARK_FOUND_COLOR
);
611 q
= edit
->search
->normal_offset
+ 1;
615 edit_error_dialog (_("Search"), _(STR_E_NOTFOUND
));
617 edit_cursor_move (edit
, edit
->search_start
- edit
->buffer
.curs1
);
621 if (edit
->found_len
!= 0 && edit
->search_start
== edit
->found_start
+ 1
622 && edit_search_options
.backwards
)
623 edit
->search_start
--;
625 if (edit
->found_len
!= 0 && edit
->search_start
== edit
->found_start
- 1
626 && !edit_search_options
.backwards
)
627 edit
->search_start
++;
629 if (edit_find (&esm
, &len
))
631 edit
->found_start
= edit
->search_start
= edit
->search
->normal_offset
;
632 edit
->found_len
= len
;
634 edit_cursor_move (edit
, edit
->search_start
- edit
->buffer
.curs1
);
635 edit_scroll_screen_over_cursor (edit
);
636 if (edit_search_options
.backwards
)
637 edit
->search_start
--;
639 edit
->search_start
++;
643 edit
->search_start
= edit
->buffer
.curs1
;
644 edit_show_search_error (edit
, _("Search"));
648 status_msg_deinit (STATUS_MSG (&esm
));
650 edit
->force
|= REDRAW_COMPLETELY
;
651 edit_scroll_screen_over_cursor (edit
);
654 /* --------------------------------------------------------------------------------------------- */
657 edit_search (WEdit
* edit
)
659 if (edit_dialog_search_show (edit
))
661 edit
->search_line_type
= edit_get_search_line_type (edit
->search
);
662 edit_search_fix_search_start_if_selection (edit
);
663 edit_do_search (edit
);
667 /* --------------------------------------------------------------------------------------------- */
668 /*** public functions ****************************************************************************/
669 /* --------------------------------------------------------------------------------------------- */
672 edit_search_init (WEdit
* edit
, const char *str
)
675 edit
->search
= mc_search_new (str
, cp_source
);
677 edit
->search
= mc_search_new (str
, NULL
);
680 if (edit
->search
== NULL
)
683 edit
->search
->search_type
= edit_search_options
.type
;
685 edit
->search
->is_all_charsets
= edit_search_options
.all_codepages
;
687 edit
->search
->is_case_sensitive
= edit_search_options
.case_sens
;
688 edit
->search
->whole_words
= edit_search_options
.whole_words
;
689 edit
->search
->search_fn
= edit_search_cmd_callback
;
690 edit
->search
->update_fn
= edit_search_update_callback
;
695 /* --------------------------------------------------------------------------------------------- */
698 edit_search_deinit (WEdit
* edit
)
700 mc_search_free (edit
->search
);
701 g_free (edit
->last_search_string
);
704 /* --------------------------------------------------------------------------------------------- */
707 edit_search_cmd_callback (const void *user_data
, gsize char_offset
, int *current_char
)
709 WEdit
*edit
= ((const edit_search_status_msg_t
*) user_data
)->edit
;
711 *current_char
= edit_buffer_get_byte (&edit
->buffer
, (off_t
) char_offset
);
713 return MC_SEARCH_CB_OK
;
716 /* --------------------------------------------------------------------------------------------- */
719 edit_search_update_callback (const void *user_data
, gsize char_offset
)
721 status_msg_t
*sm
= STATUS_MSG (user_data
);
723 ((edit_search_status_msg_t
*) sm
)->offset
= (off_t
) char_offset
;
725 return (sm
->update (sm
) == B_CANCEL
? MC_SEARCH_CB_ABORT
: MC_SEARCH_CB_OK
);
728 /* --------------------------------------------------------------------------------------------- */
731 edit_search_status_update_cb (status_msg_t
* sm
)
733 simple_status_msg_t
*ssm
= SIMPLE_STATUS_MSG (sm
);
734 edit_search_status_msg_t
*esm
= (edit_search_status_msg_t
*) sm
;
735 Widget
*wd
= WIDGET (sm
->dlg
);
738 label_set_textv (ssm
->label
, _("Searching %s: %3d%%"), esm
->edit
->last_search_string
,
739 edit_buffer_calc_percent (&esm
->edit
->buffer
, esm
->offset
));
741 label_set_textv (ssm
->label
, _("Searching %s"), esm
->edit
->last_search_string
);
746 Widget
*lw
= WIDGET (ssm
->label
);
748 wd_width
= MAX (wd
->cols
, lw
->cols
+ 6);
749 widget_set_size (wd
, wd
->y
, wd
->x
, wd
->lines
, wd_width
);
750 widget_set_size (lw
, lw
->y
, wd
->x
+ (wd
->cols
- lw
->cols
) / 2, lw
->lines
, lw
->cols
);
754 return status_msg_common_update (sm
);
757 /* --------------------------------------------------------------------------------------------- */
760 edit_search_cmd (WEdit
* edit
, gboolean again
)
764 else if (edit
->last_search_string
!= NULL
)
765 edit_do_search (edit
);
768 /* find last search string in history */
771 history
= mc_config_history_get (MC_HISTORY_SHARED_SEARCH
);
774 /* FIXME: is it possible that history->data == NULL? */
775 edit
->last_search_string
= (char *) history
->data
;
776 history
->data
= NULL
;
777 history
= g_list_first (history
);
778 g_list_free_full (history
, g_free
);
780 if (edit_search_init (edit
, edit
->last_search_string
))
782 edit_do_search (edit
);
786 /* found, but cannot init search */
787 MC_PTR_FREE (edit
->last_search_string
);
790 /* if not... then ask for an expression */
795 /* --------------------------------------------------------------------------------------------- */
796 /** call with edit = 0 before shutdown to close memory leaks */
799 edit_replace_cmd (WEdit
* edit
, gboolean again
)
801 /* 1 = search string, 2 = replace with */
802 static char *saved1
= NULL
; /* saved default[123] */
803 static char *saved2
= NULL
;
804 char *input1
= NULL
; /* user input from the dialog */
806 GString
*input2_str
= NULL
;
809 long times_replaced
= 0;
810 gboolean once_found
= FALSE
;
811 edit_search_status_msg_t esm
;
815 MC_PTR_FREE (saved1
);
816 MC_PTR_FREE (saved2
);
820 edit
->force
|= REDRAW_COMPLETELY
;
822 if (again
&& saved1
== NULL
&& saved2
== NULL
)
827 input1
= g_strdup (saved1
!= NULL
? saved1
: "");
828 input2
= g_strdup (saved2
!= NULL
? saved2
: "");
832 char *tmp_inp1
, *tmp_inp2
;
834 disp1
= edit_replace_cmd__conv_to_display (saved1
!= NULL
? saved1
: "");
835 disp2
= edit_replace_cmd__conv_to_display (saved2
!= NULL
? saved2
: "");
837 edit_push_undo_action (edit
, KEY_PRESS
+ edit
->start_display
);
839 edit_dialog_replace_show (edit
, disp1
, disp2
, &input1
, &input2
);
844 if (input1
== NULL
|| *input1
== '\0')
846 edit
->force
= REDRAW_COMPLETELY
;
852 input1
= edit_replace_cmd__conv_to_input (input1
);
853 input2
= edit_replace_cmd__conv_to_input (input2
);
858 saved1
= g_strdup (input1
);
860 saved2
= g_strdup (input2
);
862 mc_search_free (edit
->search
);
866 input2_str
= g_string_new (input2
);
868 if (edit
->search
== NULL
)
870 if (edit_search_init (edit
, input1
))
871 edit_search_fix_search_start_if_selection (edit
);
874 edit
->search_start
= edit
->buffer
.curs1
;
879 if (edit
->found_len
!= 0 && edit
->search_start
== edit
->found_start
+ 1
880 && edit_search_options
.backwards
)
881 edit
->search_start
--;
883 if (edit
->found_len
!= 0 && edit
->search_start
== edit
->found_start
- 1
884 && !edit_search_options
.backwards
)
885 edit
->search_start
++;
889 esm
.offset
= edit
->search_start
;
891 status_msg_init (STATUS_MSG (&esm
), _("Search"), 1.0, simple_status_msg_init_cb
,
892 edit_search_status_update_cb
, NULL
);
898 if (!edit_find (&esm
, &len
))
900 if (!(edit
->search
->error
== MC_SEARCH_E_OK
||
901 (once_found
&& edit
->search
->error
== MC_SEARCH_E_NOTFOUND
)))
902 edit_show_search_error (edit
, _("Search"));
908 edit
->search_start
= edit
->search
->normal_offset
;
909 /* returns negative on not found or error in pattern */
911 if (edit
->search_start
>= 0 && edit
->search_start
< edit
->buffer
.size
)
916 edit
->found_start
= edit
->search_start
;
917 i
= edit
->found_len
= len
;
919 edit_cursor_move (edit
, edit
->search_start
- edit
->buffer
.curs1
);
920 edit_scroll_screen_over_cursor (edit
);
922 if (edit
->replace_mode
== 0)
927 l
= edit
->curs_row
- WIDGET (edit
)->lines
/ 3;
929 edit_scroll_downward (edit
, l
);
931 edit_scroll_upward (edit
, -l
);
933 edit_scroll_screen_over_cursor (edit
);
934 edit
->force
|= REDRAW_PAGE
;
935 edit_render_keypress (edit
);
937 /*so that undo stops at each query */
938 edit_push_key_press (edit
);
939 /* and prompt 2/3 down */
940 disp1
= edit_replace_cmd__conv_to_display (saved1
);
941 disp2
= edit_replace_cmd__conv_to_display (saved2
);
942 prompt
= edit_dialog_replace_prompt_show (edit
, disp1
, disp2
, -1, -1);
946 if (prompt
== B_REPLACE_ALL
)
947 edit
->replace_mode
= 1;
948 else if (prompt
== B_SKIP_REPLACE
)
950 if (edit_search_options
.backwards
)
951 edit
->search_start
--;
953 edit
->search_start
++;
956 else if (prompt
== B_CANCEL
)
958 edit
->replace_mode
= -1;
963 repl_str
= mc_search_prepare_replace_str (edit
->search
, input2_str
);
965 if (edit
->search
->error
!= MC_SEARCH_E_OK
)
967 edit_show_search_error (edit
, _("Replace"));
968 if (repl_str
!= NULL
)
969 g_string_free (repl_str
, TRUE
);
973 /* delete then insert new */
974 for (i
= 0; i
< len
; i
++)
975 edit_delete (edit
, TRUE
);
977 for (i
= 0; i
< repl_str
->len
; i
++)
978 edit_insert (edit
, repl_str
->str
[i
]);
980 edit
->found_len
= repl_str
->len
;
981 g_string_free (repl_str
, TRUE
);
984 /* so that we don't find the same string again */
985 if (edit_search_options
.backwards
)
986 edit
->search_start
--;
989 edit
->search_start
+= edit
->found_len
+ (len
== 0 ? 1 : 0);
991 if (edit
->search_start
>= edit
->buffer
.size
)
995 edit_scroll_screen_over_cursor (edit
);
999 /* try and find from right here for next search */
1000 edit
->search_start
= edit
->buffer
.curs1
;
1001 edit_update_curs_col (edit
);
1003 edit
->force
|= REDRAW_PAGE
;
1004 edit_render_keypress (edit
);
1006 if (times_replaced
== 0)
1007 query_dialog (_("Replace"), _(STR_E_NOTFOUND
), D_NORMAL
, 1, _("&OK"));
1011 while (edit
->replace_mode
>= 0);
1013 status_msg_deinit (STATUS_MSG (&esm
));
1014 edit_scroll_screen_over_cursor (edit
);
1015 edit
->force
|= REDRAW_COMPLETELY
;
1016 edit_render_keypress (edit
);
1018 if (edit
->replace_mode
== 1 && times_replaced
!= 0)
1019 message (D_NORMAL
, _("Replace"), _("%ld replacements made"), times_replaced
);
1024 if (input2_str
!= NULL
)
1025 g_string_free (input2_str
, TRUE
);
1028 /* --------------------------------------------------------------------------------------------- */