1 /* editor high level editing commands.
3 Copyright (C) 1996, 1997 the Free Software Foundation
5 Authors: 1996, 1997 Paul Sheer
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
32 #include "editcmddef.h"
35 #include "src/charsets.h"
40 /* search and replace: */
41 int replace_scanf
= 0;
42 int replace_regexp
= 0;
44 int replace_prompt
= 1;
45 int replace_whole
= 0;
47 int replace_backwards
= 0;
48 int search_create_bookmark
= 0;
50 /* queries on a save */
51 int edit_confirm_save
= 1;
53 #define NUM_REPL_ARGS 64
54 #define MAX_REPL_LEN 1024
56 static inline int my_lower_case (int c
)
58 return tolower(c
& 0xFF);
61 char *strcasechr (const unsigned char *s
, int c
)
63 for (c
= my_lower_case (c
); my_lower_case ((int) *s
) != c
; ++s
)
71 static void *memmove (void *dest
, const void *src
, size_t n
)
81 t
= (char *) dest
+ n
;
88 #endif /* !HAVE_MEMMOVE */
90 /* #define itoa MY_itoa <---- this line is now in edit.h */
99 } while ((i
= i
/ 10));
106 This joins strings end on end and allocates memory for the result.
107 The result is later automatically free'd and must not be free'd
110 char *catstrs (const char *first
,...)
112 static char *stacked
[16] =
113 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
122 len
= strlen (first
);
123 va_start (ap
, first
);
125 while ((data
= va_arg (ap
, char *)) != 0)
126 len
+= strlen (data
);
134 stacked
[i
] = malloc (len
);
136 va_start (ap
, first
);
137 strcpy (stacked
[i
], first
);
138 while ((data
= va_arg (ap
, char *)) != 0)
139 strcat (stacked
[i
], data
);
145 void edit_help_cmd (WEdit
* edit
)
147 interactive_display (NULL
, "[Internal File Editor]");
148 edit
->force
|= REDRAW_COMPLETELY
;
151 void edit_refresh_cmd (WEdit
* edit
)
159 edit_get_syntax_color (edit
, -1, &fg
, &bg
);
162 #endif /* !HAVE_SLANG */
167 /* "Oleg Yu. Repin" <repin@ssd.sscc.ru> added backup filenames
170 /* If 0 (quick save) then a) create/truncate <filename> file,
171 b) save to <filename>;
172 if 1 (safe save) then a) save to <tempnam>,
173 b) rename <tempnam> to <filename>;
174 if 2 (do backups) then a) save to <tempnam>,
175 b) rename <filename> to <filename.backup_ext>,
176 c) rename <tempnam> to <filename>. */
178 /* returns 0 on error */
179 int edit_save_file (WEdit
* edit
, const char *filename
)
184 int this_save_mode
, fd
;
191 if ((fd
= open (filename
, O_WRONLY
)) == -1) {
193 * The file does not exists yet, so no safe save or
194 * backup are necessary.
199 this_save_mode
= option_save_mode
;
202 if (this_save_mode
> 0) {
203 char *savedir
, *slashpos
, *saveprefix
;
204 savedir
= (char *) strdup (".");
205 slashpos
= strrchr (filename
, '/');
208 savedir
= (char *) strdup (filename
);
209 savedir
[slashpos
- filename
+ 1] = '\0';
211 saveprefix
= concat_dir_and_file (savedir
, "cooledit");
213 fd
= mc_mkstemps(&savename
, saveprefix
, NULL
);
219 savename
= g_strdup (filename
);
221 if ((fd
= open (savename
, O_CREAT
| O_WRONLY
| O_TRUNC
| MY_O_TEXT
,
222 edit
->stat1
.st_mode
)) == -1)
225 chmod (savename
, edit
->stat1
.st_mode
);
226 chown (savename
, edit
->stat1
.st_uid
, edit
->stat1
.st_gid
);
229 if ((p
= (char *) edit_get_write_filter (savename
, filename
))) {
233 file
= (FILE *) popen (p
, "w");
236 filelen
= edit_write_stream (edit
, file
);
240 if (pclose (file
) != 0) {
241 edit_error_dialog (_ (" Error "), catstrs (_ (" Error writing to pipe: "), p
, " ", 0));
247 edit_error_dialog (_ (" Error "), get_sys_error (catstrs (_ (" Failed trying to open pipe for writing: "), p
, " ", 0)));
252 #ifdef CR_LF_TRANSLATION
253 } else { /* optimised save */
254 filelen
= edit_write_stream (edit
, f
);
261 filelen
= edit
->last_byte
;
262 while (buf
<= (edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1) {
263 if (write (fd
, (char *) edit
->buffers1
[buf
], EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
269 if (write (fd
, (char *) edit
->buffers1
[buf
], edit
->curs1
& M_EDIT_BUF_SIZE
) != (edit
->curs1
& M_EDIT_BUF_SIZE
)) {
271 } else if (edit
->curs2
) {
273 buf
= (edit
->curs2
>> S_EDIT_BUF_SIZE
);
274 if (write (fd
, (char *) edit
->buffers2
[buf
] + EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
) - 1, 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) != 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) {
278 if (write (fd
, (char *) edit
->buffers2
[buf
], EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
288 #endif /* !CR_LF_TRANSLATION */
291 if (filelen
!= edit
->last_byte
)
293 if (this_save_mode
== 2)
294 if (rename (filename
, catstrs (filename
, option_backup_ext
, 0)) == -1)
296 if (this_save_mode
> 0)
297 if (rename (savename
, filename
) == -1)
309 I changed this from Oleg's original routine so
310 that option_backup_ext works with coolwidgets as well. This
311 does mean there is a memory leak - paul.
313 void menu_save_mode_cmd (void)
317 static char *str_result
;
318 static int save_mode_new
;
323 N_("Do backups -->")};
324 static QuickWidget widgets
[] =
326 {quick_button
, 18, DLG_X
, 7, DLG_Y
, N_("&Cancel"), 0,
327 B_CANCEL
, 0, 0, "c"},
328 {quick_button
, 6, DLG_X
, 7, DLG_Y
, N_("&Ok"), 0,
330 {quick_input
, 23, DLG_X
, 5, DLG_Y
, 0, 9,
331 0, 0, &str_result
, "edit-backup-ext"},
332 {quick_label
, 22, DLG_X
, 4, DLG_Y
, N_("Extension:"), 0,
333 0, 0, 0, "savemext"},
334 {quick_radio
, 4, DLG_X
, 3, DLG_Y
, "", 3,
335 0, &save_mode_new
, str
, "t"},
337 static QuickDialog dialog
=
338 {DLG_X
, DLG_Y
, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
340 static int i18n_flag
= 0;
348 /* Ok/Cancel buttons */
349 l1
= strlen (_(widgets
[0].text
)) + strlen (_(widgets
[1].text
)) + 5;
350 maxlen
= max (maxlen
, l1
);
352 for (i
= 0; i
< 3; i
++ ) {
354 maxlen
= max (maxlen
, strlen (str
[i
]) + 7);
358 dlg_x
= maxlen
+ strlen (_(widgets
[3].text
)) + 5 + 1;
359 widgets
[2].hotkey_pos
= strlen (_(widgets
[3].text
)); /* input field length */
360 dlg_x
= min (COLS
, dlg_x
);
364 widgets
[1].relative_x
= i
;
365 widgets
[0].relative_x
= i
+ strlen (_(widgets
[1].text
)) + i
+ 4;
367 widgets
[2].relative_x
= widgets
[3].relative_x
= maxlen
+ 2;
369 for (i
= 0; i
< sizeof (widgets
)/sizeof (widgets
[0]); i
++)
370 widgets
[i
].x_divisions
= dlg_x
;
373 widgets
[2].text
= option_backup_ext
;
374 widgets
[4].value
= option_save_mode
;
375 if (quick_dialog (&dialog
) != B_ENTER
)
377 option_save_mode
= save_mode_new
;
378 option_backup_ext
= str_result
; /* this is a memory leak */
379 option_backup_ext_int
= 0;
380 str_result
[min (strlen (str_result
), sizeof (int))] = '\0';
381 memcpy ((char *) &option_backup_ext_int
, str_result
, strlen (option_backup_ext
));
384 void edit_split_filename (WEdit
* edit
, const char *f
)
387 free (edit
->filename
);
388 edit
->filename
= (char *) strdup (f
);
391 edit
->dir
= (char *) strdup ("");
394 /* here we want to warn the user of overwriting an existing file, but only if they
395 have made a change to the filename */
396 /* returns 1 on success */
397 int edit_save_as_cmd (WEdit
* edit
)
399 /* This heads the 'Save As' dialog box */
401 int different_filename
= 0;
403 exp
= edit_get_save_file (edit
->dir
, edit
->filename
, _(" Save As "));
404 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
409 edit
->force
|= REDRAW_COMPLETELY
;
412 if (strcmp(catstrs (edit
->dir
, edit
->filename
, 0), exp
)) {
414 different_filename
= 1;
415 if ((file
= open ((char *) exp
, O_RDONLY
)) != -1) { /* the file exists */
417 if (edit_query_dialog2 (_(" Warning "),
418 _(" A file already exists with this name. "),
419 /* Push buttons to over-write the current file, or cancel the operation */
420 _("Overwrite"), _("Cancel"))) {
421 edit
->force
|= REDRAW_COMPLETELY
;
427 if (edit_save_file (edit
, exp
)) {
428 edit_split_filename (edit
, exp
);
431 edit
->delete_file
= 0;
432 if (different_filename
&& !edit
->explicit_syntax
)
433 edit_load_syntax (edit
, 0, 0);
434 edit
->force
|= REDRAW_COMPLETELY
;
438 edit_error_dialog (_(" Save as "), get_sys_error (_(" Error trying to save file. ")));
439 edit
->force
|= REDRAW_COMPLETELY
;
444 edit
->force
|= REDRAW_COMPLETELY
;
448 /* {{{ Macro stuff starts here */
450 int raw_callback (struct Dlg_head
*h
, int key
, int Msg
)
454 attrset (REVERSE_COLOR
);
456 draw_box (h
, 1, 1, h
->lines
- 2, h
->cols
- 2);
458 attrset (COLOR_HOT_NORMAL
);
471 /* gets a raw key from the keyboard. Passing cancel = 1 draws
472 a cancel button thus allowing c-c etc.. Alternatively, cancel = 0
473 will return the next key pressed */
474 int edit_raw_key_query (char *heading
, char *query
, int cancel
)
476 int w
= strlen (query
) + 7;
477 struct Dlg_head
*raw_dlg
= create_dlg (0, 0, 7, w
, dialog_colors
,
479 raw_callback
, "[Raw Key Query]",
481 DLG_CENTER
| DLG_TRYUP
);
482 x_set_dialog_title (raw_dlg
, heading
);
483 raw_dlg
->raw
= 1; /* to return even a tab key */
485 add_widget (raw_dlg
, button_new (4, w
/ 2 - 5, B_CANCEL
, NORMAL_BUTTON
, _("Cancel"), 0, 0, 0));
486 add_widget (raw_dlg
, label_new (3 - cancel
, 2, query
, 0));
487 add_widget (raw_dlg
, input_new (3 - cancel
, w
- 5, INPUT_COLOR
, 2, "", 0));
489 w
= raw_dlg
->ret_value
;
490 destroy_dlg (raw_dlg
);
492 if (w
== XCTRL ('g') || w
== XCTRL ('c') || w
== ESC_CHAR
|| w
== B_CANCEL
)
494 /* hence ctrl-a (=B_CANCEL), ctrl-g, ctrl-c, and Esc are cannot returned */
498 /* creates a macro file if it doesn't exist */
499 static FILE *edit_open_macro_file (const char *r
)
503 filename
= catstrs (home_dir
, MACRO_FILE
, 0);
504 if ((file
= open (filename
, O_CREAT
| O_RDWR
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
507 return fopen (filename
, r
);
510 #define MAX_MACROS 1024
511 static int saved_macro
[MAX_MACROS
+ 1];
512 static int saved_macros_loaded
= 0;
515 This is just to stop the macro file be loaded over and over for keys
516 that aren't defined to anything. On slow systems this could be annoying.
518 int macro_exists (int k
)
521 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++)
522 if (saved_macro
[i
] == k
)
527 /* returns 1 on error */
528 int edit_delete_macro (WEdit
* edit
, int k
)
530 struct macro macro
[MAX_MACRO_LENGTH
];
534 if (saved_macros_loaded
)
535 if ((j
= macro_exists (k
)) < 0)
537 g
= fopen (catstrs (home_dir
, TEMP_FILE
, 0), "w");
539 /* This heads the delete macro error dialog box */
540 edit_error_dialog (_(" Delete macro "),
541 /* 'Open' = load temp file */
542 get_sys_error (_(" Error trying to open temp file ")));
545 f
= edit_open_macro_file ("r");
547 /* This heads the delete macro error dialog box */
548 edit_error_dialog (_(" Delete macro "),
549 /* 'Open' = load temp file */
550 get_sys_error (_(" Error trying to open macro file ")));
555 n
= fscanf (f
, ("key '%d 0': "), &s
);
559 while (fscanf (f
, "%hd %hd, ", ¯o
[n
].command
, ¯o
[n
].ch
))
563 fprintf (g
, ("key '%d 0': "), s
);
564 for (i
= 0; i
< n
; i
++)
565 fprintf (g
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
571 if (rename (catstrs (home_dir
, TEMP_FILE
, 0), catstrs (home_dir
, MACRO_FILE
, 0)) == -1) {
572 /* This heads the delete macro error dialog box */
573 edit_error_dialog (_(" Delete macro "),
574 get_sys_error (_(" Error trying to overwrite macro file ")));
577 if (saved_macros_loaded
)
578 memmove (saved_macro
+ j
, saved_macro
+ j
+ 1, sizeof (int) * (MAX_MACROS
- j
- 1));
582 /* returns 0 on error */
583 int edit_save_macro_cmd (WEdit
* edit
, struct macro macro
[], int n
)
588 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
589 /* This heads the 'Macro' dialog box */
590 s
= edit_raw_key_query (_(" Macro "),
591 /* Input line for a single key press follows the ':' */
592 _(" Press the macro's new hotkey: "), 1);
593 edit
->force
|= REDRAW_COMPLETELY
;
595 if (edit_delete_macro (edit
, s
))
597 f
= edit_open_macro_file ("a+");
599 fprintf (f
, ("key '%d 0': "), s
);
600 for (i
= 0; i
< n
; i
++)
601 fprintf (f
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
604 if (saved_macros_loaded
) {
605 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++);
610 /* This heads the 'Save Macro' dialog box */
611 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Error trying to open macro file ")));
616 void edit_delete_macro_cmd (WEdit
* edit
)
620 command
= edit_raw_key_query (_ (" Delete Macro "),
621 _ (" Press macro hotkey: "), 1);
626 edit_delete_macro (edit
, command
);
629 /* return 0 on error */
630 int edit_load_macro_cmd (WEdit
* edit
, struct macro macro
[], int *n
, int k
)
633 int s
, i
= 0, found
= 0;
635 if (saved_macros_loaded
)
636 if (macro_exists (k
) < 0)
639 if ((f
= edit_open_macro_file ("r"))) {
643 u
= fscanf (f
, ("key '%d 0': "), &s
);
646 if (!saved_macros_loaded
)
647 saved_macro
[i
++] = s
;
650 while (*n
< MAX_MACRO_LENGTH
&& 2 == fscanf (f
, "%hd %hd, ", ¯o
[*n
].command
, ¯o
[*n
].ch
))
653 while (2 == fscanf (f
, "%hd %hd, ", &dummy
.command
, &dummy
.ch
));
658 } while (!found
|| !saved_macros_loaded
);
659 if (!saved_macros_loaded
) {
661 saved_macros_loaded
= 1;
666 /* This heads the 'Load Macro' dialog box */
667 edit_error_dialog (_(" Load macro "),
668 get_sys_error (_(" Error trying to open macro file ")));
672 /* }}} Macro stuff starts here */
674 /* returns 1 on success */
675 int edit_save_confirm_cmd (WEdit
* edit
)
679 if (edit_confirm_save
) {
680 f
= catstrs (_(" Confirm save file? : "), edit
->filename
, " ", 0);
681 /* Buttons to 'Confirm save file' query */
682 if (edit_query_dialog2 (_(" Save file "), f
, _("Save"), _("Cancel")))
685 return edit_save_cmd (edit
);
689 /* returns 1 on success */
690 int edit_save_cmd (WEdit
* edit
)
692 if (!edit_save_file (edit
, catstrs (edit
->dir
, edit
->filename
, 0)))
693 return edit_save_as_cmd (edit
);
694 edit
->force
|= REDRAW_COMPLETELY
;
696 edit
->delete_file
= 0;
702 /* returns 1 on success */
703 int edit_new_cmd (WEdit
* edit
)
705 if (edit
->modified
) {
706 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
707 edit
->force
|= REDRAW_COMPLETELY
;
711 edit
->force
|= REDRAW_COMPLETELY
;
713 return edit_renew (edit
); /* if this gives an error, something has really screwed up */
716 /* returns 1 on error */
717 int edit_load_file_from_filename (WEdit
* edit
, char *exp
)
719 if (!edit_reload (edit
, exp
, 0, "", 0))
721 edit_split_filename (edit
, exp
);
726 int edit_load_cmd (WEdit
* edit
)
730 if (edit
->modified
) {
731 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
732 edit
->force
|= REDRAW_COMPLETELY
;
737 exp
= edit_get_load_file (edit
->dir
, edit
->filename
, _ (" Load "));
741 edit_load_file_from_filename (edit
, exp
);
744 edit
->force
|= REDRAW_COMPLETELY
;
749 if mark2 is -1 then marking is from mark1 to the cursor.
750 Otherwise its between the markers. This handles this.
751 Returns 1 if no text is marked.
753 int eval_marks (WEdit
* edit
, long *start_mark
, long *end_mark
)
755 if (edit
->mark1
!= edit
->mark2
) {
756 if (edit
->mark2
>= 0) {
757 *start_mark
= min (edit
->mark1
, edit
->mark2
);
758 *end_mark
= max (edit
->mark1
, edit
->mark2
);
760 *start_mark
= min (edit
->mark1
, edit
->curs1
);
761 *end_mark
= max (edit
->mark1
, edit
->curs1
);
762 edit
->column2
= edit
->curs_col
;
766 *start_mark
= *end_mark
= 0;
767 edit
->column2
= edit
->column1
= 0;
772 /*Block copy, move and delete commands */
773 extern int column_highlighting
;
775 #define space_width 1
777 void edit_insert_column_of_text (WEdit
* edit
, unsigned char *data
, int size
, int width
)
781 cursor
= edit
->curs1
;
782 col
= edit_get_col (edit
);
783 for (i
= 0; i
< size
; i
++) {
784 if (data
[i
] == '\n') { /* fill in and move to next line */
787 if (edit_get_byte (edit
, edit
->curs1
) != '\n') {
788 l
= width
- (edit_get_col (edit
) - col
);
790 edit_insert (edit
, ' ');
794 for (p
= edit
->curs1
;; p
++) {
795 if (p
== edit
->last_byte
)
796 edit_insert_ahead (edit
, '\n');
797 if (edit_get_byte (edit
, p
) == '\n') {
802 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, col
, 0) - edit
->curs1
);
803 l
= col
- edit_get_col (edit
);
804 while (l
>= space_width
) {
805 edit_insert (edit
, ' ');
810 edit_insert (edit
, data
[i
]);
812 edit_cursor_move (edit
, cursor
- edit
->curs1
);
816 void edit_block_copy_cmd (WEdit
* edit
)
818 long start_mark
, end_mark
, current
= edit
->curs1
;
820 unsigned char *copy_buf
;
822 edit_update_curs_col (edit
);
824 if (eval_marks (edit
, &start_mark
, &end_mark
))
826 if (column_highlighting
)
827 if ((x
>= edit
->column1
&& x
< edit
->column2
) || (x
> edit
->column2
&& x
<= edit
->column1
))
830 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
832 /* all that gets pushed are deletes hence little space is used on the stack */
834 edit_push_markers (edit
);
836 if (column_highlighting
) {
837 edit_insert_column_of_text (edit
, copy_buf
, size
, abs (edit
->column2
- edit
->column1
));
840 edit_insert_ahead (edit
, copy_buf
[size
]);
844 edit_scroll_screen_over_cursor (edit
);
846 if (column_highlighting
) {
847 edit_set_markers (edit
, 0, 0, 0, 0);
848 edit_push_action (edit
, COLUMN_ON
);
849 column_highlighting
= 0;
850 } else if (start_mark
< current
&& end_mark
> current
)
851 edit_set_markers (edit
, start_mark
, end_mark
+ end_mark
- start_mark
, 0, 0);
853 edit
->force
|= REDRAW_PAGE
;
857 void edit_block_move_cmd (WEdit
* edit
)
861 unsigned char *copy_buf
;
862 long start_mark
, end_mark
;
866 if (eval_marks (edit
, &start_mark
, &end_mark
))
868 if (column_highlighting
) {
869 edit_update_curs_col (edit
);
871 if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
872 if ((x
> edit
->column1
&& x
< edit
->column2
) || (x
> edit
->column2
&& x
< edit
->column1
))
874 } else if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
877 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
878 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ ("Continue"), _ ("Cancel")))
881 edit_push_markers (edit
);
882 current
= edit
->curs1
;
883 if (column_highlighting
) {
884 int size
, c1
, c2
, line
;
885 line
= edit
->curs_line
;
887 edit_mark_cmd (edit
, 0);
888 c1
= min (edit
->column1
, edit
->column2
);
889 c2
= max (edit
->column1
, edit
->column2
);
890 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
892 edit_block_delete_cmd (edit
);
895 edit_move_to_line (edit
, line
);
896 edit_cursor_move (edit
, edit_move_forward3 (edit
, edit_bol (edit
, edit
->curs1
), x
, 0) - edit
->curs1
);
897 edit_insert_column_of_text (edit
, copy_buf
, size
, c2
- c1
);
899 line
= edit
->curs_line
;
900 edit_update_curs_col (edit
);
902 edit_block_delete_cmd (edit
);
903 edit_move_to_line (edit
, line
);
904 edit_cursor_move (edit
, edit_move_forward3 (edit
, edit_bol (edit
, edit
->curs1
), x
, 0) - edit
->curs1
);
906 edit_set_markers (edit
, 0, 0, 0, 0);
907 edit_push_action (edit
, COLUMN_ON
);
908 column_highlighting
= 0;
910 copy_buf
= malloc (end_mark
- start_mark
);
911 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
912 edit_scroll_screen_over_cursor (edit
);
914 while (count
< end_mark
) {
915 copy_buf
[end_mark
- count
- 1] = edit_delete (edit
);
918 edit_scroll_screen_over_cursor (edit
);
919 edit_cursor_move (edit
, current
- edit
->curs1
- (((current
- edit
->curs1
) > 0) ? end_mark
- start_mark
: 0));
920 edit_scroll_screen_over_cursor (edit
);
921 while (count
-- > start_mark
)
922 edit_insert_ahead (edit
, copy_buf
[end_mark
- count
- 1]);
923 edit_set_markers (edit
, edit
->curs1
, edit
->curs1
+ end_mark
- start_mark
, 0, 0);
925 edit_scroll_screen_over_cursor (edit
);
927 edit
->force
|= REDRAW_PAGE
;
930 void edit_cursor_to_bol (WEdit
* edit
);
932 void edit_delete_column_of_text (WEdit
* edit
)
934 long p
, q
, r
, m1
, m2
;
938 eval_marks (edit
, &m1
, &m2
);
939 n
= edit_move_forward (edit
, m1
, 0, m2
) + 1;
940 c
= edit_move_forward3 (edit
, edit_bol (edit
, m1
), 0, m1
);
941 d
= edit_move_forward3 (edit
, edit_bol (edit
, m2
), 0, m2
);
947 r
= edit_bol (edit
, edit
->curs1
);
948 p
= edit_move_forward3 (edit
, r
, b
, 0);
949 q
= edit_move_forward3 (edit
, r
, c
, 0);
954 edit_cursor_move (edit
, p
- edit
->curs1
);
955 while (q
> p
) { /* delete line between margins */
956 if (edit_get_byte (edit
, edit
->curs1
) != '\n')
960 if (n
) /* move to next line except on the last delete */
961 edit_cursor_move (edit
, edit_move_forward (edit
, edit
->curs1
, 1, 0) - edit
->curs1
);
965 /* if success return 0 */
966 int edit_block_delete (WEdit
* edit
)
969 long start_mark
, end_mark
;
970 if (eval_marks (edit
, &start_mark
, &end_mark
))
972 if (column_highlighting
&& edit
->mark2
< 0)
973 edit_mark_cmd (edit
, 0);
974 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
975 /* Warning message with a query to continue or cancel the operation */
976 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ (" Continue "), _ (" Cancel ")))
978 edit_push_markers (edit
);
979 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
980 edit_scroll_screen_over_cursor (edit
);
982 if (start_mark
< end_mark
) {
983 if (column_highlighting
) {
985 edit_mark_cmd (edit
, 0);
986 edit_delete_column_of_text (edit
);
988 while (count
< end_mark
) {
994 edit_set_markers (edit
, 0, 0, 0, 0);
995 edit
->force
|= REDRAW_PAGE
;
999 /* returns 1 if canceelled by user */
1000 int edit_block_delete_cmd (WEdit
* edit
)
1002 long start_mark
, end_mark
;
1003 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
1004 edit_delete_line (edit
);
1007 return edit_block_delete (edit
);
1011 #define INPUT_INDEX 9
1012 #define SEARCH_DLG_WIDTH 58
1013 #define SEARCH_DLG_HEIGHT 10
1014 #define REPLACE_DLG_WIDTH 58
1015 #define REPLACE_DLG_HEIGHT 15
1016 #define CONFIRM_DLG_WIDTH 79
1017 #define CONFIRM_DLG_HEIGTH 6
1018 #define B_REPLACE_ALL B_USER+1
1019 #define B_REPLACE_ONE B_USER+2
1020 #define B_SKIP_REPLACE B_USER+3
1022 int edit_replace_prompt (WEdit
* edit
, char *replace_text
, int xpos
, int ypos
)
1024 QuickWidget quick_widgets
[] =
1026 {quick_button
, 63, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Cancel"),
1027 0, B_CANCEL
, 0, 0, NULL
},
1028 {quick_button
, 50, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("o&Ne"),
1029 0, B_REPLACE_ONE
, 0, 0, NULL
},
1030 {quick_button
, 37, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("al&L"),
1031 0, B_REPLACE_ALL
, 0, 0, NULL
},
1032 {quick_button
, 21, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Skip"),
1033 0, B_SKIP_REPLACE
, 0, 0, NULL
},
1034 {quick_button
, 4, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Replace"),
1035 0, B_ENTER
, 0, 0, NULL
},
1036 {quick_label
, 2, CONFIRM_DLG_WIDTH
, 2, CONFIRM_DLG_HEIGTH
, 0,
1041 char *msg
= _(" Replace with: ");
1043 quick_widgets
[5].text
= catstrs (msg
, replace_text
, 0);
1046 convert_to_display (quick_widgets
[5].text
+ strlen (msg
));
1048 quick_widgets
[5].text
= catstrs (_ (" Replace with: "), replace_text
, 0);
1049 #endif /* !HAVE_CHARSET */
1052 QuickDialog Quick_input
=
1053 {CONFIRM_DLG_WIDTH
, CONFIRM_DLG_HEIGTH
, 0, 0, N_ (" Confirm replace "),
1054 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1056 Quick_input
.widgets
= quick_widgets
;
1058 Quick_input
.xpos
= xpos
;
1060 /* Sometimes menu can hide replaced text. I don't like it */
1062 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ CONFIRM_DLG_HEIGTH
- 1))
1063 ypos
-= CONFIRM_DLG_HEIGTH
;
1065 Quick_input
.ypos
= ypos
;
1066 return quick_dialog (&Quick_input
);
1070 void edit_replace_dialog (WEdit
* edit
, char **search_text
, char **replace_text
, char **arg_order
)
1072 int treplace_scanf
= replace_scanf
;
1073 int treplace_regexp
= replace_regexp
;
1074 int treplace_all
= replace_all
;
1075 int treplace_prompt
= replace_prompt
;
1076 int treplace_backwards
= replace_backwards
;
1077 int treplace_whole
= replace_whole
;
1078 int treplace_case
= replace_case
;
1080 QuickWidget quick_widgets
[] =
1082 {quick_button
, 6, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1084 {quick_button
, 2, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Ok"), 0, B_ENTER
, 0,
1086 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1088 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("replace &All"), 0, 0,
1090 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("pr&Ompt on replace"), 0, 0,
1092 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1094 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1096 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1098 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 8, REPLACE_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1100 {quick_input
, 3, REPLACE_DLG_WIDTH
, 7, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1102 {quick_label
, 2, REPLACE_DLG_WIDTH
, 6, REPLACE_DLG_HEIGHT
, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1104 {quick_input
, 3, REPLACE_DLG_WIDTH
, 5, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1106 {quick_label
, 2, REPLACE_DLG_WIDTH
, 4, REPLACE_DLG_HEIGHT
, N_(" Enter replacement string:"), 0, 0, 0,
1108 {quick_input
, 3, REPLACE_DLG_WIDTH
, 3, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1110 {quick_label
, 2, REPLACE_DLG_WIDTH
, 2, REPLACE_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1114 quick_widgets
[2].result
= &treplace_scanf
;
1115 quick_widgets
[3].result
= &treplace_all
;
1116 quick_widgets
[4].result
= &treplace_prompt
;
1117 quick_widgets
[5].result
= &treplace_backwards
;
1118 quick_widgets
[6].result
= &treplace_regexp
;
1119 quick_widgets
[7].result
= &treplace_whole
;
1120 quick_widgets
[8].result
= &treplace_case
;
1121 quick_widgets
[9].str_result
= arg_order
;
1122 quick_widgets
[9].text
= *arg_order
;
1123 quick_widgets
[11].str_result
= replace_text
;
1124 quick_widgets
[11].text
= *replace_text
;
1125 quick_widgets
[13].str_result
= search_text
;
1126 quick_widgets
[13].text
= *search_text
;
1128 QuickDialog Quick_input
=
1129 {REPLACE_DLG_WIDTH
, REPLACE_DLG_HEIGHT
, -1, 0, N_(" Replace "),
1130 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1132 Quick_input
.widgets
= quick_widgets
;
1134 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1135 replace_scanf
= treplace_scanf
;
1136 replace_backwards
= treplace_backwards
;
1137 replace_regexp
= treplace_regexp
;
1138 replace_all
= treplace_all
;
1139 replace_prompt
= treplace_prompt
;
1140 replace_whole
= treplace_whole
;
1141 replace_case
= treplace_case
;
1145 *replace_text
= NULL
;
1146 *search_text
= NULL
;
1153 void edit_search_dialog (WEdit
* edit
, char **search_text
)
1155 int treplace_scanf
= replace_scanf
;
1156 int treplace_regexp
= replace_regexp
;
1157 int treplace_whole
= replace_whole
;
1158 int treplace_case
= replace_case
;
1159 int treplace_backwards
= replace_backwards
;
1161 QuickWidget quick_widgets
[] =
1163 {quick_button
, 6, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1165 {quick_button
, 2, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Ok"), 0, B_ENTER
, 0,
1167 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1169 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1171 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1173 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1175 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 4, SEARCH_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1177 {quick_input
, 3, SEARCH_DLG_WIDTH
, 3, SEARCH_DLG_HEIGHT
, "", 52, 0, 0,
1179 {quick_label
, 2, SEARCH_DLG_WIDTH
, 2, SEARCH_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1183 quick_widgets
[2].result
= &treplace_scanf
;
1184 quick_widgets
[3].result
= &treplace_backwards
;
1185 quick_widgets
[4].result
= &treplace_regexp
;
1186 quick_widgets
[5].result
= &treplace_whole
;
1187 quick_widgets
[6].result
= &treplace_case
;
1188 quick_widgets
[7].str_result
= search_text
;
1189 quick_widgets
[7].text
= *search_text
;
1192 QuickDialog Quick_input
=
1193 {SEARCH_DLG_WIDTH
, SEARCH_DLG_HEIGHT
, -1, 0, N_(" Search "),
1194 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1196 Quick_input
.widgets
= quick_widgets
;
1198 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1199 replace_scanf
= treplace_scanf
;
1200 replace_backwards
= treplace_backwards
;
1201 replace_regexp
= treplace_regexp
;
1202 replace_whole
= treplace_whole
;
1203 replace_case
= treplace_case
;
1205 *search_text
= NULL
;
1211 static long sargs
[NUM_REPL_ARGS
][256 / sizeof (long)];
1213 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1214 sargs[4], sargs[5], sargs[6], sargs[7], \
1215 sargs[8], sargs[9], sargs[10], sargs[11], \
1216 sargs[12], sargs[13], sargs[14], sargs[15]
1218 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1219 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1220 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1221 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1224 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1225 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1226 int string_regexp_search (char *pattern
, char *string
, int len
, int match_type
, int match_bol
, int icase
, int *found_len
, void *d
)
1229 static char *old_pattern
= NULL
;
1230 static int old_type
, old_icase
;
1232 static regmatch_t s
[1];
1234 pmatch
= (regmatch_t
*) d
;
1238 if (!old_pattern
|| strcmp (old_pattern
, pattern
) || old_type
!= match_type
|| old_icase
!= icase
) {
1244 if (regcomp (&r
, pattern
, REG_EXTENDED
| (icase
? REG_ICASE
: 0))) {
1248 old_pattern
= (char *) strdup (pattern
);
1249 old_type
= match_type
;
1252 if (regexec (&r
, string
, d
? NUM_REPL_ARGS
: 1, pmatch
, ((match_bol
|| match_type
!= match_normal
) ? 0 : REG_NOTBOL
)) != 0) {
1256 *found_len
= pmatch
[0].rm_eo
- pmatch
[0].rm_so
;
1257 return (pmatch
[0].rm_so
);
1260 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1261 (and the above) routines to work properly - paul */
1263 long edit_find_string (long start
, unsigned char *exp
, int *len
, long last_byte
, int (*get_byte
) (void *, long), void *data
, int once_only
, void *d
)
1266 long l
= strlen ((char *) exp
), f
= 0;
1269 for (p
= 0; p
< l
; p
++) /* count conversions... */
1271 if (exp
[++p
] != '%') /* ...except for "%%" */
1274 if (replace_scanf
|| replace_regexp
) {
1277 unsigned char mbuf
[MAX_REPL_LEN
* 2 + 3];
1279 replace_scanf
= (!replace_regexp
); /* can't have both */
1283 if (replace_scanf
) {
1284 unsigned char e
[MAX_REPL_LEN
];
1285 if (n
>= NUM_REPL_ARGS
)
1289 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++)
1290 buf
[p
- start
] = (*get_byte
) (data
, p
);
1292 for (p
= 0; exp
[p
] != 0; p
++)
1293 exp
[p
] = my_lower_case (exp
[p
]);
1294 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++) {
1295 c
= (*get_byte
) (data
, p
);
1296 buf
[p
- start
] = my_lower_case (c
);
1300 buf
[(q
= p
- start
)] = 0;
1301 strcpy ((char *) e
, (char *) exp
);
1302 strcat ((char *) e
, "%n");
1306 *((int *) sargs
[n
]) = 0; /* --> here was the problem - now fixed: good */
1307 if (n
== sscanf ((char *) buf
, (char *) exp
, SCANF_ARGS
)) {
1308 if (*((int *) sargs
[n
])) {
1309 *len
= *((int *) sargs
[n
]);
1315 if (q
+ start
< last_byte
) {
1317 buf
[q
] = (*get_byte
) (data
, q
+ start
);
1319 c
= (*get_byte
) (data
, q
+ start
);
1320 buf
[q
] = my_lower_case (c
);
1326 buf
++; /* move the window along */
1327 if (buf
== mbuf
+ MAX_REPL_LEN
) { /* the window is about to go past the end of array, so... */
1328 memmove (mbuf
, buf
, strlen ((char *) buf
) + 1); /* reset it */
1333 } else { /* regexp matching */
1335 int found_start
, match_bol
, move_win
= 0;
1337 while (start
+ offset
< last_byte
) {
1338 match_bol
= (offset
== 0 || (*get_byte
) (data
, start
+ offset
- 1) == '\n');
1343 for (; p
< last_byte
&& q
< MAX_REPL_LEN
; p
++, q
++) {
1344 mbuf
[q
] = (*get_byte
) (data
, p
);
1345 if (mbuf
[q
] == '\n')
1354 found_start
= string_regexp_search ((char *) exp
, (char *) buf
, q
, match_normal
, match_bol
, !replace_case
, len
, d
);
1356 if (found_start
<= -2) { /* regcomp/regexec error */
1360 else if (found_start
== -1) /* not found: try next line */
1362 else if (*len
== 0) { /* null pattern: try again at next character */
1369 return (start
+ offset
- q
+ found_start
);
1374 if (buf
[q
- 1] != '\n') { /* incomplete line: try to recover */
1375 buf
= mbuf
+ MAX_REPL_LEN
/ 2;
1376 q
= strlen ((char *) buf
);
1377 memmove (mbuf
, buf
, q
);
1386 *len
= strlen ((char *) exp
);
1388 for (p
= start
; p
<= last_byte
- l
; p
++) {
1389 if ((*get_byte
) (data
, p
) == (unsigned char)exp
[0]) { /* check if first char matches */
1390 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1391 if ((*get_byte
) (data
, q
+ p
) != (unsigned char)exp
[q
])
1400 for (p
= 0; exp
[p
] != 0; p
++)
1401 exp
[p
] = my_lower_case (exp
[p
]);
1403 for (p
= start
; p
<= last_byte
- l
; p
++) {
1404 if (my_lower_case ((*get_byte
) (data
, p
)) == (unsigned char)exp
[0]) {
1405 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1406 if (my_lower_case ((*get_byte
) (data
, q
+ p
)) != (unsigned char)exp
[q
])
1420 long edit_find_forwards (long search_start
, unsigned char *exp
, int *len
, long last_byte
, int (*get_byte
) (void *, long), void *data
, int once_only
, void *d
)
1421 { /*front end to find_string to check for
1426 while ((p
= edit_find_string (p
, exp
, len
, last_byte
, get_byte
, data
, once_only
, d
)) >= 0) {
1427 if (replace_whole
) {
1428 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1429 if (!strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
- 1))
1430 && !strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
+ *len
)))
1438 p
++; /*not a whole word so continue search. */
1443 long edit_find (long search_start
, unsigned char *exp
, int *len
, long last_byte
, int (*get_byte
) (void *, long), void *data
, void *d
)
1446 if (replace_backwards
) {
1447 while (search_start
>= 0) {
1448 p
= edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 1, d
);
1449 if (p
== search_start
)
1454 return edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 0, d
);
1459 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1461 #define snprintf(v) { \
1466 sprintf(s,q1,v,&n); \
1470 /* this function uses the sprintf command to do a vprintf */
1471 /* it takes pointers to arguments instead of the arguments themselves */
1472 static int sprintf_p (char *str
, const char *fmt
,...)
1473 __attribute__ ((format (printf
, 2, 3)));
1475 static int sprintf_p (char *str
, const char *fmt
,...)
1479 char *q
, *p
, *s
= str
;
1484 p
= q
= (char *) fmt
;
1486 while ((p
= strchr (p
, '%'))) {
1487 n
= (int) ((unsigned long) p
- (unsigned long) q
);
1488 strncpy (s
, q
, n
); /* copy stuff between format specifiers */
1516 strcpy (p1
, itoa (*va_arg (ap
, int *))); /* replace field width with a number */
1519 while (is_digit (*p
))
1526 strcpy (p1
, itoa (*va_arg (ap
, int *))); /* replace precision with a number */
1529 while (is_digit (*p
))
1532 /* flags done, now get argument */
1534 snprintf (va_arg (ap
, char *));
1535 } else if (*p
== 'h') {
1536 if (strchr ("diouxX", *p
))
1537 snprintf (*va_arg (ap
, short *));
1538 } else if (*p
== 'l') {
1540 if (strchr ("diouxX", *p
))
1541 snprintf (*va_arg (ap
, long *));
1542 } else if (strchr ("cdiouxX", *p
)) {
1543 snprintf (*va_arg (ap
, int *));
1544 } else if (*p
== 'L') {
1546 if (strchr ("EefgG", *p
))
1547 snprintf (*va_arg (ap
, double *)); /* should be long double */
1548 } else if (strchr ("EefgG", *p
)) {
1549 snprintf (*va_arg (ap
, double *));
1550 } else if (strchr ("DOU", *p
)) {
1551 snprintf (*va_arg (ap
, long *));
1552 } else if (*p
== 'p') {
1553 snprintf (*va_arg (ap
, void **));
1558 sprintf (s
, q
); /* print trailing leftover */
1559 return (unsigned long) s
- (unsigned long) str
+ strlen (s
);
1562 static void regexp_error (WEdit
*edit
)
1564 /* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */
1565 edit_error_dialog (_(" Error "), _(" Invalid regular expression, or scanf expression with to many conversions "));
1568 /* call with edit = 0 before shutdown to close memory leaks */
1569 void edit_replace_cmd (WEdit
* edit
, int again
)
1571 static regmatch_t pmatch
[NUM_REPL_ARGS
];
1572 static char *old1
= NULL
;
1573 static char *old2
= NULL
;
1574 static char *old3
= NULL
;
1579 int replace_continue
;
1580 int treplace_prompt
= 0;
1582 long times_replaced
= 0, last_search
;
1583 char fin_string
[64];
1584 int argord
[NUM_REPL_ARGS
];
1601 last_search
= edit
->last_byte
;
1603 edit
->force
|= REDRAW_COMPLETELY
;
1605 exp1
= old1
? old1
: exp1
;
1606 exp2
= old2
? old2
: exp2
;
1607 exp3
= old3
? old3
: exp3
;
1612 exp1
= g_strdup (old1
);
1613 exp2
= g_strdup (old2
);
1614 exp3
= g_strdup (old3
);
1616 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1620 convert_to_display (exp1
);
1622 convert_to_display (exp2
);
1623 #endif /* HAVE_CHARSET */
1625 edit_replace_dialog (edit
, &exp1
, &exp2
, &exp3
);
1629 convert_from_input (exp1
);
1631 convert_from_input (exp2
);
1632 #endif /* HAVE_CHARSET */
1634 treplace_prompt
= replace_prompt
;
1637 if (!exp1
|| !*exp1
) {
1638 edit
->force
= REDRAW_COMPLETELY
;
1653 old1
= g_strdup (exp1
);
1654 old2
= g_strdup (exp2
);
1655 old3
= g_strdup (exp3
);
1660 while ((s
= strchr (exp3
, ' ')))
1661 memmove (s
, s
+ 1, strlen (s
));
1663 for (i
= 0; i
< NUM_REPL_ARGS
; i
++) {
1664 if (s
!= (char *)1 && *s
) {
1666 if ((ord
> 0) && (ord
< NUM_REPL_ARGS
))
1667 argord
[i
] = ord
- 1;
1670 s
= strchr (s
, ',') + 1;
1676 replace_continue
= replace_all
;
1678 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
1679 edit
->search_start
--;
1681 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
1682 edit
->search_start
++;
1687 new_start
= edit_find (edit
->search_start
, (unsigned char *) exp1
, &len
, last_search
,
1688 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, pmatch
);
1689 if (new_start
== -3) {
1690 regexp_error (edit
);
1693 edit
->search_start
= new_start
;
1694 /*returns negative on not found or error in pattern */
1696 if (edit
->search_start
>= 0) {
1697 edit
->found_start
= edit
->search_start
;
1698 i
= edit
->found_len
= len
;
1700 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1701 edit_scroll_screen_over_cursor (edit
);
1705 if (treplace_prompt
) {
1707 l
= edit
->curs_row
- edit
->num_widget_lines
/ 3;
1709 edit_scroll_downward (edit
, l
);
1711 edit_scroll_upward (edit
, -l
);
1713 edit_scroll_screen_over_cursor (edit
);
1714 edit
->force
|= REDRAW_PAGE
;
1715 edit_render_keypress (edit
);
1717 /*so that undo stops at each query */
1718 edit_push_key_press (edit
);
1720 switch (edit_replace_prompt (edit
, exp2
, /* and prompt 2/3 down */
1721 (edit
->num_widget_columns
- CONFIRM_DLG_WIDTH
)/2,
1722 edit
->num_widget_lines
* 2 / 3)) {
1725 case B_SKIP_REPLACE
:
1729 treplace_prompt
= 0;
1730 replace_continue
= 1;
1733 replace_continue
= 0;
1737 replace_continue
= 0;
1741 if (replace_yes
) { /* delete then insert new */
1742 if (replace_scanf
|| replace_regexp
) {
1743 char repl_str
[MAX_REPL_LEN
+ 2];
1744 if (replace_regexp
) { /* we need to fill in sargs just like with scanf */
1746 for (k
= 1; k
< NUM_REPL_ARGS
&& pmatch
[k
].rm_eo
>= 0; k
++) {
1748 t
= (unsigned char *) &sargs
[k
- 1][0];
1749 for (j
= 0; j
< pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
&& j
< 255; j
++, t
++)
1750 *t
= (unsigned char) edit_get_byte (edit
, edit
->search_start
- pmatch
[0].rm_so
+ pmatch
[k
].rm_so
+ j
);
1753 for (; k
<= NUM_REPL_ARGS
; k
++)
1754 sargs
[k
- 1][0] = 0;
1756 if (sprintf_p (repl_str
, exp2
, PRINTF_ARGS
) >= 0) {
1760 while (repl_str
[++i
])
1761 edit_insert (edit
, repl_str
[i
]);
1763 edit_error_dialog (_ (" Replace "),
1764 /* "Invalid regexp string or scanf string" */
1765 _ (" Error in replacement format string. "));
1766 replace_continue
= 0;
1773 edit_insert (edit
, exp2
[i
]);
1775 edit
->found_len
= i
;
1777 /* so that we don't find the same string again */
1778 if (replace_backwards
) {
1779 last_search
= edit
->search_start
;
1780 edit
->search_start
--;
1782 edit
->search_start
+= i
;
1783 last_search
= edit
->last_byte
;
1785 edit_scroll_screen_over_cursor (edit
);
1787 edit
->search_start
= edit
->curs1
; /* try and find from right here for next search */
1788 edit_update_curs_col (edit
);
1790 edit
->force
|= REDRAW_PAGE
;
1791 edit_render_keypress (edit
);
1792 if (times_replaced
) {
1793 sprintf (fin_string
, _ (" %ld replacements made. "), times_replaced
);
1794 edit_message_dialog (_ (" Replace "), fin_string
);
1796 edit_message_dialog (_ (" Replace "), _ (" Search string not found. "));
1797 replace_continue
= 0;
1799 } while (replace_continue
);
1804 edit
->force
= REDRAW_COMPLETELY
;
1805 edit_scroll_screen_over_cursor (edit
);
1811 void edit_search_cmd (WEdit
* edit
, int again
)
1813 static char *old
= NULL
;
1823 exp
= old
? old
: exp
;
1824 if (again
) { /*ctrl-hotkey for search again. */
1827 exp
= (char *) g_strdup (old
);
1832 convert_to_display (exp
);
1833 #endif /* HAVE_CHARSET */
1835 edit_search_dialog (edit
, &exp
);
1839 convert_from_input (exp
);
1840 #endif /* HAVE_CHARSET */
1842 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1850 old
= (char *) g_strdup (exp
);
1852 if (search_create_bookmark
) {
1853 int found
= 0, books
= 0;
1854 int l
= 0, l_last
= -1;
1857 p
= edit_find (q
, (unsigned char *) exp
, &len
, edit
->last_byte
,
1858 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, 0);
1862 l
+= edit_count_lines (edit
, q
, p
);
1864 book_mark_insert (edit
, l
, BOOK_MARK_FOUND_COLOR
);
1871 char fin_string
[64];
1872 /* in response to number of bookmarks added because of string being found %d times */
1873 sprintf (fin_string
, _ (" %d finds made, %d bookmarks added "), found
, books
);
1874 edit_message_dialog (_ (" Search "), fin_string
);
1876 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
1880 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
1881 edit
->search_start
--;
1883 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
1884 edit
->search_start
++;
1886 edit
->search_start
= edit_find (edit
->search_start
, (unsigned char *) exp
, &len
, edit
->last_byte
,
1887 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, 0);
1889 if (edit
->search_start
>= 0) {
1890 edit
->found_start
= edit
->search_start
;
1891 edit
->found_len
= len
;
1893 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1894 edit_scroll_screen_over_cursor (edit
);
1895 if (replace_backwards
)
1896 edit
->search_start
--;
1898 edit
->search_start
++;
1899 } else if (edit
->search_start
== -3) {
1900 edit
->search_start
= edit
->curs1
;
1901 regexp_error (edit
);
1903 edit
->search_start
= edit
->curs1
;
1904 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
1910 edit
->force
|= REDRAW_COMPLETELY
;
1911 edit_scroll_screen_over_cursor (edit
);
1915 /* Real edit only */
1916 void edit_quit_cmd (WEdit
* edit
)
1918 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1920 edit
->force
|= REDRAW_COMPLETELY
;
1921 if (edit
->modified
) {
1922 switch (edit_query_dialog3 (_ (" Quit "), _ (" File was modified, Save with exit? "), _ ("Cancel quit"), _ ("&Yes"), _ ("&No"))) {
1924 edit_push_markers (edit
);
1925 edit_set_markers (edit
, 0, 0, 0, 0);
1926 if (!edit_save_cmd (edit
))
1930 if (edit
->delete_file
)
1931 unlink (catstrs (edit
->dir
, edit
->filename
, 0));
1938 else if (edit
->delete_file
)
1939 unlink (catstrs (edit
->dir
, edit
->filename
, 0));
1940 dlg_stop (edit
->widget
.parent
);
1943 #define TEMP_BUF_LEN 1024
1945 /* returns a null terminated length of text. Result must be free'd */
1946 unsigned char *edit_get_block (WEdit
* edit
, long start
, long finish
, int *l
)
1948 unsigned char *s
, *r
;
1949 r
= s
= malloc (finish
- start
+ 1);
1950 if (column_highlighting
) {
1952 while (start
< finish
) { /* copy from buffer, excluding chars that are out of the column 'margins' */
1954 x
= edit_move_forward3 (edit
, edit_bol (edit
, start
), 0, start
);
1955 c
= edit_get_byte (edit
, start
);
1956 if ((x
>= edit
->column1
&& x
< edit
->column2
)
1957 || (x
>= edit
->column2
&& x
< edit
->column1
) || c
== '\n') {
1964 *l
= finish
- start
;
1965 while (start
< finish
)
1966 *s
++ = edit_get_byte (edit
, start
++);
1972 /* save block, returns 1 on success */
1973 int edit_save_block (WEdit
* edit
, const char *filename
, long start
, long finish
)
1977 if ((file
= open ((char *) filename
, O_CREAT
| O_WRONLY
| O_TRUNC
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
1980 if (column_highlighting
) {
1981 unsigned char *block
, *p
;
1983 p
= block
= edit_get_block (edit
, start
, finish
, &len
);
1985 r
= write (file
, p
, len
);
1995 len
= finish
- start
;
1996 buf
= malloc (TEMP_BUF_LEN
);
1997 while (start
!= finish
) {
1998 end
= min (finish
, start
+ TEMP_BUF_LEN
);
1999 for (; i
< end
; i
++)
2000 buf
[i
- start
] = edit_get_byte (edit
, i
);
2001 len
-= write (file
, (char *) buf
, end
- start
);
2012 /* copies a block to clipboard file */
2013 static int edit_save_block_to_clip_file (WEdit
* edit
, long start
, long finish
)
2015 return edit_save_block (edit
, catstrs (home_dir
, CLIP_FILE
, 0), start
, finish
);
2019 void edit_paste_from_history (WEdit
*edit
)
2023 int edit_copy_to_X_buf_cmd (WEdit
* edit
)
2025 long start_mark
, end_mark
;
2026 if (eval_marks (edit
, &start_mark
, &end_mark
))
2028 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2029 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2032 edit_mark_cmd (edit
, 1);
2036 int edit_cut_to_X_buf_cmd (WEdit
* edit
)
2038 long start_mark
, end_mark
;
2039 if (eval_marks (edit
, &start_mark
, &end_mark
))
2041 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2042 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2045 edit_block_delete_cmd (edit
);
2046 edit_mark_cmd (edit
, 1);
2050 void edit_paste_from_X_buf_cmd (WEdit
* edit
)
2052 edit_insert_file (edit
, catstrs (home_dir
, CLIP_FILE
, 0));
2056 void edit_goto_cmd (WEdit
*edit
)
2061 sprintf (s
, "%d", l
);
2062 f
= input_dialog (_(" Goto line "), _(" Enter line: "), l
? s
: "");
2066 edit_move_display (edit
, l
- edit
->num_widget_lines
/ 2 - 1);
2067 edit_move_to_line (edit
, l
- 1);
2068 edit
->force
|= REDRAW_COMPLETELY
;
2074 /*returns 1 on success */
2075 int edit_save_block_cmd (WEdit
* edit
)
2077 long start_mark
, end_mark
;
2079 if (eval_marks (edit
, &start_mark
, &end_mark
))
2081 exp
= edit_get_save_file (edit
->dir
, catstrs (home_dir
, CLIP_FILE
, 0), _ (" Save Block "));
2082 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2088 if (edit_save_block (edit
, exp
, start_mark
, end_mark
)) {
2090 edit
->force
|= REDRAW_COMPLETELY
;
2094 edit_error_dialog (_ (" Save Block "), get_sys_error (_ (" Error trying to save file. ")));
2098 edit
->force
|= REDRAW_COMPLETELY
;
2103 /* returns 1 on success */
2104 int edit_insert_file_cmd (WEdit
* edit
)
2106 char *exp
= edit_get_load_file (edit
->dir
, catstrs (home_dir
, CLIP_FILE
, 0), _ (" Insert File "));
2107 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2113 if (edit_insert_file (edit
, exp
)) {
2115 edit
->force
|= REDRAW_COMPLETELY
;
2119 edit_error_dialog (_ (" Insert file "), get_sys_error (_ (" Error trying to insert file. ")));
2123 edit
->force
|= REDRAW_COMPLETELY
;
2127 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2128 int edit_sort_cmd (WEdit
* edit
)
2130 static char *old
= 0;
2132 long start_mark
, end_mark
;
2135 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2136 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2139 edit_save_block (edit
, catstrs (home_dir
, BLOCK_FILE
, 0), start_mark
, end_mark
);
2141 exp
= old
? old
: "";
2143 exp
= input_dialog (_(" Run Sort "),
2144 _(" Enter sort options (see manpage) separated by whitespace: "), exp
);
2152 e
= system (catstrs (" sort ", exp
, " ", home_dir
, BLOCK_FILE
, " > ", home_dir
, TEMP_FILE
, 0));
2154 if (e
== -1 || e
== 127) {
2155 edit_error_dialog (_(" Sort "),
2156 get_sys_error (_(" Error trying to execute sort command ")));
2159 sprintf (q
, "%d ", e
);
2160 edit_error_dialog (_(" Sort "),
2161 catstrs (_(" Sort returned non-zero: "), q
, 0));
2166 edit
->force
|= REDRAW_COMPLETELY
;
2168 if (edit_block_delete_cmd (edit
))
2170 edit_insert_file (edit
, catstrs (home_dir
, TEMP_FILE
, 0));
2174 /* if block is 1, a block must be highlighted and the shell command
2175 processes it. If block is 0 the shell command is a straight system
2176 command, that just produces some output which is to be inserted */
2177 void edit_block_process_cmd (WEdit
* edit
, const char *shell_cmd
, int block
)
2179 long start_mark
, end_mark
;
2182 FILE *script_home
= NULL
;
2183 FILE *script_src
= NULL
;
2184 FILE *block_file
= NULL
;
2186 char *o
= catstrs (mc_home
, shell_cmd
, 0); /* original source script */
2187 char *h
= catstrs (home_dir
, EDIT_DIR
, shell_cmd
, 0); /* home script */
2188 char *b
= catstrs (home_dir
, BLOCK_FILE
, 0); /* block file */
2189 char *e
= catstrs (home_dir
, ERROR_FILE
, 0); /* error file */
2191 if (! (script_home
= fopen (h
, "r"))) {
2192 if (! (script_home
= fopen (h
, "w"))) {
2193 edit_error_dialog ("",
2194 get_sys_error (catstrs (_ ("Error create script:"), h
, 0)));
2197 if (! (script_src
= fopen (o
, "r"))) {
2198 fclose (script_home
); unlink (h
);
2199 edit_error_dialog ("",
2200 get_sys_error (catstrs (_ ("Error read script:"), o
, 0)));
2203 while (fgets(buf
, sizeof(buf
), script_src
))
2204 fputs (buf
, script_home
);
2205 if (fclose(script_home
)) {
2206 edit_error_dialog ("",
2207 get_sys_error (catstrs (_ ("Error close script:"), h
, 0)));
2211 edit_error_dialog ("",
2212 get_sys_error (catstrs (_ ("Script created:"), h
, 0)));
2217 if (block
) { /* for marked block run indent formatter */
2218 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2219 edit_error_dialog (_("Process block"),
2220 _(" You must first highlight a block of text. "));
2223 edit_save_block (edit
, b
, start_mark
, end_mark
);
2227 * Initial space is to avoid polluting bash history.
2229 * $1 - name of the edited file (to check its extention etc).
2230 * $2 - file containing the current block.
2231 * $3 - file where error messages should be put.
2233 execute (catstrs (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ",
2234 edit
->filename
, " ", home_dir
, BLOCK_FILE
, " ",
2235 home_dir
, ERROR_FILE
, NULL
));
2239 * No block selected, just execute the command for the file.
2241 * $1 - name of the edited file.
2243 execute (catstrs (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ",
2244 edit
->filename
, NULL
));
2247 edit_refresh_cmd (edit
);
2248 edit
->force
|= REDRAW_COMPLETELY
;
2250 /* insert result block */
2252 if (mc_stat (e
, &s
) == 0) {
2253 if (!s
.st_size
) { /* no error messages */
2254 if (edit_block_delete_cmd (edit
))
2256 edit_insert_file (edit
, b
);
2258 edit_insert_file (edit
, e
);
2261 edit_error_dialog ("",
2262 get_sys_error (catstrs (_ ("Error trying to stat file:"), e
, 0)));
2263 edit
->force
|= REDRAW_COMPLETELY
;
2265 if ((block_file
= fopen (b
, "w")))
2266 fclose (block_file
);
2272 /* prints at the cursor */
2273 /* returns the number of chars printed */
2274 int edit_print_string (WEdit
* e
, const char *s
)
2278 edit_execute_cmd (e
, -1, (unsigned char) s
[i
++]);
2279 e
->force
|= REDRAW_COMPLETELY
;
2280 edit_update_screen (e
);
2284 int edit_printf (WEdit
* e
, const char *fmt
,...)
2290 sprintf (s
, fmt
, pa
);
2291 i
= edit_print_string (e
, s
);
2296 /* FIXME: does this function break NT_OS2 ? */
2298 static void pipe_mail (WEdit
*edit
, char *to
, char *subject
, char *cc
)
2303 s
= g_strdup_printf ("mail -s \"%s\" -c \"%s\" \"%s\"", subject
, cc
, to
);
2312 for (i
= 0; i
< edit
->last_byte
; i
++)
2313 fputc (edit_get_byte (edit
, i
), p
);
2318 #define MAIL_DLG_HEIGHT 12
2320 void edit_mail_dialog (WEdit
* edit
)
2323 char *tmail_subject
;
2326 static char *mail_cc_last
= 0;
2327 static char *mail_subject_last
= 0;
2328 static char *mail_to_last
= 0;
2330 QuickDialog Quick_input
=
2331 {50, MAIL_DLG_HEIGHT
, -1, 0, N_(" Mail "),
2332 "[Input Line Keys]", "quick_input", 0};
2334 QuickWidget quick_widgets
[] =
2336 {quick_button
, 6, 10, 9, MAIL_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
2338 {quick_button
, 2, 10, 9, MAIL_DLG_HEIGHT
, N_("&Ok"), 0, B_ENTER
, 0,
2340 {quick_input
, 3, 50, 8, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2341 0, "mail-dlg-input"},
2342 {quick_label
, 2, 50, 7, MAIL_DLG_HEIGHT
, N_(" Copies to"), 0, 0, 0,
2344 {quick_input
, 3, 50, 6, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2345 0, "mail-dlg-input-2"},
2346 {quick_label
, 2, 50, 5, MAIL_DLG_HEIGHT
, N_(" Subject"), 0, 0, 0,
2348 {quick_input
, 3, 50, 4, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2349 0, "mail-dlg-input-3"},
2350 {quick_label
, 2, 50, 3, MAIL_DLG_HEIGHT
, N_(" To"), 0, 0, 0,
2352 {quick_label
, 2, 50, 2, MAIL_DLG_HEIGHT
, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2356 quick_widgets
[2].str_result
= &tmail_cc
;
2357 quick_widgets
[2].text
= mail_cc_last
? mail_cc_last
: "";
2358 quick_widgets
[4].str_result
= &tmail_subject
;
2359 quick_widgets
[4].text
= mail_subject_last
? mail_subject_last
: "";
2360 quick_widgets
[6].str_result
= &tmail_to
;
2361 quick_widgets
[6].text
= mail_to_last
? mail_to_last
: "";
2363 Quick_input
.widgets
= quick_widgets
;
2365 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
2367 g_free (mail_cc_last
);
2368 if (mail_subject_last
)
2369 g_free (mail_subject_last
);
2371 g_free (mail_to_last
);
2372 mail_cc_last
= *(quick_widgets
[2].str_result
);
2373 mail_subject_last
= *(quick_widgets
[4].str_result
);
2374 mail_to_last
= *(quick_widgets
[6].str_result
);
2375 pipe_mail (edit
, mail_to_last
, mail_subject_last
, mail_cc_last
);