1 /* editor high level editing commands.
3 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007 Free Software Foundation, Inc.
6 Authors: 1996, 1997 Paul Sheer
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
34 #include <sys/types.h>
42 #include "../src/global.h"
46 #include "editcmddef.h"
47 #include "edit-widget.h"
49 #include "../src/color.h" /* dialog_colors */
50 #include "../src/tty.h" /* LINES */
51 #include "../src/widget.h" /* listbox_new() */
52 #include "../src/layout.h" /* clr_scr() */
53 #include "../src/main.h" /* mc_home */
54 #include "../src/help.h" /* interactive_display() */
55 #include "../src/key.h" /* XCTRL */
56 #include "../src/dialog.h" /* do_refresh() */
57 #include "../src/wtools.h" /* message() */
58 #include "../src/charsets.h"
59 #include "../src/selcodepage.h"
68 /* search and replace: */
69 static int replace_scanf
= 0;
70 static int replace_regexp
= 0;
71 static int replace_all
= 0;
72 static int replace_prompt
= 1;
73 static int replace_whole
= 0;
74 static int replace_case
= 0;
75 static int replace_backwards
= 0;
76 static int search_create_bookmark
= 0;
78 /* queries on a save */
79 int edit_confirm_save
= 1;
81 #define NUM_REPL_ARGS 64
82 #define MAX_REPL_LEN 1024
84 static int edit_save_cmd (WEdit
*edit
);
85 static unsigned char *edit_get_block (WEdit
*edit
, long start
,
88 static inline int my_lower_case (int c
)
90 return tolower(c
& 0xFF);
94 strcasechr (const char *s
, int c
)
96 for (c
= my_lower_case (c
); my_lower_case ((int) *s
) != c
; ++s
)
104 static void *memmove (void *dest
, const void *src
, size_t n
)
111 s
= (const char *) src
;
115 t
= (char *) dest
+ n
;
116 s
= (const char *) src
+ n
;
122 #endif /* !HAVE_MEMMOVE */
124 /* #define itoa MY_itoa <---- this line is now in edit.h */
134 } while ((i
= i
/ 10));
140 /* Temporary strings */
141 static char *stacked
[16];
144 This joins strings end on end and allocates memory for the result.
145 The result is later automatically free'd and must not be free'd
149 catstrs (const char *first
,...)
159 len
= strlen (first
);
160 va_start (ap
, first
);
162 while ((data
= va_arg (ap
, char *)) != 0)
163 len
+= strlen (data
);
170 stacked
[i
] = g_malloc (len
);
172 va_start (ap
, first
);
173 strcpy (stacked
[i
], first
);
174 while ((data
= va_arg (ap
, char *)) != 0)
175 strcat (stacked
[i
], data
);
181 /* Free temporary strings */
186 for (i
= 0; i
< sizeof(stacked
) / sizeof(stacked
[0]); i
++) {
192 void edit_help_cmd (WEdit
* edit
)
194 interactive_display (NULL
, "[Internal File Editor]");
195 edit
->force
|= REDRAW_COMPLETELY
;
198 void edit_refresh_cmd (WEdit
* edit
)
206 edit_get_syntax_color (edit
, -1, &color
);
209 #endif /* !HAVE_SLANG */
214 /* If 0 (quick save) then a) create/truncate <filename> file,
215 b) save to <filename>;
216 if 1 (safe save) then a) save to <tempnam>,
217 b) rename <tempnam> to <filename>;
218 if 2 (do backups) then a) save to <tempnam>,
219 b) rename <filename> to <filename.backup_ext>,
220 c) rename <tempnam> to <filename>. */
222 /* returns 0 on error, -1 on abort */
224 edit_save_file (WEdit
*edit
, const char *filename
)
229 int this_save_mode
, fd
= -1;
236 if (*filename
!= PATH_SEP
&& edit
->dir
) {
237 savename
= concat_dir_and_file (edit
->dir
, filename
);
238 filename
= catstrs (savename
, (char *) NULL
);
242 this_save_mode
= option_save_mode
;
243 if (this_save_mode
!= EDIT_QUICK_SAVE
) {
244 if (!vfs_file_is_local (filename
) ||
245 (fd
= mc_open (filename
, O_RDONLY
| O_BINARY
)) == -1) {
247 * The file does not exists yet, so no safe save or
248 * backup are necessary.
250 this_save_mode
= EDIT_QUICK_SAVE
;
256 if (this_save_mode
== EDIT_QUICK_SAVE
&&
257 !edit
->skip_detach_prompt
) {
261 rv
= mc_stat (filename
, &sb
);
262 if (rv
== 0 && sb
.st_nlink
> 1) {
263 rv
= edit_query_dialog3 (_("Warning"),
264 _(" File has hard-links. Detach before saving? "),
265 _("&Yes"), _("&No"), _("&Cancel"));
268 this_save_mode
= EDIT_SAFE_SAVE
;
271 edit
->skip_detach_prompt
= 1;
278 /* Prevent overwriting changes from other editor sessions. */
279 if (rv
== 0 && edit
->stat1
.st_mtime
!= 0 && edit
->stat1
.st_mtime
!= sb
.st_mtime
) {
281 /* The default action is "Cancel". */
284 rv
= edit_query_dialog2 (
286 _("The file has been modified in the meantime. Save anyway?"),
294 if (this_save_mode
!= EDIT_QUICK_SAVE
) {
295 char *savedir
, *saveprefix
;
296 const char *slashpos
;
297 slashpos
= strrchr (filename
, PATH_SEP
);
299 savedir
= g_strdup (filename
);
300 savedir
[slashpos
- filename
+ 1] = '\0';
302 savedir
= g_strdup (".");
303 saveprefix
= concat_dir_and_file (savedir
, "cooledit");
305 fd
= mc_mkstemps (&savename
, saveprefix
, NULL
);
310 * Close for now because mc_mkstemps use pure open system call
311 * to create temporary file and it needs to be reopened by
312 * VFS-aware mc_open().
316 savename
= g_strdup (filename
);
318 mc_chown (savename
, edit
->stat1
.st_uid
, edit
->stat1
.st_gid
);
319 mc_chmod (savename
, edit
->stat1
.st_mode
);
322 mc_open (savename
, O_CREAT
| O_WRONLY
| O_TRUNC
| O_BINARY
,
323 edit
->stat1
.st_mode
)) == -1)
327 if ((p
= edit_get_write_filter (savename
, filename
))) {
331 file
= (FILE *) popen (p
, "w");
334 filelen
= edit_write_stream (edit
, file
);
338 if (pclose (file
) != 0) {
339 edit_error_dialog (_("Error"),
340 catstrs (_(" Error writing to pipe: "),
341 p
, " ", (char *) NULL
));
347 edit_error_dialog (_("Error"),
348 get_sys_error (catstrs
350 (" Cannot open pipe for writing: "),
351 p
, " ", (char *) NULL
)));
359 filelen
= edit
->last_byte
;
360 while (buf
<= (edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1) {
361 if (mc_write (fd
, (char *) edit
->buffers1
[buf
], EDIT_BUF_SIZE
)
369 (fd
, (char *) edit
->buffers1
[buf
],
370 edit
->curs1
& M_EDIT_BUF_SIZE
) !=
371 (edit
->curs1
& M_EDIT_BUF_SIZE
)) {
373 } else if (edit
->curs2
) {
375 buf
= (edit
->curs2
>> S_EDIT_BUF_SIZE
);
378 (char *) edit
->buffers2
[buf
] + EDIT_BUF_SIZE
-
379 (edit
->curs2
& M_EDIT_BUF_SIZE
) - 1,
380 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) !=
381 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) {
386 (fd
, (char *) edit
->buffers2
[buf
],
387 EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
398 /* Update the file information, especially the mtime. */
399 if (mc_stat (savename
, &edit
->stat1
) == -1)
403 if (filelen
!= edit
->last_byte
)
406 if (this_save_mode
== EDIT_DO_BACKUP
) {
407 assert (option_backup_ext
!= NULL
);
408 if (mc_rename (filename
, catstrs (filename
, option_backup_ext
,
409 (char *) NULL
)) == -1)
413 if (this_save_mode
!= EDIT_QUICK_SAVE
)
414 if (mc_rename (savename
, filename
) == -1)
419 /* FIXME: Is this safe ?
420 * if (this_save_mode != EDIT_QUICK_SAVE)
421 * mc_unlink (savename);
427 void menu_save_mode_cmd (void)
431 static char *str_result
;
432 static int save_mode_new
;
433 static const char *str
[] =
437 N_("Do backups -->")};
438 static QuickWidget widgets
[] =
440 {quick_button
, 18, DLG_X
, 7, DLG_Y
, N_("&Cancel"), 0,
441 B_CANCEL
, 0, 0, NULL
},
442 {quick_button
, 6, DLG_X
, 7, DLG_Y
, N_("&OK"), 0,
443 B_ENTER
, 0, 0, NULL
},
444 {quick_input
, 23, DLG_X
, 5, DLG_Y
, 0, 9,
445 0, 0, &str_result
, "edit-backup-ext"},
446 {quick_label
, 22, DLG_X
, 4, DLG_Y
, N_("Extension:"), 0,
448 {quick_radio
, 4, DLG_X
, 3, DLG_Y
, "", 3,
449 0, &save_mode_new
, (char **) str
, NULL
},
451 static QuickDialog dialog
=
452 {DLG_X
, DLG_Y
, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
454 static int i18n_flag
= 0;
462 /* OK/Cancel buttons */
463 l1
= strlen (_(widgets
[0].text
)) + strlen (_(widgets
[1].text
)) + 5;
464 maxlen
= max (maxlen
, l1
);
466 for (i
= 0; i
< 3; i
++ ) {
468 maxlen
= max (maxlen
, strlen (str
[i
]) + 7);
472 dlg_x
= maxlen
+ strlen (_(widgets
[3].text
)) + 5 + 1;
473 widgets
[2].hotkey_pos
= strlen (_(widgets
[3].text
)); /* input field length */
474 dlg_x
= min (COLS
, dlg_x
);
478 widgets
[1].relative_x
= i
;
479 widgets
[0].relative_x
= i
+ strlen (_(widgets
[1].text
)) + i
+ 4;
481 widgets
[2].relative_x
= widgets
[3].relative_x
= maxlen
+ 2;
483 for (i
= 0; i
< sizeof (widgets
)/sizeof (widgets
[0]); i
++)
484 widgets
[i
].x_divisions
= dlg_x
;
487 assert (option_backup_ext
!= NULL
);
488 widgets
[2].text
= option_backup_ext
;
489 widgets
[4].value
= option_save_mode
;
490 if (quick_dialog (&dialog
) != B_ENTER
)
492 option_save_mode
= save_mode_new
;
494 g_free (option_backup_ext
);
495 option_backup_ext
= str_result
;
500 edit_set_filename (WEdit
*edit
, const char *f
)
502 g_free (edit
->filename
);
505 edit
->filename
= g_strdup (f
);
506 if (edit
->dir
== NULL
&& *f
!= PATH_SEP
)
508 edit
->dir
= g_strdup (vfs_get_current_dir ());
510 edit
->dir
= g_get_current_dir ();
514 /* Here we want to warn the users of overwriting an existing file,
515 but only if they have made a change to the filename */
516 /* returns 1 on success */
518 edit_save_as_cmd (WEdit
*edit
)
520 /* This heads the 'Save As' dialog box */
523 int different_filename
= 0;
525 exp
= input_expand_dialog (_(" Save As "), _(" Enter file name: "),
526 ":edit_save_as_cmd: Save As ", edit
->filename
);
527 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
532 edit
->force
|= REDRAW_COMPLETELY
;
536 if (strcmp (edit
->filename
, exp
)) {
538 different_filename
= 1;
539 if ((file
= mc_open (exp
, O_RDONLY
| O_BINARY
)) != -1) {
540 /* the file exists */
542 /* Overwrite the current file or cancel the operation */
543 if (edit_query_dialog2
545 _(" A file already exists with this name. "),
546 _("&Overwrite"), _("&Cancel"))) {
547 edit
->force
|= REDRAW_COMPLETELY
;
552 save_lock
= edit_lock_file (exp
);
554 /* filenames equal, check if already locked */
555 if (!edit
->locked
&& !edit
->delete_file
)
556 save_lock
= edit_lock_file (exp
);
559 rv
= edit_save_file (edit
, exp
);
562 /* Succesful, so unlock both files */
563 if (different_filename
) {
565 edit_unlock_file (exp
);
567 edit
->locked
= edit_unlock_file (edit
->filename
);
569 if (edit
->locked
|| save_lock
)
570 edit
->locked
= edit_unlock_file (edit
->filename
);
573 edit_set_filename (edit
, exp
);
576 edit
->delete_file
= 0;
577 if (different_filename
)
578 edit_load_syntax (edit
, NULL
, option_syntax_type
);
579 edit
->force
|= REDRAW_COMPLETELY
;
582 edit_error_dialog (_(" Save As "),
584 (" Cannot save file. ")));
587 /* Failed, so maintain modify (not save) lock */
589 edit_unlock_file (exp
);
591 edit
->force
|= REDRAW_COMPLETELY
;
596 edit
->force
|= REDRAW_COMPLETELY
;
600 /* {{{ Macro stuff starts here */
603 raw_callback (struct Dlg_head
*h
, dlg_msg_t msg
, int parm
)
611 return default_dlg_callback (h
, msg
, parm
);
615 /* gets a raw key from the keyboard. Passing cancel = 1 draws
616 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
617 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
618 and Esc are cannot returned */
620 edit_raw_key_query (const char *heading
, const char *query
, int cancel
)
622 int w
= strlen (query
) + 7;
623 struct Dlg_head
*raw_dlg
=
624 create_dlg (0, 0, 7, w
, dialog_colors
, raw_callback
,
626 DLG_CENTER
| DLG_TRYUP
| DLG_WANT_TAB
);
628 input_new (3 - cancel
, w
- 5, INPUT_COLOR
, 2, "", 0));
629 add_widget (raw_dlg
, label_new (3 - cancel
, 2, query
));
632 button_new (4, w
/ 2 - 5, B_CANCEL
, NORMAL_BUTTON
,
635 w
= raw_dlg
->ret_value
;
636 destroy_dlg (raw_dlg
);
638 if (w
== XCTRL ('g') || w
== XCTRL ('c') || w
== ESC_CHAR
646 /* creates a macro file if it doesn't exist */
647 static FILE *edit_open_macro_file (const char *r
)
649 const char *filename
;
651 filename
= catstrs (home_dir
, PATH_SEP_STR MACRO_FILE
, (char *) NULL
);
652 if ((file
= open (filename
, O_CREAT
| O_RDWR
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
655 return fopen (filename
, r
);
658 #define MAX_MACROS 1024
659 static int saved_macro
[MAX_MACROS
+ 1];
660 static int saved_macros_loaded
= 0;
663 This is just to stop the macro file be loaded over and over for keys
664 that aren't defined to anything. On slow systems this could be annoying.
670 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++)
671 if (saved_macro
[i
] == k
)
676 /* returns 1 on error */
678 edit_delete_macro (WEdit
* edit
, int k
)
680 struct macro macro
[MAX_MACRO_LENGTH
];
686 if (saved_macros_loaded
)
687 if ((j
= macro_exists (k
)) < 0)
689 g
= fopen (catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
), "w");
691 edit_error_dialog (_(" Delete macro "),
692 get_sys_error (_(" Cannot open temp file ")));
695 f
= edit_open_macro_file ("r");
697 edit_error_dialog (_(" Delete macro "),
698 get_sys_error (_(" Cannot open macro file ")));
703 n
= fscanf (f
, ("key '%d 0': "), &s
);
707 while (fscanf (f
, "%hd %hd, ", ¯o
[n
].command
, ¯o
[n
].ch
))
711 fprintf (g
, ("key '%d 0': "), s
);
712 for (i
= 0; i
< n
; i
++)
713 fprintf (g
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
719 if (rename (catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
), catstrs (home_dir
, PATH_SEP_STR MACRO_FILE
, (char *) NULL
)) == -1) {
720 edit_error_dialog (_(" Delete macro "),
721 get_sys_error (_(" Cannot overwrite macro file ")));
724 if (saved_macros_loaded
)
725 memmove (saved_macro
+ j
, saved_macro
+ j
+ 1, sizeof (int) * (MAX_MACROS
- j
- 1));
729 /* returns 0 on error */
730 int edit_save_macro_cmd (WEdit
* edit
, struct macro macro
[], int n
)
735 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
736 s
= edit_raw_key_query (_(" Save macro "),
737 _(" Press the macro's new hotkey: "), 1);
738 edit
->force
|= REDRAW_COMPLETELY
;
740 if (edit_delete_macro (edit
, s
))
742 f
= edit_open_macro_file ("a+");
744 fprintf (f
, ("key '%d 0': "), s
);
745 for (i
= 0; i
< n
; i
++)
746 fprintf (f
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
749 if (saved_macros_loaded
) {
750 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++);
755 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
760 void edit_delete_macro_cmd (WEdit
* edit
)
764 command
= edit_raw_key_query (_ (" Delete macro "),
765 _ (" Press macro hotkey: "), 1);
770 edit_delete_macro (edit
, command
);
773 /* return 0 on error */
774 int edit_load_macro_cmd (WEdit
* edit
, struct macro macro
[], int *n
, int k
)
777 int s
, i
= 0, found
= 0;
781 if (saved_macros_loaded
)
782 if (macro_exists (k
) < 0)
785 if ((f
= edit_open_macro_file ("r"))) {
789 u
= fscanf (f
, ("key '%d 0': "), &s
);
792 if (!saved_macros_loaded
)
793 saved_macro
[i
++] = s
;
796 while (*n
< MAX_MACRO_LENGTH
&& 2 == fscanf (f
, "%hd %hd, ", ¯o
[*n
].command
, ¯o
[*n
].ch
))
799 while (2 == fscanf (f
, "%hd %hd, ", &dummy
.command
, &dummy
.ch
));
804 } while (!found
|| !saved_macros_loaded
);
805 if (!saved_macros_loaded
) {
807 saved_macros_loaded
= 1;
812 edit_error_dialog (_(" Load macro "),
813 get_sys_error (_(" Cannot open macro file ")));
817 /* }}} Macro stuff starts here */
819 /* returns 1 on success */
820 int edit_save_confirm_cmd (WEdit
* edit
)
824 if (edit_confirm_save
) {
825 f
= catstrs (_(" Confirm save file? : "), edit
->filename
, " ", (char *) NULL
);
826 if (edit_query_dialog2 (_(" Save file "), f
, _("&Save"), _("&Cancel")))
829 return edit_save_cmd (edit
);
833 /* returns 1 on success */
835 edit_save_cmd (WEdit
*edit
)
837 int res
, save_lock
= 0;
839 if (!edit
->locked
&& !edit
->delete_file
)
840 save_lock
= edit_lock_file (edit
->filename
);
841 res
= edit_save_file (edit
, edit
->filename
);
843 /* Maintain modify (not save) lock on failure */
844 if ((res
> 0 && edit
->locked
) || save_lock
)
845 edit
->locked
= edit_unlock_file (edit
->filename
);
847 /* On failure try 'save as', it does locking on its own */
849 return edit_save_as_cmd (edit
);
850 edit
->force
|= REDRAW_COMPLETELY
;
852 edit
->delete_file
= 0;
860 /* returns 1 on success */
861 int edit_new_cmd (WEdit
* edit
)
863 if (edit
->modified
) {
864 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
865 edit
->force
|= REDRAW_COMPLETELY
;
869 edit
->force
|= REDRAW_COMPLETELY
;
871 return edit_renew (edit
); /* if this gives an error, something has really screwed up */
874 /* returns 1 on error */
876 edit_load_file_from_filename (WEdit
* edit
, char *exp
)
878 int prev_locked
= edit
->locked
;
879 char *prev_filename
= g_strdup (edit
->filename
);
881 if (!edit_reload (edit
, exp
)) {
882 g_free (prev_filename
);
887 edit_unlock_file (prev_filename
);
888 g_free (prev_filename
);
893 edit_load_cmd (WEdit
*edit
)
897 if (edit
->modified
) {
898 if (edit_query_dialog2
900 _(" Current text was modified without a file save. \n"
901 " Continue discards these changes. "), _("C&ontinue"),
903 edit
->force
|= REDRAW_COMPLETELY
;
908 exp
= input_expand_dialog (_(" Load "), _(" Enter file name: "),
909 ":edit_load_cmd: Load ", edit
->filename
);
913 edit_load_file_from_filename (edit
, exp
);
916 edit
->force
|= REDRAW_COMPLETELY
;
921 if mark2 is -1 then marking is from mark1 to the cursor.
922 Otherwise its between the markers. This handles this.
923 Returns 1 if no text is marked.
925 int eval_marks (WEdit
* edit
, long *start_mark
, long *end_mark
)
927 if (edit
->mark1
!= edit
->mark2
) {
928 if (edit
->mark2
>= 0) {
929 *start_mark
= min (edit
->mark1
, edit
->mark2
);
930 *end_mark
= max (edit
->mark1
, edit
->mark2
);
932 *start_mark
= min (edit
->mark1
, edit
->curs1
);
933 *end_mark
= max (edit
->mark1
, edit
->curs1
);
934 edit
->column2
= edit
->curs_col
;
938 *start_mark
= *end_mark
= 0;
939 edit
->column2
= edit
->column1
= 0;
944 #define space_width 1
947 edit_insert_column_of_text (WEdit
* edit
, unsigned char *data
, int size
, int width
)
951 cursor
= edit
->curs1
;
952 col
= edit_get_col (edit
);
953 for (i
= 0; i
< size
; i
++) {
954 if (data
[i
] == '\n') { /* fill in and move to next line */
957 if (edit_get_byte (edit
, edit
->curs1
) != '\n') {
958 l
= width
- (edit_get_col (edit
) - col
);
960 edit_insert (edit
, ' ');
964 for (p
= edit
->curs1
;; p
++) {
965 if (p
== edit
->last_byte
) {
966 edit_cursor_move (edit
, edit
->last_byte
- edit
->curs1
);
967 edit_insert_ahead (edit
, '\n');
971 if (edit_get_byte (edit
, p
) == '\n') {
976 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, col
, 0) - edit
->curs1
);
977 l
= col
- edit_get_col (edit
);
978 while (l
>= space_width
) {
979 edit_insert (edit
, ' ');
984 edit_insert (edit
, data
[i
]);
986 edit_cursor_move (edit
, cursor
- edit
->curs1
);
991 edit_block_copy_cmd (WEdit
*edit
)
993 long start_mark
, end_mark
, current
= edit
->curs1
;
995 unsigned char *copy_buf
;
997 edit_update_curs_col (edit
);
998 if (eval_marks (edit
, &start_mark
, &end_mark
))
1001 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
1003 /* all that gets pushed are deletes hence little space is used on the stack */
1005 edit_push_markers (edit
);
1007 if (column_highlighting
) {
1008 edit_insert_column_of_text (edit
, copy_buf
, size
,
1009 abs (edit
->column2
- edit
->column1
));
1012 edit_insert_ahead (edit
, copy_buf
[size
]);
1016 edit_scroll_screen_over_cursor (edit
);
1018 if (column_highlighting
) {
1019 edit_set_markers (edit
, 0, 0, 0, 0);
1020 edit_push_action (edit
, COLUMN_ON
);
1021 column_highlighting
= 0;
1022 } else if (start_mark
< current
&& end_mark
> current
)
1023 edit_set_markers (edit
, start_mark
,
1024 end_mark
+ end_mark
- start_mark
, 0, 0);
1026 edit
->force
|= REDRAW_PAGE
;
1031 edit_block_move_cmd (WEdit
*edit
)
1035 unsigned char *copy_buf
;
1036 long start_mark
, end_mark
;
1040 if (eval_marks (edit
, &start_mark
, &end_mark
))
1042 if (column_highlighting
) {
1043 edit_update_curs_col (edit
);
1045 if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
1046 if ((x
> edit
->column1
&& x
< edit
->column2
)
1047 || (x
> edit
->column2
&& x
< edit
->column1
))
1049 } else if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
1052 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
1053 if (edit_query_dialog2
1056 (" Block is large, you may not be able to undo this action. "),
1057 _("C&ontinue"), _("&Cancel")))
1060 edit_push_markers (edit
);
1061 current
= edit
->curs1
;
1062 if (column_highlighting
) {
1063 int size
, c1
, c2
, line
;
1064 line
= edit
->curs_line
;
1065 if (edit
->mark2
< 0)
1066 edit_mark_cmd (edit
, 0);
1067 c1
= min (edit
->column1
, edit
->column2
);
1068 c2
= max (edit
->column1
, edit
->column2
);
1069 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
1071 edit_block_delete_cmd (edit
);
1074 edit_move_to_line (edit
, line
);
1075 edit_cursor_move (edit
,
1076 edit_move_forward3 (edit
,
1077 edit_bol (edit
, edit
->curs1
),
1078 x
, 0) - edit
->curs1
);
1079 edit_insert_column_of_text (edit
, copy_buf
, size
, c2
- c1
);
1081 line
= edit
->curs_line
;
1082 edit_update_curs_col (edit
);
1084 edit_block_delete_cmd (edit
);
1085 edit_move_to_line (edit
, line
);
1086 edit_cursor_move (edit
,
1087 edit_move_forward3 (edit
,
1090 x
, 0) - edit
->curs1
);
1092 edit_set_markers (edit
, 0, 0, 0, 0);
1093 edit_push_action (edit
, COLUMN_ON
);
1094 column_highlighting
= 0;
1096 copy_buf
= g_malloc (end_mark
- start_mark
);
1097 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
1098 edit_scroll_screen_over_cursor (edit
);
1100 while (count
< end_mark
) {
1101 copy_buf
[end_mark
- count
- 1] = edit_delete (edit
);
1104 edit_scroll_screen_over_cursor (edit
);
1105 edit_cursor_move (edit
,
1106 current
- edit
->curs1
-
1107 (((current
- edit
->curs1
) >
1108 0) ? end_mark
- start_mark
: 0));
1109 edit_scroll_screen_over_cursor (edit
);
1110 while (count
-- > start_mark
)
1111 edit_insert_ahead (edit
, copy_buf
[end_mark
- count
- 1]);
1112 edit_set_markers (edit
, edit
->curs1
,
1113 edit
->curs1
+ end_mark
- start_mark
, 0, 0);
1115 edit_scroll_screen_over_cursor (edit
);
1117 edit
->force
|= REDRAW_PAGE
;
1121 edit_delete_column_of_text (WEdit
* edit
)
1123 long p
, q
, r
, m1
, m2
;
1127 eval_marks (edit
, &m1
, &m2
);
1128 n
= edit_move_forward (edit
, m1
, 0, m2
) + 1;
1129 c
= edit_move_forward3 (edit
, edit_bol (edit
, m1
), 0, m1
);
1130 d
= edit_move_forward3 (edit
, edit_bol (edit
, m2
), 0, m2
);
1136 r
= edit_bol (edit
, edit
->curs1
);
1137 p
= edit_move_forward3 (edit
, r
, b
, 0);
1138 q
= edit_move_forward3 (edit
, r
, c
, 0);
1143 edit_cursor_move (edit
, p
- edit
->curs1
);
1144 while (q
> p
) { /* delete line between margins */
1145 if (edit_get_byte (edit
, edit
->curs1
) != '\n')
1149 if (n
) /* move to next line except on the last delete */
1150 edit_cursor_move (edit
, edit_move_forward (edit
, edit
->curs1
, 1, 0) - edit
->curs1
);
1154 /* if success return 0 */
1156 edit_block_delete (WEdit
*edit
)
1159 long start_mark
, end_mark
;
1160 if (eval_marks (edit
, &start_mark
, &end_mark
))
1162 if (column_highlighting
&& edit
->mark2
< 0)
1163 edit_mark_cmd (edit
, 0);
1164 if ((end_mark
- start_mark
) > option_max_undo
/ 2) {
1165 /* Warning message with a query to continue or cancel the operation */
1166 if (edit_query_dialog2
1169 (" Block is large, you may not be able to undo this action. "),
1170 _("C&ontinue"), _("&Cancel"))) {
1174 edit_push_markers (edit
);
1175 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
1176 edit_scroll_screen_over_cursor (edit
);
1178 if (start_mark
< end_mark
) {
1179 if (column_highlighting
) {
1180 if (edit
->mark2
< 0)
1181 edit_mark_cmd (edit
, 0);
1182 edit_delete_column_of_text (edit
);
1184 while (count
< end_mark
) {
1190 edit_set_markers (edit
, 0, 0, 0, 0);
1191 edit
->force
|= REDRAW_PAGE
;
1195 /* returns 1 if canceelled by user */
1196 int edit_block_delete_cmd (WEdit
* edit
)
1198 long start_mark
, end_mark
;
1199 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
1200 edit_delete_line (edit
);
1203 return edit_block_delete (edit
);
1207 #define INPUT_INDEX 9
1208 #define SEARCH_DLG_WIDTH 58
1209 #define SEARCH_DLG_HEIGHT 10
1210 #define REPLACE_DLG_WIDTH 58
1211 #define REPLACE_DLG_HEIGHT 15
1212 #define CONFIRM_DLG_WIDTH 79
1213 #define CONFIRM_DLG_HEIGTH 6
1214 #define B_REPLACE_ALL (B_USER+1)
1215 #define B_REPLACE_ONE (B_USER+2)
1216 #define B_SKIP_REPLACE (B_USER+3)
1219 edit_replace_prompt (WEdit
* edit
, char *replace_text
, int xpos
, int ypos
)
1221 QuickWidget quick_widgets
[] =
1223 {quick_button
, 63, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Cancel"),
1224 0, B_CANCEL
, 0, 0, NULL
},
1225 {quick_button
, 50, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("O&ne"),
1226 0, B_REPLACE_ONE
, 0, 0, NULL
},
1227 {quick_button
, 37, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("A&ll"),
1228 0, B_REPLACE_ALL
, 0, 0, NULL
},
1229 {quick_button
, 21, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Skip"),
1230 0, B_SKIP_REPLACE
, 0, 0, NULL
},
1231 {quick_button
, 4, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Replace"),
1232 0, B_ENTER
, 0, 0, NULL
},
1233 {quick_label
, 2, CONFIRM_DLG_WIDTH
, 2, CONFIRM_DLG_HEIGTH
, 0,
1237 GString
*label_text
= g_string_new (_(" Replace with: "));
1238 if (*replace_text
) {
1240 label_len
= label_text
->len
;
1241 g_string_append (label_text
, replace_text
);
1242 convert_to_display (label_text
->str
+ label_len
);
1244 quick_widgets
[5].text
= label_text
->str
;
1248 QuickDialog Quick_input
=
1249 {CONFIRM_DLG_WIDTH
, CONFIRM_DLG_HEIGTH
, 0, 0, N_ (" Confirm replace "),
1250 "[Input Line Keys]", 0 /*quick_widgets */, 0 };
1252 Quick_input
.widgets
= quick_widgets
;
1254 Quick_input
.xpos
= xpos
;
1256 /* Sometimes menu can hide replaced text. I don't like it */
1258 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ CONFIRM_DLG_HEIGTH
- 1))
1259 ypos
-= CONFIRM_DLG_HEIGTH
;
1261 Quick_input
.ypos
= ypos
;
1262 retval
= quick_dialog (&Quick_input
);
1263 g_string_free (label_text
, TRUE
);
1269 edit_replace_dialog (WEdit
* edit
, const char *search_default
,
1270 const char *replace_default
, const char *argorder_default
,
1271 /*@out@*/ char **search_text
, /*@out@*/ char **replace_text
,
1272 /*@out@*/ char **arg_order
)
1274 int treplace_scanf
= replace_scanf
;
1275 int treplace_regexp
= replace_regexp
;
1276 int treplace_all
= replace_all
;
1277 int treplace_prompt
= replace_prompt
;
1278 int treplace_backwards
= replace_backwards
;
1279 int treplace_whole
= replace_whole
;
1280 int treplace_case
= replace_case
;
1282 /* Alt-p is in use as hotkey for previous entry; don't use */
1283 QuickWidget quick_widgets
[] =
1285 {quick_button
, 6, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1287 {quick_button
, 2, 10, 12, REPLACE_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1289 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1291 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("replace &All"), 0, 0,
1293 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("pro&Mpt on replace"), 0, 0,
1295 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1297 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1299 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1301 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 8, REPLACE_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1303 {quick_input
, 3, REPLACE_DLG_WIDTH
, 7, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1305 {quick_label
, 2, REPLACE_DLG_WIDTH
, 6, REPLACE_DLG_HEIGHT
, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1307 {quick_input
, 3, REPLACE_DLG_WIDTH
, 5, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1309 {quick_label
, 2, REPLACE_DLG_WIDTH
, 4, REPLACE_DLG_HEIGHT
, N_(" Enter replacement string:"), 0, 0, 0,
1311 {quick_input
, 3, REPLACE_DLG_WIDTH
, 3, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1313 {quick_label
, 2, REPLACE_DLG_WIDTH
, 2, REPLACE_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1319 quick_widgets
[2].result
= &treplace_scanf
;
1320 quick_widgets
[3].result
= &treplace_all
;
1321 quick_widgets
[4].result
= &treplace_prompt
;
1322 quick_widgets
[5].result
= &treplace_backwards
;
1323 quick_widgets
[6].result
= &treplace_regexp
;
1324 quick_widgets
[7].result
= &treplace_whole
;
1325 quick_widgets
[8].result
= &treplace_case
;
1326 quick_widgets
[9].str_result
= arg_order
;
1327 quick_widgets
[9].text
= argorder_default
;
1328 quick_widgets
[11].str_result
= replace_text
;
1329 quick_widgets
[11].text
= replace_default
;
1330 quick_widgets
[13].str_result
= search_text
;
1331 quick_widgets
[13].text
= search_default
;
1333 QuickDialog Quick_input
=
1334 {REPLACE_DLG_WIDTH
, REPLACE_DLG_HEIGHT
, -1, 0, N_(" Replace "),
1335 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1337 Quick_input
.widgets
= quick_widgets
;
1339 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1340 replace_scanf
= treplace_scanf
;
1341 replace_backwards
= treplace_backwards
;
1342 replace_regexp
= treplace_regexp
;
1343 replace_all
= treplace_all
;
1344 replace_prompt
= treplace_prompt
;
1345 replace_whole
= treplace_whole
;
1346 replace_case
= treplace_case
;
1350 *replace_text
= NULL
;
1351 *search_text
= NULL
;
1359 edit_search_dialog (WEdit
* edit
, char **search_text
)
1361 int treplace_scanf
= replace_scanf
;
1362 int treplace_regexp
= replace_regexp
;
1363 int treplace_whole
= replace_whole
;
1364 int treplace_case
= replace_case
;
1365 int treplace_backwards
= replace_backwards
;
1367 QuickWidget quick_widgets
[] =
1369 {quick_button
, 6, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1371 {quick_button
, 2, 10, 7, SEARCH_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1373 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1375 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1377 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1379 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1381 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 4, SEARCH_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1383 {quick_input
, 3, SEARCH_DLG_WIDTH
, 3, SEARCH_DLG_HEIGHT
, "", 52, 0, 0,
1385 {quick_label
, 2, SEARCH_DLG_WIDTH
, 2, SEARCH_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1391 quick_widgets
[2].result
= &treplace_scanf
;
1392 quick_widgets
[3].result
= &treplace_backwards
;
1393 quick_widgets
[4].result
= &treplace_regexp
;
1394 quick_widgets
[5].result
= &treplace_whole
;
1395 quick_widgets
[6].result
= &treplace_case
;
1396 quick_widgets
[7].str_result
= search_text
;
1397 quick_widgets
[7].text
= *search_text
;
1400 QuickDialog Quick_input
=
1401 {SEARCH_DLG_WIDTH
, SEARCH_DLG_HEIGHT
, -1, 0, N_("Search"),
1402 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1404 Quick_input
.widgets
= quick_widgets
;
1406 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1407 replace_scanf
= treplace_scanf
;
1408 replace_backwards
= treplace_backwards
;
1409 replace_regexp
= treplace_regexp
;
1410 replace_whole
= treplace_whole
;
1411 replace_case
= treplace_case
;
1413 *search_text
= NULL
;
1419 static long sargs
[NUM_REPL_ARGS
][256 / sizeof (long)];
1421 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1422 sargs[4], sargs[5], sargs[6], sargs[7], \
1423 sargs[8], sargs[9], sargs[10], sargs[11], \
1424 sargs[12], sargs[13], sargs[14], sargs[15]
1426 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1427 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1428 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1429 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1432 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1433 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1435 string_regexp_search (char *pattern
, char *string
, int match_type
,
1436 int match_bol
, int icase
, int *found_len
, void *d
)
1439 static char *old_pattern
= NULL
;
1440 static int old_type
, old_icase
;
1442 static regmatch_t s
[1];
1444 pmatch
= (regmatch_t
*) d
;
1448 if (!old_pattern
|| strcmp (old_pattern
, pattern
)
1449 || old_type
!= match_type
|| old_icase
!= icase
) {
1452 g_free (old_pattern
);
1455 if (regcomp (&r
, pattern
, REG_EXTENDED
| (icase
? REG_ICASE
: 0) |
1460 old_pattern
= g_strdup (pattern
);
1461 old_type
= match_type
;
1465 (&r
, string
, d
? NUM_REPL_ARGS
: 1, pmatch
,
1467 || match_type
!= match_normal
) ? 0 : REG_NOTBOL
)) != 0) {
1471 *found_len
= pmatch
[0].rm_eo
- pmatch
[0].rm_so
;
1472 return (pmatch
[0].rm_so
);
1475 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1476 (and the above) routines to work properly - paul */
1478 typedef int (*edit_getbyte_fn
) (WEdit
*, long);
1481 edit_find_string (long start
, unsigned char *exp
, int *len
, long last_byte
, edit_getbyte_fn get_byte
, void *data
, int once_only
, void *d
)
1484 long l
= strlen ((char *) exp
), f
= 0;
1487 for (p
= 0; p
< l
; p
++) /* count conversions... */
1489 if (exp
[++p
] != '%') /* ...except for "%%" */
1492 if (replace_scanf
|| replace_regexp
) {
1495 unsigned char mbuf
[MAX_REPL_LEN
* 2 + 3];
1497 replace_scanf
= (!replace_regexp
); /* can't have both */
1501 if (replace_scanf
) {
1502 unsigned char e
[MAX_REPL_LEN
];
1503 if (n
>= NUM_REPL_ARGS
)
1507 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++)
1508 buf
[p
- start
] = (*get_byte
) (data
, p
);
1510 for (p
= 0; exp
[p
] != 0; p
++)
1511 exp
[p
] = my_lower_case (exp
[p
]);
1512 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++) {
1513 c
= (*get_byte
) (data
, p
);
1514 buf
[p
- start
] = my_lower_case (c
);
1518 buf
[(q
= p
- start
)] = 0;
1519 strcpy ((char *) e
, (char *) exp
);
1520 strcat ((char *) e
, "%n");
1524 *((int *) sargs
[n
]) = 0; /* --> here was the problem - now fixed: good */
1525 if (n
== sscanf ((char *) buf
, (char *) exp
, SCANF_ARGS
)) {
1526 if (*((int *) sargs
[n
])) {
1527 *len
= *((int *) sargs
[n
]);
1533 if (q
+ start
< last_byte
) {
1535 buf
[q
] = (*get_byte
) (data
, q
+ start
);
1537 c
= (*get_byte
) (data
, q
+ start
);
1538 buf
[q
] = my_lower_case (c
);
1544 buf
++; /* move the window along */
1545 if (buf
== mbuf
+ MAX_REPL_LEN
) { /* the window is about to go past the end of array, so... */
1546 memmove (mbuf
, buf
, strlen ((char *) buf
) + 1); /* reset it */
1551 } else { /* regexp matching */
1553 int found_start
, match_bol
, move_win
= 0;
1555 while (start
+ offset
< last_byte
) {
1556 match_bol
= (start
== 0 || (*get_byte
) (data
, start
+ offset
- 1) == '\n');
1561 for (; p
< last_byte
&& q
< MAX_REPL_LEN
; p
++, q
++) {
1562 mbuf
[q
] = (*get_byte
) (data
, p
);
1563 if (mbuf
[q
] == '\n') {
1573 found_start
= string_regexp_search ((char *) exp
, (char *) buf
, match_normal
, match_bol
, !replace_case
, len
, d
);
1575 if (found_start
<= -2) { /* regcomp/regexec error */
1579 else if (found_start
== -1) /* not found: try next line */
1581 else if (*len
== 0) { /* null pattern: try again at next character */
1588 return (start
+ offset
- q
+ found_start
);
1593 if (buf
[q
- 1] != '\n') { /* incomplete line: try to recover */
1594 buf
= mbuf
+ MAX_REPL_LEN
/ 2;
1595 q
= strlen ((const char *) buf
);
1596 memmove (mbuf
, buf
, q
);
1605 *len
= strlen ((const char *) exp
);
1607 for (p
= start
; p
<= last_byte
- l
; p
++) {
1608 if ((*get_byte
) (data
, p
) == (unsigned char)exp
[0]) { /* check if first char matches */
1609 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1610 if ((*get_byte
) (data
, q
+ p
) != (unsigned char)exp
[q
])
1619 for (p
= 0; exp
[p
] != 0; p
++)
1620 exp
[p
] = my_lower_case (exp
[p
]);
1622 for (p
= start
; p
<= last_byte
- l
; p
++) {
1623 if (my_lower_case ((*get_byte
) (data
, p
)) == (unsigned char)exp
[0]) {
1624 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1625 if (my_lower_case ((*get_byte
) (data
, q
+ p
)) != (unsigned char)exp
[q
])
1640 edit_find_forwards (long search_start
, unsigned char *exp
, int *len
, long last_byte
, edit_getbyte_fn get_byte
, void *data
, int once_only
, void *d
)
1641 { /*front end to find_string to check for
1646 while ((p
= edit_find_string (p
, exp
, len
, last_byte
, get_byte
, data
, once_only
, d
)) >= 0) {
1647 if (replace_whole
) {
1648 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1649 if (!strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
- 1))
1650 && !strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
+ *len
)))
1658 p
++; /*not a whole word so continue search. */
1664 edit_find (long search_start
, unsigned char *exp
, int *len
, long last_byte
, edit_getbyte_fn get_byte
, void *data
, void *d
)
1667 if (replace_backwards
) {
1668 while (search_start
>= 0) {
1669 p
= edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 1, d
);
1670 if (p
== search_start
)
1675 return edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 0, d
);
1680 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1682 #define snprint(v) { \
1685 n = snprintf(s,e-s,q1,v); \
1686 if (n >= (size_t) (e - s)) goto nospc; \
1690 /* this function uses the sprintf command to do a vprintf */
1691 /* it takes pointers to arguments instead of the arguments themselves */
1692 /* The return value is the number of bytes written excluding '\0'
1693 if successfull, -1 if the resulting string would be too long and
1694 -2 if the format string is errorneous. */
1695 static int snprintf_p (char *str
, size_t size
, const char *fmt
,...)
1696 __attribute__ ((format (printf
, 3, 4)));
1698 static int snprintf_p (char *str
, size_t size
, const char *fmt
,...)
1703 char *s
= str
, *e
= str
+ size
;
1711 while ((p
= strchr (p
, '%'))) {
1713 if (n
>= (size_t) (e
- s
))
1715 memcpy (s
, q
, n
); /* copy stuff between format specifiers */
1730 /* We were passed only 16 arguments. */
1743 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace field width with a number */
1746 while (is_digit (*p
) && p1
< q1
+ 20)
1755 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace precision with a number */
1758 while (is_digit (*p
) && p1
< q1
+ 32)
1763 /* flags done, now get argument */
1765 snprint (va_arg (ap
, char *));
1766 } else if (*p
== 'h') {
1767 if (strchr ("diouxX", *p
))
1768 snprint (*va_arg (ap
, short *));
1769 } else if (*p
== 'l') {
1771 if (strchr ("diouxX", *p
))
1772 snprint (*va_arg (ap
, long *));
1773 } else if (strchr ("cdiouxX", *p
)) {
1774 snprint (*va_arg (ap
, int *));
1775 } else if (*p
== 'L') {
1777 if (strchr ("EefgG", *p
))
1778 snprint (*va_arg (ap
, double *)); /* should be long double */
1779 } else if (strchr ("EefgG", *p
)) {
1780 snprint (*va_arg (ap
, double *));
1781 } else if (strchr ("DOU", *p
)) {
1782 snprint (*va_arg (ap
, long *));
1783 } else if (*p
== 'p') {
1784 snprint (*va_arg (ap
, void **));
1791 if (n
>= (size_t) (e
- s
))
1793 memcpy (s
, q
, n
+ 1);
1803 static void regexp_error (WEdit
*edit
)
1806 edit_error_dialog (_("Error"), _(" Invalid regular expression, or scanf expression with too many conversions "));
1809 /* call with edit = 0 before shutdown to close memory leaks */
1811 edit_replace_cmd (WEdit
*edit
, int again
)
1813 static regmatch_t pmatch
[NUM_REPL_ARGS
];
1814 /* 1 = search string, 2 = replace with, 3 = argument order */
1815 static char *saved1
= NULL
; /* saved default[123] */
1816 static char *saved2
= NULL
;
1817 static char *saved3
= NULL
;
1818 char *input1
= NULL
; /* user input from the dialog */
1819 char *input2
= NULL
;
1820 char *input3
= NULL
;
1822 int replace_continue
;
1823 int treplace_prompt
= 0;
1824 long times_replaced
= 0, last_search
;
1825 int argord
[NUM_REPL_ARGS
];
1828 g_free (saved1
), saved1
= NULL
;
1829 g_free (saved2
), saved2
= NULL
;
1830 g_free (saved3
), saved3
= NULL
;
1834 last_search
= edit
->last_byte
;
1836 edit
->force
|= REDRAW_COMPLETELY
;
1838 if (again
&& !saved1
&& !saved2
)
1842 input1
= g_strdup (saved1
? saved1
: "");
1843 input2
= g_strdup (saved2
? saved2
: "");
1844 input3
= g_strdup (saved3
? saved3
: "");
1846 char *disp1
= g_strdup (saved1
? saved1
: "");
1847 char *disp2
= g_strdup (saved2
? saved2
: "");
1848 char *disp3
= g_strdup (saved3
? saved3
: "");
1850 convert_to_display (disp1
);
1851 convert_to_display (disp2
);
1852 convert_to_display (disp3
);
1854 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1855 edit_replace_dialog (edit
, disp1
, disp2
, disp3
, &input1
, &input2
,
1862 convert_from_input (input1
);
1863 convert_from_input (input2
);
1864 convert_from_input (input3
);
1866 treplace_prompt
= replace_prompt
;
1867 if (input1
== NULL
|| *input1
== '\0') {
1868 edit
->force
= REDRAW_COMPLETELY
;
1872 g_free (saved1
), saved1
= g_strdup (input1
);
1873 g_free (saved2
), saved2
= g_strdup (input2
);
1874 g_free (saved3
), saved3
= g_strdup (input3
);
1884 for (i
= 0; i
< NUM_REPL_ARGS
; i
++) {
1885 if (s
!= NULL
&& *s
!= '\0') {
1887 if ((ord
> 0) && (ord
<= NUM_REPL_ARGS
))
1888 argord
[i
] = ord
- 1;
1891 s
= strchr (s
, ',');
1899 replace_continue
= replace_all
;
1901 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1
1902 && replace_backwards
)
1903 edit
->search_start
--;
1905 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1
1906 && !replace_backwards
)
1907 edit
->search_start
++;
1913 edit_find (edit
->search_start
, (unsigned char *) input1
, &len
,
1914 last_search
, edit_get_byte
, (void *) edit
, pmatch
);
1915 if (new_start
== -3) {
1916 regexp_error (edit
);
1919 edit
->search_start
= new_start
;
1920 /*returns negative on not found or error in pattern */
1922 if (edit
->search_start
>= 0) {
1925 edit
->found_start
= edit
->search_start
;
1926 i
= edit
->found_len
= len
;
1928 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1929 edit_scroll_screen_over_cursor (edit
);
1933 if (treplace_prompt
) {
1935 l
= edit
->curs_row
- edit
->num_widget_lines
/ 3;
1937 edit_scroll_downward (edit
, l
);
1939 edit_scroll_upward (edit
, -l
);
1941 edit_scroll_screen_over_cursor (edit
);
1942 edit
->force
|= REDRAW_PAGE
;
1943 edit_render_keypress (edit
);
1945 /*so that undo stops at each query */
1946 edit_push_key_press (edit
);
1948 switch (edit_replace_prompt (edit
, input2
, /* and prompt 2/3 down */
1949 (edit
->num_widget_columns
-
1950 CONFIRM_DLG_WIDTH
) / 2,
1951 edit
->num_widget_lines
* 2 /
1955 case B_SKIP_REPLACE
:
1959 treplace_prompt
= 0;
1960 replace_continue
= 1;
1963 replace_continue
= 0;
1967 replace_continue
= 0;
1971 if (replace_yes
) { /* delete then insert new */
1972 if (replace_scanf
) {
1973 char repl_str
[MAX_REPL_LEN
+ 2];
1976 /* we need to fill in sargs just like with scanf */
1977 if (replace_regexp
) {
1980 k
< NUM_REPL_ARGS
&& pmatch
[k
].rm_eo
>= 0;
1984 if (pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
> 255) {
1988 t
= (unsigned char *) &sargs
[k
- 1][0];
1990 j
< pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
1991 && j
< 255; j
++, t
++)
1992 *t
= (unsigned char) edit_get_byte (edit
,
2005 for (; k
<= NUM_REPL_ARGS
; k
++)
2006 sargs
[k
- 1][0] = 0;
2010 snprintf_p (repl_str
, MAX_REPL_LEN
+ 2, input2
,
2016 while (repl_str
[++i
])
2017 edit_insert (edit
, repl_str
[i
]);
2019 edit_error_dialog (_(" Replace "),
2023 (" Error in replacement format string. ")
2024 : _(" Replacement too long. "));
2025 replace_continue
= 0;
2032 edit_insert (edit
, input2
[i
]);
2034 edit
->found_len
= i
;
2036 /* so that we don't find the same string again */
2037 if (replace_backwards
) {
2038 last_search
= edit
->search_start
;
2039 edit
->search_start
--;
2041 edit
->search_start
+= i
;
2042 last_search
= edit
->last_byte
;
2044 edit_scroll_screen_over_cursor (edit
);
2046 const char *msg
= _(" Replace ");
2047 /* try and find from right here for next search */
2048 edit
->search_start
= edit
->curs1
;
2049 edit_update_curs_col (edit
);
2051 edit
->force
|= REDRAW_PAGE
;
2052 edit_render_keypress (edit
);
2053 if (times_replaced
) {
2054 message (0, msg
, _(" %ld replacements made. "),
2057 query_dialog (msg
, _(" Search string not found "),
2058 D_NORMAL
, 1, _("&OK"));
2059 replace_continue
= 0;
2061 } while (replace_continue
);
2063 edit
->force
= REDRAW_COMPLETELY
;
2064 edit_scroll_screen_over_cursor (edit
);
2074 void edit_search_cmd (WEdit
* edit
, int again
)
2076 static char *old
= NULL
;
2085 exp
= old
? old
: exp
;
2086 if (again
) { /*ctrl-hotkey for search again. */
2089 exp
= g_strdup (old
);
2094 convert_to_display (exp
);
2095 #endif /* HAVE_CHARSET */
2097 edit_search_dialog (edit
, &exp
);
2101 convert_from_input (exp
);
2102 #endif /* HAVE_CHARSET */
2104 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2111 old
= g_strdup (exp
);
2113 if (search_create_bookmark
) {
2114 int found
= 0, books
= 0;
2115 int l
= 0, l_last
= -1;
2118 p
= edit_find (q
, (unsigned char *) exp
, &len
, edit
->last_byte
,
2119 edit_get_byte
, (void *) edit
, 0);
2123 l
+= edit_count_lines (edit
, q
, p
);
2125 book_mark_insert (edit
, l
, BOOK_MARK_FOUND_COLOR
);
2132 /* in response to number of bookmarks added because of string being found %d times */
2133 message (0, _("Search"), _(" %d items found, %d bookmarks added "), found
, books
);
2135 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2139 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
2140 edit
->search_start
--;
2142 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
2143 edit
->search_start
++;
2145 edit
->search_start
= edit_find (edit
->search_start
, (unsigned char *) exp
, &len
, edit
->last_byte
,
2146 edit_get_byte
, (void *) edit
, 0);
2148 if (edit
->search_start
>= 0) {
2149 edit
->found_start
= edit
->search_start
;
2150 edit
->found_len
= len
;
2152 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
2153 edit_scroll_screen_over_cursor (edit
);
2154 if (replace_backwards
)
2155 edit
->search_start
--;
2157 edit
->search_start
++;
2158 } else if (edit
->search_start
== -3) {
2159 edit
->search_start
= edit
->curs1
;
2160 regexp_error (edit
);
2162 edit
->search_start
= edit
->curs1
;
2163 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2169 edit
->force
|= REDRAW_COMPLETELY
;
2170 edit_scroll_screen_over_cursor (edit
);
2175 * Check if it's OK to close the editor. If there are unsaved changes,
2176 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2179 edit_ok_to_exit (WEdit
*edit
)
2181 if (!edit
->modified
)
2184 switch (edit_query_dialog3
2185 (_("Quit"), _(" File was modified, Save with exit? "),
2186 _("&Cancel quit"), _("&Yes"), _("&No"))) {
2188 edit_push_markers (edit
);
2189 edit_set_markers (edit
, 0, 0, 0, 0);
2190 if (!edit_save_cmd (edit
))
2204 #define TEMP_BUF_LEN 1024
2206 /* Return a null terminated length of text. Result must be g_free'd */
2207 static unsigned char *
2208 edit_get_block (WEdit
*edit
, long start
, long finish
, int *l
)
2210 unsigned char *s
, *r
;
2211 r
= s
= g_malloc (finish
- start
+ 1);
2212 if (column_highlighting
) {
2214 /* copy from buffer, excluding chars that are out of the column 'margins' */
2215 while (start
< finish
) {
2217 x
= edit_move_forward3 (edit
, edit_bol (edit
, start
), 0,
2219 c
= edit_get_byte (edit
, start
);
2220 if ((x
>= edit
->column1
&& x
< edit
->column2
)
2221 || (x
>= edit
->column2
&& x
< edit
->column1
) || c
== '\n') {
2228 *l
= finish
- start
;
2229 while (start
< finish
)
2230 *s
++ = edit_get_byte (edit
, start
++);
2236 /* save block, returns 1 on success */
2238 edit_save_block (WEdit
* edit
, const char *filename
, long start
,
2244 mc_open (filename
, O_CREAT
| O_WRONLY
| O_TRUNC
,
2245 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
| O_BINARY
)) == -1)
2248 if (column_highlighting
) {
2249 unsigned char *block
, *p
;
2251 p
= block
= edit_get_block (edit
, start
, finish
, &len
);
2253 r
= mc_write (file
, p
, len
);
2263 len
= finish
- start
;
2264 buf
= g_malloc (TEMP_BUF_LEN
);
2265 while (start
!= finish
) {
2266 end
= min (finish
, start
+ TEMP_BUF_LEN
);
2267 for (; i
< end
; i
++)
2268 buf
[i
- start
] = edit_get_byte (edit
, i
);
2269 len
-= mc_write (file
, (char *) buf
, end
- start
);
2280 /* copies a block to clipboard file */
2281 static int edit_save_block_to_clip_file (WEdit
* edit
, long start
, long finish
)
2283 return edit_save_block (edit
, catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
), start
, finish
);
2287 void edit_paste_from_history (WEdit
*edit
)
2290 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
2293 int edit_copy_to_X_buf_cmd (WEdit
* edit
)
2295 long start_mark
, end_mark
;
2296 if (eval_marks (edit
, &start_mark
, &end_mark
))
2298 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2299 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2302 edit_mark_cmd (edit
, 1);
2306 int edit_cut_to_X_buf_cmd (WEdit
* edit
)
2308 long start_mark
, end_mark
;
2309 if (eval_marks (edit
, &start_mark
, &end_mark
))
2311 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2312 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2315 edit_block_delete_cmd (edit
);
2316 edit_mark_cmd (edit
, 1);
2320 void edit_paste_from_X_buf_cmd (WEdit
* edit
)
2322 edit_insert_file (edit
, catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
));
2327 * Ask user for the line and go to that line.
2328 * Negative numbers mean line from the end (i.e. -1 is the last line).
2331 edit_goto_cmd (WEdit
*edit
)
2334 static long line
= 0; /* line as typed, saved as default */
2339 g_snprintf (s
, sizeof (s
), "%ld", line
);
2340 f
= input_dialog (_(" Goto line "), _(" Enter line: "), ":edit_goto_cmd: Goto line ",
2350 l
= strtol (f
, &error
, 0);
2358 l
= edit
->total_lines
+ l
+ 2;
2359 edit_move_display (edit
, l
- edit
->num_widget_lines
/ 2 - 1);
2360 edit_move_to_line (edit
, l
- 1);
2361 edit
->force
|= REDRAW_COMPLETELY
;
2366 /* Return 1 on success */
2368 edit_save_block_cmd (WEdit
*edit
)
2370 long start_mark
, end_mark
;
2372 if (eval_marks (edit
, &start_mark
, &end_mark
))
2375 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2376 ":edit_save_block_cmd: Save Block ",
2377 catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
));
2378 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2384 if (edit_save_block (edit
, exp
, start_mark
, end_mark
)) {
2386 edit
->force
|= REDRAW_COMPLETELY
;
2390 edit_error_dialog (_(" Save Block "),
2392 (" Cannot save file. ")));
2396 edit
->force
|= REDRAW_COMPLETELY
;
2401 /* returns 1 on success */
2403 edit_insert_file_cmd (WEdit
*edit
)
2405 char *exp
= input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2406 ":edit_insert_file_cmd: Insert File ",
2407 catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
));
2408 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2414 if (edit_insert_file (edit
, exp
)) {
2416 edit
->force
|= REDRAW_COMPLETELY
;
2420 edit_error_dialog (_(" Insert File "),
2422 (" Cannot insert file. ")));
2426 edit
->force
|= REDRAW_COMPLETELY
;
2430 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2431 int edit_sort_cmd (WEdit
* edit
)
2433 static char *old
= 0;
2435 long start_mark
, end_mark
;
2438 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2439 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2442 edit_save_block (edit
, catstrs (home_dir
, PATH_SEP_STR BLOCK_FILE
, (char *) NULL
), start_mark
, end_mark
);
2444 exp
= input_dialog (_(" Run Sort "),
2445 _(" Enter sort options (see manpage) separated by whitespace: "),
2446 ":edit_sort_cmd: Run Sort ", (old
!= NULL
) ? old
: "");
2453 e
= system (catstrs (" sort ", exp
, " ", home_dir
, PATH_SEP_STR BLOCK_FILE
, " > ", home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2455 if (e
== -1 || e
== 127) {
2456 edit_error_dialog (_(" Sort "),
2457 get_sys_error (_(" Cannot execute sort command ")));
2460 sprintf (q
, "%d ", e
);
2461 edit_error_dialog (_(" Sort "),
2462 catstrs (_(" Sort returned non-zero: "), q
, (char *) NULL
));
2467 edit
->force
|= REDRAW_COMPLETELY
;
2469 if (edit_block_delete_cmd (edit
))
2471 edit_insert_file (edit
, catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2476 * Ask user for a command, execute it and paste its output back to the
2480 edit_ext_cmd (WEdit
*edit
)
2486 input_dialog (_("Paste output of external command"),
2487 _("Enter shell command(s):"),
2488 ":edit_ext_cmd: Paste output of ext.cmd ", NULL
);
2493 e
= system (catstrs (exp
, " > ", home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2497 edit_error_dialog (_("External command"),
2498 get_sys_error (_("Cannot execute command")));
2502 edit
->force
|= REDRAW_COMPLETELY
;
2504 edit_insert_file (edit
, catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2508 /* if block is 1, a block must be highlighted and the shell command
2509 processes it. If block is 0 the shell command is a straight system
2510 command, that just produces some output which is to be inserted */
2512 edit_block_process_cmd (WEdit
*edit
, const char *shell_cmd
, int block
)
2514 long start_mark
, end_mark
;
2516 FILE *script_home
= NULL
;
2517 FILE *script_src
= NULL
;
2518 FILE *block_file
= NULL
;
2519 const char *o
= NULL
;
2520 const char *h
= NULL
;
2521 const char *b
= NULL
;
2522 char *quoted_name
= NULL
;
2524 o
= catstrs (mc_home
, shell_cmd
, (char *) NULL
); /* original source script */
2525 h
= catstrs (home_dir
, PATH_SEP_STR EDIT_DIR
, shell_cmd
, (char *) NULL
); /* home script */
2526 b
= catstrs (home_dir
, PATH_SEP_STR BLOCK_FILE
, (char *) NULL
); /* block file */
2528 if (!(script_home
= fopen (h
, "r"))) {
2529 if (!(script_home
= fopen (h
, "w"))) {
2530 edit_error_dialog ("", get_sys_error (catstrs
2532 ("Error creating script:"),
2533 h
, (char *) NULL
)));
2536 if (!(script_src
= fopen (o
, "r"))) {
2537 fclose (script_home
);
2539 edit_error_dialog ("", get_sys_error (catstrs
2540 (_("Error reading script:"),
2541 o
, (char *) NULL
)));
2544 while (fgets (buf
, sizeof (buf
), script_src
))
2545 fputs (buf
, script_home
);
2546 if (fclose (script_home
)) {
2547 edit_error_dialog ("", get_sys_error (catstrs
2549 ("Error closing script:"),
2550 h
, (char *) NULL
)));
2554 edit_error_dialog ("", get_sys_error (catstrs
2555 (_("Script created:"), h
, (char *) NULL
)));
2560 if (block
) { /* for marked block run indent formatter */
2561 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2562 edit_error_dialog (_("Process block"),
2564 (" You must first highlight a block of text. "));
2567 edit_save_block (edit
, b
, start_mark
, end_mark
);
2568 quoted_name
= name_quote (edit
->filename
, 0);
2571 * Initial space is to avoid polluting bash history.
2573 * $1 - name of the edited file (to check its extension etc).
2574 * $2 - file containing the current block.
2575 * $3 - file where error messages should be put
2576 * (for compatibility with old scripts).
2578 system (catstrs (" ", home_dir
, PATH_SEP_STR EDIT_DIR
, shell_cmd
, " ", quoted_name
,
2579 " ", home_dir
, PATH_SEP_STR BLOCK_FILE
" /dev/null", (char *) NULL
));
2583 * No block selected, just execute the command for the file.
2585 * $1 - name of the edited file.
2587 system (catstrs (" ", home_dir
, PATH_SEP_STR EDIT_DIR
, shell_cmd
, " ",
2588 quoted_name
, (char *) NULL
));
2590 g_free (quoted_name
);
2591 close_error_pipe (0, 0);
2593 edit_refresh_cmd (edit
);
2594 edit
->force
|= REDRAW_COMPLETELY
;
2596 /* insert result block */
2598 if (edit_block_delete_cmd (edit
))
2600 edit_insert_file (edit
, b
);
2601 if ((block_file
= fopen (b
, "w")))
2602 fclose (block_file
);
2609 /* prints at the cursor */
2610 /* returns the number of chars printed */
2611 int edit_print_string (WEdit
* e
, const char *s
)
2615 edit_execute_cmd (e
, -1, (unsigned char) s
[i
++]);
2616 e
->force
|= REDRAW_COMPLETELY
;
2617 edit_update_screen (e
);
2622 static void pipe_mail (WEdit
*edit
, char *to
, char *subject
, char *cc
)
2627 to
= name_quote (to
, 0);
2628 subject
= name_quote (subject
, 0);
2629 cc
= name_quote (cc
, 0);
2630 s
= g_strconcat ("mail -s ", subject
, *cc
? " -c " : "" , cc
, " ", to
, (char *) NULL
);
2642 for (i
= 0; i
< edit
->last_byte
; i
++)
2643 fputc (edit_get_byte (edit
, i
), p
);
2648 #define MAIL_DLG_HEIGHT 12
2650 void edit_mail_dialog (WEdit
* edit
)
2653 char *tmail_subject
;
2656 static char *mail_cc_last
= 0;
2657 static char *mail_subject_last
= 0;
2658 static char *mail_to_last
= 0;
2660 QuickDialog Quick_input
=
2661 {50, MAIL_DLG_HEIGHT
, -1, 0, N_(" Mail "),
2662 "[Input Line Keys]", 0, 0};
2664 QuickWidget quick_widgets
[] =
2666 {quick_button
, 6, 10, 9, MAIL_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
2668 {quick_button
, 2, 10, 9, MAIL_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
2670 {quick_input
, 3, 50, 8, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2671 0, "mail-dlg-input"},
2672 {quick_label
, 2, 50, 7, MAIL_DLG_HEIGHT
, N_(" Copies to"), 0, 0, 0,
2674 {quick_input
, 3, 50, 6, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2675 0, "mail-dlg-input-2"},
2676 {quick_label
, 2, 50, 5, MAIL_DLG_HEIGHT
, N_(" Subject"), 0, 0, 0,
2678 {quick_input
, 3, 50, 4, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2679 0, "mail-dlg-input-3"},
2680 {quick_label
, 2, 50, 3, MAIL_DLG_HEIGHT
, N_(" To"), 0, 0, 0,
2682 {quick_label
, 2, 50, 2, MAIL_DLG_HEIGHT
, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2686 quick_widgets
[2].str_result
= &tmail_cc
;
2687 quick_widgets
[2].text
= mail_cc_last
? mail_cc_last
: "";
2688 quick_widgets
[4].str_result
= &tmail_subject
;
2689 quick_widgets
[4].text
= mail_subject_last
? mail_subject_last
: "";
2690 quick_widgets
[6].str_result
= &tmail_to
;
2691 quick_widgets
[6].text
= mail_to_last
? mail_to_last
: "";
2693 Quick_input
.widgets
= quick_widgets
;
2695 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
2696 g_free (mail_cc_last
);
2697 g_free (mail_subject_last
);
2698 g_free (mail_to_last
);
2699 mail_cc_last
= tmail_cc
;
2700 mail_subject_last
= tmail_subject
;
2701 mail_to_last
= tmail_to
;
2702 pipe_mail (edit
, mail_to_last
, mail_subject_last
, mail_cc_last
);
2707 /*******************/
2708 /* Word Completion */
2709 /*******************/
2712 /* find first character of current word */
2713 static int edit_find_word_start (WEdit
*edit
, long *word_start
, int *word_len
)
2717 /* return if at begin of file */
2718 if (edit
->curs1
<= 0)
2721 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- 1);
2722 /* return if not at end or in word */
2723 if (isspace (c
) || !(isalnum (c
) || c
== '_'))
2726 /* search start of word to be completed */
2728 /* return if at begin of file */
2729 if (edit
->curs1
- i
< 0)
2733 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- i
);
2735 if (!(isalnum (c
) || c
== '_')) {
2736 /* return if word starts with digit */
2740 *word_start
= edit
->curs1
- (i
- 1); /* start found */
2750 /* (re)set search parameters to the given values */
2751 static void edit_set_search_parameters (int rs
, int rb
, int rr
, int rw
, int rc
)
2754 replace_backwards
= rb
;
2755 replace_regexp
= rr
;
2761 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2763 /* collect the possible completions */
2765 edit_collect_completions (WEdit
*edit
, long start
, int word_len
,
2766 char *match_expr
, struct selection
*compl,
2769 int len
, max_len
= 0, i
, skip
;
2770 unsigned char *bufpos
;
2772 /* collect max MAX_WORD_COMPLETIONS completions */
2773 while (*num
< MAX_WORD_COMPLETIONS
) {
2774 /* get next match */
2776 edit_find (start
- 1, (unsigned char *) match_expr
, &len
,
2777 edit
->last_byte
, edit_get_byte
, (void *) edit
, 0);
2783 /* add matched completion if not yet added */
2786 buffers1
[start
>> S_EDIT_BUF_SIZE
][start
& M_EDIT_BUF_SIZE
];
2788 for (i
= 0; i
< *num
; i
++) {
2790 ((char *) &compl[i
].text
[word_len
],
2791 (char *) &bufpos
[word_len
], max (len
,
2795 break; /* skip it, already added */
2801 compl[*num
].text
= g_malloc (len
+ 1);
2802 compl[*num
].len
= len
;
2803 for (i
= 0; i
< len
; i
++)
2804 compl[*num
].text
[i
] = *(bufpos
+ i
);
2805 compl[*num
].text
[i
] = '\0';
2808 /* note the maximal length needed for the completion dialog */
2816 /* let the user select its preferred completion */
2818 edit_completion_dialog (WEdit
* edit
, int max_len
, int word_len
,
2819 struct selection
*compl, int num_compl
)
2821 int start_x
, start_y
, offset
, i
;
2823 Dlg_head
*compl_dlg
;
2824 WListbox
*compl_list
;
2825 int compl_dlg_h
; /* completion dialog height */
2826 int compl_dlg_w
; /* completion dialog width */
2828 /* calculate the dialog metrics */
2829 compl_dlg_h
= num_compl
+ 2;
2830 compl_dlg_w
= max_len
+ 4;
2831 start_x
= edit
->curs_col
+ edit
->start_col
- (compl_dlg_w
/ 2);
2832 start_y
= edit
->curs_row
+ EDIT_TEXT_VERTICAL_OFFSET
+ 1;
2836 if (compl_dlg_w
> COLS
)
2838 if (compl_dlg_h
> LINES
- 2)
2839 compl_dlg_h
= LINES
- 2;
2841 offset
= start_x
+ compl_dlg_w
- COLS
;
2844 offset
= start_y
+ compl_dlg_h
- LINES
;
2846 start_y
-= (offset
+ 1);
2848 /* create the dialog */
2850 create_dlg (start_y
, start_x
, compl_dlg_h
, compl_dlg_w
,
2851 dialog_colors
, NULL
, "[Completion]", NULL
,
2854 /* create the listbox */
2856 listbox_new (1, 1, compl_dlg_w
- 2, compl_dlg_h
- 2, NULL
);
2858 /* add the dialog */
2859 add_widget (compl_dlg
, compl_list
);
2861 /* fill the listbox with the completions */
2862 for (i
= 0; i
< num_compl
; i
++)
2863 listbox_add_item (compl_list
, LISTBOX_APPEND_AT_END
, 0,
2864 (char *) compl[i
].text
, NULL
);
2866 /* pop up the dialog */
2867 run_dlg (compl_dlg
);
2869 /* apply the choosen completion */
2870 if (compl_dlg
->ret_value
== B_ENTER
) {
2871 listbox_get_current (compl_list
, &curr
, NULL
);
2873 for (curr
+= word_len
; *curr
; curr
++)
2874 edit_insert (edit
, *curr
);
2877 /* destroy dialog before return */
2878 destroy_dlg (compl_dlg
);
2883 * Complete current word using regular expression search
2884 * backwards beginning at the current cursor position.
2887 edit_complete_word_cmd (WEdit
*edit
)
2889 int word_len
= 0, i
, num_compl
= 0, max_len
;
2890 long word_start
= 0;
2891 unsigned char *bufpos
;
2893 struct selection
compl[MAX_WORD_COMPLETIONS
]; /* completions */
2895 /* don't want to disturb another search */
2896 int old_rs
= replace_scanf
;
2897 int old_rb
= replace_backwards
;
2898 int old_rr
= replace_regexp
;
2899 int old_rw
= replace_whole
;
2900 int old_rc
= replace_case
;
2902 /* search start of word to be completed */
2903 if (!edit_find_word_start (edit
, &word_start
, &word_len
))
2906 /* prepare match expression */
2907 bufpos
= &edit
->buffers1
[word_start
>> S_EDIT_BUF_SIZE
]
2908 [word_start
& M_EDIT_BUF_SIZE
];
2909 match_expr
= g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len
, bufpos
);
2911 /* init search: backward, regexp, whole word, case sensitive */
2912 edit_set_search_parameters (0, 1, 1, 1, 1);
2914 /* collect the possible completions */
2915 /* start search from curs1 down to begin of file */
2917 edit_collect_completions (edit
, word_start
, word_len
, match_expr
,
2918 (struct selection
*) &compl, &num_compl
);
2920 if (num_compl
> 0) {
2921 /* insert completed word if there is only one match */
2922 if (num_compl
== 1) {
2923 for (i
= word_len
; i
< compl[0].len
; i
++)
2924 edit_insert (edit
, *(compl[0].text
+ i
));
2926 /* more than one possible completion => ask the user */
2928 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2929 /* !!! pressed again the selection dialog pops up, but that !!! */
2930 /* !!! seems to require a further internal state !!! */
2933 /* let the user select the preferred completion */
2934 edit_completion_dialog (edit
, max_len
, word_len
,
2935 (struct selection
*) &compl,
2940 g_free (match_expr
);
2941 /* release memory before return */
2942 for (i
= 0; i
< num_compl
; i
++)
2943 g_free (compl[i
].text
);
2945 /* restore search parameters */
2946 edit_set_search_parameters (old_rs
, old_rb
, old_rr
, old_rw
, old_rc
);
2950 edit_select_codepage_cmd (WEdit
*edit
)
2953 do_select_codepage ();
2954 edit
->force
= REDRAW_COMPLETELY
;
2955 edit_refresh_cmd (edit
);
2960 edit_insert_literal_cmd (WEdit
*edit
)
2962 int char_for_insertion
=
2963 edit_raw_key_query (_(" Insert Literal "),
2964 _(" Press any key: "), 0);
2965 edit_execute_key_command (edit
, -1,
2966 ascii_alpha_to_cntrl (char_for_insertion
));
2970 edit_execute_macro_cmd (WEdit
*edit
)
2973 CK_Macro (edit_raw_key_query
2974 (_(" Execute Macro "), _(" Press macro hotkey: "),
2976 if (command
== CK_Macro (0))
2977 command
= CK_Insert_Char
;
2979 edit_execute_key_command (edit
, command
, -1);
2983 edit_begin_end_macro_cmd(WEdit
*edit
)
2987 /* edit is a pointer to the widget */
2991 0 ? CK_Begin_Record_Macro
: CK_End_Record_Macro
;
2992 edit_execute_key_command (edit
, command
, -1);