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 slashpos
= strrchr (filename
, PATH_SEP
);
206 savedir
= (char *) strdup (filename
);
207 savedir
[slashpos
- filename
+ 1] = '\0';
209 savedir
= (char *) strdup (".");
210 saveprefix
= concat_dir_and_file (savedir
, "cooledit");
212 fd
= mc_mkstemps(&savename
, saveprefix
, NULL
);
217 * FIXME: mc_mkstemps use pure open system call to create temporary file...
218 * This file handle must be close()d, but there is next line in edit.h:
219 * #define close mc_close
220 * So this hack needed.
224 #define close mc_close
226 savename
= g_strdup (filename
);
228 if ((fd
= open (savename
, O_CREAT
| O_WRONLY
| O_TRUNC
| MY_O_TEXT
,
229 edit
->stat1
.st_mode
)) == -1)
232 chmod (savename
, edit
->stat1
.st_mode
);
233 chown (savename
, edit
->stat1
.st_uid
, edit
->stat1
.st_gid
);
236 if ((p
= (char *) edit_get_write_filter (savename
, filename
))) {
240 file
= (FILE *) popen (p
, "w");
243 filelen
= edit_write_stream (edit
, file
);
247 if (pclose (file
) != 0) {
248 edit_error_dialog (_ (" Error "), catstrs (_ (" Error writing to pipe: "), p
, " ", 0));
254 edit_error_dialog (_ (" Error "), get_sys_error (catstrs (_ (" Failed trying to open pipe for writing: "), p
, " ", 0)));
259 #ifdef CR_LF_TRANSLATION
260 } else { /* optimised save */
261 filelen
= edit_write_stream (edit
, f
);
268 filelen
= edit
->last_byte
;
269 while (buf
<= (edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1) {
270 if (write (fd
, (char *) edit
->buffers1
[buf
], EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
276 if (write (fd
, (char *) edit
->buffers1
[buf
], edit
->curs1
& M_EDIT_BUF_SIZE
) != (edit
->curs1
& M_EDIT_BUF_SIZE
)) {
278 } else if (edit
->curs2
) {
280 buf
= (edit
->curs2
>> S_EDIT_BUF_SIZE
);
281 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
)) {
285 if (write (fd
, (char *) edit
->buffers2
[buf
], EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
295 #endif /* !CR_LF_TRANSLATION */
298 if (filelen
!= edit
->last_byte
)
300 if (this_save_mode
== 2)
301 if (rename (filename
, catstrs (filename
, option_backup_ext
, 0)) == -1)
303 if (this_save_mode
> 0)
304 if (rename (savename
, filename
) == -1)
316 I changed this from Oleg's original routine so
317 that option_backup_ext works with coolwidgets as well. This
318 does mean there is a memory leak - paul.
320 void menu_save_mode_cmd (void)
324 static char *str_result
;
325 static int save_mode_new
;
330 N_("Do backups -->")};
331 static QuickWidget widgets
[] =
333 {quick_button
, 18, DLG_X
, 7, DLG_Y
, N_("&Cancel"), 0,
334 B_CANCEL
, 0, 0, "c"},
335 {quick_button
, 6, DLG_X
, 7, DLG_Y
, N_("&Ok"), 0,
337 {quick_input
, 23, DLG_X
, 5, DLG_Y
, 0, 9,
338 0, 0, &str_result
, "edit-backup-ext"},
339 {quick_label
, 22, DLG_X
, 4, DLG_Y
, N_("Extension:"), 0,
340 0, 0, 0, "savemext"},
341 {quick_radio
, 4, DLG_X
, 3, DLG_Y
, "", 3,
342 0, &save_mode_new
, str
, "t"},
344 static QuickDialog dialog
=
345 {DLG_X
, DLG_Y
, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
347 static int i18n_flag
= 0;
355 /* Ok/Cancel buttons */
356 l1
= strlen (_(widgets
[0].text
)) + strlen (_(widgets
[1].text
)) + 5;
357 maxlen
= max (maxlen
, l1
);
359 for (i
= 0; i
< 3; i
++ ) {
361 maxlen
= max (maxlen
, strlen (str
[i
]) + 7);
365 dlg_x
= maxlen
+ strlen (_(widgets
[3].text
)) + 5 + 1;
366 widgets
[2].hotkey_pos
= strlen (_(widgets
[3].text
)); /* input field length */
367 dlg_x
= min (COLS
, dlg_x
);
371 widgets
[1].relative_x
= i
;
372 widgets
[0].relative_x
= i
+ strlen (_(widgets
[1].text
)) + i
+ 4;
374 widgets
[2].relative_x
= widgets
[3].relative_x
= maxlen
+ 2;
376 for (i
= 0; i
< sizeof (widgets
)/sizeof (widgets
[0]); i
++)
377 widgets
[i
].x_divisions
= dlg_x
;
380 widgets
[2].text
= option_backup_ext
;
381 widgets
[4].value
= option_save_mode
;
382 if (quick_dialog (&dialog
) != B_ENTER
)
384 option_save_mode
= save_mode_new
;
385 option_backup_ext
= str_result
; /* this is a memory leak */
386 option_backup_ext_int
= 0;
387 str_result
[min (strlen (str_result
), sizeof (int))] = '\0';
388 memcpy ((char *) &option_backup_ext_int
, str_result
, strlen (option_backup_ext
));
391 void edit_split_filename (WEdit
* edit
, const char *f
)
394 free (edit
->filename
);
395 edit
->filename
= (char *) strdup (f
);
398 edit
->dir
= (char *) strdup ("");
401 /* Here we want to warn the users of overwriting an existing file,
402 but only if they have made a change to the filename */
403 /* returns 1 on success */
404 int edit_save_as_cmd (WEdit
* edit
)
406 /* This heads the 'Save As' dialog box */
408 int different_filename
= 0;
410 exp
= edit_get_save_file (edit
->dir
, edit
->filename
, _(" Save As "));
411 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
416 edit
->force
|= REDRAW_COMPLETELY
;
419 if (strcmp(catstrs (edit
->dir
, edit
->filename
, 0), exp
)) {
421 different_filename
= 1;
422 if ((file
= open ((char *) exp
, O_RDONLY
)) != -1) { /* the file exists */
424 if (edit_query_dialog2 (_(" Warning "),
425 _(" A file already exists with this name. "),
426 /* Push buttons to over-write the current file, or cancel the operation */
427 _("Overwrite"), _("Cancel"))) {
428 edit
->force
|= REDRAW_COMPLETELY
;
434 if (edit_save_file (edit
, exp
)) {
435 edit_split_filename (edit
, exp
);
438 edit
->delete_file
= 0;
439 if (different_filename
&& !edit
->explicit_syntax
)
440 edit_load_syntax (edit
, 0, 0);
441 edit
->force
|= REDRAW_COMPLETELY
;
445 edit_error_dialog (_(" Save as "), get_sys_error (_(" Error trying to save file. ")));
446 edit
->force
|= REDRAW_COMPLETELY
;
451 edit
->force
|= REDRAW_COMPLETELY
;
455 /* {{{ Macro stuff starts here */
457 int raw_callback (struct Dlg_head
*h
, int key
, int Msg
)
461 attrset (REVERSE_COLOR
);
463 draw_box (h
, 1, 1, h
->lines
- 2, h
->cols
- 2);
465 attrset (COLOR_HOT_NORMAL
);
478 /* gets a raw key from the keyboard. Passing cancel = 1 draws
479 a cancel button thus allowing c-c etc.. Alternatively, cancel = 0
480 will return the next key pressed */
481 int edit_raw_key_query (char *heading
, char *query
, int cancel
)
483 int w
= strlen (query
) + 7;
484 struct Dlg_head
*raw_dlg
= create_dlg (0, 0, 7, w
, dialog_colors
,
486 raw_callback
, "[Raw Key Query]",
488 DLG_CENTER
| DLG_TRYUP
);
489 x_set_dialog_title (raw_dlg
, heading
);
490 raw_dlg
->raw
= 1; /* to return even a tab key */
492 add_widget (raw_dlg
, button_new (4, w
/ 2 - 5, B_CANCEL
, NORMAL_BUTTON
, _("Cancel"), 0, 0, 0));
493 add_widget (raw_dlg
, label_new (3 - cancel
, 2, query
, 0));
494 add_widget (raw_dlg
, input_new (3 - cancel
, w
- 5, INPUT_COLOR
, 2, "", 0));
496 w
= raw_dlg
->ret_value
;
497 destroy_dlg (raw_dlg
);
499 if (w
== XCTRL ('g') || w
== XCTRL ('c') || w
== ESC_CHAR
|| w
== B_CANCEL
)
501 /* hence ctrl-a (=B_CANCEL), ctrl-g, ctrl-c, and Esc are cannot returned */
505 /* creates a macro file if it doesn't exist */
506 static FILE *edit_open_macro_file (const char *r
)
510 filename
= catstrs (home_dir
, MACRO_FILE
, 0);
511 if ((file
= open (filename
, O_CREAT
| O_RDWR
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
514 return fopen (filename
, r
);
517 #define MAX_MACROS 1024
518 static int saved_macro
[MAX_MACROS
+ 1];
519 static int saved_macros_loaded
= 0;
522 This is just to stop the macro file be loaded over and over for keys
523 that aren't defined to anything. On slow systems this could be annoying.
525 int macro_exists (int k
)
528 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++)
529 if (saved_macro
[i
] == k
)
534 /* returns 1 on error */
535 int edit_delete_macro (WEdit
* edit
, int k
)
537 struct macro macro
[MAX_MACRO_LENGTH
];
541 if (saved_macros_loaded
)
542 if ((j
= macro_exists (k
)) < 0)
544 g
= fopen (catstrs (home_dir
, TEMP_FILE
, 0), "w");
546 /* This heads the delete macro error dialog box */
547 edit_error_dialog (_(" Delete macro "),
548 /* 'Open' = load temp file */
549 get_sys_error (_(" Error trying to open temp file ")));
552 f
= edit_open_macro_file ("r");
554 /* This heads the delete macro error dialog box */
555 edit_error_dialog (_(" Delete macro "),
556 /* 'Open' = load temp file */
557 get_sys_error (_(" Error trying to open macro file ")));
562 n
= fscanf (f
, ("key '%d 0': "), &s
);
566 while (fscanf (f
, "%hd %hd, ", ¯o
[n
].command
, ¯o
[n
].ch
))
570 fprintf (g
, ("key '%d 0': "), s
);
571 for (i
= 0; i
< n
; i
++)
572 fprintf (g
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
578 if (rename (catstrs (home_dir
, TEMP_FILE
, 0), catstrs (home_dir
, MACRO_FILE
, 0)) == -1) {
579 /* This heads the delete macro error dialog box */
580 edit_error_dialog (_(" Delete macro "),
581 get_sys_error (_(" Error trying to overwrite macro file ")));
584 if (saved_macros_loaded
)
585 memmove (saved_macro
+ j
, saved_macro
+ j
+ 1, sizeof (int) * (MAX_MACROS
- j
- 1));
589 /* returns 0 on error */
590 int edit_save_macro_cmd (WEdit
* edit
, struct macro macro
[], int n
)
595 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
596 /* This heads the 'Macro' dialog box */
597 s
= edit_raw_key_query (_(" Macro "),
598 /* Input line for a single key press follows the ':' */
599 _(" Press the macro's new hotkey: "), 1);
600 edit
->force
|= REDRAW_COMPLETELY
;
602 if (edit_delete_macro (edit
, s
))
604 f
= edit_open_macro_file ("a+");
606 fprintf (f
, ("key '%d 0': "), s
);
607 for (i
= 0; i
< n
; i
++)
608 fprintf (f
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
611 if (saved_macros_loaded
) {
612 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++);
617 /* This heads the 'Save Macro' dialog box */
618 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Error trying to open macro file ")));
623 void edit_delete_macro_cmd (WEdit
* edit
)
627 command
= edit_raw_key_query (_ (" Delete Macro "),
628 _ (" Press macro hotkey: "), 1);
633 edit_delete_macro (edit
, command
);
636 /* return 0 on error */
637 int edit_load_macro_cmd (WEdit
* edit
, struct macro macro
[], int *n
, int k
)
640 int s
, i
= 0, found
= 0;
642 if (saved_macros_loaded
)
643 if (macro_exists (k
) < 0)
646 if ((f
= edit_open_macro_file ("r"))) {
650 u
= fscanf (f
, ("key '%d 0': "), &s
);
653 if (!saved_macros_loaded
)
654 saved_macro
[i
++] = s
;
657 while (*n
< MAX_MACRO_LENGTH
&& 2 == fscanf (f
, "%hd %hd, ", ¯o
[*n
].command
, ¯o
[*n
].ch
))
660 while (2 == fscanf (f
, "%hd %hd, ", &dummy
.command
, &dummy
.ch
));
665 } while (!found
|| !saved_macros_loaded
);
666 if (!saved_macros_loaded
) {
668 saved_macros_loaded
= 1;
673 /* This heads the 'Load Macro' dialog box */
674 edit_error_dialog (_(" Load macro "),
675 get_sys_error (_(" Error trying to open macro file ")));
679 /* }}} Macro stuff starts here */
681 /* returns 1 on success */
682 int edit_save_confirm_cmd (WEdit
* edit
)
686 if (edit_confirm_save
) {
687 f
= catstrs (_(" Confirm save file? : "), edit
->filename
, " ", 0);
688 /* Buttons to 'Confirm save file' query */
689 if (edit_query_dialog2 (_(" Save file "), f
, _("Save"), _("Cancel")))
692 return edit_save_cmd (edit
);
696 /* returns 1 on success */
697 int edit_save_cmd (WEdit
* edit
)
699 if (!edit_save_file (edit
, catstrs (edit
->dir
, edit
->filename
, 0)))
700 return edit_save_as_cmd (edit
);
701 edit
->force
|= REDRAW_COMPLETELY
;
703 edit
->delete_file
= 0;
709 /* returns 1 on success */
710 int edit_new_cmd (WEdit
* edit
)
712 if (edit
->modified
) {
713 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
714 edit
->force
|= REDRAW_COMPLETELY
;
718 edit
->force
|= REDRAW_COMPLETELY
;
720 return edit_renew (edit
); /* if this gives an error, something has really screwed up */
723 /* returns 1 on error */
724 int edit_load_file_from_filename (WEdit
* edit
, char *exp
)
726 if (!edit_reload (edit
, exp
, 0, "", 0))
728 edit_split_filename (edit
, exp
);
733 int edit_load_cmd (WEdit
* edit
)
737 if (edit
->modified
) {
738 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
739 edit
->force
|= REDRAW_COMPLETELY
;
744 exp
= edit_get_load_file (edit
->dir
, edit
->filename
, _ (" Load "));
748 edit_load_file_from_filename (edit
, exp
);
751 edit
->force
|= REDRAW_COMPLETELY
;
756 if mark2 is -1 then marking is from mark1 to the cursor.
757 Otherwise its between the markers. This handles this.
758 Returns 1 if no text is marked.
760 int eval_marks (WEdit
* edit
, long *start_mark
, long *end_mark
)
762 if (edit
->mark1
!= edit
->mark2
) {
763 if (edit
->mark2
>= 0) {
764 *start_mark
= min (edit
->mark1
, edit
->mark2
);
765 *end_mark
= max (edit
->mark1
, edit
->mark2
);
767 *start_mark
= min (edit
->mark1
, edit
->curs1
);
768 *end_mark
= max (edit
->mark1
, edit
->curs1
);
769 edit
->column2
= edit
->curs_col
;
773 *start_mark
= *end_mark
= 0;
774 edit
->column2
= edit
->column1
= 0;
779 /*Block copy, move and delete commands */
780 extern int column_highlighting
;
782 #define space_width 1
784 void edit_insert_column_of_text (WEdit
* edit
, unsigned char *data
, int size
, int width
)
788 cursor
= edit
->curs1
;
789 col
= edit_get_col (edit
);
790 for (i
= 0; i
< size
; i
++) {
791 if (data
[i
] == '\n') { /* fill in and move to next line */
794 if (edit_get_byte (edit
, edit
->curs1
) != '\n') {
795 l
= width
- (edit_get_col (edit
) - col
);
797 edit_insert (edit
, ' ');
801 for (p
= edit
->curs1
;; p
++) {
802 if (p
== edit
->last_byte
)
803 edit_insert_ahead (edit
, '\n');
804 if (edit_get_byte (edit
, p
) == '\n') {
809 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, col
, 0) - edit
->curs1
);
810 l
= col
- edit_get_col (edit
);
811 while (l
>= space_width
) {
812 edit_insert (edit
, ' ');
817 edit_insert (edit
, data
[i
]);
819 edit_cursor_move (edit
, cursor
- edit
->curs1
);
823 void edit_block_copy_cmd (WEdit
* edit
)
825 long start_mark
, end_mark
, current
= edit
->curs1
;
827 unsigned char *copy_buf
;
829 edit_update_curs_col (edit
);
831 if (eval_marks (edit
, &start_mark
, &end_mark
))
833 if (column_highlighting
)
834 if ((x
>= edit
->column1
&& x
< edit
->column2
) || (x
> edit
->column2
&& x
<= edit
->column1
))
837 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
839 /* all that gets pushed are deletes hence little space is used on the stack */
841 edit_push_markers (edit
);
843 if (column_highlighting
) {
844 edit_insert_column_of_text (edit
, copy_buf
, size
, abs (edit
->column2
- edit
->column1
));
847 edit_insert_ahead (edit
, copy_buf
[size
]);
851 edit_scroll_screen_over_cursor (edit
);
853 if (column_highlighting
) {
854 edit_set_markers (edit
, 0, 0, 0, 0);
855 edit_push_action (edit
, COLUMN_ON
);
856 column_highlighting
= 0;
857 } else if (start_mark
< current
&& end_mark
> current
)
858 edit_set_markers (edit
, start_mark
, end_mark
+ end_mark
- start_mark
, 0, 0);
860 edit
->force
|= REDRAW_PAGE
;
864 void edit_block_move_cmd (WEdit
* edit
)
868 unsigned char *copy_buf
;
869 long start_mark
, end_mark
;
873 if (eval_marks (edit
, &start_mark
, &end_mark
))
875 if (column_highlighting
) {
876 edit_update_curs_col (edit
);
878 if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
879 if ((x
> edit
->column1
&& x
< edit
->column2
) || (x
> edit
->column2
&& x
< edit
->column1
))
881 } else if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
884 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
885 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ ("Continue"), _ ("Cancel")))
888 edit_push_markers (edit
);
889 current
= edit
->curs1
;
890 if (column_highlighting
) {
891 int size
, c1
, c2
, line
;
892 line
= edit
->curs_line
;
894 edit_mark_cmd (edit
, 0);
895 c1
= min (edit
->column1
, edit
->column2
);
896 c2
= max (edit
->column1
, edit
->column2
);
897 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
899 edit_block_delete_cmd (edit
);
902 edit_move_to_line (edit
, line
);
903 edit_cursor_move (edit
, edit_move_forward3 (edit
, edit_bol (edit
, edit
->curs1
), x
, 0) - edit
->curs1
);
904 edit_insert_column_of_text (edit
, copy_buf
, size
, c2
- c1
);
906 line
= edit
->curs_line
;
907 edit_update_curs_col (edit
);
909 edit_block_delete_cmd (edit
);
910 edit_move_to_line (edit
, line
);
911 edit_cursor_move (edit
, edit_move_forward3 (edit
, edit_bol (edit
, edit
->curs1
), x
, 0) - edit
->curs1
);
913 edit_set_markers (edit
, 0, 0, 0, 0);
914 edit_push_action (edit
, COLUMN_ON
);
915 column_highlighting
= 0;
917 copy_buf
= malloc (end_mark
- start_mark
);
918 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
919 edit_scroll_screen_over_cursor (edit
);
921 while (count
< end_mark
) {
922 copy_buf
[end_mark
- count
- 1] = edit_delete (edit
);
925 edit_scroll_screen_over_cursor (edit
);
926 edit_cursor_move (edit
, current
- edit
->curs1
- (((current
- edit
->curs1
) > 0) ? end_mark
- start_mark
: 0));
927 edit_scroll_screen_over_cursor (edit
);
928 while (count
-- > start_mark
)
929 edit_insert_ahead (edit
, copy_buf
[end_mark
- count
- 1]);
930 edit_set_markers (edit
, edit
->curs1
, edit
->curs1
+ end_mark
- start_mark
, 0, 0);
932 edit_scroll_screen_over_cursor (edit
);
934 edit
->force
|= REDRAW_PAGE
;
937 void edit_cursor_to_bol (WEdit
* edit
);
939 void edit_delete_column_of_text (WEdit
* edit
)
941 long p
, q
, r
, m1
, m2
;
945 eval_marks (edit
, &m1
, &m2
);
946 n
= edit_move_forward (edit
, m1
, 0, m2
) + 1;
947 c
= edit_move_forward3 (edit
, edit_bol (edit
, m1
), 0, m1
);
948 d
= edit_move_forward3 (edit
, edit_bol (edit
, m2
), 0, m2
);
954 r
= edit_bol (edit
, edit
->curs1
);
955 p
= edit_move_forward3 (edit
, r
, b
, 0);
956 q
= edit_move_forward3 (edit
, r
, c
, 0);
961 edit_cursor_move (edit
, p
- edit
->curs1
);
962 while (q
> p
) { /* delete line between margins */
963 if (edit_get_byte (edit
, edit
->curs1
) != '\n')
967 if (n
) /* move to next line except on the last delete */
968 edit_cursor_move (edit
, edit_move_forward (edit
, edit
->curs1
, 1, 0) - edit
->curs1
);
972 /* if success return 0 */
973 int edit_block_delete (WEdit
* edit
)
976 long start_mark
, end_mark
;
977 if (eval_marks (edit
, &start_mark
, &end_mark
))
979 if (column_highlighting
&& edit
->mark2
< 0)
980 edit_mark_cmd (edit
, 0);
981 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
982 /* Warning message with a query to continue or cancel the operation */
983 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ (" Continue "), _ (" Cancel ")))
985 edit_push_markers (edit
);
986 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
987 edit_scroll_screen_over_cursor (edit
);
989 if (start_mark
< end_mark
) {
990 if (column_highlighting
) {
992 edit_mark_cmd (edit
, 0);
993 edit_delete_column_of_text (edit
);
995 while (count
< end_mark
) {
1001 edit_set_markers (edit
, 0, 0, 0, 0);
1002 edit
->force
|= REDRAW_PAGE
;
1006 /* returns 1 if canceelled by user */
1007 int edit_block_delete_cmd (WEdit
* edit
)
1009 long start_mark
, end_mark
;
1010 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
1011 edit_delete_line (edit
);
1014 return edit_block_delete (edit
);
1018 #define INPUT_INDEX 9
1019 #define SEARCH_DLG_WIDTH 58
1020 #define SEARCH_DLG_HEIGHT 10
1021 #define REPLACE_DLG_WIDTH 58
1022 #define REPLACE_DLG_HEIGHT 15
1023 #define CONFIRM_DLG_WIDTH 79
1024 #define CONFIRM_DLG_HEIGTH 6
1025 #define B_REPLACE_ALL B_USER+1
1026 #define B_REPLACE_ONE B_USER+2
1027 #define B_SKIP_REPLACE B_USER+3
1029 int edit_replace_prompt (WEdit
* edit
, char *replace_text
, int xpos
, int ypos
)
1031 QuickWidget quick_widgets
[] =
1033 {quick_button
, 63, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Cancel"),
1034 0, B_CANCEL
, 0, 0, NULL
},
1035 {quick_button
, 50, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("o&Ne"),
1036 0, B_REPLACE_ONE
, 0, 0, NULL
},
1037 {quick_button
, 37, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("al&L"),
1038 0, B_REPLACE_ALL
, 0, 0, NULL
},
1039 {quick_button
, 21, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Skip"),
1040 0, B_SKIP_REPLACE
, 0, 0, NULL
},
1041 {quick_button
, 4, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Replace"),
1042 0, B_ENTER
, 0, 0, NULL
},
1043 {quick_label
, 2, CONFIRM_DLG_WIDTH
, 2, CONFIRM_DLG_HEIGTH
, 0,
1048 char *msg
= _(" Replace with: ");
1050 quick_widgets
[5].text
= catstrs (msg
, replace_text
, 0);
1053 convert_to_display (quick_widgets
[5].text
+ strlen (msg
));
1055 quick_widgets
[5].text
= catstrs (_ (" Replace with: "), replace_text
, 0);
1056 #endif /* !HAVE_CHARSET */
1059 QuickDialog Quick_input
=
1060 {CONFIRM_DLG_WIDTH
, CONFIRM_DLG_HEIGTH
, 0, 0, N_ (" Confirm replace "),
1061 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1063 Quick_input
.widgets
= quick_widgets
;
1065 Quick_input
.xpos
= xpos
;
1067 /* Sometimes menu can hide replaced text. I don't like it */
1069 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ CONFIRM_DLG_HEIGTH
- 1))
1070 ypos
-= CONFIRM_DLG_HEIGTH
;
1072 Quick_input
.ypos
= ypos
;
1073 return quick_dialog (&Quick_input
);
1077 void edit_replace_dialog (WEdit
* edit
, char **search_text
, char **replace_text
, char **arg_order
)
1079 int treplace_scanf
= replace_scanf
;
1080 int treplace_regexp
= replace_regexp
;
1081 int treplace_all
= replace_all
;
1082 int treplace_prompt
= replace_prompt
;
1083 int treplace_backwards
= replace_backwards
;
1084 int treplace_whole
= replace_whole
;
1085 int treplace_case
= replace_case
;
1087 QuickWidget quick_widgets
[] =
1089 {quick_button
, 6, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1091 {quick_button
, 2, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Ok"), 0, B_ENTER
, 0,
1093 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1095 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("replace &All"), 0, 0,
1097 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("pr&Ompt on replace"), 0, 0,
1099 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1101 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1103 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1105 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 8, REPLACE_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1107 {quick_input
, 3, REPLACE_DLG_WIDTH
, 7, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1109 {quick_label
, 2, REPLACE_DLG_WIDTH
, 6, REPLACE_DLG_HEIGHT
, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1111 {quick_input
, 3, REPLACE_DLG_WIDTH
, 5, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1113 {quick_label
, 2, REPLACE_DLG_WIDTH
, 4, REPLACE_DLG_HEIGHT
, N_(" Enter replacement string:"), 0, 0, 0,
1115 {quick_input
, 3, REPLACE_DLG_WIDTH
, 3, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1117 {quick_label
, 2, REPLACE_DLG_WIDTH
, 2, REPLACE_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1121 quick_widgets
[2].result
= &treplace_scanf
;
1122 quick_widgets
[3].result
= &treplace_all
;
1123 quick_widgets
[4].result
= &treplace_prompt
;
1124 quick_widgets
[5].result
= &treplace_backwards
;
1125 quick_widgets
[6].result
= &treplace_regexp
;
1126 quick_widgets
[7].result
= &treplace_whole
;
1127 quick_widgets
[8].result
= &treplace_case
;
1128 quick_widgets
[9].str_result
= arg_order
;
1129 quick_widgets
[9].text
= *arg_order
;
1130 quick_widgets
[11].str_result
= replace_text
;
1131 quick_widgets
[11].text
= *replace_text
;
1132 quick_widgets
[13].str_result
= search_text
;
1133 quick_widgets
[13].text
= *search_text
;
1135 QuickDialog Quick_input
=
1136 {REPLACE_DLG_WIDTH
, REPLACE_DLG_HEIGHT
, -1, 0, N_(" Replace "),
1137 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1139 Quick_input
.widgets
= quick_widgets
;
1141 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1142 replace_scanf
= treplace_scanf
;
1143 replace_backwards
= treplace_backwards
;
1144 replace_regexp
= treplace_regexp
;
1145 replace_all
= treplace_all
;
1146 replace_prompt
= treplace_prompt
;
1147 replace_whole
= treplace_whole
;
1148 replace_case
= treplace_case
;
1152 *replace_text
= NULL
;
1153 *search_text
= NULL
;
1160 void edit_search_dialog (WEdit
* edit
, char **search_text
)
1162 int treplace_scanf
= replace_scanf
;
1163 int treplace_regexp
= replace_regexp
;
1164 int treplace_whole
= replace_whole
;
1165 int treplace_case
= replace_case
;
1166 int treplace_backwards
= replace_backwards
;
1168 QuickWidget quick_widgets
[] =
1170 {quick_button
, 6, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1172 {quick_button
, 2, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Ok"), 0, B_ENTER
, 0,
1174 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1176 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1178 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1180 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1182 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 4, SEARCH_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1184 {quick_input
, 3, SEARCH_DLG_WIDTH
, 3, SEARCH_DLG_HEIGHT
, "", 52, 0, 0,
1186 {quick_label
, 2, SEARCH_DLG_WIDTH
, 2, SEARCH_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1190 quick_widgets
[2].result
= &treplace_scanf
;
1191 quick_widgets
[3].result
= &treplace_backwards
;
1192 quick_widgets
[4].result
= &treplace_regexp
;
1193 quick_widgets
[5].result
= &treplace_whole
;
1194 quick_widgets
[6].result
= &treplace_case
;
1195 quick_widgets
[7].str_result
= search_text
;
1196 quick_widgets
[7].text
= *search_text
;
1199 QuickDialog Quick_input
=
1200 {SEARCH_DLG_WIDTH
, SEARCH_DLG_HEIGHT
, -1, 0, N_(" Search "),
1201 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1203 Quick_input
.widgets
= quick_widgets
;
1205 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1206 replace_scanf
= treplace_scanf
;
1207 replace_backwards
= treplace_backwards
;
1208 replace_regexp
= treplace_regexp
;
1209 replace_whole
= treplace_whole
;
1210 replace_case
= treplace_case
;
1212 *search_text
= NULL
;
1218 static long sargs
[NUM_REPL_ARGS
][256 / sizeof (long)];
1220 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1221 sargs[4], sargs[5], sargs[6], sargs[7], \
1222 sargs[8], sargs[9], sargs[10], sargs[11], \
1223 sargs[12], sargs[13], sargs[14], sargs[15]
1225 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1226 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1227 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1228 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1231 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1232 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1233 int string_regexp_search (char *pattern
, char *string
, int len
, int match_type
, int match_bol
, int icase
, int *found_len
, void *d
)
1236 static char *old_pattern
= NULL
;
1237 static int old_type
, old_icase
;
1239 static regmatch_t s
[1];
1241 pmatch
= (regmatch_t
*) d
;
1245 if (!old_pattern
|| strcmp (old_pattern
, pattern
) || old_type
!= match_type
|| old_icase
!= icase
) {
1251 if (regcomp (&r
, pattern
, REG_EXTENDED
| (icase
? REG_ICASE
: 0))) {
1255 old_pattern
= (char *) strdup (pattern
);
1256 old_type
= match_type
;
1259 if (regexec (&r
, string
, d
? NUM_REPL_ARGS
: 1, pmatch
, ((match_bol
|| match_type
!= match_normal
) ? 0 : REG_NOTBOL
)) != 0) {
1263 *found_len
= pmatch
[0].rm_eo
- pmatch
[0].rm_so
;
1264 return (pmatch
[0].rm_so
);
1267 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1268 (and the above) routines to work properly - paul */
1270 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
)
1273 long l
= strlen ((char *) exp
), f
= 0;
1276 for (p
= 0; p
< l
; p
++) /* count conversions... */
1278 if (exp
[++p
] != '%') /* ...except for "%%" */
1281 if (replace_scanf
|| replace_regexp
) {
1284 unsigned char mbuf
[MAX_REPL_LEN
* 2 + 3];
1286 replace_scanf
= (!replace_regexp
); /* can't have both */
1290 if (replace_scanf
) {
1291 unsigned char e
[MAX_REPL_LEN
];
1292 if (n
>= NUM_REPL_ARGS
)
1296 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++)
1297 buf
[p
- start
] = (*get_byte
) (data
, p
);
1299 for (p
= 0; exp
[p
] != 0; p
++)
1300 exp
[p
] = my_lower_case (exp
[p
]);
1301 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++) {
1302 c
= (*get_byte
) (data
, p
);
1303 buf
[p
- start
] = my_lower_case (c
);
1307 buf
[(q
= p
- start
)] = 0;
1308 strcpy ((char *) e
, (char *) exp
);
1309 strcat ((char *) e
, "%n");
1313 *((int *) sargs
[n
]) = 0; /* --> here was the problem - now fixed: good */
1314 if (n
== sscanf ((char *) buf
, (char *) exp
, SCANF_ARGS
)) {
1315 if (*((int *) sargs
[n
])) {
1316 *len
= *((int *) sargs
[n
]);
1322 if (q
+ start
< last_byte
) {
1324 buf
[q
] = (*get_byte
) (data
, q
+ start
);
1326 c
= (*get_byte
) (data
, q
+ start
);
1327 buf
[q
] = my_lower_case (c
);
1333 buf
++; /* move the window along */
1334 if (buf
== mbuf
+ MAX_REPL_LEN
) { /* the window is about to go past the end of array, so... */
1335 memmove (mbuf
, buf
, strlen ((char *) buf
) + 1); /* reset it */
1340 } else { /* regexp matching */
1342 int found_start
, match_bol
, move_win
= 0;
1344 while (start
+ offset
< last_byte
) {
1345 match_bol
= (offset
== 0 || (*get_byte
) (data
, start
+ offset
- 1) == '\n');
1350 for (; p
< last_byte
&& q
< MAX_REPL_LEN
; p
++, q
++) {
1351 mbuf
[q
] = (*get_byte
) (data
, p
);
1352 if (mbuf
[q
] == '\n')
1361 found_start
= string_regexp_search ((char *) exp
, (char *) buf
, q
, match_normal
, match_bol
, !replace_case
, len
, d
);
1363 if (found_start
<= -2) { /* regcomp/regexec error */
1367 else if (found_start
== -1) /* not found: try next line */
1369 else if (*len
== 0) { /* null pattern: try again at next character */
1376 return (start
+ offset
- q
+ found_start
);
1381 if (buf
[q
- 1] != '\n') { /* incomplete line: try to recover */
1382 buf
= mbuf
+ MAX_REPL_LEN
/ 2;
1383 q
= strlen ((char *) buf
);
1384 memmove (mbuf
, buf
, q
);
1393 *len
= strlen ((char *) exp
);
1395 for (p
= start
; p
<= last_byte
- l
; p
++) {
1396 if ((*get_byte
) (data
, p
) == (unsigned char)exp
[0]) { /* check if first char matches */
1397 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1398 if ((*get_byte
) (data
, q
+ p
) != (unsigned char)exp
[q
])
1407 for (p
= 0; exp
[p
] != 0; p
++)
1408 exp
[p
] = my_lower_case (exp
[p
]);
1410 for (p
= start
; p
<= last_byte
- l
; p
++) {
1411 if (my_lower_case ((*get_byte
) (data
, p
)) == (unsigned char)exp
[0]) {
1412 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1413 if (my_lower_case ((*get_byte
) (data
, q
+ p
)) != (unsigned char)exp
[q
])
1427 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
)
1428 { /*front end to find_string to check for
1433 while ((p
= edit_find_string (p
, exp
, len
, last_byte
, get_byte
, data
, once_only
, d
)) >= 0) {
1434 if (replace_whole
) {
1435 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1436 if (!strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
- 1))
1437 && !strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
+ *len
)))
1445 p
++; /*not a whole word so continue search. */
1450 long edit_find (long search_start
, unsigned char *exp
, int *len
, long last_byte
, int (*get_byte
) (void *, long), void *data
, void *d
)
1453 if (replace_backwards
) {
1454 while (search_start
>= 0) {
1455 p
= edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 1, d
);
1456 if (p
== search_start
)
1461 return edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 0, d
);
1466 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1468 #define snprintf(v) { \
1473 sprintf(s,q1,v,&n); \
1477 /* this function uses the sprintf command to do a vprintf */
1478 /* it takes pointers to arguments instead of the arguments themselves */
1479 static int sprintf_p (char *str
, const char *fmt
,...)
1480 __attribute__ ((format (printf
, 2, 3)));
1482 static int sprintf_p (char *str
, const char *fmt
,...)
1486 char *q
, *p
, *s
= str
;
1491 p
= q
= (char *) fmt
;
1493 while ((p
= strchr (p
, '%'))) {
1495 strncpy (s
, q
, n
); /* copy stuff between format specifiers */
1523 strcpy (p1
, itoa (*va_arg (ap
, int *))); /* replace field width with a number */
1526 while (is_digit (*p
))
1533 strcpy (p1
, itoa (*va_arg (ap
, int *))); /* replace precision with a number */
1536 while (is_digit (*p
))
1539 /* flags done, now get argument */
1541 snprintf (va_arg (ap
, char *));
1542 } else if (*p
== 'h') {
1543 if (strchr ("diouxX", *p
))
1544 snprintf (*va_arg (ap
, short *));
1545 } else if (*p
== 'l') {
1547 if (strchr ("diouxX", *p
))
1548 snprintf (*va_arg (ap
, long *));
1549 } else if (strchr ("cdiouxX", *p
)) {
1550 snprintf (*va_arg (ap
, int *));
1551 } else if (*p
== 'L') {
1553 if (strchr ("EefgG", *p
))
1554 snprintf (*va_arg (ap
, double *)); /* should be long double */
1555 } else if (strchr ("EefgG", *p
)) {
1556 snprintf (*va_arg (ap
, double *));
1557 } else if (strchr ("DOU", *p
)) {
1558 snprintf (*va_arg (ap
, long *));
1559 } else if (*p
== 'p') {
1560 snprintf (*va_arg (ap
, void **));
1565 sprintf (s
, q
); /* print trailing leftover */
1566 return s
- str
+ strlen (s
);
1569 static void regexp_error (WEdit
*edit
)
1571 /* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */
1572 edit_error_dialog (_(" Error "), _(" Invalid regular expression, or scanf expression with to many conversions "));
1575 /* call with edit = 0 before shutdown to close memory leaks */
1576 void edit_replace_cmd (WEdit
* edit
, int again
)
1578 static regmatch_t pmatch
[NUM_REPL_ARGS
];
1579 static char *old1
= NULL
;
1580 static char *old2
= NULL
;
1581 static char *old3
= NULL
;
1586 int replace_continue
;
1587 int treplace_prompt
= 0;
1589 long times_replaced
= 0, last_search
;
1590 char fin_string
[64];
1591 int argord
[NUM_REPL_ARGS
];
1608 last_search
= edit
->last_byte
;
1610 edit
->force
|= REDRAW_COMPLETELY
;
1612 exp1
= old1
? old1
: exp1
;
1613 exp2
= old2
? old2
: exp2
;
1614 exp3
= old3
? old3
: exp3
;
1619 exp1
= g_strdup (old1
);
1620 exp2
= g_strdup (old2
);
1621 exp3
= g_strdup (old3
);
1623 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1627 convert_to_display (exp1
);
1629 convert_to_display (exp2
);
1630 #endif /* HAVE_CHARSET */
1632 edit_replace_dialog (edit
, &exp1
, &exp2
, &exp3
);
1636 convert_from_input (exp1
);
1638 convert_from_input (exp2
);
1639 #endif /* HAVE_CHARSET */
1641 treplace_prompt
= replace_prompt
;
1644 if (!exp1
|| !*exp1
) {
1645 edit
->force
= REDRAW_COMPLETELY
;
1660 old1
= g_strdup (exp1
);
1661 old2
= g_strdup (exp2
);
1662 old3
= g_strdup (exp3
);
1667 while ((s
= strchr (exp3
, ' ')))
1668 memmove (s
, s
+ 1, strlen (s
));
1670 for (i
= 0; i
< NUM_REPL_ARGS
; i
++) {
1671 if (s
!= (char *)1 && *s
) {
1673 if ((ord
> 0) && (ord
< NUM_REPL_ARGS
))
1674 argord
[i
] = ord
- 1;
1677 s
= strchr (s
, ',') + 1;
1683 replace_continue
= replace_all
;
1685 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
1686 edit
->search_start
--;
1688 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
1689 edit
->search_start
++;
1694 new_start
= edit_find (edit
->search_start
, (unsigned char *) exp1
, &len
, last_search
,
1695 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, pmatch
);
1696 if (new_start
== -3) {
1697 regexp_error (edit
);
1700 edit
->search_start
= new_start
;
1701 /*returns negative on not found or error in pattern */
1703 if (edit
->search_start
>= 0) {
1704 edit
->found_start
= edit
->search_start
;
1705 i
= edit
->found_len
= len
;
1707 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1708 edit_scroll_screen_over_cursor (edit
);
1712 if (treplace_prompt
) {
1714 l
= edit
->curs_row
- edit
->num_widget_lines
/ 3;
1716 edit_scroll_downward (edit
, l
);
1718 edit_scroll_upward (edit
, -l
);
1720 edit_scroll_screen_over_cursor (edit
);
1721 edit
->force
|= REDRAW_PAGE
;
1722 edit_render_keypress (edit
);
1724 /*so that undo stops at each query */
1725 edit_push_key_press (edit
);
1727 switch (edit_replace_prompt (edit
, exp2
, /* and prompt 2/3 down */
1728 (edit
->num_widget_columns
- CONFIRM_DLG_WIDTH
)/2,
1729 edit
->num_widget_lines
* 2 / 3)) {
1732 case B_SKIP_REPLACE
:
1736 treplace_prompt
= 0;
1737 replace_continue
= 1;
1740 replace_continue
= 0;
1744 replace_continue
= 0;
1748 if (replace_yes
) { /* delete then insert new */
1749 if (replace_scanf
|| replace_regexp
) {
1750 char repl_str
[MAX_REPL_LEN
+ 2];
1751 if (replace_regexp
) { /* we need to fill in sargs just like with scanf */
1753 for (k
= 1; k
< NUM_REPL_ARGS
&& pmatch
[k
].rm_eo
>= 0; k
++) {
1755 t
= (unsigned char *) &sargs
[k
- 1][0];
1756 for (j
= 0; j
< pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
&& j
< 255; j
++, t
++)
1757 *t
= (unsigned char) edit_get_byte (edit
, edit
->search_start
- pmatch
[0].rm_so
+ pmatch
[k
].rm_so
+ j
);
1760 for (; k
<= NUM_REPL_ARGS
; k
++)
1761 sargs
[k
- 1][0] = 0;
1763 if (sprintf_p (repl_str
, exp2
, PRINTF_ARGS
) >= 0) {
1767 while (repl_str
[++i
])
1768 edit_insert (edit
, repl_str
[i
]);
1770 edit_error_dialog (_ (" Replace "),
1771 /* "Invalid regexp string or scanf string" */
1772 _ (" Error in replacement format string. "));
1773 replace_continue
= 0;
1780 edit_insert (edit
, exp2
[i
]);
1782 edit
->found_len
= i
;
1784 /* so that we don't find the same string again */
1785 if (replace_backwards
) {
1786 last_search
= edit
->search_start
;
1787 edit
->search_start
--;
1789 edit
->search_start
+= i
;
1790 last_search
= edit
->last_byte
;
1792 edit_scroll_screen_over_cursor (edit
);
1794 edit
->search_start
= edit
->curs1
; /* try and find from right here for next search */
1795 edit_update_curs_col (edit
);
1797 edit
->force
|= REDRAW_PAGE
;
1798 edit_render_keypress (edit
);
1799 if (times_replaced
) {
1800 sprintf (fin_string
, _ (" %ld replacements made. "), times_replaced
);
1801 edit_message_dialog (_ (" Replace "), fin_string
);
1803 edit_message_dialog (_ (" Replace "), _ (" Search string not found. "));
1804 replace_continue
= 0;
1806 } while (replace_continue
);
1811 edit
->force
= REDRAW_COMPLETELY
;
1812 edit_scroll_screen_over_cursor (edit
);
1818 void edit_search_cmd (WEdit
* edit
, int again
)
1820 static char *old
= NULL
;
1830 exp
= old
? old
: exp
;
1831 if (again
) { /*ctrl-hotkey for search again. */
1834 exp
= (char *) g_strdup (old
);
1839 convert_to_display (exp
);
1840 #endif /* HAVE_CHARSET */
1842 edit_search_dialog (edit
, &exp
);
1846 convert_from_input (exp
);
1847 #endif /* HAVE_CHARSET */
1849 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1857 old
= (char *) g_strdup (exp
);
1859 if (search_create_bookmark
) {
1860 int found
= 0, books
= 0;
1861 int l
= 0, l_last
= -1;
1864 p
= edit_find (q
, (unsigned char *) exp
, &len
, edit
->last_byte
,
1865 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, 0);
1869 l
+= edit_count_lines (edit
, q
, p
);
1871 book_mark_insert (edit
, l
, BOOK_MARK_FOUND_COLOR
);
1878 char fin_string
[64];
1879 /* in response to number of bookmarks added because of string being found %d times */
1880 sprintf (fin_string
, _ (" %d finds made, %d bookmarks added "), found
, books
);
1881 edit_message_dialog (_ (" Search "), fin_string
);
1883 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
1887 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
1888 edit
->search_start
--;
1890 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
1891 edit
->search_start
++;
1893 edit
->search_start
= edit_find (edit
->search_start
, (unsigned char *) exp
, &len
, edit
->last_byte
,
1894 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, 0);
1896 if (edit
->search_start
>= 0) {
1897 edit
->found_start
= edit
->search_start
;
1898 edit
->found_len
= len
;
1900 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1901 edit_scroll_screen_over_cursor (edit
);
1902 if (replace_backwards
)
1903 edit
->search_start
--;
1905 edit
->search_start
++;
1906 } else if (edit
->search_start
== -3) {
1907 edit
->search_start
= edit
->curs1
;
1908 regexp_error (edit
);
1910 edit
->search_start
= edit
->curs1
;
1911 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
1917 edit
->force
|= REDRAW_COMPLETELY
;
1918 edit_scroll_screen_over_cursor (edit
);
1922 /* Real edit only */
1923 void edit_quit_cmd (WEdit
* edit
)
1925 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1927 edit
->force
|= REDRAW_COMPLETELY
;
1928 if (edit
->modified
) {
1929 switch (edit_query_dialog3 (_ (" Quit "), _ (" File was modified, Save with exit? "), _ ("Cancel quit"), _ ("&Yes"), _ ("&No"))) {
1931 edit_push_markers (edit
);
1932 edit_set_markers (edit
, 0, 0, 0, 0);
1933 if (!edit_save_cmd (edit
))
1937 if (edit
->delete_file
)
1938 unlink (catstrs (edit
->dir
, edit
->filename
, 0));
1945 else if (edit
->delete_file
)
1946 unlink (catstrs (edit
->dir
, edit
->filename
, 0));
1947 dlg_stop (edit
->widget
.parent
);
1950 #define TEMP_BUF_LEN 1024
1952 /* returns a null terminated length of text. Result must be free'd */
1953 unsigned char *edit_get_block (WEdit
* edit
, long start
, long finish
, int *l
)
1955 unsigned char *s
, *r
;
1956 r
= s
= malloc (finish
- start
+ 1);
1957 if (column_highlighting
) {
1959 while (start
< finish
) { /* copy from buffer, excluding chars that are out of the column 'margins' */
1961 x
= edit_move_forward3 (edit
, edit_bol (edit
, start
), 0, start
);
1962 c
= edit_get_byte (edit
, start
);
1963 if ((x
>= edit
->column1
&& x
< edit
->column2
)
1964 || (x
>= edit
->column2
&& x
< edit
->column1
) || c
== '\n') {
1971 *l
= finish
- start
;
1972 while (start
< finish
)
1973 *s
++ = edit_get_byte (edit
, start
++);
1979 /* save block, returns 1 on success */
1980 int edit_save_block (WEdit
* edit
, const char *filename
, long start
, long finish
)
1984 if ((file
= open ((char *) filename
, O_CREAT
| O_WRONLY
| O_TRUNC
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
1987 if (column_highlighting
) {
1988 unsigned char *block
, *p
;
1990 p
= block
= edit_get_block (edit
, start
, finish
, &len
);
1992 r
= write (file
, p
, len
);
2002 len
= finish
- start
;
2003 buf
= malloc (TEMP_BUF_LEN
);
2004 while (start
!= finish
) {
2005 end
= min (finish
, start
+ TEMP_BUF_LEN
);
2006 for (; i
< end
; i
++)
2007 buf
[i
- start
] = edit_get_byte (edit
, i
);
2008 len
-= write (file
, (char *) buf
, end
- start
);
2019 /* copies a block to clipboard file */
2020 static int edit_save_block_to_clip_file (WEdit
* edit
, long start
, long finish
)
2022 return edit_save_block (edit
, catstrs (home_dir
, CLIP_FILE
, 0), start
, finish
);
2026 void edit_paste_from_history (WEdit
*edit
)
2030 int edit_copy_to_X_buf_cmd (WEdit
* edit
)
2032 long start_mark
, end_mark
;
2033 if (eval_marks (edit
, &start_mark
, &end_mark
))
2035 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2036 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2039 edit_mark_cmd (edit
, 1);
2043 int edit_cut_to_X_buf_cmd (WEdit
* edit
)
2045 long start_mark
, end_mark
;
2046 if (eval_marks (edit
, &start_mark
, &end_mark
))
2048 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2049 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2052 edit_block_delete_cmd (edit
);
2053 edit_mark_cmd (edit
, 1);
2057 void edit_paste_from_X_buf_cmd (WEdit
* edit
)
2059 edit_insert_file (edit
, catstrs (home_dir
, CLIP_FILE
, 0));
2063 void edit_goto_cmd (WEdit
*edit
)
2068 sprintf (s
, "%d", l
);
2069 f
= input_dialog (_(" Goto line "), _(" Enter line: "), l
? s
: "");
2073 edit_move_display (edit
, l
- edit
->num_widget_lines
/ 2 - 1);
2074 edit_move_to_line (edit
, l
- 1);
2075 edit
->force
|= REDRAW_COMPLETELY
;
2081 /*returns 1 on success */
2082 int edit_save_block_cmd (WEdit
* edit
)
2084 long start_mark
, end_mark
;
2086 if (eval_marks (edit
, &start_mark
, &end_mark
))
2088 exp
= edit_get_save_file (edit
->dir
, catstrs (home_dir
, CLIP_FILE
, 0), _ (" Save Block "));
2089 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2095 if (edit_save_block (edit
, exp
, start_mark
, end_mark
)) {
2097 edit
->force
|= REDRAW_COMPLETELY
;
2101 edit_error_dialog (_ (" Save Block "), get_sys_error (_ (" Error trying to save file. ")));
2105 edit
->force
|= REDRAW_COMPLETELY
;
2110 /* returns 1 on success */
2111 int edit_insert_file_cmd (WEdit
* edit
)
2113 char *exp
= edit_get_load_file (edit
->dir
, catstrs (home_dir
, CLIP_FILE
, 0), _ (" Insert File "));
2114 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2120 if (edit_insert_file (edit
, exp
)) {
2122 edit
->force
|= REDRAW_COMPLETELY
;
2126 edit_error_dialog (_ (" Insert file "), get_sys_error (_ (" Error trying to insert file. ")));
2130 edit
->force
|= REDRAW_COMPLETELY
;
2134 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2135 int edit_sort_cmd (WEdit
* edit
)
2137 static char *old
= 0;
2139 long start_mark
, end_mark
;
2142 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2143 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2146 edit_save_block (edit
, catstrs (home_dir
, BLOCK_FILE
, 0), start_mark
, end_mark
);
2148 exp
= old
? old
: "";
2150 exp
= input_dialog (_(" Run Sort "),
2151 _(" Enter sort options (see manpage) separated by whitespace: "), exp
);
2159 e
= system (catstrs (" sort ", exp
, " ", home_dir
, BLOCK_FILE
, " > ", home_dir
, TEMP_FILE
, 0));
2161 if (e
== -1 || e
== 127) {
2162 edit_error_dialog (_(" Sort "),
2163 get_sys_error (_(" Error trying to execute sort command ")));
2166 sprintf (q
, "%d ", e
);
2167 edit_error_dialog (_(" Sort "),
2168 catstrs (_(" Sort returned non-zero: "), q
, 0));
2173 edit
->force
|= REDRAW_COMPLETELY
;
2175 if (edit_block_delete_cmd (edit
))
2177 edit_insert_file (edit
, catstrs (home_dir
, TEMP_FILE
, 0));
2181 /* if block is 1, a block must be highlighted and the shell command
2182 processes it. If block is 0 the shell command is a straight system
2183 command, that just produces some output which is to be inserted */
2184 void edit_block_process_cmd (WEdit
* edit
, const char *shell_cmd
, int block
)
2186 long start_mark
, end_mark
;
2189 FILE *script_home
= NULL
;
2190 FILE *script_src
= NULL
;
2191 FILE *block_file
= NULL
;
2193 char *o
= catstrs (mc_home
, shell_cmd
, 0); /* original source script */
2194 char *h
= catstrs (home_dir
, EDIT_DIR
, shell_cmd
, 0); /* home script */
2195 char *b
= catstrs (home_dir
, BLOCK_FILE
, 0); /* block file */
2196 char *e
= catstrs (home_dir
, ERROR_FILE
, 0); /* error file */
2198 if (! (script_home
= fopen (h
, "r"))) {
2199 if (! (script_home
= fopen (h
, "w"))) {
2200 edit_error_dialog ("",
2201 get_sys_error (catstrs (_ ("Error create script:"), h
, 0)));
2204 if (! (script_src
= fopen (o
, "r"))) {
2205 fclose (script_home
); unlink (h
);
2206 edit_error_dialog ("",
2207 get_sys_error (catstrs (_ ("Error read script:"), o
, 0)));
2210 while (fgets(buf
, sizeof(buf
), script_src
))
2211 fputs (buf
, script_home
);
2212 if (fclose(script_home
)) {
2213 edit_error_dialog ("",
2214 get_sys_error (catstrs (_ ("Error close script:"), h
, 0)));
2218 edit_error_dialog ("",
2219 get_sys_error (catstrs (_ ("Script created:"), h
, 0)));
2224 if (block
) { /* for marked block run indent formatter */
2225 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2226 edit_error_dialog (_("Process block"),
2227 _(" You must first highlight a block of text. "));
2230 edit_save_block (edit
, b
, start_mark
, end_mark
);
2234 * Initial space is to avoid polluting bash history.
2236 * $1 - name of the edited file (to check its extention etc).
2237 * $2 - file containing the current block.
2238 * $3 - file where error messages should be put.
2240 execute (catstrs (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ",
2241 edit
->filename
, " ", home_dir
, BLOCK_FILE
, " ",
2242 home_dir
, ERROR_FILE
, NULL
));
2246 * No block selected, just execute the command for the file.
2248 * $1 - name of the edited file.
2250 execute (catstrs (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ",
2251 edit
->filename
, NULL
));
2254 edit_refresh_cmd (edit
);
2255 edit
->force
|= REDRAW_COMPLETELY
;
2257 /* insert result block */
2259 if (mc_stat (e
, &s
) == 0) {
2260 if (!s
.st_size
) { /* no error messages */
2261 if (edit_block_delete_cmd (edit
))
2263 edit_insert_file (edit
, b
);
2265 edit_insert_file (edit
, e
);
2268 edit_error_dialog ("",
2269 get_sys_error (catstrs (_ ("Error trying to stat file:"), e
, 0)));
2270 edit
->force
|= REDRAW_COMPLETELY
;
2272 if ((block_file
= fopen (b
, "w")))
2273 fclose (block_file
);
2279 /* prints at the cursor */
2280 /* returns the number of chars printed */
2281 int edit_print_string (WEdit
* e
, const char *s
)
2285 edit_execute_cmd (e
, -1, (unsigned char) s
[i
++]);
2286 e
->force
|= REDRAW_COMPLETELY
;
2287 edit_update_screen (e
);
2291 int edit_printf (WEdit
* e
, const char *fmt
,...)
2297 sprintf (s
, fmt
, pa
);
2298 i
= edit_print_string (e
, s
);
2303 /* FIXME: does this function break NT_OS2 ? */
2305 static void pipe_mail (WEdit
*edit
, char *to
, char *subject
, char *cc
)
2310 s
= g_strdup_printf ("mail -s \"%s\" -c \"%s\" \"%s\"", subject
, cc
, to
);
2319 for (i
= 0; i
< edit
->last_byte
; i
++)
2320 fputc (edit_get_byte (edit
, i
), p
);
2325 #define MAIL_DLG_HEIGHT 12
2327 void edit_mail_dialog (WEdit
* edit
)
2330 char *tmail_subject
;
2333 static char *mail_cc_last
= 0;
2334 static char *mail_subject_last
= 0;
2335 static char *mail_to_last
= 0;
2337 QuickDialog Quick_input
=
2338 {50, MAIL_DLG_HEIGHT
, -1, 0, N_(" Mail "),
2339 "[Input Line Keys]", "quick_input", 0};
2341 QuickWidget quick_widgets
[] =
2343 {quick_button
, 6, 10, 9, MAIL_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
2345 {quick_button
, 2, 10, 9, MAIL_DLG_HEIGHT
, N_("&Ok"), 0, B_ENTER
, 0,
2347 {quick_input
, 3, 50, 8, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2348 0, "mail-dlg-input"},
2349 {quick_label
, 2, 50, 7, MAIL_DLG_HEIGHT
, N_(" Copies to"), 0, 0, 0,
2351 {quick_input
, 3, 50, 6, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2352 0, "mail-dlg-input-2"},
2353 {quick_label
, 2, 50, 5, MAIL_DLG_HEIGHT
, N_(" Subject"), 0, 0, 0,
2355 {quick_input
, 3, 50, 4, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2356 0, "mail-dlg-input-3"},
2357 {quick_label
, 2, 50, 3, MAIL_DLG_HEIGHT
, N_(" To"), 0, 0, 0,
2359 {quick_label
, 2, 50, 2, MAIL_DLG_HEIGHT
, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2363 quick_widgets
[2].str_result
= &tmail_cc
;
2364 quick_widgets
[2].text
= mail_cc_last
? mail_cc_last
: "";
2365 quick_widgets
[4].str_result
= &tmail_subject
;
2366 quick_widgets
[4].text
= mail_subject_last
? mail_subject_last
: "";
2367 quick_widgets
[6].str_result
= &tmail_to
;
2368 quick_widgets
[6].text
= mail_to_last
? mail_to_last
: "";
2370 Quick_input
.widgets
= quick_widgets
;
2372 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
2374 g_free (mail_cc_last
);
2375 if (mail_subject_last
)
2376 g_free (mail_subject_last
);
2378 g_free (mail_to_last
);
2379 mail_cc_last
= *(quick_widgets
[2].str_result
);
2380 mail_subject_last
= *(quick_widgets
[4].str_result
);
2381 mail_to_last
= *(quick_widgets
[6].str_result
);
2382 pipe_mail (edit
, mail_to_last
, mail_subject_last
, mail_cc_last
);