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>
41 #include <mhl/memory.h>
42 #include <mhl/string.h>
44 #include "../src/global.h"
45 #include "../src/history.h"
49 #include "editcmddef.h"
50 #include "edit-widget.h"
52 #include "../src/color.h" /* dialog_colors */
53 #include "../src/tty.h" /* LINES */
54 #include "../src/widget.h" /* listbox_new() */
55 #include "../src/layout.h" /* clr_scr() */
56 #include "../src/main.h" /* mc_home */
57 #include "../src/help.h" /* interactive_display() */
58 #include "../src/key.h" /* XCTRL */
59 #include "../src/dialog.h" /* do_refresh() */
60 #include "../src/wtools.h" /* message() */
61 #include "../src/charsets.h"
62 #include "../src/selcodepage.h"
71 /* search and replace: */
72 static int replace_scanf
= 0;
73 static int replace_regexp
= 0;
74 static int replace_all
= 0;
75 static int replace_prompt
= 1;
76 static int replace_whole
= 0;
77 static int replace_case
= 0;
78 static int replace_backwards
= 0;
79 static int search_create_bookmark
= 0;
81 /* queries on a save */
82 int edit_confirm_save
= 1;
84 #define NUM_REPL_ARGS 64
85 #define MAX_REPL_LEN 1024
87 static int edit_save_cmd (WEdit
*edit
);
88 static unsigned char *edit_get_block (WEdit
*edit
, long start
,
91 static inline int my_lower_case (int c
)
93 return tolower(c
& 0xFF);
97 strcasechr (const char *s
, int c
)
99 for (c
= my_lower_case (c
); my_lower_case ((int) *s
) != c
; ++s
)
105 /* #define itoa MY_itoa <---- this line is now in edit.h */
115 } while ((i
= i
/ 10));
121 /* Temporary strings */
122 static char *stacked
[16];
125 This joins strings end on end and allocates memory for the result.
126 The result is later automatically free'd and must not be free'd
130 catstrs (const char *first
,...)
140 len
= strlen (first
);
141 va_start (ap
, first
);
143 while ((data
= va_arg (ap
, char *)) != 0)
144 len
+= strlen (data
);
151 stacked
[i
] = g_malloc (len
);
153 va_start (ap
, first
);
154 strcpy (stacked
[i
], first
);
155 while ((data
= va_arg (ap
, char *)) != 0)
156 strcat (stacked
[i
], data
);
162 /* Free temporary strings */
167 for (i
= 0; i
< sizeof(stacked
) / sizeof(stacked
[0]); i
++) {
173 void edit_help_cmd (WEdit
* edit
)
175 interactive_display (NULL
, "[Internal File Editor]");
176 edit
->force
|= REDRAW_COMPLETELY
;
179 void edit_refresh_cmd (WEdit
* edit
)
187 edit_get_syntax_color (edit
, -1, &color
);
190 #endif /* !HAVE_SLANG */
195 /* If 0 (quick save) then a) create/truncate <filename> file,
196 b) save to <filename>;
197 if 1 (safe save) then a) save to <tempnam>,
198 b) rename <tempnam> to <filename>;
199 if 2 (do backups) then a) save to <tempnam>,
200 b) rename <filename> to <filename.backup_ext>,
201 c) rename <tempnam> to <filename>. */
203 /* returns 0 on error, -1 on abort */
205 edit_save_file (WEdit
*edit
, const char *filename
)
210 int this_save_mode
, fd
= -1;
217 if (*filename
!= PATH_SEP
&& edit
->dir
) {
218 savename
= mhl_str_dir_plus_file (edit
->dir
, filename
);
219 filename
= catstrs (savename
, (char *) NULL
);
223 this_save_mode
= option_save_mode
;
224 if (this_save_mode
!= EDIT_QUICK_SAVE
) {
225 if (!vfs_file_is_local (filename
) ||
226 (fd
= mc_open (filename
, O_RDONLY
| O_BINARY
)) == -1) {
228 * The file does not exists yet, so no safe save or
229 * backup are necessary.
231 this_save_mode
= EDIT_QUICK_SAVE
;
237 if (this_save_mode
== EDIT_QUICK_SAVE
&&
238 !edit
->skip_detach_prompt
) {
242 rv
= mc_stat (filename
, &sb
);
243 if (rv
== 0 && sb
.st_nlink
> 1) {
244 rv
= edit_query_dialog3 (_("Warning"),
245 _(" File has hard-links. Detach before saving? "),
246 _("&Yes"), _("&No"), _("&Cancel"));
249 this_save_mode
= EDIT_SAFE_SAVE
;
252 edit
->skip_detach_prompt
= 1;
259 /* Prevent overwriting changes from other editor sessions. */
260 if (rv
== 0 && edit
->stat1
.st_mtime
!= 0 && edit
->stat1
.st_mtime
!= sb
.st_mtime
) {
262 /* The default action is "Cancel". */
265 rv
= edit_query_dialog2 (
267 _("The file has been modified in the meantime. Save anyway?"),
275 if (this_save_mode
!= EDIT_QUICK_SAVE
) {
276 char *savedir
, *saveprefix
;
277 const char *slashpos
;
278 slashpos
= strrchr (filename
, PATH_SEP
);
280 savedir
= mhl_str_dup (filename
);
281 savedir
[slashpos
- filename
+ 1] = '\0';
283 savedir
= mhl_str_dup (".");
284 saveprefix
= mhl_str_dir_plus_file (savedir
, "cooledit");
286 fd
= mc_mkstemps (&savename
, saveprefix
, NULL
);
291 * Close for now because mc_mkstemps use pure open system call
292 * to create temporary file and it needs to be reopened by
293 * VFS-aware mc_open().
297 savename
= g_strdup (filename
);
299 mc_chown (savename
, edit
->stat1
.st_uid
, edit
->stat1
.st_gid
);
300 mc_chmod (savename
, edit
->stat1
.st_mode
);
303 mc_open (savename
, O_CREAT
| O_WRONLY
| O_TRUNC
| O_BINARY
,
304 edit
->stat1
.st_mode
)) == -1)
308 if ((p
= edit_get_write_filter (savename
, filename
))) {
312 file
= (FILE *) popen (p
, "w");
315 filelen
= edit_write_stream (edit
, file
);
319 if (pclose (file
) != 0) {
320 edit_error_dialog (_("Error"),
321 catstrs (_(" Error writing to pipe: "),
322 p
, " ", (char *) NULL
));
328 edit_error_dialog (_("Error"),
329 get_sys_error (catstrs
331 (" Cannot open pipe for writing: "),
332 p
, " ", (char *) NULL
)));
340 filelen
= edit
->last_byte
;
341 while (buf
<= (edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1) {
342 if (mc_write (fd
, (char *) edit
->buffers1
[buf
], EDIT_BUF_SIZE
)
350 (fd
, (char *) edit
->buffers1
[buf
],
351 edit
->curs1
& M_EDIT_BUF_SIZE
) !=
352 (edit
->curs1
& M_EDIT_BUF_SIZE
)) {
354 } else if (edit
->curs2
) {
356 buf
= (edit
->curs2
>> S_EDIT_BUF_SIZE
);
359 (char *) edit
->buffers2
[buf
] + EDIT_BUF_SIZE
-
360 (edit
->curs2
& M_EDIT_BUF_SIZE
) - 1,
361 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) !=
362 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) {
367 (fd
, (char *) edit
->buffers2
[buf
],
368 EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
379 /* Update the file information, especially the mtime. */
380 if (mc_stat (savename
, &edit
->stat1
) == -1)
384 if (filelen
!= edit
->last_byte
)
387 if (this_save_mode
== EDIT_DO_BACKUP
) {
388 assert (option_backup_ext
!= NULL
);
389 if (mc_rename (filename
, catstrs (filename
, option_backup_ext
,
390 (char *) NULL
)) == -1)
394 if (this_save_mode
!= EDIT_QUICK_SAVE
)
395 if (mc_rename (savename
, filename
) == -1)
400 /* FIXME: Is this safe ?
401 * if (this_save_mode != EDIT_QUICK_SAVE)
402 * mc_unlink (savename);
408 void menu_save_mode_cmd (void)
412 static char *str_result
;
413 static int save_mode_new
;
414 static const char *str
[] =
418 N_("Do backups -->")};
419 static QuickWidget widgets
[] =
421 {quick_button
, 18, DLG_X
, 7, DLG_Y
, N_("&Cancel"), 0,
422 B_CANCEL
, 0, 0, NULL
},
423 {quick_button
, 6, DLG_X
, 7, DLG_Y
, N_("&OK"), 0,
424 B_ENTER
, 0, 0, NULL
},
425 {quick_input
, 23, DLG_X
, 5, DLG_Y
, 0, 9,
426 0, 0, &str_result
, "edit-backup-ext"},
427 {quick_label
, 22, DLG_X
, 4, DLG_Y
, N_("Extension:"), 0,
429 {quick_radio
, 4, DLG_X
, 3, DLG_Y
, "", 3,
430 0, &save_mode_new
, (char **) str
, NULL
},
432 static QuickDialog dialog
=
433 {DLG_X
, DLG_Y
, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
435 static int i18n_flag
= 0;
443 /* OK/Cancel buttons */
444 l1
= strlen (_(widgets
[0].text
)) + strlen (_(widgets
[1].text
)) + 5;
445 maxlen
= max (maxlen
, l1
);
447 for (i
= 0; i
< 3; i
++ ) {
449 maxlen
= max (maxlen
, strlen (str
[i
]) + 7);
453 dlg_x
= maxlen
+ strlen (_(widgets
[3].text
)) + 5 + 1;
454 widgets
[2].hotkey_pos
= strlen (_(widgets
[3].text
)); /* input field length */
455 dlg_x
= min (COLS
, dlg_x
);
459 widgets
[1].relative_x
= i
;
460 widgets
[0].relative_x
= i
+ strlen (_(widgets
[1].text
)) + i
+ 4;
462 widgets
[2].relative_x
= widgets
[3].relative_x
= maxlen
+ 2;
464 for (i
= 0; i
< sizeof (widgets
)/sizeof (widgets
[0]); i
++)
465 widgets
[i
].x_divisions
= dlg_x
;
468 assert (option_backup_ext
!= NULL
);
469 widgets
[2].text
= option_backup_ext
;
470 widgets
[4].value
= option_save_mode
;
471 if (quick_dialog (&dialog
) != B_ENTER
)
473 option_save_mode
= save_mode_new
;
475 g_free (option_backup_ext
);
476 option_backup_ext
= str_result
;
481 edit_set_filename (WEdit
*edit
, const char *f
)
483 g_free (edit
->filename
);
486 edit
->filename
= g_strdup (f
);
487 if (edit
->dir
== NULL
&& *f
!= PATH_SEP
)
489 edit
->dir
= g_strdup (vfs_get_current_dir ());
491 edit
->dir
= g_get_current_dir ();
495 /* Here we want to warn the users of overwriting an existing file,
496 but only if they have made a change to the filename */
497 /* returns 1 on success */
499 edit_save_as_cmd (WEdit
*edit
)
501 /* This heads the 'Save As' dialog box */
504 int different_filename
= 0;
506 exp
= input_expand_dialog (
507 _(" Save As "), _(" Enter file name: "),MC_HISTORY_EDIT_SAVE_AS
, edit
->filename
);
508 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
513 edit
->force
|= REDRAW_COMPLETELY
;
517 if (strcmp (edit
->filename
, exp
)) {
519 different_filename
= 1;
520 if ((file
= mc_open (exp
, O_RDONLY
| O_BINARY
)) != -1) {
521 /* the file exists */
523 /* Overwrite the current file or cancel the operation */
524 if (edit_query_dialog2
526 _(" A file already exists with this name. "),
527 _("&Overwrite"), _("&Cancel"))) {
528 edit
->force
|= REDRAW_COMPLETELY
;
533 save_lock
= edit_lock_file (exp
);
535 /* filenames equal, check if already locked */
536 if (!edit
->locked
&& !edit
->delete_file
)
537 save_lock
= edit_lock_file (exp
);
540 rv
= edit_save_file (edit
, exp
);
543 /* Succesful, so unlock both files */
544 if (different_filename
) {
546 edit_unlock_file (exp
);
548 edit
->locked
= edit_unlock_file (edit
->filename
);
550 if (edit
->locked
|| save_lock
)
551 edit
->locked
= edit_unlock_file (edit
->filename
);
554 edit_set_filename (edit
, exp
);
557 edit
->delete_file
= 0;
558 if (different_filename
)
559 edit_load_syntax (edit
, NULL
, option_syntax_type
);
560 edit
->force
|= REDRAW_COMPLETELY
;
563 edit_error_dialog (_(" Save As "),
565 (" Cannot save file. ")));
568 /* Failed, so maintain modify (not save) lock */
570 edit_unlock_file (exp
);
572 edit
->force
|= REDRAW_COMPLETELY
;
577 edit
->force
|= REDRAW_COMPLETELY
;
581 /* {{{ Macro stuff starts here */
584 raw_callback (struct Dlg_head
*h
, dlg_msg_t msg
, int parm
)
592 return default_dlg_callback (h
, msg
, parm
);
596 /* gets a raw key from the keyboard. Passing cancel = 1 draws
597 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
598 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
599 and Esc are cannot returned */
601 edit_raw_key_query (const char *heading
, const char *query
, int cancel
)
603 int w
= strlen (query
) + 7;
604 struct Dlg_head
*raw_dlg
=
605 create_dlg (0, 0, 7, w
, dialog_colors
, raw_callback
,
607 DLG_CENTER
| DLG_TRYUP
| DLG_WANT_TAB
);
609 input_new (3 - cancel
, w
- 5, INPUT_COLOR
, 2, "", 0, INPUT_COMPLETE_DEFAULT
));
610 add_widget (raw_dlg
, label_new (3 - cancel
, 2, query
));
613 button_new (4, w
/ 2 - 5, B_CANCEL
, NORMAL_BUTTON
,
616 w
= raw_dlg
->ret_value
;
617 destroy_dlg (raw_dlg
);
619 if (w
== XCTRL ('g') || w
== XCTRL ('c') || w
== ESC_CHAR
627 /* creates a macro file if it doesn't exist */
628 static FILE *edit_open_macro_file (const char *r
)
630 const char *filename
;
632 filename
= catstrs (home_dir
, PATH_SEP_STR MACRO_FILE
, (char *) NULL
);
633 if ((file
= open (filename
, O_CREAT
| O_RDWR
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
636 return fopen (filename
, r
);
639 #define MAX_MACROS 1024
640 static int saved_macro
[MAX_MACROS
+ 1];
641 static int saved_macros_loaded
= 0;
644 This is just to stop the macro file be loaded over and over for keys
645 that aren't defined to anything. On slow systems this could be annoying.
651 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++)
652 if (saved_macro
[i
] == k
)
657 /* returns 1 on error */
659 edit_delete_macro (WEdit
* edit
, int k
)
661 struct macro macro
[MAX_MACRO_LENGTH
];
667 if (saved_macros_loaded
)
668 if ((j
= macro_exists (k
)) < 0)
670 g
= fopen (catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
), "w");
672 edit_error_dialog (_(" Delete macro "),
673 get_sys_error (_(" Cannot open temp file ")));
676 f
= edit_open_macro_file ("r");
678 edit_error_dialog (_(" Delete macro "),
679 get_sys_error (_(" Cannot open macro file ")));
684 n
= fscanf (f
, ("key '%d 0': "), &s
);
688 while (fscanf (f
, "%hd %hd, ", ¯o
[n
].command
, ¯o
[n
].ch
))
692 fprintf (g
, ("key '%d 0': "), s
);
693 for (i
= 0; i
< n
; i
++)
694 fprintf (g
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
700 if (rename (catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
), catstrs (home_dir
, PATH_SEP_STR MACRO_FILE
, (char *) NULL
)) == -1) {
701 edit_error_dialog (_(" Delete macro "),
702 get_sys_error (_(" Cannot overwrite macro file ")));
705 if (saved_macros_loaded
)
706 memmove (saved_macro
+ j
, saved_macro
+ j
+ 1, sizeof (int) * (MAX_MACROS
- j
- 1));
710 /* returns 0 on error */
711 int edit_save_macro_cmd (WEdit
* edit
, struct macro macro
[], int n
)
716 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
717 s
= edit_raw_key_query (_(" Save macro "),
718 _(" Press the macro's new hotkey: "), 1);
719 edit
->force
|= REDRAW_COMPLETELY
;
721 if (edit_delete_macro (edit
, s
))
723 f
= edit_open_macro_file ("a+");
725 fprintf (f
, ("key '%d 0': "), s
);
726 for (i
= 0; i
< n
; i
++)
727 fprintf (f
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
730 if (saved_macros_loaded
) {
731 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++);
736 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
741 void edit_delete_macro_cmd (WEdit
* edit
)
745 command
= edit_raw_key_query (_ (" Delete macro "),
746 _ (" Press macro hotkey: "), 1);
751 edit_delete_macro (edit
, command
);
754 /* return 0 on error */
755 int edit_load_macro_cmd (WEdit
* edit
, struct macro macro
[], int *n
, int k
)
758 int s
, i
= 0, found
= 0;
762 if (saved_macros_loaded
)
763 if (macro_exists (k
) < 0)
766 if ((f
= edit_open_macro_file ("r"))) {
770 u
= fscanf (f
, ("key '%d 0': "), &s
);
773 if (!saved_macros_loaded
)
774 saved_macro
[i
++] = s
;
777 while (*n
< MAX_MACRO_LENGTH
&& 2 == fscanf (f
, "%hd %hd, ", ¯o
[*n
].command
, ¯o
[*n
].ch
))
780 while (2 == fscanf (f
, "%hd %hd, ", &dummy
.command
, &dummy
.ch
));
785 } while (!found
|| !saved_macros_loaded
);
786 if (!saved_macros_loaded
) {
788 saved_macros_loaded
= 1;
793 edit_error_dialog (_(" Load macro "),
794 get_sys_error (_(" Cannot open macro file ")));
798 /* }}} Macro stuff starts here */
800 /* returns 1 on success */
801 int edit_save_confirm_cmd (WEdit
* edit
)
805 if (edit_confirm_save
) {
806 f
= catstrs (_(" Confirm save file? : "), edit
->filename
, " ", (char *) NULL
);
807 if (edit_query_dialog2 (_(" Save file "), f
, _("&Save"), _("&Cancel")))
810 return edit_save_cmd (edit
);
814 /* returns 1 on success */
816 edit_save_cmd (WEdit
*edit
)
818 int res
, save_lock
= 0;
820 if (!edit
->locked
&& !edit
->delete_file
)
821 save_lock
= edit_lock_file (edit
->filename
);
822 res
= edit_save_file (edit
, edit
->filename
);
824 /* Maintain modify (not save) lock on failure */
825 if ((res
> 0 && edit
->locked
) || save_lock
)
826 edit
->locked
= edit_unlock_file (edit
->filename
);
828 /* On failure try 'save as', it does locking on its own */
830 return edit_save_as_cmd (edit
);
831 edit
->force
|= REDRAW_COMPLETELY
;
833 edit
->delete_file
= 0;
841 /* returns 1 on success */
842 int edit_new_cmd (WEdit
* edit
)
844 if (edit
->modified
) {
845 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
846 edit
->force
|= REDRAW_COMPLETELY
;
850 edit
->force
|= REDRAW_COMPLETELY
;
852 return edit_renew (edit
); /* if this gives an error, something has really screwed up */
855 /* returns 1 on error */
857 edit_load_file_from_filename (WEdit
* edit
, char *exp
)
859 int prev_locked
= edit
->locked
;
860 char *prev_filename
= g_strdup (edit
->filename
);
862 if (!edit_reload (edit
, exp
)) {
863 g_free (prev_filename
);
868 edit_unlock_file (prev_filename
);
869 g_free (prev_filename
);
874 edit_load_cmd (WEdit
*edit
)
878 if (edit
->modified
) {
879 if (edit_query_dialog2
881 _(" Current text was modified without a file save. \n"
882 " Continue discards these changes. "), _("C&ontinue"),
884 edit
->force
|= REDRAW_COMPLETELY
;
889 exp
= input_expand_dialog (_(" Load "), _(" Enter file name: "),
890 MC_HISTORY_EDIT_LOAD
, edit
->filename
);
894 edit_load_file_from_filename (edit
, exp
);
897 edit
->force
|= REDRAW_COMPLETELY
;
902 if mark2 is -1 then marking is from mark1 to the cursor.
903 Otherwise its between the markers. This handles this.
904 Returns 1 if no text is marked.
906 int eval_marks (WEdit
* edit
, long *start_mark
, long *end_mark
)
908 if (edit
->mark1
!= edit
->mark2
) {
909 if (edit
->mark2
>= 0) {
910 *start_mark
= min (edit
->mark1
, edit
->mark2
);
911 *end_mark
= max (edit
->mark1
, edit
->mark2
);
913 *start_mark
= min (edit
->mark1
, edit
->curs1
);
914 *end_mark
= max (edit
->mark1
, edit
->curs1
);
915 edit
->column2
= edit
->curs_col
;
919 *start_mark
= *end_mark
= 0;
920 edit
->column2
= edit
->column1
= 0;
925 #define space_width 1
928 edit_insert_column_of_text (WEdit
* edit
, unsigned char *data
, int size
, int width
)
932 cursor
= edit
->curs1
;
933 col
= edit_get_col (edit
);
934 for (i
= 0; i
< size
; i
++) {
935 if (data
[i
] == '\n') { /* fill in and move to next line */
938 if (edit_get_byte (edit
, edit
->curs1
) != '\n') {
939 l
= width
- (edit_get_col (edit
) - col
);
941 edit_insert (edit
, ' ');
945 for (p
= edit
->curs1
;; p
++) {
946 if (p
== edit
->last_byte
) {
947 edit_cursor_move (edit
, edit
->last_byte
- edit
->curs1
);
948 edit_insert_ahead (edit
, '\n');
952 if (edit_get_byte (edit
, p
) == '\n') {
957 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, col
, 0) - edit
->curs1
);
958 l
= col
- edit_get_col (edit
);
959 while (l
>= space_width
) {
960 edit_insert (edit
, ' ');
965 edit_insert (edit
, data
[i
]);
967 edit_cursor_move (edit
, cursor
- edit
->curs1
);
972 edit_block_copy_cmd (WEdit
*edit
)
974 long start_mark
, end_mark
, current
= edit
->curs1
;
976 unsigned char *copy_buf
;
978 edit_update_curs_col (edit
);
979 if (eval_marks (edit
, &start_mark
, &end_mark
))
982 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
984 /* all that gets pushed are deletes hence little space is used on the stack */
986 edit_push_markers (edit
);
988 if (column_highlighting
) {
989 edit_insert_column_of_text (edit
, copy_buf
, size
,
990 abs (edit
->column2
- edit
->column1
));
993 edit_insert_ahead (edit
, copy_buf
[size
]);
997 edit_scroll_screen_over_cursor (edit
);
999 if (column_highlighting
) {
1000 edit_set_markers (edit
, 0, 0, 0, 0);
1001 edit_push_action (edit
, COLUMN_ON
);
1002 column_highlighting
= 0;
1003 } else if (start_mark
< current
&& end_mark
> current
)
1004 edit_set_markers (edit
, start_mark
,
1005 end_mark
+ end_mark
- start_mark
, 0, 0);
1007 edit
->force
|= REDRAW_PAGE
;
1012 edit_block_move_cmd (WEdit
*edit
)
1016 unsigned char *copy_buf
;
1017 long start_mark
, end_mark
;
1021 if (eval_marks (edit
, &start_mark
, &end_mark
))
1023 if (column_highlighting
) {
1024 edit_update_curs_col (edit
);
1026 if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
1027 if ((x
> edit
->column1
&& x
< edit
->column2
)
1028 || (x
> edit
->column2
&& x
< edit
->column1
))
1030 } else if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
1033 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
1034 if (edit_query_dialog2
1037 (" Block is large, you may not be able to undo this action. "),
1038 _("C&ontinue"), _("&Cancel")))
1041 edit_push_markers (edit
);
1042 current
= edit
->curs1
;
1043 if (column_highlighting
) {
1044 int size
, c1
, c2
, line
;
1045 line
= edit
->curs_line
;
1046 if (edit
->mark2
< 0)
1047 edit_mark_cmd (edit
, 0);
1048 c1
= min (edit
->column1
, edit
->column2
);
1049 c2
= max (edit
->column1
, edit
->column2
);
1050 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
1052 edit_block_delete_cmd (edit
);
1055 edit_move_to_line (edit
, line
);
1056 edit_cursor_move (edit
,
1057 edit_move_forward3 (edit
,
1058 edit_bol (edit
, edit
->curs1
),
1059 x
, 0) - edit
->curs1
);
1060 edit_insert_column_of_text (edit
, copy_buf
, size
, c2
- c1
);
1062 line
= edit
->curs_line
;
1063 edit_update_curs_col (edit
);
1065 edit_block_delete_cmd (edit
);
1066 edit_move_to_line (edit
, line
);
1067 edit_cursor_move (edit
,
1068 edit_move_forward3 (edit
,
1071 x
, 0) - edit
->curs1
);
1073 edit_set_markers (edit
, 0, 0, 0, 0);
1074 edit_push_action (edit
, COLUMN_ON
);
1075 column_highlighting
= 0;
1077 copy_buf
= g_malloc (end_mark
- start_mark
);
1078 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
1079 edit_scroll_screen_over_cursor (edit
);
1081 while (count
< end_mark
) {
1082 copy_buf
[end_mark
- count
- 1] = edit_delete (edit
);
1085 edit_scroll_screen_over_cursor (edit
);
1086 edit_cursor_move (edit
,
1087 current
- edit
->curs1
-
1088 (((current
- edit
->curs1
) >
1089 0) ? end_mark
- start_mark
: 0));
1090 edit_scroll_screen_over_cursor (edit
);
1091 while (count
-- > start_mark
)
1092 edit_insert_ahead (edit
, copy_buf
[end_mark
- count
- 1]);
1093 edit_set_markers (edit
, edit
->curs1
,
1094 edit
->curs1
+ end_mark
- start_mark
, 0, 0);
1096 edit_scroll_screen_over_cursor (edit
);
1098 edit
->force
|= REDRAW_PAGE
;
1102 edit_delete_column_of_text (WEdit
* edit
)
1104 long p
, q
, r
, m1
, m2
;
1108 eval_marks (edit
, &m1
, &m2
);
1109 n
= edit_move_forward (edit
, m1
, 0, m2
) + 1;
1110 c
= edit_move_forward3 (edit
, edit_bol (edit
, m1
), 0, m1
);
1111 d
= edit_move_forward3 (edit
, edit_bol (edit
, m2
), 0, m2
);
1117 r
= edit_bol (edit
, edit
->curs1
);
1118 p
= edit_move_forward3 (edit
, r
, b
, 0);
1119 q
= edit_move_forward3 (edit
, r
, c
, 0);
1124 edit_cursor_move (edit
, p
- edit
->curs1
);
1125 while (q
> p
) { /* delete line between margins */
1126 if (edit_get_byte (edit
, edit
->curs1
) != '\n')
1130 if (n
) /* move to next line except on the last delete */
1131 edit_cursor_move (edit
, edit_move_forward (edit
, edit
->curs1
, 1, 0) - edit
->curs1
);
1135 /* if success return 0 */
1137 edit_block_delete (WEdit
*edit
)
1140 long start_mark
, end_mark
;
1141 if (eval_marks (edit
, &start_mark
, &end_mark
))
1143 if (column_highlighting
&& edit
->mark2
< 0)
1144 edit_mark_cmd (edit
, 0);
1145 if ((end_mark
- start_mark
) > option_max_undo
/ 2) {
1146 /* Warning message with a query to continue or cancel the operation */
1147 if (edit_query_dialog2
1150 (" Block is large, you may not be able to undo this action. "),
1151 _("C&ontinue"), _("&Cancel"))) {
1155 edit_push_markers (edit
);
1156 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
1157 edit_scroll_screen_over_cursor (edit
);
1159 if (start_mark
< end_mark
) {
1160 if (column_highlighting
) {
1161 if (edit
->mark2
< 0)
1162 edit_mark_cmd (edit
, 0);
1163 edit_delete_column_of_text (edit
);
1165 while (count
< end_mark
) {
1171 edit_set_markers (edit
, 0, 0, 0, 0);
1172 edit
->force
|= REDRAW_PAGE
;
1176 /* returns 1 if canceelled by user */
1177 int edit_block_delete_cmd (WEdit
* edit
)
1179 long start_mark
, end_mark
;
1180 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
1181 edit_delete_line (edit
);
1184 return edit_block_delete (edit
);
1188 #define INPUT_INDEX 9
1189 #define SEARCH_DLG_WIDTH 58
1190 #define SEARCH_DLG_HEIGHT 10
1191 #define REPLACE_DLG_WIDTH 58
1192 #define REPLACE_DLG_HEIGHT 15
1193 #define CONFIRM_DLG_WIDTH 79
1194 #define CONFIRM_DLG_HEIGTH 6
1195 #define B_REPLACE_ALL (B_USER+1)
1196 #define B_REPLACE_ONE (B_USER+2)
1197 #define B_SKIP_REPLACE (B_USER+3)
1200 edit_replace_prompt (WEdit
* edit
, char *replace_text
, int xpos
, int ypos
)
1202 QuickWidget quick_widgets
[] =
1204 {quick_button
, 63, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Cancel"),
1205 0, B_CANCEL
, 0, 0, NULL
},
1206 {quick_button
, 50, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("O&ne"),
1207 0, B_REPLACE_ONE
, 0, 0, NULL
},
1208 {quick_button
, 37, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("A&ll"),
1209 0, B_REPLACE_ALL
, 0, 0, NULL
},
1210 {quick_button
, 21, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Skip"),
1211 0, B_SKIP_REPLACE
, 0, 0, NULL
},
1212 {quick_button
, 4, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Replace"),
1213 0, B_ENTER
, 0, 0, NULL
},
1214 {quick_label
, 2, CONFIRM_DLG_WIDTH
, 2, CONFIRM_DLG_HEIGTH
, 0,
1218 GString
*label_text
= g_string_new (_(" Replace with: "));
1219 if (*replace_text
) {
1221 label_len
= label_text
->len
;
1222 g_string_append (label_text
, replace_text
);
1223 convert_to_display (label_text
->str
+ label_len
);
1225 quick_widgets
[5].text
= label_text
->str
;
1229 QuickDialog Quick_input
=
1230 {CONFIRM_DLG_WIDTH
, CONFIRM_DLG_HEIGTH
, 0, 0, N_ (" Confirm replace "),
1231 "[Input Line Keys]", 0 /*quick_widgets */, 0 };
1233 Quick_input
.widgets
= quick_widgets
;
1235 Quick_input
.xpos
= xpos
;
1237 /* Sometimes menu can hide replaced text. I don't like it */
1239 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ CONFIRM_DLG_HEIGTH
- 1))
1240 ypos
-= CONFIRM_DLG_HEIGTH
;
1242 Quick_input
.ypos
= ypos
;
1243 retval
= quick_dialog (&Quick_input
);
1244 g_string_free (label_text
, TRUE
);
1250 edit_replace_dialog (WEdit
* edit
, const char *search_default
,
1251 const char *replace_default
, const char *argorder_default
,
1252 /*@out@*/ char **search_text
, /*@out@*/ char **replace_text
,
1253 /*@out@*/ char **arg_order
)
1255 int treplace_scanf
= replace_scanf
;
1256 int treplace_regexp
= replace_regexp
;
1257 int treplace_all
= replace_all
;
1258 int treplace_prompt
= replace_prompt
;
1259 int treplace_backwards
= replace_backwards
;
1260 int treplace_whole
= replace_whole
;
1261 int treplace_case
= replace_case
;
1263 /* Alt-p is in use as hotkey for previous entry; don't use */
1264 QuickWidget quick_widgets
[] =
1266 {quick_button
, 6, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1268 {quick_button
, 2, 10, 12, REPLACE_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1270 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1272 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("replace &All"), 0, 0,
1274 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("pro&Mpt on replace"), 0, 0,
1276 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1278 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1280 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1282 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 8, REPLACE_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1284 {quick_input
, 3, REPLACE_DLG_WIDTH
, 7, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1286 {quick_label
, 2, REPLACE_DLG_WIDTH
, 6, REPLACE_DLG_HEIGHT
, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1288 {quick_input
, 3, REPLACE_DLG_WIDTH
, 5, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1290 {quick_label
, 2, REPLACE_DLG_WIDTH
, 4, REPLACE_DLG_HEIGHT
, N_(" Enter replacement string:"), 0, 0, 0,
1292 {quick_input
, 3, REPLACE_DLG_WIDTH
, 3, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1294 {quick_label
, 2, REPLACE_DLG_WIDTH
, 2, REPLACE_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1300 quick_widgets
[2].result
= &treplace_scanf
;
1301 quick_widgets
[3].result
= &treplace_all
;
1302 quick_widgets
[4].result
= &treplace_prompt
;
1303 quick_widgets
[5].result
= &treplace_backwards
;
1304 quick_widgets
[6].result
= &treplace_regexp
;
1305 quick_widgets
[7].result
= &treplace_whole
;
1306 quick_widgets
[8].result
= &treplace_case
;
1307 quick_widgets
[9].str_result
= arg_order
;
1308 quick_widgets
[9].text
= argorder_default
;
1309 quick_widgets
[11].str_result
= replace_text
;
1310 quick_widgets
[11].text
= replace_default
;
1311 quick_widgets
[13].str_result
= search_text
;
1312 quick_widgets
[13].text
= search_default
;
1314 QuickDialog Quick_input
=
1315 {REPLACE_DLG_WIDTH
, REPLACE_DLG_HEIGHT
, -1, 0, N_(" Replace "),
1316 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1318 Quick_input
.widgets
= quick_widgets
;
1320 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1321 replace_scanf
= treplace_scanf
;
1322 replace_backwards
= treplace_backwards
;
1323 replace_regexp
= treplace_regexp
;
1324 replace_all
= treplace_all
;
1325 replace_prompt
= treplace_prompt
;
1326 replace_whole
= treplace_whole
;
1327 replace_case
= treplace_case
;
1331 *replace_text
= NULL
;
1332 *search_text
= NULL
;
1340 edit_search_dialog (WEdit
* edit
, char **search_text
)
1342 int treplace_scanf
= replace_scanf
;
1343 int treplace_regexp
= replace_regexp
;
1344 int treplace_whole
= replace_whole
;
1345 int treplace_case
= replace_case
;
1346 int treplace_backwards
= replace_backwards
;
1348 QuickWidget quick_widgets
[] =
1350 {quick_button
, 6, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1352 {quick_button
, 2, 10, 7, SEARCH_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1354 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1356 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1358 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1360 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1362 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 4, SEARCH_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1364 {quick_input
, 3, SEARCH_DLG_WIDTH
, 3, SEARCH_DLG_HEIGHT
, "", 52, 0, 0,
1366 {quick_label
, 2, SEARCH_DLG_WIDTH
, 2, SEARCH_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1372 quick_widgets
[2].result
= &treplace_scanf
;
1373 quick_widgets
[3].result
= &treplace_backwards
;
1374 quick_widgets
[4].result
= &treplace_regexp
;
1375 quick_widgets
[5].result
= &treplace_whole
;
1376 quick_widgets
[6].result
= &treplace_case
;
1377 quick_widgets
[7].str_result
= search_text
;
1378 quick_widgets
[7].text
= *search_text
;
1381 QuickDialog Quick_input
=
1382 {SEARCH_DLG_WIDTH
, SEARCH_DLG_HEIGHT
, -1, 0, N_("Search"),
1383 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1385 Quick_input
.widgets
= quick_widgets
;
1387 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1388 replace_scanf
= treplace_scanf
;
1389 replace_backwards
= treplace_backwards
;
1390 replace_regexp
= treplace_regexp
;
1391 replace_whole
= treplace_whole
;
1392 replace_case
= treplace_case
;
1394 *search_text
= NULL
;
1400 static long sargs
[NUM_REPL_ARGS
][256 / sizeof (long)];
1402 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1403 sargs[4], sargs[5], sargs[6], sargs[7], \
1404 sargs[8], sargs[9], sargs[10], sargs[11], \
1405 sargs[12], sargs[13], sargs[14], sargs[15]
1407 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1408 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1409 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1410 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1413 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1414 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1416 string_regexp_search (char *pattern
, char *string
, int match_type
,
1417 int match_bol
, int icase
, int *found_len
, void *d
)
1420 static char *old_pattern
= NULL
;
1421 static int old_type
, old_icase
;
1423 static regmatch_t s
[1];
1425 pmatch
= (regmatch_t
*) d
;
1429 if (!old_pattern
|| strcmp (old_pattern
, pattern
)
1430 || old_type
!= match_type
|| old_icase
!= icase
) {
1433 g_free (old_pattern
);
1436 if (regcomp (&r
, pattern
, REG_EXTENDED
| (icase
? REG_ICASE
: 0) |
1441 old_pattern
= g_strdup (pattern
);
1442 old_type
= match_type
;
1446 (&r
, string
, d
? NUM_REPL_ARGS
: 1, pmatch
,
1448 || match_type
!= match_normal
) ? 0 : REG_NOTBOL
)) != 0) {
1452 *found_len
= pmatch
[0].rm_eo
- pmatch
[0].rm_so
;
1453 return (pmatch
[0].rm_so
);
1456 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1457 (and the above) routines to work properly - paul */
1459 typedef int (*edit_getbyte_fn
) (WEdit
*, long);
1462 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
)
1465 long l
= strlen ((char *) exp
), f
= 0;
1468 for (p
= 0; p
< l
; p
++) /* count conversions... */
1470 if (exp
[++p
] != '%') /* ...except for "%%" */
1473 if (replace_scanf
|| replace_regexp
) {
1476 unsigned char mbuf
[MAX_REPL_LEN
* 2 + 3];
1478 replace_scanf
= (!replace_regexp
); /* can't have both */
1482 if (replace_scanf
) {
1483 unsigned char e
[MAX_REPL_LEN
];
1484 if (n
>= NUM_REPL_ARGS
)
1488 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++)
1489 buf
[p
- start
] = (*get_byte
) (data
, p
);
1491 for (p
= 0; exp
[p
] != 0; p
++)
1492 exp
[p
] = my_lower_case (exp
[p
]);
1493 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++) {
1494 c
= (*get_byte
) (data
, p
);
1495 buf
[p
- start
] = my_lower_case (c
);
1499 buf
[(q
= p
- start
)] = 0;
1500 strcpy ((char *) e
, (char *) exp
);
1501 strcat ((char *) e
, "%n");
1505 *((int *) sargs
[n
]) = 0; /* --> here was the problem - now fixed: good */
1506 if (n
== sscanf ((char *) buf
, (char *) exp
, SCANF_ARGS
)) {
1507 if (*((int *) sargs
[n
])) {
1508 *len
= *((int *) sargs
[n
]);
1514 if (q
+ start
< last_byte
) {
1516 buf
[q
] = (*get_byte
) (data
, q
+ start
);
1518 c
= (*get_byte
) (data
, q
+ start
);
1519 buf
[q
] = my_lower_case (c
);
1525 buf
++; /* move the window along */
1526 if (buf
== mbuf
+ MAX_REPL_LEN
) { /* the window is about to go past the end of array, so... */
1527 memmove (mbuf
, buf
, strlen ((char *) buf
) + 1); /* reset it */
1532 } else { /* regexp matching */
1534 int found_start
, match_bol
, move_win
= 0;
1536 while (start
+ offset
< last_byte
) {
1537 match_bol
= (start
== 0 || (*get_byte
) (data
, start
+ offset
- 1) == '\n');
1542 for (; p
< last_byte
&& q
< MAX_REPL_LEN
; p
++, q
++) {
1543 mbuf
[q
] = (*get_byte
) (data
, p
);
1544 if (mbuf
[q
] == '\n') {
1554 found_start
= string_regexp_search ((char *) exp
, (char *) buf
, match_normal
, match_bol
, !replace_case
, len
, d
);
1556 if (found_start
<= -2) { /* regcomp/regexec error */
1560 else if (found_start
== -1) /* not found: try next line */
1562 else if (*len
== 0) { /* null pattern: try again at next character */
1569 return (start
+ offset
- q
+ found_start
);
1574 if (buf
[q
- 1] != '\n') { /* incomplete line: try to recover */
1575 buf
= mbuf
+ MAX_REPL_LEN
/ 2;
1576 q
= strlen ((const char *) buf
);
1577 memmove (mbuf
, buf
, q
);
1586 *len
= strlen ((const char *) exp
);
1588 for (p
= start
; p
<= last_byte
- l
; p
++) {
1589 if ((*get_byte
) (data
, p
) == (unsigned char)exp
[0]) { /* check if first char matches */
1590 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1591 if ((*get_byte
) (data
, q
+ p
) != (unsigned char)exp
[q
])
1600 for (p
= 0; exp
[p
] != 0; p
++)
1601 exp
[p
] = my_lower_case (exp
[p
]);
1603 for (p
= start
; p
<= last_byte
- l
; p
++) {
1604 if (my_lower_case ((*get_byte
) (data
, p
)) == (unsigned char)exp
[0]) {
1605 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1606 if (my_lower_case ((*get_byte
) (data
, q
+ p
)) != (unsigned char)exp
[q
])
1621 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
)
1622 { /*front end to find_string to check for
1627 while ((p
= edit_find_string (p
, exp
, len
, last_byte
, get_byte
, data
, once_only
, d
)) >= 0) {
1628 if (replace_whole
) {
1629 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1630 if (!strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
- 1))
1631 && !strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
+ *len
)))
1639 p
++; /*not a whole word so continue search. */
1645 edit_find (long search_start
, unsigned char *exp
, int *len
, long last_byte
, edit_getbyte_fn get_byte
, void *data
, void *d
)
1648 if (replace_backwards
) {
1649 while (search_start
>= 0) {
1650 p
= edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 1, d
);
1651 if (p
== search_start
)
1656 return edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 0, d
);
1661 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1663 #define snprint(v) { \
1666 n = snprintf(s,e-s,q1,v); \
1667 if (n >= (size_t) (e - s)) goto nospc; \
1671 /* this function uses the sprintf command to do a vprintf */
1672 /* it takes pointers to arguments instead of the arguments themselves */
1673 /* The return value is the number of bytes written excluding '\0'
1674 if successfull, -1 if the resulting string would be too long and
1675 -2 if the format string is errorneous. */
1676 static int snprintf_p (char *str
, size_t size
, const char *fmt
,...)
1677 __attribute__ ((format (printf
, 3, 4)));
1679 static int snprintf_p (char *str
, size_t size
, const char *fmt
,...)
1684 char *s
= str
, *e
= str
+ size
;
1692 while ((p
= strchr (p
, '%'))) {
1694 if (n
>= (size_t) (e
- s
))
1696 memcpy (s
, q
, n
); /* copy stuff between format specifiers */
1711 /* We were passed only 16 arguments. */
1724 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace field width with a number */
1727 while (is_digit (*p
) && p1
< q1
+ 20)
1736 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace precision with a number */
1739 while (is_digit (*p
) && p1
< q1
+ 32)
1744 /* flags done, now get argument */
1746 snprint (va_arg (ap
, char *));
1747 } else if (*p
== 'h') {
1748 if (strchr ("diouxX", *p
))
1749 snprint (*va_arg (ap
, short *));
1750 } else if (*p
== 'l') {
1752 if (strchr ("diouxX", *p
))
1753 snprint (*va_arg (ap
, long *));
1754 } else if (strchr ("cdiouxX", *p
)) {
1755 snprint (*va_arg (ap
, int *));
1756 } else if (*p
== 'L') {
1758 if (strchr ("EefgG", *p
))
1759 snprint (*va_arg (ap
, double *)); /* should be long double */
1760 } else if (strchr ("EefgG", *p
)) {
1761 snprint (*va_arg (ap
, double *));
1762 } else if (strchr ("DOU", *p
)) {
1763 snprint (*va_arg (ap
, long *));
1764 } else if (*p
== 'p') {
1765 snprint (*va_arg (ap
, void **));
1772 if (n
>= (size_t) (e
- s
))
1774 memcpy (s
, q
, n
+ 1);
1784 static void regexp_error (WEdit
*edit
)
1787 edit_error_dialog (_("Error"), _(" Invalid regular expression, or scanf expression with too many conversions "));
1790 /* call with edit = 0 before shutdown to close memory leaks */
1792 edit_replace_cmd (WEdit
*edit
, int again
)
1794 static regmatch_t pmatch
[NUM_REPL_ARGS
];
1795 /* 1 = search string, 2 = replace with, 3 = argument order */
1796 static char *saved1
= NULL
; /* saved default[123] */
1797 static char *saved2
= NULL
;
1798 static char *saved3
= NULL
;
1799 char *input1
= NULL
; /* user input from the dialog */
1800 char *input2
= NULL
;
1801 char *input3
= NULL
;
1803 int replace_continue
;
1804 int treplace_prompt
= 0;
1805 long times_replaced
= 0, last_search
;
1806 int argord
[NUM_REPL_ARGS
];
1809 g_free (saved1
), saved1
= NULL
;
1810 g_free (saved2
), saved2
= NULL
;
1811 g_free (saved3
), saved3
= NULL
;
1815 last_search
= edit
->last_byte
;
1817 edit
->force
|= REDRAW_COMPLETELY
;
1819 if (again
&& !saved1
&& !saved2
)
1823 input1
= g_strdup (saved1
? saved1
: "");
1824 input2
= g_strdup (saved2
? saved2
: "");
1825 input3
= g_strdup (saved3
? saved3
: "");
1827 char *disp1
= g_strdup (saved1
? saved1
: "");
1828 char *disp2
= g_strdup (saved2
? saved2
: "");
1829 char *disp3
= g_strdup (saved3
? saved3
: "");
1831 convert_to_display (disp1
);
1832 convert_to_display (disp2
);
1833 convert_to_display (disp3
);
1835 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1836 edit_replace_dialog (edit
, disp1
, disp2
, disp3
, &input1
, &input2
,
1843 convert_from_input (input1
);
1844 convert_from_input (input2
);
1845 convert_from_input (input3
);
1847 treplace_prompt
= replace_prompt
;
1848 if (input1
== NULL
|| *input1
== '\0') {
1849 edit
->force
= REDRAW_COMPLETELY
;
1853 g_free (saved1
), saved1
= mhl_str_dup (input1
);
1854 g_free (saved2
), saved2
= mhl_str_dup (input2
);
1855 g_free (saved3
), saved3
= mhl_str_dup (input3
);
1864 for (i
= 0; i
< NUM_REPL_ARGS
; i
++) {
1865 if (s
!= NULL
&& *s
!= '\0') {
1867 if ((ord
> 0) && (ord
<= NUM_REPL_ARGS
))
1868 argord
[i
] = ord
- 1;
1871 s
= strchr (s
, ',');
1879 replace_continue
= replace_all
;
1881 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1
1882 && replace_backwards
)
1883 edit
->search_start
--;
1885 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1
1886 && !replace_backwards
)
1887 edit
->search_start
++;
1893 edit_find (edit
->search_start
, (unsigned char *) input1
, &len
,
1894 last_search
, edit_get_byte
, (void *) edit
, pmatch
);
1895 if (new_start
== -3) {
1896 regexp_error (edit
);
1899 edit
->search_start
= new_start
;
1900 /*returns negative on not found or error in pattern */
1902 if (edit
->search_start
>= 0) {
1905 edit
->found_start
= edit
->search_start
;
1906 i
= edit
->found_len
= len
;
1908 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1909 edit_scroll_screen_over_cursor (edit
);
1913 if (treplace_prompt
) {
1915 l
= edit
->curs_row
- edit
->num_widget_lines
/ 3;
1917 edit_scroll_downward (edit
, l
);
1919 edit_scroll_upward (edit
, -l
);
1921 edit_scroll_screen_over_cursor (edit
);
1922 edit
->force
|= REDRAW_PAGE
;
1923 edit_render_keypress (edit
);
1925 /*so that undo stops at each query */
1926 edit_push_key_press (edit
);
1928 switch (edit_replace_prompt (edit
, input2
, /* and prompt 2/3 down */
1929 (edit
->num_widget_columns
-
1930 CONFIRM_DLG_WIDTH
) / 2,
1931 edit
->num_widget_lines
* 2 /
1935 case B_SKIP_REPLACE
:
1939 treplace_prompt
= 0;
1940 replace_continue
= 1;
1943 replace_continue
= 0;
1947 replace_continue
= 0;
1951 if (replace_yes
) { /* delete then insert new */
1952 if (replace_scanf
) {
1953 char repl_str
[MAX_REPL_LEN
+ 2];
1956 /* we need to fill in sargs just like with scanf */
1957 if (replace_regexp
) {
1960 k
< NUM_REPL_ARGS
&& pmatch
[k
].rm_eo
>= 0;
1964 if (pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
> 255) {
1968 t
= (unsigned char *) &sargs
[k
- 1][0];
1970 j
< pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
1971 && j
< 255; j
++, t
++)
1972 *t
= (unsigned char) edit_get_byte (edit
,
1985 for (; k
<= NUM_REPL_ARGS
; k
++)
1986 sargs
[k
- 1][0] = 0;
1990 snprintf_p (repl_str
, MAX_REPL_LEN
+ 2, input2
,
1996 while (repl_str
[++i
])
1997 edit_insert (edit
, repl_str
[i
]);
1999 edit_error_dialog (_(" Replace "),
2003 (" Error in replacement format string. ")
2004 : _(" Replacement too long. "));
2005 replace_continue
= 0;
2012 edit_insert (edit
, input2
[i
]);
2014 edit
->found_len
= i
;
2016 /* so that we don't find the same string again */
2017 if (replace_backwards
) {
2018 last_search
= edit
->search_start
;
2019 edit
->search_start
--;
2021 edit
->search_start
+= i
;
2022 last_search
= edit
->last_byte
;
2024 edit_scroll_screen_over_cursor (edit
);
2026 const char *msg
= _(" Replace ");
2027 /* try and find from right here for next search */
2028 edit
->search_start
= edit
->curs1
;
2029 edit_update_curs_col (edit
);
2031 edit
->force
|= REDRAW_PAGE
;
2032 edit_render_keypress (edit
);
2033 if (times_replaced
) {
2034 message (D_NORMAL
, msg
, _(" %ld replacements made. "),
2037 query_dialog (msg
, _(" Search string not found "),
2038 D_NORMAL
, 1, _("&OK"));
2039 replace_continue
= 0;
2041 } while (replace_continue
);
2043 edit
->force
= REDRAW_COMPLETELY
;
2044 edit_scroll_screen_over_cursor (edit
);
2054 void edit_search_cmd (WEdit
* edit
, int again
)
2056 static char *old
= NULL
;
2065 exp
= old
? old
: exp
;
2066 if (again
) { /*ctrl-hotkey for search again. */
2069 exp
= g_strdup (old
);
2074 convert_to_display (exp
);
2075 #endif /* HAVE_CHARSET */
2077 edit_search_dialog (edit
, &exp
);
2081 convert_from_input (exp
);
2082 #endif /* HAVE_CHARSET */
2084 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2091 old
= g_strdup (exp
);
2093 if (search_create_bookmark
) {
2094 int found
= 0, books
= 0;
2095 int l
= 0, l_last
= -1;
2098 p
= edit_find (q
, (unsigned char *) exp
, &len
, edit
->last_byte
,
2099 edit_get_byte
, (void *) edit
, 0);
2103 l
+= edit_count_lines (edit
, q
, p
);
2105 book_mark_insert (edit
, l
, BOOK_MARK_FOUND_COLOR
);
2112 /* in response to number of bookmarks added because of string being found %d times */
2113 message (D_NORMAL
, _("Search"), _(" %d items found, %d bookmarks added "), found
, books
);
2115 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2119 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
2120 edit
->search_start
--;
2122 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
2123 edit
->search_start
++;
2125 edit
->search_start
= edit_find (edit
->search_start
, (unsigned char *) exp
, &len
, edit
->last_byte
,
2126 edit_get_byte
, (void *) edit
, 0);
2128 if (edit
->search_start
>= 0) {
2129 edit
->found_start
= edit
->search_start
;
2130 edit
->found_len
= len
;
2132 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
2133 edit_scroll_screen_over_cursor (edit
);
2134 if (replace_backwards
)
2135 edit
->search_start
--;
2137 edit
->search_start
++;
2138 } else if (edit
->search_start
== -3) {
2139 edit
->search_start
= edit
->curs1
;
2140 regexp_error (edit
);
2142 edit
->search_start
= edit
->curs1
;
2143 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2149 edit
->force
|= REDRAW_COMPLETELY
;
2150 edit_scroll_screen_over_cursor (edit
);
2155 * Check if it's OK to close the editor. If there are unsaved changes,
2156 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2159 edit_ok_to_exit (WEdit
*edit
)
2161 if (!edit
->modified
)
2164 switch (edit_query_dialog3
2165 (_("Quit"), _(" File was modified, Save with exit? "),
2166 _("&Cancel quit"), _("&Yes"), _("&No"))) {
2168 edit_push_markers (edit
);
2169 edit_set_markers (edit
, 0, 0, 0, 0);
2170 if (!edit_save_cmd (edit
))
2184 #define TEMP_BUF_LEN 1024
2186 /* Return a null terminated length of text. Result must be g_free'd */
2187 static unsigned char *
2188 edit_get_block (WEdit
*edit
, long start
, long finish
, int *l
)
2190 unsigned char *s
, *r
;
2191 r
= s
= g_malloc (finish
- start
+ 1);
2192 if (column_highlighting
) {
2194 /* copy from buffer, excluding chars that are out of the column 'margins' */
2195 while (start
< finish
) {
2197 x
= edit_move_forward3 (edit
, edit_bol (edit
, start
), 0,
2199 c
= edit_get_byte (edit
, start
);
2200 if ((x
>= edit
->column1
&& x
< edit
->column2
)
2201 || (x
>= edit
->column2
&& x
< edit
->column1
) || c
== '\n') {
2208 *l
= finish
- start
;
2209 while (start
< finish
)
2210 *s
++ = edit_get_byte (edit
, start
++);
2216 /* save block, returns 1 on success */
2218 edit_save_block (WEdit
* edit
, const char *filename
, long start
,
2224 mc_open (filename
, O_CREAT
| O_WRONLY
| O_TRUNC
,
2225 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
| O_BINARY
)) == -1)
2228 if (column_highlighting
) {
2229 unsigned char *block
, *p
;
2231 p
= block
= edit_get_block (edit
, start
, finish
, &len
);
2233 r
= mc_write (file
, p
, len
);
2243 len
= finish
- start
;
2244 buf
= g_malloc (TEMP_BUF_LEN
);
2245 while (start
!= finish
) {
2246 end
= min (finish
, start
+ TEMP_BUF_LEN
);
2247 for (; i
< end
; i
++)
2248 buf
[i
- start
] = edit_get_byte (edit
, i
);
2249 len
-= mc_write (file
, (char *) buf
, end
- start
);
2260 /* copies a block to clipboard file */
2261 static int edit_save_block_to_clip_file (WEdit
* edit
, long start
, long finish
)
2263 return edit_save_block (edit
, catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
), start
, finish
);
2267 void edit_paste_from_history (WEdit
*edit
)
2270 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
2273 int edit_copy_to_X_buf_cmd (WEdit
* edit
)
2275 long start_mark
, end_mark
;
2276 if (eval_marks (edit
, &start_mark
, &end_mark
))
2278 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2279 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2282 edit_mark_cmd (edit
, 1);
2286 int edit_cut_to_X_buf_cmd (WEdit
* edit
)
2288 long start_mark
, end_mark
;
2289 if (eval_marks (edit
, &start_mark
, &end_mark
))
2291 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2292 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2295 edit_block_delete_cmd (edit
);
2296 edit_mark_cmd (edit
, 1);
2300 void edit_paste_from_X_buf_cmd (WEdit
* edit
)
2302 edit_insert_file (edit
, catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
));
2307 * Ask user for the line and go to that line.
2308 * Negative numbers mean line from the end (i.e. -1 is the last line).
2311 edit_goto_cmd (WEdit
*edit
)
2314 static long line
= 0; /* line as typed, saved as default */
2319 g_snprintf (s
, sizeof (s
), "%ld", line
);
2320 f
= input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE
,
2330 l
= strtol (f
, &error
, 0);
2338 l
= edit
->total_lines
+ l
+ 2;
2339 edit_move_display (edit
, l
- edit
->num_widget_lines
/ 2 - 1);
2340 edit_move_to_line (edit
, l
- 1);
2341 edit
->force
|= REDRAW_COMPLETELY
;
2346 /* Return 1 on success */
2348 edit_save_block_cmd (WEdit
*edit
)
2350 long start_mark
, end_mark
;
2352 if (eval_marks (edit
, &start_mark
, &end_mark
))
2355 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2356 MC_HISTORY_EDIT_SAVE_BLOCK
,
2357 catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
));
2358 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2364 if (edit_save_block (edit
, exp
, start_mark
, end_mark
)) {
2366 edit
->force
|= REDRAW_COMPLETELY
;
2370 edit_error_dialog (_(" Save Block "),
2372 (" Cannot save file. ")));
2376 edit
->force
|= REDRAW_COMPLETELY
;
2381 /* returns 1 on success */
2383 edit_insert_file_cmd (WEdit
*edit
)
2385 char *exp
= input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2386 MC_HISTORY_EDIT_INSERT_FILE
,
2387 catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
));
2388 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2394 if (edit_insert_file (edit
, exp
)) {
2396 edit
->force
|= REDRAW_COMPLETELY
;
2400 edit_error_dialog (_(" Insert File "),
2402 (" Cannot insert file. ")));
2406 edit
->force
|= REDRAW_COMPLETELY
;
2410 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2411 int edit_sort_cmd (WEdit
* edit
)
2413 static char *old
= 0;
2415 long start_mark
, end_mark
;
2418 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2419 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2422 edit_save_block (edit
, catstrs (home_dir
, PATH_SEP_STR BLOCK_FILE
, (char *) NULL
), start_mark
, end_mark
);
2424 exp
= input_dialog (_(" Run Sort "),
2425 _(" Enter sort options (see manpage) separated by whitespace: "),
2426 MC_HISTORY_EDIT_SORT
, (old
!= NULL
) ? old
: "");
2433 e
= system (catstrs (" sort ", exp
, " ", home_dir
, PATH_SEP_STR BLOCK_FILE
, " > ", home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2435 if (e
== -1 || e
== 127) {
2436 edit_error_dialog (_(" Sort "),
2437 get_sys_error (_(" Cannot execute sort command ")));
2440 sprintf (q
, "%d ", e
);
2441 edit_error_dialog (_(" Sort "),
2442 catstrs (_(" Sort returned non-zero: "), q
, (char *) NULL
));
2447 edit
->force
|= REDRAW_COMPLETELY
;
2449 if (edit_block_delete_cmd (edit
))
2451 edit_insert_file (edit
, catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2456 * Ask user for a command, execute it and paste its output back to the
2460 edit_ext_cmd (WEdit
*edit
)
2466 input_dialog (_("Paste output of external command"),
2467 _("Enter shell command(s):"),
2468 MC_HISTORY_EDIT_PASTE_EXTCMD
, NULL
);
2473 e
= system (catstrs (exp
, " > ", home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2477 edit_error_dialog (_("External command"),
2478 get_sys_error (_("Cannot execute command")));
2482 edit
->force
|= REDRAW_COMPLETELY
;
2484 edit_insert_file (edit
, catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2488 /* if block is 1, a block must be highlighted and the shell command
2489 processes it. If block is 0 the shell command is a straight system
2490 command, that just produces some output which is to be inserted */
2492 edit_block_process_cmd (WEdit
*edit
, const char *shell_cmd
, int block
)
2494 long start_mark
, end_mark
;
2496 FILE *script_home
= NULL
;
2497 FILE *script_src
= NULL
;
2498 FILE *block_file
= NULL
;
2499 const char *o
= NULL
;
2500 const char *h
= NULL
;
2501 const char *b
= NULL
;
2502 char *quoted_name
= NULL
;
2504 o
= catstrs (mc_home
, shell_cmd
, (char *) NULL
); /* original source script */
2505 h
= catstrs (home_dir
, PATH_SEP_STR EDIT_DIR
, shell_cmd
, (char *) NULL
); /* home script */
2506 b
= catstrs (home_dir
, PATH_SEP_STR BLOCK_FILE
, (char *) NULL
); /* block file */
2508 if (!(script_home
= fopen (h
, "r"))) {
2509 if (!(script_home
= fopen (h
, "w"))) {
2510 edit_error_dialog ("", get_sys_error (catstrs
2512 ("Error creating script:"),
2513 h
, (char *) NULL
)));
2516 if (!(script_src
= fopen (o
, "r"))) {
2517 fclose (script_home
);
2519 edit_error_dialog ("", get_sys_error (catstrs
2520 (_("Error reading script:"),
2521 o
, (char *) NULL
)));
2524 while (fgets (buf
, sizeof (buf
), script_src
))
2525 fputs (buf
, script_home
);
2526 if (fclose (script_home
)) {
2527 edit_error_dialog ("", get_sys_error (catstrs
2529 ("Error closing script:"),
2530 h
, (char *) NULL
)));
2534 edit_error_dialog ("", get_sys_error (catstrs
2535 (_("Script created:"), h
, (char *) NULL
)));
2540 if (block
) { /* for marked block run indent formatter */
2541 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2542 edit_error_dialog (_("Process block"),
2544 (" You must first highlight a block of text. "));
2547 edit_save_block (edit
, b
, start_mark
, end_mark
);
2548 quoted_name
= name_quote (edit
->filename
, 0);
2551 * Initial space is to avoid polluting bash history.
2553 * $1 - name of the edited file (to check its extension etc).
2554 * $2 - file containing the current block.
2555 * $3 - file where error messages should be put
2556 * (for compatibility with old scripts).
2558 system (catstrs (" ", home_dir
, PATH_SEP_STR EDIT_DIR
, shell_cmd
, " ", quoted_name
,
2559 " ", home_dir
, PATH_SEP_STR BLOCK_FILE
" /dev/null", (char *) NULL
));
2563 * No block selected, just execute the command for the file.
2565 * $1 - name of the edited file.
2567 system (catstrs (" ", home_dir
, PATH_SEP_STR EDIT_DIR
, shell_cmd
, " ",
2568 quoted_name
, (char *) NULL
));
2570 g_free (quoted_name
);
2571 close_error_pipe (D_NORMAL
, NULL
);
2573 edit_refresh_cmd (edit
);
2574 edit
->force
|= REDRAW_COMPLETELY
;
2576 /* insert result block */
2578 if (edit_block_delete_cmd (edit
))
2580 edit_insert_file (edit
, b
);
2581 if ((block_file
= fopen (b
, "w")))
2582 fclose (block_file
);
2589 /* prints at the cursor */
2590 /* returns the number of chars printed */
2591 int edit_print_string (WEdit
* e
, const char *s
)
2595 edit_execute_cmd (e
, -1, (unsigned char) s
[i
++]);
2596 e
->force
|= REDRAW_COMPLETELY
;
2597 edit_update_screen (e
);
2602 static void pipe_mail (WEdit
*edit
, char *to
, char *subject
, char *cc
)
2607 to
= name_quote (to
, 0);
2608 subject
= name_quote (subject
, 0);
2609 cc
= name_quote (cc
, 0);
2610 s
= g_strconcat ("mail -s ", subject
, *cc
? " -c " : "" , cc
, " ", to
, (char *) NULL
);
2622 for (i
= 0; i
< edit
->last_byte
; i
++)
2623 fputc (edit_get_byte (edit
, i
), p
);
2628 #define MAIL_DLG_HEIGHT 12
2630 void edit_mail_dialog (WEdit
* edit
)
2633 char *tmail_subject
;
2636 static char *mail_cc_last
= 0;
2637 static char *mail_subject_last
= 0;
2638 static char *mail_to_last
= 0;
2640 QuickDialog Quick_input
=
2641 {50, MAIL_DLG_HEIGHT
, -1, 0, N_(" Mail "),
2642 "[Input Line Keys]", 0, 0};
2644 QuickWidget quick_widgets
[] =
2646 {quick_button
, 6, 10, 9, MAIL_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
2648 {quick_button
, 2, 10, 9, MAIL_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
2650 {quick_input
, 3, 50, 8, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2651 0, "mail-dlg-input"},
2652 {quick_label
, 2, 50, 7, MAIL_DLG_HEIGHT
, N_(" Copies to"), 0, 0, 0,
2654 {quick_input
, 3, 50, 6, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2655 0, "mail-dlg-input-2"},
2656 {quick_label
, 2, 50, 5, MAIL_DLG_HEIGHT
, N_(" Subject"), 0, 0, 0,
2658 {quick_input
, 3, 50, 4, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2659 0, "mail-dlg-input-3"},
2660 {quick_label
, 2, 50, 3, MAIL_DLG_HEIGHT
, N_(" To"), 0, 0, 0,
2662 {quick_label
, 2, 50, 2, MAIL_DLG_HEIGHT
, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2666 quick_widgets
[2].str_result
= &tmail_cc
;
2667 quick_widgets
[2].text
= mail_cc_last
? mail_cc_last
: "";
2668 quick_widgets
[4].str_result
= &tmail_subject
;
2669 quick_widgets
[4].text
= mail_subject_last
? mail_subject_last
: "";
2670 quick_widgets
[6].str_result
= &tmail_to
;
2671 quick_widgets
[6].text
= mail_to_last
? mail_to_last
: "";
2673 Quick_input
.widgets
= quick_widgets
;
2675 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
2676 g_free (mail_cc_last
);
2677 g_free (mail_subject_last
);
2678 g_free (mail_to_last
);
2679 mail_cc_last
= tmail_cc
;
2680 mail_subject_last
= tmail_subject
;
2681 mail_to_last
= tmail_to
;
2682 pipe_mail (edit
, mail_to_last
, mail_subject_last
, mail_cc_last
);
2687 /*******************/
2688 /* Word Completion */
2689 /*******************/
2692 /* find first character of current word */
2693 static int edit_find_word_start (WEdit
*edit
, long *word_start
, int *word_len
)
2697 /* return if at begin of file */
2698 if (edit
->curs1
<= 0)
2701 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- 1);
2702 /* return if not at end or in word */
2703 if (isspace (c
) || !(isalnum (c
) || c
== '_'))
2706 /* search start of word to be completed */
2708 /* return if at begin of file */
2709 if (edit
->curs1
- i
< 0)
2713 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- i
);
2715 if (!(isalnum (c
) || c
== '_')) {
2716 /* return if word starts with digit */
2720 *word_start
= edit
->curs1
- (i
- 1); /* start found */
2730 /* (re)set search parameters to the given values */
2731 static void edit_set_search_parameters (int rs
, int rb
, int rr
, int rw
, int rc
)
2734 replace_backwards
= rb
;
2735 replace_regexp
= rr
;
2741 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2743 /* collect the possible completions */
2745 edit_collect_completions (WEdit
*edit
, long start
, int word_len
,
2746 char *match_expr
, struct selection
*compl,
2749 int len
, max_len
= 0, i
, skip
;
2750 unsigned char *bufpos
;
2752 /* collect max MAX_WORD_COMPLETIONS completions */
2753 while (*num
< MAX_WORD_COMPLETIONS
) {
2754 /* get next match */
2756 edit_find (start
- 1, (unsigned char *) match_expr
, &len
,
2757 edit
->last_byte
, edit_get_byte
, (void *) edit
, 0);
2763 /* add matched completion if not yet added */
2766 buffers1
[start
>> S_EDIT_BUF_SIZE
][start
& M_EDIT_BUF_SIZE
];
2768 for (i
= 0; i
< *num
; i
++) {
2770 ((char *) &compl[i
].text
[word_len
],
2771 (char *) &bufpos
[word_len
], max (len
,
2775 break; /* skip it, already added */
2781 compl[*num
].text
= g_malloc (len
+ 1);
2782 compl[*num
].len
= len
;
2783 for (i
= 0; i
< len
; i
++)
2784 compl[*num
].text
[i
] = *(bufpos
+ i
);
2785 compl[*num
].text
[i
] = '\0';
2788 /* note the maximal length needed for the completion dialog */
2796 /* let the user select its preferred completion */
2798 edit_completion_dialog (WEdit
* edit
, int max_len
, int word_len
,
2799 struct selection
*compl, int num_compl
)
2801 int start_x
, start_y
, offset
, i
;
2803 Dlg_head
*compl_dlg
;
2804 WListbox
*compl_list
;
2805 int compl_dlg_h
; /* completion dialog height */
2806 int compl_dlg_w
; /* completion dialog width */
2808 /* calculate the dialog metrics */
2809 compl_dlg_h
= num_compl
+ 2;
2810 compl_dlg_w
= max_len
+ 4;
2811 start_x
= edit
->curs_col
+ edit
->start_col
- (compl_dlg_w
/ 2);
2812 start_y
= edit
->curs_row
+ EDIT_TEXT_VERTICAL_OFFSET
+ 1;
2816 if (compl_dlg_w
> COLS
)
2818 if (compl_dlg_h
> LINES
- 2)
2819 compl_dlg_h
= LINES
- 2;
2821 offset
= start_x
+ compl_dlg_w
- COLS
;
2824 offset
= start_y
+ compl_dlg_h
- LINES
;
2826 start_y
-= (offset
+ 1);
2828 /* create the dialog */
2830 create_dlg (start_y
, start_x
, compl_dlg_h
, compl_dlg_w
,
2831 dialog_colors
, NULL
, "[Completion]", NULL
,
2834 /* create the listbox */
2836 listbox_new (1, 1, compl_dlg_w
- 2, compl_dlg_h
- 2, NULL
);
2838 /* add the dialog */
2839 add_widget (compl_dlg
, compl_list
);
2841 /* fill the listbox with the completions */
2842 for (i
= 0; i
< num_compl
; i
++)
2843 listbox_add_item (compl_list
, LISTBOX_APPEND_AT_END
, 0,
2844 (char *) compl[i
].text
, NULL
);
2846 /* pop up the dialog */
2847 run_dlg (compl_dlg
);
2849 /* apply the choosen completion */
2850 if (compl_dlg
->ret_value
== B_ENTER
) {
2851 listbox_get_current (compl_list
, &curr
, NULL
);
2853 for (curr
+= word_len
; *curr
; curr
++)
2854 edit_insert (edit
, *curr
);
2857 /* destroy dialog before return */
2858 destroy_dlg (compl_dlg
);
2863 * Complete current word using regular expression search
2864 * backwards beginning at the current cursor position.
2867 edit_complete_word_cmd (WEdit
*edit
)
2869 int word_len
= 0, i
, num_compl
= 0, max_len
;
2870 long word_start
= 0;
2871 unsigned char *bufpos
;
2873 struct selection
compl[MAX_WORD_COMPLETIONS
]; /* completions */
2875 /* don't want to disturb another search */
2876 int old_rs
= replace_scanf
;
2877 int old_rb
= replace_backwards
;
2878 int old_rr
= replace_regexp
;
2879 int old_rw
= replace_whole
;
2880 int old_rc
= replace_case
;
2882 /* search start of word to be completed */
2883 if (!edit_find_word_start (edit
, &word_start
, &word_len
))
2886 /* prepare match expression */
2887 bufpos
= &edit
->buffers1
[word_start
>> S_EDIT_BUF_SIZE
]
2888 [word_start
& M_EDIT_BUF_SIZE
];
2889 match_expr
= g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len
, bufpos
);
2891 /* init search: backward, regexp, whole word, case sensitive */
2892 edit_set_search_parameters (0, 1, 1, 1, 1);
2894 /* collect the possible completions */
2895 /* start search from curs1 down to begin of file */
2897 edit_collect_completions (edit
, word_start
, word_len
, match_expr
,
2898 (struct selection
*) &compl, &num_compl
);
2900 if (num_compl
> 0) {
2901 /* insert completed word if there is only one match */
2902 if (num_compl
== 1) {
2903 for (i
= word_len
; i
< compl[0].len
; i
++)
2904 edit_insert (edit
, *(compl[0].text
+ i
));
2906 /* more than one possible completion => ask the user */
2908 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2909 /* !!! pressed again the selection dialog pops up, but that !!! */
2910 /* !!! seems to require a further internal state !!! */
2913 /* let the user select the preferred completion */
2914 edit_completion_dialog (edit
, max_len
, word_len
,
2915 (struct selection
*) &compl,
2920 g_free (match_expr
);
2921 /* release memory before return */
2922 for (i
= 0; i
< num_compl
; i
++)
2923 g_free (compl[i
].text
);
2925 /* restore search parameters */
2926 edit_set_search_parameters (old_rs
, old_rb
, old_rr
, old_rw
, old_rc
);
2930 edit_select_codepage_cmd (WEdit
*edit
)
2933 do_select_codepage ();
2934 edit
->force
= REDRAW_COMPLETELY
;
2935 edit_refresh_cmd (edit
);
2940 edit_insert_literal_cmd (WEdit
*edit
)
2942 int char_for_insertion
=
2943 edit_raw_key_query (_(" Insert Literal "),
2944 _(" Press any key: "), 0);
2945 edit_execute_key_command (edit
, -1,
2946 ascii_alpha_to_cntrl (char_for_insertion
));
2950 edit_execute_macro_cmd (WEdit
*edit
)
2953 CK_Macro (edit_raw_key_query
2954 (_(" Execute Macro "), _(" Press macro hotkey: "),
2956 if (command
== CK_Macro (0))
2957 command
= CK_Insert_Char
;
2959 edit_execute_key_command (edit
, command
, -1);
2963 edit_begin_end_macro_cmd(WEdit
*edit
)
2967 /* edit is a pointer to the widget */
2971 0 ? CK_Begin_Record_Macro
: CK_End_Record_Macro
;
2972 edit_execute_key_command (edit
, command
, -1);