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"
43 #include "../src/history.h"
47 #include "editcmddef.h"
48 #include "edit-widget.h"
50 #include "../src/color.h" /* dialog_colors */
51 #include "../src/tty.h" /* LINES */
52 #include "../src/widget.h" /* listbox_new() */
53 #include "../src/layout.h" /* clr_scr() */
54 #include "../src/main.h" /* mc_home */
55 #include "../src/help.h" /* interactive_display() */
56 #include "../src/key.h" /* XCTRL */
57 #include "../src/dialog.h" /* do_refresh() */
58 #include "../src/wtools.h" /* message() */
59 #include "../src/charsets.h"
60 #include "../src/selcodepage.h"
69 /* search and replace: */
70 static int replace_scanf
= 0;
71 static int replace_regexp
= 0;
72 static int replace_all
= 0;
73 static int replace_prompt
= 1;
74 static int replace_whole
= 0;
75 static int replace_case
= 0;
76 static int replace_backwards
= 0;
77 static int search_create_bookmark
= 0;
79 /* queries on a save */
80 int edit_confirm_save
= 1;
82 #define NUM_REPL_ARGS 64
83 #define MAX_REPL_LEN 1024
85 static int edit_save_cmd (WEdit
*edit
);
86 static unsigned char *edit_get_block (WEdit
*edit
, long start
,
89 static inline int my_lower_case (int c
)
91 return tolower(c
& 0xFF);
95 strcasechr (const char *s
, int c
)
97 for (c
= my_lower_case (c
); my_lower_case ((int) *s
) != c
; ++s
)
105 static void *memmove (void *dest
, const void *src
, size_t n
)
112 s
= (const char *) src
;
116 t
= (char *) dest
+ n
;
117 s
= (const char *) src
+ n
;
123 #endif /* !HAVE_MEMMOVE */
125 /* #define itoa MY_itoa <---- this line is now in edit.h */
135 } while ((i
= i
/ 10));
141 /* Temporary strings */
142 static char *stacked
[16];
145 This joins strings end on end and allocates memory for the result.
146 The result is later automatically free'd and must not be free'd
150 catstrs (const char *first
,...)
160 len
= strlen (first
);
161 va_start (ap
, first
);
163 while ((data
= va_arg (ap
, char *)) != 0)
164 len
+= strlen (data
);
171 stacked
[i
] = g_malloc (len
);
173 va_start (ap
, first
);
174 strcpy (stacked
[i
], first
);
175 while ((data
= va_arg (ap
, char *)) != 0)
176 strcat (stacked
[i
], data
);
182 /* Free temporary strings */
187 for (i
= 0; i
< sizeof(stacked
) / sizeof(stacked
[0]); i
++) {
193 void edit_help_cmd (WEdit
* edit
)
195 interactive_display (NULL
, "[Internal File Editor]");
196 edit
->force
|= REDRAW_COMPLETELY
;
199 void edit_refresh_cmd (WEdit
* edit
)
207 edit_get_syntax_color (edit
, -1, &color
);
210 #endif /* !HAVE_SLANG */
215 /* If 0 (quick save) then a) create/truncate <filename> file,
216 b) save to <filename>;
217 if 1 (safe save) then a) save to <tempnam>,
218 b) rename <tempnam> to <filename>;
219 if 2 (do backups) then a) save to <tempnam>,
220 b) rename <filename> to <filename.backup_ext>,
221 c) rename <tempnam> to <filename>. */
223 /* returns 0 on error, -1 on abort */
225 edit_save_file (WEdit
*edit
, const char *filename
)
230 int this_save_mode
, fd
= -1;
237 if (*filename
!= PATH_SEP
&& edit
->dir
) {
238 savename
= concat_dir_and_file (edit
->dir
, filename
);
239 filename
= catstrs (savename
, (char *) NULL
);
243 this_save_mode
= option_save_mode
;
244 if (this_save_mode
!= EDIT_QUICK_SAVE
) {
245 if (!vfs_file_is_local (filename
) ||
246 (fd
= mc_open (filename
, O_RDONLY
| O_BINARY
)) == -1) {
248 * The file does not exists yet, so no safe save or
249 * backup are necessary.
251 this_save_mode
= EDIT_QUICK_SAVE
;
257 if (this_save_mode
== EDIT_QUICK_SAVE
&&
258 !edit
->skip_detach_prompt
) {
262 rv
= mc_stat (filename
, &sb
);
263 if (rv
== 0 && sb
.st_nlink
> 1) {
264 rv
= edit_query_dialog3 (_("Warning"),
265 _(" File has hard-links. Detach before saving? "),
266 _("&Yes"), _("&No"), _("&Cancel"));
269 this_save_mode
= EDIT_SAFE_SAVE
;
272 edit
->skip_detach_prompt
= 1;
279 /* Prevent overwriting changes from other editor sessions. */
280 if (rv
== 0 && edit
->stat1
.st_mtime
!= 0 && edit
->stat1
.st_mtime
!= sb
.st_mtime
) {
282 /* The default action is "Cancel". */
285 rv
= edit_query_dialog2 (
287 _("The file has been modified in the meantime. Save anyway?"),
295 if (this_save_mode
!= EDIT_QUICK_SAVE
) {
296 char *savedir
, *saveprefix
;
297 const char *slashpos
;
298 slashpos
= strrchr (filename
, PATH_SEP
);
300 savedir
= g_strdup (filename
);
301 savedir
[slashpos
- filename
+ 1] = '\0';
303 savedir
= g_strdup (".");
304 saveprefix
= concat_dir_and_file (savedir
, "cooledit");
306 fd
= mc_mkstemps (&savename
, saveprefix
, NULL
);
311 * Close for now because mc_mkstemps use pure open system call
312 * to create temporary file and it needs to be reopened by
313 * VFS-aware mc_open().
317 savename
= g_strdup (filename
);
319 mc_chown (savename
, edit
->stat1
.st_uid
, edit
->stat1
.st_gid
);
320 mc_chmod (savename
, edit
->stat1
.st_mode
);
323 mc_open (savename
, O_CREAT
| O_WRONLY
| O_TRUNC
| O_BINARY
,
324 edit
->stat1
.st_mode
)) == -1)
328 if ((p
= edit_get_write_filter (savename
, filename
))) {
332 file
= (FILE *) popen (p
, "w");
335 filelen
= edit_write_stream (edit
, file
);
339 if (pclose (file
) != 0) {
340 edit_error_dialog (_("Error"),
341 catstrs (_(" Error writing to pipe: "),
342 p
, " ", (char *) NULL
));
348 edit_error_dialog (_("Error"),
349 get_sys_error (catstrs
351 (" Cannot open pipe for writing: "),
352 p
, " ", (char *) NULL
)));
360 filelen
= edit
->last_byte
;
361 while (buf
<= (edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1) {
362 if (mc_write (fd
, (char *) edit
->buffers1
[buf
], EDIT_BUF_SIZE
)
370 (fd
, (char *) edit
->buffers1
[buf
],
371 edit
->curs1
& M_EDIT_BUF_SIZE
) !=
372 (edit
->curs1
& M_EDIT_BUF_SIZE
)) {
374 } else if (edit
->curs2
) {
376 buf
= (edit
->curs2
>> S_EDIT_BUF_SIZE
);
379 (char *) edit
->buffers2
[buf
] + EDIT_BUF_SIZE
-
380 (edit
->curs2
& M_EDIT_BUF_SIZE
) - 1,
381 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) !=
382 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) {
387 (fd
, (char *) edit
->buffers2
[buf
],
388 EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
399 /* Update the file information, especially the mtime. */
400 if (mc_stat (savename
, &edit
->stat1
) == -1)
404 if (filelen
!= edit
->last_byte
)
407 if (this_save_mode
== EDIT_DO_BACKUP
) {
408 assert (option_backup_ext
!= NULL
);
409 if (mc_rename (filename
, catstrs (filename
, option_backup_ext
,
410 (char *) NULL
)) == -1)
414 if (this_save_mode
!= EDIT_QUICK_SAVE
)
415 if (mc_rename (savename
, filename
) == -1)
420 /* FIXME: Is this safe ?
421 * if (this_save_mode != EDIT_QUICK_SAVE)
422 * mc_unlink (savename);
428 void menu_save_mode_cmd (void)
432 static char *str_result
;
433 static int save_mode_new
;
434 static const char *str
[] =
438 N_("Do backups -->")};
439 static QuickWidget widgets
[] =
441 {quick_button
, 18, DLG_X
, 7, DLG_Y
, N_("&Cancel"), 0,
442 B_CANCEL
, 0, 0, NULL
},
443 {quick_button
, 6, DLG_X
, 7, DLG_Y
, N_("&OK"), 0,
444 B_ENTER
, 0, 0, NULL
},
445 {quick_input
, 23, DLG_X
, 5, DLG_Y
, 0, 9,
446 0, 0, &str_result
, "edit-backup-ext"},
447 {quick_label
, 22, DLG_X
, 4, DLG_Y
, N_("Extension:"), 0,
449 {quick_radio
, 4, DLG_X
, 3, DLG_Y
, "", 3,
450 0, &save_mode_new
, (char **) str
, NULL
},
452 static QuickDialog dialog
=
453 {DLG_X
, DLG_Y
, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
455 static int i18n_flag
= 0;
463 /* OK/Cancel buttons */
464 l1
= strlen (_(widgets
[0].text
)) + strlen (_(widgets
[1].text
)) + 5;
465 maxlen
= max (maxlen
, l1
);
467 for (i
= 0; i
< 3; i
++ ) {
469 maxlen
= max (maxlen
, strlen (str
[i
]) + 7);
473 dlg_x
= maxlen
+ strlen (_(widgets
[3].text
)) + 5 + 1;
474 widgets
[2].hotkey_pos
= strlen (_(widgets
[3].text
)); /* input field length */
475 dlg_x
= min (COLS
, dlg_x
);
479 widgets
[1].relative_x
= i
;
480 widgets
[0].relative_x
= i
+ strlen (_(widgets
[1].text
)) + i
+ 4;
482 widgets
[2].relative_x
= widgets
[3].relative_x
= maxlen
+ 2;
484 for (i
= 0; i
< sizeof (widgets
)/sizeof (widgets
[0]); i
++)
485 widgets
[i
].x_divisions
= dlg_x
;
488 assert (option_backup_ext
!= NULL
);
489 widgets
[2].text
= option_backup_ext
;
490 widgets
[4].value
= option_save_mode
;
491 if (quick_dialog (&dialog
) != B_ENTER
)
493 option_save_mode
= save_mode_new
;
495 g_free (option_backup_ext
);
496 option_backup_ext
= str_result
;
501 edit_set_filename (WEdit
*edit
, const char *f
)
503 g_free (edit
->filename
);
506 edit
->filename
= g_strdup (f
);
507 if (edit
->dir
== NULL
&& *f
!= PATH_SEP
)
509 edit
->dir
= g_strdup (vfs_get_current_dir ());
511 edit
->dir
= g_get_current_dir ();
515 /* Here we want to warn the users of overwriting an existing file,
516 but only if they have made a change to the filename */
517 /* returns 1 on success */
519 edit_save_as_cmd (WEdit
*edit
)
521 /* This heads the 'Save As' dialog box */
524 int different_filename
= 0;
526 exp
= input_expand_dialog (
527 _(" Save As "), _(" Enter file name: "),MC_HISTORY_EDIT_SAVE_AS
, edit
->filename
);
528 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
533 edit
->force
|= REDRAW_COMPLETELY
;
537 if (strcmp (edit
->filename
, exp
)) {
539 different_filename
= 1;
540 if ((file
= mc_open (exp
, O_RDONLY
| O_BINARY
)) != -1) {
541 /* the file exists */
543 /* Overwrite the current file or cancel the operation */
544 if (edit_query_dialog2
546 _(" A file already exists with this name. "),
547 _("&Overwrite"), _("&Cancel"))) {
548 edit
->force
|= REDRAW_COMPLETELY
;
553 save_lock
= edit_lock_file (exp
);
555 /* filenames equal, check if already locked */
556 if (!edit
->locked
&& !edit
->delete_file
)
557 save_lock
= edit_lock_file (exp
);
560 rv
= edit_save_file (edit
, exp
);
563 /* Succesful, so unlock both files */
564 if (different_filename
) {
566 edit_unlock_file (exp
);
568 edit
->locked
= edit_unlock_file (edit
->filename
);
570 if (edit
->locked
|| save_lock
)
571 edit
->locked
= edit_unlock_file (edit
->filename
);
574 edit_set_filename (edit
, exp
);
577 edit
->delete_file
= 0;
578 if (different_filename
)
579 edit_load_syntax (edit
, NULL
, option_syntax_type
);
580 edit
->force
|= REDRAW_COMPLETELY
;
583 edit_error_dialog (_(" Save As "),
585 (" Cannot save file. ")));
588 /* Failed, so maintain modify (not save) lock */
590 edit_unlock_file (exp
);
592 edit
->force
|= REDRAW_COMPLETELY
;
597 edit
->force
|= REDRAW_COMPLETELY
;
601 /* {{{ Macro stuff starts here */
604 raw_callback (struct Dlg_head
*h
, dlg_msg_t msg
, int parm
)
612 return default_dlg_callback (h
, msg
, parm
);
616 /* gets a raw key from the keyboard. Passing cancel = 1 draws
617 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
618 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
619 and Esc are cannot returned */
621 edit_raw_key_query (const char *heading
, const char *query
, int cancel
)
623 int w
= strlen (query
) + 7;
624 struct Dlg_head
*raw_dlg
=
625 create_dlg (0, 0, 7, w
, dialog_colors
, raw_callback
,
627 DLG_CENTER
| DLG_TRYUP
| DLG_WANT_TAB
);
629 input_new (3 - cancel
, w
- 5, INPUT_COLOR
, 2, "", 0));
630 add_widget (raw_dlg
, label_new (3 - cancel
, 2, query
));
633 button_new (4, w
/ 2 - 5, B_CANCEL
, NORMAL_BUTTON
,
636 w
= raw_dlg
->ret_value
;
637 destroy_dlg (raw_dlg
);
639 if (w
== XCTRL ('g') || w
== XCTRL ('c') || w
== ESC_CHAR
647 /* creates a macro file if it doesn't exist */
648 static FILE *edit_open_macro_file (const char *r
)
650 const char *filename
;
652 filename
= catstrs (home_dir
, PATH_SEP_STR MACRO_FILE
, (char *) NULL
);
653 if ((file
= open (filename
, O_CREAT
| O_RDWR
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
656 return fopen (filename
, r
);
659 #define MAX_MACROS 1024
660 static int saved_macro
[MAX_MACROS
+ 1];
661 static int saved_macros_loaded
= 0;
664 This is just to stop the macro file be loaded over and over for keys
665 that aren't defined to anything. On slow systems this could be annoying.
671 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++)
672 if (saved_macro
[i
] == k
)
677 /* returns 1 on error */
679 edit_delete_macro (WEdit
* edit
, int k
)
681 struct macro macro
[MAX_MACRO_LENGTH
];
687 if (saved_macros_loaded
)
688 if ((j
= macro_exists (k
)) < 0)
690 g
= fopen (catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
), "w");
692 edit_error_dialog (_(" Delete macro "),
693 get_sys_error (_(" Cannot open temp file ")));
696 f
= edit_open_macro_file ("r");
698 edit_error_dialog (_(" Delete macro "),
699 get_sys_error (_(" Cannot open macro file ")));
704 n
= fscanf (f
, ("key '%d 0': "), &s
);
708 while (fscanf (f
, "%hd %hd, ", ¯o
[n
].command
, ¯o
[n
].ch
))
712 fprintf (g
, ("key '%d 0': "), s
);
713 for (i
= 0; i
< n
; i
++)
714 fprintf (g
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
720 if (rename (catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
), catstrs (home_dir
, PATH_SEP_STR MACRO_FILE
, (char *) NULL
)) == -1) {
721 edit_error_dialog (_(" Delete macro "),
722 get_sys_error (_(" Cannot overwrite macro file ")));
725 if (saved_macros_loaded
)
726 memmove (saved_macro
+ j
, saved_macro
+ j
+ 1, sizeof (int) * (MAX_MACROS
- j
- 1));
730 /* returns 0 on error */
731 int edit_save_macro_cmd (WEdit
* edit
, struct macro macro
[], int n
)
736 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
737 s
= edit_raw_key_query (_(" Save macro "),
738 _(" Press the macro's new hotkey: "), 1);
739 edit
->force
|= REDRAW_COMPLETELY
;
741 if (edit_delete_macro (edit
, s
))
743 f
= edit_open_macro_file ("a+");
745 fprintf (f
, ("key '%d 0': "), s
);
746 for (i
= 0; i
< n
; i
++)
747 fprintf (f
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
750 if (saved_macros_loaded
) {
751 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++);
756 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
761 void edit_delete_macro_cmd (WEdit
* edit
)
765 command
= edit_raw_key_query (_ (" Delete macro "),
766 _ (" Press macro hotkey: "), 1);
771 edit_delete_macro (edit
, command
);
774 /* return 0 on error */
775 int edit_load_macro_cmd (WEdit
* edit
, struct macro macro
[], int *n
, int k
)
778 int s
, i
= 0, found
= 0;
782 if (saved_macros_loaded
)
783 if (macro_exists (k
) < 0)
786 if ((f
= edit_open_macro_file ("r"))) {
790 u
= fscanf (f
, ("key '%d 0': "), &s
);
793 if (!saved_macros_loaded
)
794 saved_macro
[i
++] = s
;
797 while (*n
< MAX_MACRO_LENGTH
&& 2 == fscanf (f
, "%hd %hd, ", ¯o
[*n
].command
, ¯o
[*n
].ch
))
800 while (2 == fscanf (f
, "%hd %hd, ", &dummy
.command
, &dummy
.ch
));
805 } while (!found
|| !saved_macros_loaded
);
806 if (!saved_macros_loaded
) {
808 saved_macros_loaded
= 1;
813 edit_error_dialog (_(" Load macro "),
814 get_sys_error (_(" Cannot open macro file ")));
818 /* }}} Macro stuff starts here */
820 /* returns 1 on success */
821 int edit_save_confirm_cmd (WEdit
* edit
)
825 if (edit_confirm_save
) {
826 f
= catstrs (_(" Confirm save file? : "), edit
->filename
, " ", (char *) NULL
);
827 if (edit_query_dialog2 (_(" Save file "), f
, _("&Save"), _("&Cancel")))
830 return edit_save_cmd (edit
);
834 /* returns 1 on success */
836 edit_save_cmd (WEdit
*edit
)
838 int res
, save_lock
= 0;
840 if (!edit
->locked
&& !edit
->delete_file
)
841 save_lock
= edit_lock_file (edit
->filename
);
842 res
= edit_save_file (edit
, edit
->filename
);
844 /* Maintain modify (not save) lock on failure */
845 if ((res
> 0 && edit
->locked
) || save_lock
)
846 edit
->locked
= edit_unlock_file (edit
->filename
);
848 /* On failure try 'save as', it does locking on its own */
850 return edit_save_as_cmd (edit
);
851 edit
->force
|= REDRAW_COMPLETELY
;
853 edit
->delete_file
= 0;
861 /* returns 1 on success */
862 int edit_new_cmd (WEdit
* edit
)
864 if (edit
->modified
) {
865 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
866 edit
->force
|= REDRAW_COMPLETELY
;
870 edit
->force
|= REDRAW_COMPLETELY
;
872 return edit_renew (edit
); /* if this gives an error, something has really screwed up */
875 /* returns 1 on error */
877 edit_load_file_from_filename (WEdit
* edit
, char *exp
)
879 int prev_locked
= edit
->locked
;
880 char *prev_filename
= g_strdup (edit
->filename
);
882 if (!edit_reload (edit
, exp
)) {
883 g_free (prev_filename
);
888 edit_unlock_file (prev_filename
);
889 g_free (prev_filename
);
894 edit_load_cmd (WEdit
*edit
)
898 if (edit
->modified
) {
899 if (edit_query_dialog2
901 _(" Current text was modified without a file save. \n"
902 " Continue discards these changes. "), _("C&ontinue"),
904 edit
->force
|= REDRAW_COMPLETELY
;
909 exp
= input_expand_dialog (_(" Load "), _(" Enter file name: "),
910 MC_HISTORY_EDIT_LOAD
, edit
->filename
);
914 edit_load_file_from_filename (edit
, exp
);
917 edit
->force
|= REDRAW_COMPLETELY
;
922 if mark2 is -1 then marking is from mark1 to the cursor.
923 Otherwise its between the markers. This handles this.
924 Returns 1 if no text is marked.
926 int eval_marks (WEdit
* edit
, long *start_mark
, long *end_mark
)
928 if (edit
->mark1
!= edit
->mark2
) {
929 if (edit
->mark2
>= 0) {
930 *start_mark
= min (edit
->mark1
, edit
->mark2
);
931 *end_mark
= max (edit
->mark1
, edit
->mark2
);
933 *start_mark
= min (edit
->mark1
, edit
->curs1
);
934 *end_mark
= max (edit
->mark1
, edit
->curs1
);
935 edit
->column2
= edit
->curs_col
;
939 *start_mark
= *end_mark
= 0;
940 edit
->column2
= edit
->column1
= 0;
945 #define space_width 1
948 edit_insert_column_of_text (WEdit
* edit
, unsigned char *data
, int size
, int width
)
952 cursor
= edit
->curs1
;
953 col
= edit_get_col (edit
);
954 for (i
= 0; i
< size
; i
++) {
955 if (data
[i
] == '\n') { /* fill in and move to next line */
958 if (edit_get_byte (edit
, edit
->curs1
) != '\n') {
959 l
= width
- (edit_get_col (edit
) - col
);
961 edit_insert (edit
, ' ');
965 for (p
= edit
->curs1
;; p
++) {
966 if (p
== edit
->last_byte
) {
967 edit_cursor_move (edit
, edit
->last_byte
- edit
->curs1
);
968 edit_insert_ahead (edit
, '\n');
972 if (edit_get_byte (edit
, p
) == '\n') {
977 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, col
, 0) - edit
->curs1
);
978 l
= col
- edit_get_col (edit
);
979 while (l
>= space_width
) {
980 edit_insert (edit
, ' ');
985 edit_insert (edit
, data
[i
]);
987 edit_cursor_move (edit
, cursor
- edit
->curs1
);
992 edit_block_copy_cmd (WEdit
*edit
)
994 long start_mark
, end_mark
, current
= edit
->curs1
;
996 unsigned char *copy_buf
;
998 edit_update_curs_col (edit
);
999 if (eval_marks (edit
, &start_mark
, &end_mark
))
1002 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
1004 /* all that gets pushed are deletes hence little space is used on the stack */
1006 edit_push_markers (edit
);
1008 if (column_highlighting
) {
1009 edit_insert_column_of_text (edit
, copy_buf
, size
,
1010 abs (edit
->column2
- edit
->column1
));
1013 edit_insert_ahead (edit
, copy_buf
[size
]);
1017 edit_scroll_screen_over_cursor (edit
);
1019 if (column_highlighting
) {
1020 edit_set_markers (edit
, 0, 0, 0, 0);
1021 edit_push_action (edit
, COLUMN_ON
);
1022 column_highlighting
= 0;
1023 } else if (start_mark
< current
&& end_mark
> current
)
1024 edit_set_markers (edit
, start_mark
,
1025 end_mark
+ end_mark
- start_mark
, 0, 0);
1027 edit
->force
|= REDRAW_PAGE
;
1032 edit_block_move_cmd (WEdit
*edit
)
1036 unsigned char *copy_buf
;
1037 long start_mark
, end_mark
;
1041 if (eval_marks (edit
, &start_mark
, &end_mark
))
1043 if (column_highlighting
) {
1044 edit_update_curs_col (edit
);
1046 if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
1047 if ((x
> edit
->column1
&& x
< edit
->column2
)
1048 || (x
> edit
->column2
&& x
< edit
->column1
))
1050 } else if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
1053 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
1054 if (edit_query_dialog2
1057 (" Block is large, you may not be able to undo this action. "),
1058 _("C&ontinue"), _("&Cancel")))
1061 edit_push_markers (edit
);
1062 current
= edit
->curs1
;
1063 if (column_highlighting
) {
1064 int size
, c1
, c2
, line
;
1065 line
= edit
->curs_line
;
1066 if (edit
->mark2
< 0)
1067 edit_mark_cmd (edit
, 0);
1068 c1
= min (edit
->column1
, edit
->column2
);
1069 c2
= max (edit
->column1
, edit
->column2
);
1070 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
1072 edit_block_delete_cmd (edit
);
1075 edit_move_to_line (edit
, line
);
1076 edit_cursor_move (edit
,
1077 edit_move_forward3 (edit
,
1078 edit_bol (edit
, edit
->curs1
),
1079 x
, 0) - edit
->curs1
);
1080 edit_insert_column_of_text (edit
, copy_buf
, size
, c2
- c1
);
1082 line
= edit
->curs_line
;
1083 edit_update_curs_col (edit
);
1085 edit_block_delete_cmd (edit
);
1086 edit_move_to_line (edit
, line
);
1087 edit_cursor_move (edit
,
1088 edit_move_forward3 (edit
,
1091 x
, 0) - edit
->curs1
);
1093 edit_set_markers (edit
, 0, 0, 0, 0);
1094 edit_push_action (edit
, COLUMN_ON
);
1095 column_highlighting
= 0;
1097 copy_buf
= g_malloc (end_mark
- start_mark
);
1098 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
1099 edit_scroll_screen_over_cursor (edit
);
1101 while (count
< end_mark
) {
1102 copy_buf
[end_mark
- count
- 1] = edit_delete (edit
);
1105 edit_scroll_screen_over_cursor (edit
);
1106 edit_cursor_move (edit
,
1107 current
- edit
->curs1
-
1108 (((current
- edit
->curs1
) >
1109 0) ? end_mark
- start_mark
: 0));
1110 edit_scroll_screen_over_cursor (edit
);
1111 while (count
-- > start_mark
)
1112 edit_insert_ahead (edit
, copy_buf
[end_mark
- count
- 1]);
1113 edit_set_markers (edit
, edit
->curs1
,
1114 edit
->curs1
+ end_mark
- start_mark
, 0, 0);
1116 edit_scroll_screen_over_cursor (edit
);
1118 edit
->force
|= REDRAW_PAGE
;
1122 edit_delete_column_of_text (WEdit
* edit
)
1124 long p
, q
, r
, m1
, m2
;
1128 eval_marks (edit
, &m1
, &m2
);
1129 n
= edit_move_forward (edit
, m1
, 0, m2
) + 1;
1130 c
= edit_move_forward3 (edit
, edit_bol (edit
, m1
), 0, m1
);
1131 d
= edit_move_forward3 (edit
, edit_bol (edit
, m2
), 0, m2
);
1137 r
= edit_bol (edit
, edit
->curs1
);
1138 p
= edit_move_forward3 (edit
, r
, b
, 0);
1139 q
= edit_move_forward3 (edit
, r
, c
, 0);
1144 edit_cursor_move (edit
, p
- edit
->curs1
);
1145 while (q
> p
) { /* delete line between margins */
1146 if (edit_get_byte (edit
, edit
->curs1
) != '\n')
1150 if (n
) /* move to next line except on the last delete */
1151 edit_cursor_move (edit
, edit_move_forward (edit
, edit
->curs1
, 1, 0) - edit
->curs1
);
1155 /* if success return 0 */
1157 edit_block_delete (WEdit
*edit
)
1160 long start_mark
, end_mark
;
1161 if (eval_marks (edit
, &start_mark
, &end_mark
))
1163 if (column_highlighting
&& edit
->mark2
< 0)
1164 edit_mark_cmd (edit
, 0);
1165 if ((end_mark
- start_mark
) > option_max_undo
/ 2) {
1166 /* Warning message with a query to continue or cancel the operation */
1167 if (edit_query_dialog2
1170 (" Block is large, you may not be able to undo this action. "),
1171 _("C&ontinue"), _("&Cancel"))) {
1175 edit_push_markers (edit
);
1176 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
1177 edit_scroll_screen_over_cursor (edit
);
1179 if (start_mark
< end_mark
) {
1180 if (column_highlighting
) {
1181 if (edit
->mark2
< 0)
1182 edit_mark_cmd (edit
, 0);
1183 edit_delete_column_of_text (edit
);
1185 while (count
< end_mark
) {
1191 edit_set_markers (edit
, 0, 0, 0, 0);
1192 edit
->force
|= REDRAW_PAGE
;
1196 /* returns 1 if canceelled by user */
1197 int edit_block_delete_cmd (WEdit
* edit
)
1199 long start_mark
, end_mark
;
1200 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
1201 edit_delete_line (edit
);
1204 return edit_block_delete (edit
);
1208 #define INPUT_INDEX 9
1209 #define SEARCH_DLG_WIDTH 58
1210 #define SEARCH_DLG_HEIGHT 10
1211 #define REPLACE_DLG_WIDTH 58
1212 #define REPLACE_DLG_HEIGHT 15
1213 #define CONFIRM_DLG_WIDTH 79
1214 #define CONFIRM_DLG_HEIGTH 6
1215 #define B_REPLACE_ALL (B_USER+1)
1216 #define B_REPLACE_ONE (B_USER+2)
1217 #define B_SKIP_REPLACE (B_USER+3)
1220 edit_replace_prompt (WEdit
* edit
, char *replace_text
, int xpos
, int ypos
)
1222 QuickWidget quick_widgets
[] =
1224 {quick_button
, 63, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Cancel"),
1225 0, B_CANCEL
, 0, 0, NULL
},
1226 {quick_button
, 50, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("O&ne"),
1227 0, B_REPLACE_ONE
, 0, 0, NULL
},
1228 {quick_button
, 37, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("A&ll"),
1229 0, B_REPLACE_ALL
, 0, 0, NULL
},
1230 {quick_button
, 21, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Skip"),
1231 0, B_SKIP_REPLACE
, 0, 0, NULL
},
1232 {quick_button
, 4, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Replace"),
1233 0, B_ENTER
, 0, 0, NULL
},
1234 {quick_label
, 2, CONFIRM_DLG_WIDTH
, 2, CONFIRM_DLG_HEIGTH
, 0,
1238 GString
*label_text
= g_string_new (_(" Replace with: "));
1239 if (*replace_text
) {
1241 label_len
= label_text
->len
;
1242 g_string_append (label_text
, replace_text
);
1243 convert_to_display (label_text
->str
+ label_len
);
1245 quick_widgets
[5].text
= label_text
->str
;
1249 QuickDialog Quick_input
=
1250 {CONFIRM_DLG_WIDTH
, CONFIRM_DLG_HEIGTH
, 0, 0, N_ (" Confirm replace "),
1251 "[Input Line Keys]", 0 /*quick_widgets */, 0 };
1253 Quick_input
.widgets
= quick_widgets
;
1255 Quick_input
.xpos
= xpos
;
1257 /* Sometimes menu can hide replaced text. I don't like it */
1259 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ CONFIRM_DLG_HEIGTH
- 1))
1260 ypos
-= CONFIRM_DLG_HEIGTH
;
1262 Quick_input
.ypos
= ypos
;
1263 retval
= quick_dialog (&Quick_input
);
1264 g_string_free (label_text
, TRUE
);
1270 edit_replace_dialog (WEdit
* edit
, const char *search_default
,
1271 const char *replace_default
, const char *argorder_default
,
1272 /*@out@*/ char **search_text
, /*@out@*/ char **replace_text
,
1273 /*@out@*/ char **arg_order
)
1275 int treplace_scanf
= replace_scanf
;
1276 int treplace_regexp
= replace_regexp
;
1277 int treplace_all
= replace_all
;
1278 int treplace_prompt
= replace_prompt
;
1279 int treplace_backwards
= replace_backwards
;
1280 int treplace_whole
= replace_whole
;
1281 int treplace_case
= replace_case
;
1283 /* Alt-p is in use as hotkey for previous entry; don't use */
1284 QuickWidget quick_widgets
[] =
1286 {quick_button
, 6, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1288 {quick_button
, 2, 10, 12, REPLACE_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1290 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1292 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("replace &All"), 0, 0,
1294 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("pro&Mpt on replace"), 0, 0,
1296 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1298 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1300 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1302 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 8, REPLACE_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1304 {quick_input
, 3, REPLACE_DLG_WIDTH
, 7, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1306 {quick_label
, 2, REPLACE_DLG_WIDTH
, 6, REPLACE_DLG_HEIGHT
, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1308 {quick_input
, 3, REPLACE_DLG_WIDTH
, 5, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1310 {quick_label
, 2, REPLACE_DLG_WIDTH
, 4, REPLACE_DLG_HEIGHT
, N_(" Enter replacement string:"), 0, 0, 0,
1312 {quick_input
, 3, REPLACE_DLG_WIDTH
, 3, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1314 {quick_label
, 2, REPLACE_DLG_WIDTH
, 2, REPLACE_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1320 quick_widgets
[2].result
= &treplace_scanf
;
1321 quick_widgets
[3].result
= &treplace_all
;
1322 quick_widgets
[4].result
= &treplace_prompt
;
1323 quick_widgets
[5].result
= &treplace_backwards
;
1324 quick_widgets
[6].result
= &treplace_regexp
;
1325 quick_widgets
[7].result
= &treplace_whole
;
1326 quick_widgets
[8].result
= &treplace_case
;
1327 quick_widgets
[9].str_result
= arg_order
;
1328 quick_widgets
[9].text
= argorder_default
;
1329 quick_widgets
[11].str_result
= replace_text
;
1330 quick_widgets
[11].text
= replace_default
;
1331 quick_widgets
[13].str_result
= search_text
;
1332 quick_widgets
[13].text
= search_default
;
1334 QuickDialog Quick_input
=
1335 {REPLACE_DLG_WIDTH
, REPLACE_DLG_HEIGHT
, -1, 0, N_(" Replace "),
1336 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1338 Quick_input
.widgets
= quick_widgets
;
1340 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1341 replace_scanf
= treplace_scanf
;
1342 replace_backwards
= treplace_backwards
;
1343 replace_regexp
= treplace_regexp
;
1344 replace_all
= treplace_all
;
1345 replace_prompt
= treplace_prompt
;
1346 replace_whole
= treplace_whole
;
1347 replace_case
= treplace_case
;
1351 *replace_text
= NULL
;
1352 *search_text
= NULL
;
1360 edit_search_dialog (WEdit
* edit
, char **search_text
)
1362 int treplace_scanf
= replace_scanf
;
1363 int treplace_regexp
= replace_regexp
;
1364 int treplace_whole
= replace_whole
;
1365 int treplace_case
= replace_case
;
1366 int treplace_backwards
= replace_backwards
;
1368 QuickWidget quick_widgets
[] =
1370 {quick_button
, 6, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1372 {quick_button
, 2, 10, 7, SEARCH_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1374 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1376 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1378 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1380 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1382 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 4, SEARCH_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1384 {quick_input
, 3, SEARCH_DLG_WIDTH
, 3, SEARCH_DLG_HEIGHT
, "", 52, 0, 0,
1386 {quick_label
, 2, SEARCH_DLG_WIDTH
, 2, SEARCH_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1392 quick_widgets
[2].result
= &treplace_scanf
;
1393 quick_widgets
[3].result
= &treplace_backwards
;
1394 quick_widgets
[4].result
= &treplace_regexp
;
1395 quick_widgets
[5].result
= &treplace_whole
;
1396 quick_widgets
[6].result
= &treplace_case
;
1397 quick_widgets
[7].str_result
= search_text
;
1398 quick_widgets
[7].text
= *search_text
;
1401 QuickDialog Quick_input
=
1402 {SEARCH_DLG_WIDTH
, SEARCH_DLG_HEIGHT
, -1, 0, N_("Search"),
1403 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1405 Quick_input
.widgets
= quick_widgets
;
1407 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1408 replace_scanf
= treplace_scanf
;
1409 replace_backwards
= treplace_backwards
;
1410 replace_regexp
= treplace_regexp
;
1411 replace_whole
= treplace_whole
;
1412 replace_case
= treplace_case
;
1414 *search_text
= NULL
;
1420 static long sargs
[NUM_REPL_ARGS
][256 / sizeof (long)];
1422 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1423 sargs[4], sargs[5], sargs[6], sargs[7], \
1424 sargs[8], sargs[9], sargs[10], sargs[11], \
1425 sargs[12], sargs[13], sargs[14], sargs[15]
1427 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1428 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1429 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1430 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1433 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1434 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1436 string_regexp_search (char *pattern
, char *string
, int match_type
,
1437 int match_bol
, int icase
, int *found_len
, void *d
)
1440 static char *old_pattern
= NULL
;
1441 static int old_type
, old_icase
;
1443 static regmatch_t s
[1];
1445 pmatch
= (regmatch_t
*) d
;
1449 if (!old_pattern
|| strcmp (old_pattern
, pattern
)
1450 || old_type
!= match_type
|| old_icase
!= icase
) {
1453 g_free (old_pattern
);
1456 if (regcomp (&r
, pattern
, REG_EXTENDED
| (icase
? REG_ICASE
: 0) |
1461 old_pattern
= g_strdup (pattern
);
1462 old_type
= match_type
;
1466 (&r
, string
, d
? NUM_REPL_ARGS
: 1, pmatch
,
1468 || match_type
!= match_normal
) ? 0 : REG_NOTBOL
)) != 0) {
1472 *found_len
= pmatch
[0].rm_eo
- pmatch
[0].rm_so
;
1473 return (pmatch
[0].rm_so
);
1476 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1477 (and the above) routines to work properly - paul */
1479 typedef int (*edit_getbyte_fn
) (WEdit
*, long);
1482 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
)
1485 long l
= strlen ((char *) exp
), f
= 0;
1488 for (p
= 0; p
< l
; p
++) /* count conversions... */
1490 if (exp
[++p
] != '%') /* ...except for "%%" */
1493 if (replace_scanf
|| replace_regexp
) {
1496 unsigned char mbuf
[MAX_REPL_LEN
* 2 + 3];
1498 replace_scanf
= (!replace_regexp
); /* can't have both */
1502 if (replace_scanf
) {
1503 unsigned char e
[MAX_REPL_LEN
];
1504 if (n
>= NUM_REPL_ARGS
)
1508 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++)
1509 buf
[p
- start
] = (*get_byte
) (data
, p
);
1511 for (p
= 0; exp
[p
] != 0; p
++)
1512 exp
[p
] = my_lower_case (exp
[p
]);
1513 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++) {
1514 c
= (*get_byte
) (data
, p
);
1515 buf
[p
- start
] = my_lower_case (c
);
1519 buf
[(q
= p
- start
)] = 0;
1520 strcpy ((char *) e
, (char *) exp
);
1521 strcat ((char *) e
, "%n");
1525 *((int *) sargs
[n
]) = 0; /* --> here was the problem - now fixed: good */
1526 if (n
== sscanf ((char *) buf
, (char *) exp
, SCANF_ARGS
)) {
1527 if (*((int *) sargs
[n
])) {
1528 *len
= *((int *) sargs
[n
]);
1534 if (q
+ start
< last_byte
) {
1536 buf
[q
] = (*get_byte
) (data
, q
+ start
);
1538 c
= (*get_byte
) (data
, q
+ start
);
1539 buf
[q
] = my_lower_case (c
);
1545 buf
++; /* move the window along */
1546 if (buf
== mbuf
+ MAX_REPL_LEN
) { /* the window is about to go past the end of array, so... */
1547 memmove (mbuf
, buf
, strlen ((char *) buf
) + 1); /* reset it */
1552 } else { /* regexp matching */
1554 int found_start
, match_bol
, move_win
= 0;
1556 while (start
+ offset
< last_byte
) {
1557 match_bol
= (start
== 0 || (*get_byte
) (data
, start
+ offset
- 1) == '\n');
1562 for (; p
< last_byte
&& q
< MAX_REPL_LEN
; p
++, q
++) {
1563 mbuf
[q
] = (*get_byte
) (data
, p
);
1564 if (mbuf
[q
] == '\n') {
1574 found_start
= string_regexp_search ((char *) exp
, (char *) buf
, match_normal
, match_bol
, !replace_case
, len
, d
);
1576 if (found_start
<= -2) { /* regcomp/regexec error */
1580 else if (found_start
== -1) /* not found: try next line */
1582 else if (*len
== 0) { /* null pattern: try again at next character */
1589 return (start
+ offset
- q
+ found_start
);
1594 if (buf
[q
- 1] != '\n') { /* incomplete line: try to recover */
1595 buf
= mbuf
+ MAX_REPL_LEN
/ 2;
1596 q
= strlen ((const char *) buf
);
1597 memmove (mbuf
, buf
, q
);
1606 *len
= strlen ((const char *) exp
);
1608 for (p
= start
; p
<= last_byte
- l
; p
++) {
1609 if ((*get_byte
) (data
, p
) == (unsigned char)exp
[0]) { /* check if first char matches */
1610 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1611 if ((*get_byte
) (data
, q
+ p
) != (unsigned char)exp
[q
])
1620 for (p
= 0; exp
[p
] != 0; p
++)
1621 exp
[p
] = my_lower_case (exp
[p
]);
1623 for (p
= start
; p
<= last_byte
- l
; p
++) {
1624 if (my_lower_case ((*get_byte
) (data
, p
)) == (unsigned char)exp
[0]) {
1625 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1626 if (my_lower_case ((*get_byte
) (data
, q
+ p
)) != (unsigned char)exp
[q
])
1641 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
)
1642 { /*front end to find_string to check for
1647 while ((p
= edit_find_string (p
, exp
, len
, last_byte
, get_byte
, data
, once_only
, d
)) >= 0) {
1648 if (replace_whole
) {
1649 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1650 if (!strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
- 1))
1651 && !strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
+ *len
)))
1659 p
++; /*not a whole word so continue search. */
1665 edit_find (long search_start
, unsigned char *exp
, int *len
, long last_byte
, edit_getbyte_fn get_byte
, void *data
, void *d
)
1668 if (replace_backwards
) {
1669 while (search_start
>= 0) {
1670 p
= edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 1, d
);
1671 if (p
== search_start
)
1676 return edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 0, d
);
1681 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1683 #define snprint(v) { \
1686 n = snprintf(s,e-s,q1,v); \
1687 if (n >= (size_t) (e - s)) goto nospc; \
1691 /* this function uses the sprintf command to do a vprintf */
1692 /* it takes pointers to arguments instead of the arguments themselves */
1693 /* The return value is the number of bytes written excluding '\0'
1694 if successfull, -1 if the resulting string would be too long and
1695 -2 if the format string is errorneous. */
1696 static int snprintf_p (char *str
, size_t size
, const char *fmt
,...)
1697 __attribute__ ((format (printf
, 3, 4)));
1699 static int snprintf_p (char *str
, size_t size
, const char *fmt
,...)
1704 char *s
= str
, *e
= str
+ size
;
1712 while ((p
= strchr (p
, '%'))) {
1714 if (n
>= (size_t) (e
- s
))
1716 memcpy (s
, q
, n
); /* copy stuff between format specifiers */
1731 /* We were passed only 16 arguments. */
1744 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace field width with a number */
1747 while (is_digit (*p
) && p1
< q1
+ 20)
1756 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace precision with a number */
1759 while (is_digit (*p
) && p1
< q1
+ 32)
1764 /* flags done, now get argument */
1766 snprint (va_arg (ap
, char *));
1767 } else if (*p
== 'h') {
1768 if (strchr ("diouxX", *p
))
1769 snprint (*va_arg (ap
, short *));
1770 } else if (*p
== 'l') {
1772 if (strchr ("diouxX", *p
))
1773 snprint (*va_arg (ap
, long *));
1774 } else if (strchr ("cdiouxX", *p
)) {
1775 snprint (*va_arg (ap
, int *));
1776 } else if (*p
== 'L') {
1778 if (strchr ("EefgG", *p
))
1779 snprint (*va_arg (ap
, double *)); /* should be long double */
1780 } else if (strchr ("EefgG", *p
)) {
1781 snprint (*va_arg (ap
, double *));
1782 } else if (strchr ("DOU", *p
)) {
1783 snprint (*va_arg (ap
, long *));
1784 } else if (*p
== 'p') {
1785 snprint (*va_arg (ap
, void **));
1792 if (n
>= (size_t) (e
- s
))
1794 memcpy (s
, q
, n
+ 1);
1804 static void regexp_error (WEdit
*edit
)
1807 edit_error_dialog (_("Error"), _(" Invalid regular expression, or scanf expression with too many conversions "));
1810 /* call with edit = 0 before shutdown to close memory leaks */
1812 edit_replace_cmd (WEdit
*edit
, int again
)
1814 static regmatch_t pmatch
[NUM_REPL_ARGS
];
1815 /* 1 = search string, 2 = replace with, 3 = argument order */
1816 static char *saved1
= NULL
; /* saved default[123] */
1817 static char *saved2
= NULL
;
1818 static char *saved3
= NULL
;
1819 char *input1
= NULL
; /* user input from the dialog */
1820 char *input2
= NULL
;
1821 char *input3
= NULL
;
1823 int replace_continue
;
1824 int treplace_prompt
= 0;
1825 long times_replaced
= 0, last_search
;
1826 int argord
[NUM_REPL_ARGS
];
1829 g_free (saved1
), saved1
= NULL
;
1830 g_free (saved2
), saved2
= NULL
;
1831 g_free (saved3
), saved3
= NULL
;
1835 last_search
= edit
->last_byte
;
1837 edit
->force
|= REDRAW_COMPLETELY
;
1839 if (again
&& !saved1
&& !saved2
)
1843 input1
= g_strdup (saved1
? saved1
: "");
1844 input2
= g_strdup (saved2
? saved2
: "");
1845 input3
= g_strdup (saved3
? saved3
: "");
1847 char *disp1
= g_strdup (saved1
? saved1
: "");
1848 char *disp2
= g_strdup (saved2
? saved2
: "");
1849 char *disp3
= g_strdup (saved3
? saved3
: "");
1851 convert_to_display (disp1
);
1852 convert_to_display (disp2
);
1853 convert_to_display (disp3
);
1855 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1856 edit_replace_dialog (edit
, disp1
, disp2
, disp3
, &input1
, &input2
,
1863 convert_from_input (input1
);
1864 convert_from_input (input2
);
1865 convert_from_input (input3
);
1867 treplace_prompt
= replace_prompt
;
1868 if (input1
== NULL
|| *input1
== '\0') {
1869 edit
->force
= REDRAW_COMPLETELY
;
1873 g_free (saved1
), saved1
= g_strdup (input1
);
1874 g_free (saved2
), saved2
= g_strdup (input2
);
1875 g_free (saved3
), saved3
= g_strdup (input3
);
1885 for (i
= 0; i
< NUM_REPL_ARGS
; i
++) {
1886 if (s
!= NULL
&& *s
!= '\0') {
1888 if ((ord
> 0) && (ord
<= NUM_REPL_ARGS
))
1889 argord
[i
] = ord
- 1;
1892 s
= strchr (s
, ',');
1900 replace_continue
= replace_all
;
1902 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1
1903 && replace_backwards
)
1904 edit
->search_start
--;
1906 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1
1907 && !replace_backwards
)
1908 edit
->search_start
++;
1914 edit_find (edit
->search_start
, (unsigned char *) input1
, &len
,
1915 last_search
, edit_get_byte
, (void *) edit
, pmatch
);
1916 if (new_start
== -3) {
1917 regexp_error (edit
);
1920 edit
->search_start
= new_start
;
1921 /*returns negative on not found or error in pattern */
1923 if (edit
->search_start
>= 0) {
1926 edit
->found_start
= edit
->search_start
;
1927 i
= edit
->found_len
= len
;
1929 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1930 edit_scroll_screen_over_cursor (edit
);
1934 if (treplace_prompt
) {
1936 l
= edit
->curs_row
- edit
->num_widget_lines
/ 3;
1938 edit_scroll_downward (edit
, l
);
1940 edit_scroll_upward (edit
, -l
);
1942 edit_scroll_screen_over_cursor (edit
);
1943 edit
->force
|= REDRAW_PAGE
;
1944 edit_render_keypress (edit
);
1946 /*so that undo stops at each query */
1947 edit_push_key_press (edit
);
1949 switch (edit_replace_prompt (edit
, input2
, /* and prompt 2/3 down */
1950 (edit
->num_widget_columns
-
1951 CONFIRM_DLG_WIDTH
) / 2,
1952 edit
->num_widget_lines
* 2 /
1956 case B_SKIP_REPLACE
:
1960 treplace_prompt
= 0;
1961 replace_continue
= 1;
1964 replace_continue
= 0;
1968 replace_continue
= 0;
1972 if (replace_yes
) { /* delete then insert new */
1973 if (replace_scanf
) {
1974 char repl_str
[MAX_REPL_LEN
+ 2];
1977 /* we need to fill in sargs just like with scanf */
1978 if (replace_regexp
) {
1981 k
< NUM_REPL_ARGS
&& pmatch
[k
].rm_eo
>= 0;
1985 if (pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
> 255) {
1989 t
= (unsigned char *) &sargs
[k
- 1][0];
1991 j
< pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
1992 && j
< 255; j
++, t
++)
1993 *t
= (unsigned char) edit_get_byte (edit
,
2006 for (; k
<= NUM_REPL_ARGS
; k
++)
2007 sargs
[k
- 1][0] = 0;
2011 snprintf_p (repl_str
, MAX_REPL_LEN
+ 2, input2
,
2017 while (repl_str
[++i
])
2018 edit_insert (edit
, repl_str
[i
]);
2020 edit_error_dialog (_(" Replace "),
2024 (" Error in replacement format string. ")
2025 : _(" Replacement too long. "));
2026 replace_continue
= 0;
2033 edit_insert (edit
, input2
[i
]);
2035 edit
->found_len
= i
;
2037 /* so that we don't find the same string again */
2038 if (replace_backwards
) {
2039 last_search
= edit
->search_start
;
2040 edit
->search_start
--;
2042 edit
->search_start
+= i
;
2043 last_search
= edit
->last_byte
;
2045 edit_scroll_screen_over_cursor (edit
);
2047 const char *msg
= _(" Replace ");
2048 /* try and find from right here for next search */
2049 edit
->search_start
= edit
->curs1
;
2050 edit_update_curs_col (edit
);
2052 edit
->force
|= REDRAW_PAGE
;
2053 edit_render_keypress (edit
);
2054 if (times_replaced
) {
2055 message (0, msg
, _(" %ld replacements made. "),
2058 query_dialog (msg
, _(" Search string not found "),
2059 D_NORMAL
, 1, _("&OK"));
2060 replace_continue
= 0;
2062 } while (replace_continue
);
2064 edit
->force
= REDRAW_COMPLETELY
;
2065 edit_scroll_screen_over_cursor (edit
);
2075 void edit_search_cmd (WEdit
* edit
, int again
)
2077 static char *old
= NULL
;
2086 exp
= old
? old
: exp
;
2087 if (again
) { /*ctrl-hotkey for search again. */
2090 exp
= g_strdup (old
);
2095 convert_to_display (exp
);
2096 #endif /* HAVE_CHARSET */
2098 edit_search_dialog (edit
, &exp
);
2102 convert_from_input (exp
);
2103 #endif /* HAVE_CHARSET */
2105 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2112 old
= g_strdup (exp
);
2114 if (search_create_bookmark
) {
2115 int found
= 0, books
= 0;
2116 int l
= 0, l_last
= -1;
2119 p
= edit_find (q
, (unsigned char *) exp
, &len
, edit
->last_byte
,
2120 edit_get_byte
, (void *) edit
, 0);
2124 l
+= edit_count_lines (edit
, q
, p
);
2126 book_mark_insert (edit
, l
, BOOK_MARK_FOUND_COLOR
);
2133 /* in response to number of bookmarks added because of string being found %d times */
2134 message (0, _("Search"), _(" %d items found, %d bookmarks added "), found
, books
);
2136 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2140 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
2141 edit
->search_start
--;
2143 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
2144 edit
->search_start
++;
2146 edit
->search_start
= edit_find (edit
->search_start
, (unsigned char *) exp
, &len
, edit
->last_byte
,
2147 edit_get_byte
, (void *) edit
, 0);
2149 if (edit
->search_start
>= 0) {
2150 edit
->found_start
= edit
->search_start
;
2151 edit
->found_len
= len
;
2153 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
2154 edit_scroll_screen_over_cursor (edit
);
2155 if (replace_backwards
)
2156 edit
->search_start
--;
2158 edit
->search_start
++;
2159 } else if (edit
->search_start
== -3) {
2160 edit
->search_start
= edit
->curs1
;
2161 regexp_error (edit
);
2163 edit
->search_start
= edit
->curs1
;
2164 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2170 edit
->force
|= REDRAW_COMPLETELY
;
2171 edit_scroll_screen_over_cursor (edit
);
2176 * Check if it's OK to close the editor. If there are unsaved changes,
2177 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2180 edit_ok_to_exit (WEdit
*edit
)
2182 if (!edit
->modified
)
2185 switch (edit_query_dialog3
2186 (_("Quit"), _(" File was modified, Save with exit? "),
2187 _("&Cancel quit"), _("&Yes"), _("&No"))) {
2189 edit_push_markers (edit
);
2190 edit_set_markers (edit
, 0, 0, 0, 0);
2191 if (!edit_save_cmd (edit
))
2205 #define TEMP_BUF_LEN 1024
2207 /* Return a null terminated length of text. Result must be g_free'd */
2208 static unsigned char *
2209 edit_get_block (WEdit
*edit
, long start
, long finish
, int *l
)
2211 unsigned char *s
, *r
;
2212 r
= s
= g_malloc (finish
- start
+ 1);
2213 if (column_highlighting
) {
2215 /* copy from buffer, excluding chars that are out of the column 'margins' */
2216 while (start
< finish
) {
2218 x
= edit_move_forward3 (edit
, edit_bol (edit
, start
), 0,
2220 c
= edit_get_byte (edit
, start
);
2221 if ((x
>= edit
->column1
&& x
< edit
->column2
)
2222 || (x
>= edit
->column2
&& x
< edit
->column1
) || c
== '\n') {
2229 *l
= finish
- start
;
2230 while (start
< finish
)
2231 *s
++ = edit_get_byte (edit
, start
++);
2237 /* save block, returns 1 on success */
2239 edit_save_block (WEdit
* edit
, const char *filename
, long start
,
2245 mc_open (filename
, O_CREAT
| O_WRONLY
| O_TRUNC
,
2246 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
| O_BINARY
)) == -1)
2249 if (column_highlighting
) {
2250 unsigned char *block
, *p
;
2252 p
= block
= edit_get_block (edit
, start
, finish
, &len
);
2254 r
= mc_write (file
, p
, len
);
2264 len
= finish
- start
;
2265 buf
= g_malloc (TEMP_BUF_LEN
);
2266 while (start
!= finish
) {
2267 end
= min (finish
, start
+ TEMP_BUF_LEN
);
2268 for (; i
< end
; i
++)
2269 buf
[i
- start
] = edit_get_byte (edit
, i
);
2270 len
-= mc_write (file
, (char *) buf
, end
- start
);
2281 /* copies a block to clipboard file */
2282 static int edit_save_block_to_clip_file (WEdit
* edit
, long start
, long finish
)
2284 return edit_save_block (edit
, catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
), start
, finish
);
2288 void edit_paste_from_history (WEdit
*edit
)
2291 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
2294 int edit_copy_to_X_buf_cmd (WEdit
* edit
)
2296 long start_mark
, end_mark
;
2297 if (eval_marks (edit
, &start_mark
, &end_mark
))
2299 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2300 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2303 edit_mark_cmd (edit
, 1);
2307 int edit_cut_to_X_buf_cmd (WEdit
* edit
)
2309 long start_mark
, end_mark
;
2310 if (eval_marks (edit
, &start_mark
, &end_mark
))
2312 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2313 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2316 edit_block_delete_cmd (edit
);
2317 edit_mark_cmd (edit
, 1);
2321 void edit_paste_from_X_buf_cmd (WEdit
* edit
)
2323 edit_insert_file (edit
, catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
));
2328 * Ask user for the line and go to that line.
2329 * Negative numbers mean line from the end (i.e. -1 is the last line).
2332 edit_goto_cmd (WEdit
*edit
)
2335 static long line
= 0; /* line as typed, saved as default */
2340 g_snprintf (s
, sizeof (s
), "%ld", line
);
2341 f
= input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE
,
2351 l
= strtol (f
, &error
, 0);
2359 l
= edit
->total_lines
+ l
+ 2;
2360 edit_move_display (edit
, l
- edit
->num_widget_lines
/ 2 - 1);
2361 edit_move_to_line (edit
, l
- 1);
2362 edit
->force
|= REDRAW_COMPLETELY
;
2367 /* Return 1 on success */
2369 edit_save_block_cmd (WEdit
*edit
)
2371 long start_mark
, end_mark
;
2373 if (eval_marks (edit
, &start_mark
, &end_mark
))
2376 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2377 MC_HISTORY_EDIT_SAVE_BLOCK
,
2378 catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
));
2379 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2385 if (edit_save_block (edit
, exp
, start_mark
, end_mark
)) {
2387 edit
->force
|= REDRAW_COMPLETELY
;
2391 edit_error_dialog (_(" Save Block "),
2393 (" Cannot save file. ")));
2397 edit
->force
|= REDRAW_COMPLETELY
;
2402 /* returns 1 on success */
2404 edit_insert_file_cmd (WEdit
*edit
)
2406 char *exp
= input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2407 MC_HISTORY_EDIT_INSERT_FILE
,
2408 catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
));
2409 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2415 if (edit_insert_file (edit
, exp
)) {
2417 edit
->force
|= REDRAW_COMPLETELY
;
2421 edit_error_dialog (_(" Insert File "),
2423 (" Cannot insert file. ")));
2427 edit
->force
|= REDRAW_COMPLETELY
;
2431 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2432 int edit_sort_cmd (WEdit
* edit
)
2434 static char *old
= 0;
2436 long start_mark
, end_mark
;
2439 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2440 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2443 edit_save_block (edit
, catstrs (home_dir
, PATH_SEP_STR BLOCK_FILE
, (char *) NULL
), start_mark
, end_mark
);
2445 exp
= input_dialog (_(" Run Sort "),
2446 _(" Enter sort options (see manpage) separated by whitespace: "),
2447 MC_HISTORY_EDIT_SORT
, (old
!= NULL
) ? old
: "");
2454 e
= system (catstrs (" sort ", exp
, " ", home_dir
, PATH_SEP_STR BLOCK_FILE
, " > ", home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2456 if (e
== -1 || e
== 127) {
2457 edit_error_dialog (_(" Sort "),
2458 get_sys_error (_(" Cannot execute sort command ")));
2461 sprintf (q
, "%d ", e
);
2462 edit_error_dialog (_(" Sort "),
2463 catstrs (_(" Sort returned non-zero: "), q
, (char *) NULL
));
2468 edit
->force
|= REDRAW_COMPLETELY
;
2470 if (edit_block_delete_cmd (edit
))
2472 edit_insert_file (edit
, catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2477 * Ask user for a command, execute it and paste its output back to the
2481 edit_ext_cmd (WEdit
*edit
)
2487 input_dialog (_("Paste output of external command"),
2488 _("Enter shell command(s):"),
2489 MC_HISTORY_EDIT_PASTE_EXTCMD
, NULL
);
2494 e
= system (catstrs (exp
, " > ", home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2498 edit_error_dialog (_("External command"),
2499 get_sys_error (_("Cannot execute command")));
2503 edit
->force
|= REDRAW_COMPLETELY
;
2505 edit_insert_file (edit
, catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2509 /* if block is 1, a block must be highlighted and the shell command
2510 processes it. If block is 0 the shell command is a straight system
2511 command, that just produces some output which is to be inserted */
2513 edit_block_process_cmd (WEdit
*edit
, const char *shell_cmd
, int block
)
2515 long start_mark
, end_mark
;
2517 FILE *script_home
= NULL
;
2518 FILE *script_src
= NULL
;
2519 FILE *block_file
= NULL
;
2520 const char *o
= NULL
;
2521 const char *h
= NULL
;
2522 const char *b
= NULL
;
2523 char *quoted_name
= NULL
;
2525 o
= catstrs (mc_home
, shell_cmd
, (char *) NULL
); /* original source script */
2526 h
= catstrs (home_dir
, PATH_SEP_STR EDIT_DIR
, shell_cmd
, (char *) NULL
); /* home script */
2527 b
= catstrs (home_dir
, PATH_SEP_STR BLOCK_FILE
, (char *) NULL
); /* block file */
2529 if (!(script_home
= fopen (h
, "r"))) {
2530 if (!(script_home
= fopen (h
, "w"))) {
2531 edit_error_dialog ("", get_sys_error (catstrs
2533 ("Error creating script:"),
2534 h
, (char *) NULL
)));
2537 if (!(script_src
= fopen (o
, "r"))) {
2538 fclose (script_home
);
2540 edit_error_dialog ("", get_sys_error (catstrs
2541 (_("Error reading script:"),
2542 o
, (char *) NULL
)));
2545 while (fgets (buf
, sizeof (buf
), script_src
))
2546 fputs (buf
, script_home
);
2547 if (fclose (script_home
)) {
2548 edit_error_dialog ("", get_sys_error (catstrs
2550 ("Error closing script:"),
2551 h
, (char *) NULL
)));
2555 edit_error_dialog ("", get_sys_error (catstrs
2556 (_("Script created:"), h
, (char *) NULL
)));
2561 if (block
) { /* for marked block run indent formatter */
2562 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2563 edit_error_dialog (_("Process block"),
2565 (" You must first highlight a block of text. "));
2568 edit_save_block (edit
, b
, start_mark
, end_mark
);
2569 quoted_name
= name_quote (edit
->filename
, 0);
2572 * Initial space is to avoid polluting bash history.
2574 * $1 - name of the edited file (to check its extension etc).
2575 * $2 - file containing the current block.
2576 * $3 - file where error messages should be put
2577 * (for compatibility with old scripts).
2579 system (catstrs (" ", home_dir
, PATH_SEP_STR EDIT_DIR
, shell_cmd
, " ", quoted_name
,
2580 " ", home_dir
, PATH_SEP_STR BLOCK_FILE
" /dev/null", (char *) NULL
));
2584 * No block selected, just execute the command for the file.
2586 * $1 - name of the edited file.
2588 system (catstrs (" ", home_dir
, PATH_SEP_STR EDIT_DIR
, shell_cmd
, " ",
2589 quoted_name
, (char *) NULL
));
2591 g_free (quoted_name
);
2592 close_error_pipe (0, 0);
2594 edit_refresh_cmd (edit
);
2595 edit
->force
|= REDRAW_COMPLETELY
;
2597 /* insert result block */
2599 if (edit_block_delete_cmd (edit
))
2601 edit_insert_file (edit
, b
);
2602 if ((block_file
= fopen (b
, "w")))
2603 fclose (block_file
);
2610 /* prints at the cursor */
2611 /* returns the number of chars printed */
2612 int edit_print_string (WEdit
* e
, const char *s
)
2616 edit_execute_cmd (e
, -1, (unsigned char) s
[i
++]);
2617 e
->force
|= REDRAW_COMPLETELY
;
2618 edit_update_screen (e
);
2623 static void pipe_mail (WEdit
*edit
, char *to
, char *subject
, char *cc
)
2628 to
= name_quote (to
, 0);
2629 subject
= name_quote (subject
, 0);
2630 cc
= name_quote (cc
, 0);
2631 s
= g_strconcat ("mail -s ", subject
, *cc
? " -c " : "" , cc
, " ", to
, (char *) NULL
);
2643 for (i
= 0; i
< edit
->last_byte
; i
++)
2644 fputc (edit_get_byte (edit
, i
), p
);
2649 #define MAIL_DLG_HEIGHT 12
2651 void edit_mail_dialog (WEdit
* edit
)
2654 char *tmail_subject
;
2657 static char *mail_cc_last
= 0;
2658 static char *mail_subject_last
= 0;
2659 static char *mail_to_last
= 0;
2661 QuickDialog Quick_input
=
2662 {50, MAIL_DLG_HEIGHT
, -1, 0, N_(" Mail "),
2663 "[Input Line Keys]", 0, 0};
2665 QuickWidget quick_widgets
[] =
2667 {quick_button
, 6, 10, 9, MAIL_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
2669 {quick_button
, 2, 10, 9, MAIL_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
2671 {quick_input
, 3, 50, 8, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2672 0, "mail-dlg-input"},
2673 {quick_label
, 2, 50, 7, MAIL_DLG_HEIGHT
, N_(" Copies to"), 0, 0, 0,
2675 {quick_input
, 3, 50, 6, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2676 0, "mail-dlg-input-2"},
2677 {quick_label
, 2, 50, 5, MAIL_DLG_HEIGHT
, N_(" Subject"), 0, 0, 0,
2679 {quick_input
, 3, 50, 4, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2680 0, "mail-dlg-input-3"},
2681 {quick_label
, 2, 50, 3, MAIL_DLG_HEIGHT
, N_(" To"), 0, 0, 0,
2683 {quick_label
, 2, 50, 2, MAIL_DLG_HEIGHT
, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2687 quick_widgets
[2].str_result
= &tmail_cc
;
2688 quick_widgets
[2].text
= mail_cc_last
? mail_cc_last
: "";
2689 quick_widgets
[4].str_result
= &tmail_subject
;
2690 quick_widgets
[4].text
= mail_subject_last
? mail_subject_last
: "";
2691 quick_widgets
[6].str_result
= &tmail_to
;
2692 quick_widgets
[6].text
= mail_to_last
? mail_to_last
: "";
2694 Quick_input
.widgets
= quick_widgets
;
2696 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
2697 g_free (mail_cc_last
);
2698 g_free (mail_subject_last
);
2699 g_free (mail_to_last
);
2700 mail_cc_last
= tmail_cc
;
2701 mail_subject_last
= tmail_subject
;
2702 mail_to_last
= tmail_to
;
2703 pipe_mail (edit
, mail_to_last
, mail_subject_last
, mail_cc_last
);
2708 /*******************/
2709 /* Word Completion */
2710 /*******************/
2713 /* find first character of current word */
2714 static int edit_find_word_start (WEdit
*edit
, long *word_start
, int *word_len
)
2718 /* return if at begin of file */
2719 if (edit
->curs1
<= 0)
2722 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- 1);
2723 /* return if not at end or in word */
2724 if (isspace (c
) || !(isalnum (c
) || c
== '_'))
2727 /* search start of word to be completed */
2729 /* return if at begin of file */
2730 if (edit
->curs1
- i
< 0)
2734 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- i
);
2736 if (!(isalnum (c
) || c
== '_')) {
2737 /* return if word starts with digit */
2741 *word_start
= edit
->curs1
- (i
- 1); /* start found */
2751 /* (re)set search parameters to the given values */
2752 static void edit_set_search_parameters (int rs
, int rb
, int rr
, int rw
, int rc
)
2755 replace_backwards
= rb
;
2756 replace_regexp
= rr
;
2762 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2764 /* collect the possible completions */
2766 edit_collect_completions (WEdit
*edit
, long start
, int word_len
,
2767 char *match_expr
, struct selection
*compl,
2770 int len
, max_len
= 0, i
, skip
;
2771 unsigned char *bufpos
;
2773 /* collect max MAX_WORD_COMPLETIONS completions */
2774 while (*num
< MAX_WORD_COMPLETIONS
) {
2775 /* get next match */
2777 edit_find (start
- 1, (unsigned char *) match_expr
, &len
,
2778 edit
->last_byte
, edit_get_byte
, (void *) edit
, 0);
2784 /* add matched completion if not yet added */
2787 buffers1
[start
>> S_EDIT_BUF_SIZE
][start
& M_EDIT_BUF_SIZE
];
2789 for (i
= 0; i
< *num
; i
++) {
2791 ((char *) &compl[i
].text
[word_len
],
2792 (char *) &bufpos
[word_len
], max (len
,
2796 break; /* skip it, already added */
2802 compl[*num
].text
= g_malloc (len
+ 1);
2803 compl[*num
].len
= len
;
2804 for (i
= 0; i
< len
; i
++)
2805 compl[*num
].text
[i
] = *(bufpos
+ i
);
2806 compl[*num
].text
[i
] = '\0';
2809 /* note the maximal length needed for the completion dialog */
2817 /* let the user select its preferred completion */
2819 edit_completion_dialog (WEdit
* edit
, int max_len
, int word_len
,
2820 struct selection
*compl, int num_compl
)
2822 int start_x
, start_y
, offset
, i
;
2824 Dlg_head
*compl_dlg
;
2825 WListbox
*compl_list
;
2826 int compl_dlg_h
; /* completion dialog height */
2827 int compl_dlg_w
; /* completion dialog width */
2829 /* calculate the dialog metrics */
2830 compl_dlg_h
= num_compl
+ 2;
2831 compl_dlg_w
= max_len
+ 4;
2832 start_x
= edit
->curs_col
+ edit
->start_col
- (compl_dlg_w
/ 2);
2833 start_y
= edit
->curs_row
+ EDIT_TEXT_VERTICAL_OFFSET
+ 1;
2837 if (compl_dlg_w
> COLS
)
2839 if (compl_dlg_h
> LINES
- 2)
2840 compl_dlg_h
= LINES
- 2;
2842 offset
= start_x
+ compl_dlg_w
- COLS
;
2845 offset
= start_y
+ compl_dlg_h
- LINES
;
2847 start_y
-= (offset
+ 1);
2849 /* create the dialog */
2851 create_dlg (start_y
, start_x
, compl_dlg_h
, compl_dlg_w
,
2852 dialog_colors
, NULL
, "[Completion]", NULL
,
2855 /* create the listbox */
2857 listbox_new (1, 1, compl_dlg_w
- 2, compl_dlg_h
- 2, NULL
);
2859 /* add the dialog */
2860 add_widget (compl_dlg
, compl_list
);
2862 /* fill the listbox with the completions */
2863 for (i
= 0; i
< num_compl
; i
++)
2864 listbox_add_item (compl_list
, LISTBOX_APPEND_AT_END
, 0,
2865 (char *) compl[i
].text
, NULL
);
2867 /* pop up the dialog */
2868 run_dlg (compl_dlg
);
2870 /* apply the choosen completion */
2871 if (compl_dlg
->ret_value
== B_ENTER
) {
2872 listbox_get_current (compl_list
, &curr
, NULL
);
2874 for (curr
+= word_len
; *curr
; curr
++)
2875 edit_insert (edit
, *curr
);
2878 /* destroy dialog before return */
2879 destroy_dlg (compl_dlg
);
2884 * Complete current word using regular expression search
2885 * backwards beginning at the current cursor position.
2888 edit_complete_word_cmd (WEdit
*edit
)
2890 int word_len
= 0, i
, num_compl
= 0, max_len
;
2891 long word_start
= 0;
2892 unsigned char *bufpos
;
2894 struct selection
compl[MAX_WORD_COMPLETIONS
]; /* completions */
2896 /* don't want to disturb another search */
2897 int old_rs
= replace_scanf
;
2898 int old_rb
= replace_backwards
;
2899 int old_rr
= replace_regexp
;
2900 int old_rw
= replace_whole
;
2901 int old_rc
= replace_case
;
2903 /* search start of word to be completed */
2904 if (!edit_find_word_start (edit
, &word_start
, &word_len
))
2907 /* prepare match expression */
2908 bufpos
= &edit
->buffers1
[word_start
>> S_EDIT_BUF_SIZE
]
2909 [word_start
& M_EDIT_BUF_SIZE
];
2910 match_expr
= g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len
, bufpos
);
2912 /* init search: backward, regexp, whole word, case sensitive */
2913 edit_set_search_parameters (0, 1, 1, 1, 1);
2915 /* collect the possible completions */
2916 /* start search from curs1 down to begin of file */
2918 edit_collect_completions (edit
, word_start
, word_len
, match_expr
,
2919 (struct selection
*) &compl, &num_compl
);
2921 if (num_compl
> 0) {
2922 /* insert completed word if there is only one match */
2923 if (num_compl
== 1) {
2924 for (i
= word_len
; i
< compl[0].len
; i
++)
2925 edit_insert (edit
, *(compl[0].text
+ i
));
2927 /* more than one possible completion => ask the user */
2929 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2930 /* !!! pressed again the selection dialog pops up, but that !!! */
2931 /* !!! seems to require a further internal state !!! */
2934 /* let the user select the preferred completion */
2935 edit_completion_dialog (edit
, max_len
, word_len
,
2936 (struct selection
*) &compl,
2941 g_free (match_expr
);
2942 /* release memory before return */
2943 for (i
= 0; i
< num_compl
; i
++)
2944 g_free (compl[i
].text
);
2946 /* restore search parameters */
2947 edit_set_search_parameters (old_rs
, old_rb
, old_rr
, old_rw
, old_rc
);
2951 edit_select_codepage_cmd (WEdit
*edit
)
2954 do_select_codepage ();
2955 edit
->force
= REDRAW_COMPLETELY
;
2956 edit_refresh_cmd (edit
);
2961 edit_insert_literal_cmd (WEdit
*edit
)
2963 int char_for_insertion
=
2964 edit_raw_key_query (_(" Insert Literal "),
2965 _(" Press any key: "), 0);
2966 edit_execute_key_command (edit
, -1,
2967 ascii_alpha_to_cntrl (char_for_insertion
));
2971 edit_execute_macro_cmd (WEdit
*edit
)
2974 CK_Macro (edit_raw_key_query
2975 (_(" Execute Macro "), _(" Press macro hotkey: "),
2977 if (command
== CK_Macro (0))
2978 command
= CK_Insert_Char
;
2980 edit_execute_key_command (edit
, command
, -1);
2984 edit_begin_end_macro_cmd(WEdit
*edit
)
2988 /* edit is a pointer to the widget */
2992 0 ? CK_Begin_Record_Macro
: CK_End_Record_Macro
;
2993 edit_execute_key_command (edit
, command
, -1);