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 "../src/global.h"
42 #include "../src/history.h"
46 #include "editcmddef.h"
47 #include "edit-widget.h"
49 #include "../src/color.h" /* dialog_colors */
50 #include "../src/tty.h" /* LINES */
51 #include "../src/widget.h" /* listbox_new() */
52 #include "../src/layout.h" /* clr_scr() */
53 #include "../src/main.h" /* mc_home */
54 #include "../src/help.h" /* interactive_display() */
55 #include "../src/key.h" /* XCTRL */
56 #include "../src/dialog.h" /* do_refresh() */
57 #include "../src/wtools.h" /* message() */
58 #include "../src/charsets.h"
59 #include "../src/selcodepage.h"
68 /* search and replace: */
69 static int replace_scanf
= 0;
70 static int replace_regexp
= 0;
71 static int replace_all
= 0;
72 static int replace_prompt
= 1;
73 static int replace_whole
= 0;
74 static int replace_case
= 0;
75 static int replace_backwards
= 0;
76 static int search_create_bookmark
= 0;
78 /* queries on a save */
79 int edit_confirm_save
= 1;
81 #define NUM_REPL_ARGS 64
82 #define MAX_REPL_LEN 1024
84 static int edit_save_cmd (WEdit
*edit
);
85 static unsigned char *edit_get_block (WEdit
*edit
, long start
,
88 static inline int my_lower_case (int c
)
90 return tolower(c
& 0xFF);
94 strcasechr (const char *s
, int c
)
96 for (c
= my_lower_case (c
); my_lower_case ((int) *s
) != c
; ++s
)
102 /* #define itoa MY_itoa <---- this line is now in edit.h */
112 } while ((i
= i
/ 10));
118 /* Temporary strings */
119 static char *stacked
[16];
122 This joins strings end on end and allocates memory for the result.
123 The result is later automatically free'd and must not be free'd
127 catstrs (const char *first
,...)
137 len
= strlen (first
);
138 va_start (ap
, first
);
140 while ((data
= va_arg (ap
, char *)) != 0)
141 len
+= strlen (data
);
148 stacked
[i
] = g_malloc (len
);
150 va_start (ap
, first
);
151 strcpy (stacked
[i
], first
);
152 while ((data
= va_arg (ap
, char *)) != 0)
153 strcat (stacked
[i
], data
);
159 /* Free temporary strings */
164 for (i
= 0; i
< sizeof(stacked
) / sizeof(stacked
[0]); i
++) {
170 void edit_help_cmd (WEdit
* edit
)
172 interactive_display (NULL
, "[Internal File Editor]");
173 edit
->force
|= REDRAW_COMPLETELY
;
176 void edit_refresh_cmd (WEdit
* edit
)
184 edit_get_syntax_color (edit
, -1, &color
);
187 #endif /* !HAVE_SLANG */
192 /* If 0 (quick save) then a) create/truncate <filename> file,
193 b) save to <filename>;
194 if 1 (safe save) then a) save to <tempnam>,
195 b) rename <tempnam> to <filename>;
196 if 2 (do backups) then a) save to <tempnam>,
197 b) rename <filename> to <filename.backup_ext>,
198 c) rename <tempnam> to <filename>. */
200 /* returns 0 on error, -1 on abort */
202 edit_save_file (WEdit
*edit
, const char *filename
)
207 int this_save_mode
, fd
= -1;
214 if (*filename
!= PATH_SEP
&& edit
->dir
) {
215 savename
= concat_dir_and_file (edit
->dir
, filename
);
216 filename
= catstrs (savename
, (char *) NULL
);
220 this_save_mode
= option_save_mode
;
221 if (this_save_mode
!= EDIT_QUICK_SAVE
) {
222 if (!vfs_file_is_local (filename
) ||
223 (fd
= mc_open (filename
, O_RDONLY
| O_BINARY
)) == -1) {
225 * The file does not exists yet, so no safe save or
226 * backup are necessary.
228 this_save_mode
= EDIT_QUICK_SAVE
;
234 if (this_save_mode
== EDIT_QUICK_SAVE
&&
235 !edit
->skip_detach_prompt
) {
239 rv
= mc_stat (filename
, &sb
);
240 if (rv
== 0 && sb
.st_nlink
> 1) {
241 rv
= edit_query_dialog3 (_("Warning"),
242 _(" File has hard-links. Detach before saving? "),
243 _("&Yes"), _("&No"), _("&Cancel"));
246 this_save_mode
= EDIT_SAFE_SAVE
;
249 edit
->skip_detach_prompt
= 1;
256 /* Prevent overwriting changes from other editor sessions. */
257 if (rv
== 0 && edit
->stat1
.st_mtime
!= 0 && edit
->stat1
.st_mtime
!= sb
.st_mtime
) {
259 /* The default action is "Cancel". */
262 rv
= edit_query_dialog2 (
264 _("The file has been modified in the meantime. Save anyway?"),
272 if (this_save_mode
!= EDIT_QUICK_SAVE
) {
273 char *savedir
, *saveprefix
;
274 const char *slashpos
;
275 slashpos
= strrchr (filename
, PATH_SEP
);
277 savedir
= g_strdup (filename
);
278 savedir
[slashpos
- filename
+ 1] = '\0';
280 savedir
= g_strdup (".");
281 saveprefix
= concat_dir_and_file (savedir
, "cooledit");
283 fd
= mc_mkstemps (&savename
, saveprefix
, NULL
);
288 * Close for now because mc_mkstemps use pure open system call
289 * to create temporary file and it needs to be reopened by
290 * VFS-aware mc_open().
294 savename
= g_strdup (filename
);
296 mc_chown (savename
, edit
->stat1
.st_uid
, edit
->stat1
.st_gid
);
297 mc_chmod (savename
, edit
->stat1
.st_mode
);
300 mc_open (savename
, O_CREAT
| O_WRONLY
| O_TRUNC
| O_BINARY
,
301 edit
->stat1
.st_mode
)) == -1)
305 if ((p
= edit_get_write_filter (savename
, filename
))) {
309 file
= (FILE *) popen (p
, "w");
312 filelen
= edit_write_stream (edit
, file
);
316 if (pclose (file
) != 0) {
317 edit_error_dialog (_("Error"),
318 catstrs (_(" Error writing to pipe: "),
319 p
, " ", (char *) NULL
));
325 edit_error_dialog (_("Error"),
326 get_sys_error (catstrs
328 (" Cannot open pipe for writing: "),
329 p
, " ", (char *) NULL
)));
337 filelen
= edit
->last_byte
;
338 while (buf
<= (edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1) {
339 if (mc_write (fd
, (char *) edit
->buffers1
[buf
], EDIT_BUF_SIZE
)
347 (fd
, (char *) edit
->buffers1
[buf
],
348 edit
->curs1
& M_EDIT_BUF_SIZE
) !=
349 (edit
->curs1
& M_EDIT_BUF_SIZE
)) {
351 } else if (edit
->curs2
) {
353 buf
= (edit
->curs2
>> S_EDIT_BUF_SIZE
);
356 (char *) edit
->buffers2
[buf
] + EDIT_BUF_SIZE
-
357 (edit
->curs2
& M_EDIT_BUF_SIZE
) - 1,
358 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) !=
359 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) {
364 (fd
, (char *) edit
->buffers2
[buf
],
365 EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
376 /* Update the file information, especially the mtime. */
377 if (mc_stat (savename
, &edit
->stat1
) == -1)
381 if (filelen
!= edit
->last_byte
)
384 if (this_save_mode
== EDIT_DO_BACKUP
) {
385 assert (option_backup_ext
!= NULL
);
386 if (mc_rename (filename
, catstrs (filename
, option_backup_ext
,
387 (char *) NULL
)) == -1)
391 if (this_save_mode
!= EDIT_QUICK_SAVE
)
392 if (mc_rename (savename
, filename
) == -1)
397 /* FIXME: Is this safe ?
398 * if (this_save_mode != EDIT_QUICK_SAVE)
399 * mc_unlink (savename);
405 void menu_save_mode_cmd (void)
409 static char *str_result
;
410 static int save_mode_new
;
411 static const char *str
[] =
415 N_("Do backups -->")};
416 static QuickWidget widgets
[] =
418 {quick_button
, 18, DLG_X
, 7, DLG_Y
, N_("&Cancel"), 0,
419 B_CANCEL
, 0, 0, NULL
},
420 {quick_button
, 6, DLG_X
, 7, DLG_Y
, N_("&OK"), 0,
421 B_ENTER
, 0, 0, NULL
},
422 {quick_input
, 23, DLG_X
, 5, DLG_Y
, 0, 9,
423 0, 0, &str_result
, "edit-backup-ext"},
424 {quick_label
, 22, DLG_X
, 4, DLG_Y
, N_("Extension:"), 0,
426 {quick_radio
, 4, DLG_X
, 3, DLG_Y
, "", 3,
427 0, &save_mode_new
, (char **) str
, NULL
},
429 static QuickDialog dialog
=
430 {DLG_X
, DLG_Y
, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
432 static int i18n_flag
= 0;
440 /* OK/Cancel buttons */
441 l1
= strlen (_(widgets
[0].text
)) + strlen (_(widgets
[1].text
)) + 5;
442 maxlen
= max (maxlen
, l1
);
444 for (i
= 0; i
< 3; i
++ ) {
446 maxlen
= max (maxlen
, strlen (str
[i
]) + 7);
450 dlg_x
= maxlen
+ strlen (_(widgets
[3].text
)) + 5 + 1;
451 widgets
[2].hotkey_pos
= strlen (_(widgets
[3].text
)); /* input field length */
452 dlg_x
= min (COLS
, dlg_x
);
456 widgets
[1].relative_x
= i
;
457 widgets
[0].relative_x
= i
+ strlen (_(widgets
[1].text
)) + i
+ 4;
459 widgets
[2].relative_x
= widgets
[3].relative_x
= maxlen
+ 2;
461 for (i
= 0; i
< sizeof (widgets
)/sizeof (widgets
[0]); i
++)
462 widgets
[i
].x_divisions
= dlg_x
;
465 assert (option_backup_ext
!= NULL
);
466 widgets
[2].text
= option_backup_ext
;
467 widgets
[4].value
= option_save_mode
;
468 if (quick_dialog (&dialog
) != B_ENTER
)
470 option_save_mode
= save_mode_new
;
472 g_free (option_backup_ext
);
473 option_backup_ext
= str_result
;
478 edit_set_filename (WEdit
*edit
, const char *f
)
480 g_free (edit
->filename
);
483 edit
->filename
= g_strdup (f
);
484 if (edit
->dir
== NULL
&& *f
!= PATH_SEP
)
486 edit
->dir
= g_strdup (vfs_get_current_dir ());
488 edit
->dir
= g_get_current_dir ();
492 /* Here we want to warn the users of overwriting an existing file,
493 but only if they have made a change to the filename */
494 /* returns 1 on success */
496 edit_save_as_cmd (WEdit
*edit
)
498 /* This heads the 'Save As' dialog box */
501 int different_filename
= 0;
503 exp
= input_expand_dialog (
504 _(" Save As "), _(" Enter file name: "),MC_HISTORY_EDIT_SAVE_AS
, edit
->filename
);
505 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
510 edit
->force
|= REDRAW_COMPLETELY
;
514 if (strcmp (edit
->filename
, exp
)) {
516 different_filename
= 1;
517 if ((file
= mc_open (exp
, O_RDONLY
| O_BINARY
)) != -1) {
518 /* the file exists */
520 /* Overwrite the current file or cancel the operation */
521 if (edit_query_dialog2
523 _(" A file already exists with this name. "),
524 _("&Overwrite"), _("&Cancel"))) {
525 edit
->force
|= REDRAW_COMPLETELY
;
530 save_lock
= edit_lock_file (exp
);
532 /* filenames equal, check if already locked */
533 if (!edit
->locked
&& !edit
->delete_file
)
534 save_lock
= edit_lock_file (exp
);
537 rv
= edit_save_file (edit
, exp
);
540 /* Succesful, so unlock both files */
541 if (different_filename
) {
543 edit_unlock_file (exp
);
545 edit
->locked
= edit_unlock_file (edit
->filename
);
547 if (edit
->locked
|| save_lock
)
548 edit
->locked
= edit_unlock_file (edit
->filename
);
551 edit_set_filename (edit
, exp
);
554 edit
->delete_file
= 0;
555 if (different_filename
)
556 edit_load_syntax (edit
, NULL
, option_syntax_type
);
557 edit
->force
|= REDRAW_COMPLETELY
;
560 edit_error_dialog (_(" Save As "),
562 (" Cannot save file. ")));
565 /* Failed, so maintain modify (not save) lock */
567 edit_unlock_file (exp
);
569 edit
->force
|= REDRAW_COMPLETELY
;
574 edit
->force
|= REDRAW_COMPLETELY
;
578 /* {{{ Macro stuff starts here */
581 raw_callback (struct Dlg_head
*h
, dlg_msg_t msg
, int parm
)
589 return default_dlg_callback (h
, msg
, parm
);
593 /* gets a raw key from the keyboard. Passing cancel = 1 draws
594 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
595 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
596 and Esc are cannot returned */
598 edit_raw_key_query (const char *heading
, const char *query
, int cancel
)
600 int w
= strlen (query
) + 7;
601 struct Dlg_head
*raw_dlg
=
602 create_dlg (0, 0, 7, w
, dialog_colors
, raw_callback
,
604 DLG_CENTER
| DLG_TRYUP
| DLG_WANT_TAB
);
606 input_new (3 - cancel
, w
- 5, INPUT_COLOR
, 2, "", 0, INPUT_COMPLETE_DEFAULT
));
607 add_widget (raw_dlg
, label_new (3 - cancel
, 2, query
));
610 button_new (4, w
/ 2 - 5, B_CANCEL
, NORMAL_BUTTON
,
613 w
= raw_dlg
->ret_value
;
614 destroy_dlg (raw_dlg
);
616 if (w
== XCTRL ('g') || w
== XCTRL ('c') || w
== ESC_CHAR
624 /* creates a macro file if it doesn't exist */
625 static FILE *edit_open_macro_file (const char *r
)
627 const char *filename
;
629 filename
= catstrs (home_dir
, PATH_SEP_STR MACRO_FILE
, (char *) NULL
);
630 if ((file
= open (filename
, O_CREAT
| O_RDWR
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
633 return fopen (filename
, r
);
636 #define MAX_MACROS 1024
637 static int saved_macro
[MAX_MACROS
+ 1];
638 static int saved_macros_loaded
= 0;
641 This is just to stop the macro file be loaded over and over for keys
642 that aren't defined to anything. On slow systems this could be annoying.
648 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++)
649 if (saved_macro
[i
] == k
)
654 /* returns 1 on error */
656 edit_delete_macro (WEdit
* edit
, int k
)
658 struct macro macro
[MAX_MACRO_LENGTH
];
664 if (saved_macros_loaded
)
665 if ((j
= macro_exists (k
)) < 0)
667 g
= fopen (catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
), "w");
669 edit_error_dialog (_(" Delete macro "),
670 get_sys_error (_(" Cannot open temp file ")));
673 f
= edit_open_macro_file ("r");
675 edit_error_dialog (_(" Delete macro "),
676 get_sys_error (_(" Cannot open macro file ")));
681 n
= fscanf (f
, ("key '%d 0': "), &s
);
685 while (fscanf (f
, "%hd %hd, ", ¯o
[n
].command
, ¯o
[n
].ch
))
689 fprintf (g
, ("key '%d 0': "), s
);
690 for (i
= 0; i
< n
; i
++)
691 fprintf (g
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
697 if (rename (catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
), catstrs (home_dir
, PATH_SEP_STR MACRO_FILE
, (char *) NULL
)) == -1) {
698 edit_error_dialog (_(" Delete macro "),
699 get_sys_error (_(" Cannot overwrite macro file ")));
702 if (saved_macros_loaded
)
703 memmove (saved_macro
+ j
, saved_macro
+ j
+ 1, sizeof (int) * (MAX_MACROS
- j
- 1));
707 /* returns 0 on error */
708 int edit_save_macro_cmd (WEdit
* edit
, struct macro macro
[], int n
)
713 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
714 s
= edit_raw_key_query (_(" Save macro "),
715 _(" Press the macro's new hotkey: "), 1);
716 edit
->force
|= REDRAW_COMPLETELY
;
718 if (edit_delete_macro (edit
, s
))
720 f
= edit_open_macro_file ("a+");
722 fprintf (f
, ("key '%d 0': "), s
);
723 for (i
= 0; i
< n
; i
++)
724 fprintf (f
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
727 if (saved_macros_loaded
) {
728 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++);
733 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
738 void edit_delete_macro_cmd (WEdit
* edit
)
742 command
= edit_raw_key_query (_ (" Delete macro "),
743 _ (" Press macro hotkey: "), 1);
748 edit_delete_macro (edit
, command
);
751 /* return 0 on error */
752 int edit_load_macro_cmd (WEdit
* edit
, struct macro macro
[], int *n
, int k
)
755 int s
, i
= 0, found
= 0;
759 if (saved_macros_loaded
)
760 if (macro_exists (k
) < 0)
763 if ((f
= edit_open_macro_file ("r"))) {
767 u
= fscanf (f
, ("key '%d 0': "), &s
);
770 if (!saved_macros_loaded
)
771 saved_macro
[i
++] = s
;
774 while (*n
< MAX_MACRO_LENGTH
&& 2 == fscanf (f
, "%hd %hd, ", ¯o
[*n
].command
, ¯o
[*n
].ch
))
777 while (2 == fscanf (f
, "%hd %hd, ", &dummy
.command
, &dummy
.ch
));
782 } while (!found
|| !saved_macros_loaded
);
783 if (!saved_macros_loaded
) {
785 saved_macros_loaded
= 1;
790 edit_error_dialog (_(" Load macro "),
791 get_sys_error (_(" Cannot open macro file ")));
795 /* }}} Macro stuff starts here */
797 /* returns 1 on success */
798 int edit_save_confirm_cmd (WEdit
* edit
)
802 if (edit_confirm_save
) {
803 f
= catstrs (_(" Confirm save file? : "), edit
->filename
, " ", (char *) NULL
);
804 if (edit_query_dialog2 (_(" Save file "), f
, _("&Save"), _("&Cancel")))
807 return edit_save_cmd (edit
);
811 /* returns 1 on success */
813 edit_save_cmd (WEdit
*edit
)
815 int res
, save_lock
= 0;
817 if (!edit
->locked
&& !edit
->delete_file
)
818 save_lock
= edit_lock_file (edit
->filename
);
819 res
= edit_save_file (edit
, edit
->filename
);
821 /* Maintain modify (not save) lock on failure */
822 if ((res
> 0 && edit
->locked
) || save_lock
)
823 edit
->locked
= edit_unlock_file (edit
->filename
);
825 /* On failure try 'save as', it does locking on its own */
827 return edit_save_as_cmd (edit
);
828 edit
->force
|= REDRAW_COMPLETELY
;
830 edit
->delete_file
= 0;
838 /* returns 1 on success */
839 int edit_new_cmd (WEdit
* edit
)
841 if (edit
->modified
) {
842 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
843 edit
->force
|= REDRAW_COMPLETELY
;
847 edit
->force
|= REDRAW_COMPLETELY
;
849 return edit_renew (edit
); /* if this gives an error, something has really screwed up */
852 /* returns 1 on error */
854 edit_load_file_from_filename (WEdit
* edit
, char *exp
)
856 int prev_locked
= edit
->locked
;
857 char *prev_filename
= g_strdup (edit
->filename
);
859 if (!edit_reload (edit
, exp
)) {
860 g_free (prev_filename
);
865 edit_unlock_file (prev_filename
);
866 g_free (prev_filename
);
871 edit_load_cmd (WEdit
*edit
)
875 if (edit
->modified
) {
876 if (edit_query_dialog2
878 _(" Current text was modified without a file save. \n"
879 " Continue discards these changes. "), _("C&ontinue"),
881 edit
->force
|= REDRAW_COMPLETELY
;
886 exp
= input_expand_dialog (_(" Load "), _(" Enter file name: "),
887 MC_HISTORY_EDIT_LOAD
, edit
->filename
);
891 edit_load_file_from_filename (edit
, exp
);
894 edit
->force
|= REDRAW_COMPLETELY
;
899 if mark2 is -1 then marking is from mark1 to the cursor.
900 Otherwise its between the markers. This handles this.
901 Returns 1 if no text is marked.
903 int eval_marks (WEdit
* edit
, long *start_mark
, long *end_mark
)
905 if (edit
->mark1
!= edit
->mark2
) {
906 if (edit
->mark2
>= 0) {
907 *start_mark
= min (edit
->mark1
, edit
->mark2
);
908 *end_mark
= max (edit
->mark1
, edit
->mark2
);
910 *start_mark
= min (edit
->mark1
, edit
->curs1
);
911 *end_mark
= max (edit
->mark1
, edit
->curs1
);
912 edit
->column2
= edit
->curs_col
;
916 *start_mark
= *end_mark
= 0;
917 edit
->column2
= edit
->column1
= 0;
922 #define space_width 1
925 edit_insert_column_of_text (WEdit
* edit
, unsigned char *data
, int size
, int width
)
929 cursor
= edit
->curs1
;
930 col
= edit_get_col (edit
);
931 for (i
= 0; i
< size
; i
++) {
932 if (data
[i
] == '\n') { /* fill in and move to next line */
935 if (edit_get_byte (edit
, edit
->curs1
) != '\n') {
936 l
= width
- (edit_get_col (edit
) - col
);
938 edit_insert (edit
, ' ');
942 for (p
= edit
->curs1
;; p
++) {
943 if (p
== edit
->last_byte
) {
944 edit_cursor_move (edit
, edit
->last_byte
- edit
->curs1
);
945 edit_insert_ahead (edit
, '\n');
949 if (edit_get_byte (edit
, p
) == '\n') {
954 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, col
, 0) - edit
->curs1
);
955 l
= col
- edit_get_col (edit
);
956 while (l
>= space_width
) {
957 edit_insert (edit
, ' ');
962 edit_insert (edit
, data
[i
]);
964 edit_cursor_move (edit
, cursor
- edit
->curs1
);
969 edit_block_copy_cmd (WEdit
*edit
)
971 long start_mark
, end_mark
, current
= edit
->curs1
;
973 unsigned char *copy_buf
;
975 edit_update_curs_col (edit
);
976 if (eval_marks (edit
, &start_mark
, &end_mark
))
979 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
981 /* all that gets pushed are deletes hence little space is used on the stack */
983 edit_push_markers (edit
);
985 if (column_highlighting
) {
986 edit_insert_column_of_text (edit
, copy_buf
, size
,
987 abs (edit
->column2
- edit
->column1
));
990 edit_insert_ahead (edit
, copy_buf
[size
]);
994 edit_scroll_screen_over_cursor (edit
);
996 if (column_highlighting
) {
997 edit_set_markers (edit
, 0, 0, 0, 0);
998 edit_push_action (edit
, COLUMN_ON
);
999 column_highlighting
= 0;
1000 } else if (start_mark
< current
&& end_mark
> current
)
1001 edit_set_markers (edit
, start_mark
,
1002 end_mark
+ end_mark
- start_mark
, 0, 0);
1004 edit
->force
|= REDRAW_PAGE
;
1009 edit_block_move_cmd (WEdit
*edit
)
1013 unsigned char *copy_buf
;
1014 long start_mark
, end_mark
;
1018 if (eval_marks (edit
, &start_mark
, &end_mark
))
1020 if (column_highlighting
) {
1021 edit_update_curs_col (edit
);
1023 if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
1024 if ((x
> edit
->column1
&& x
< edit
->column2
)
1025 || (x
> edit
->column2
&& x
< edit
->column1
))
1027 } else if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
1030 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
1031 if (edit_query_dialog2
1034 (" Block is large, you may not be able to undo this action. "),
1035 _("C&ontinue"), _("&Cancel")))
1038 edit_push_markers (edit
);
1039 current
= edit
->curs1
;
1040 if (column_highlighting
) {
1041 int size
, c1
, c2
, line
;
1042 line
= edit
->curs_line
;
1043 if (edit
->mark2
< 0)
1044 edit_mark_cmd (edit
, 0);
1045 c1
= min (edit
->column1
, edit
->column2
);
1046 c2
= max (edit
->column1
, edit
->column2
);
1047 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
1049 edit_block_delete_cmd (edit
);
1052 edit_move_to_line (edit
, line
);
1053 edit_cursor_move (edit
,
1054 edit_move_forward3 (edit
,
1055 edit_bol (edit
, edit
->curs1
),
1056 x
, 0) - edit
->curs1
);
1057 edit_insert_column_of_text (edit
, copy_buf
, size
, c2
- c1
);
1059 line
= edit
->curs_line
;
1060 edit_update_curs_col (edit
);
1062 edit_block_delete_cmd (edit
);
1063 edit_move_to_line (edit
, line
);
1064 edit_cursor_move (edit
,
1065 edit_move_forward3 (edit
,
1068 x
, 0) - edit
->curs1
);
1070 edit_set_markers (edit
, 0, 0, 0, 0);
1071 edit_push_action (edit
, COLUMN_ON
);
1072 column_highlighting
= 0;
1074 copy_buf
= g_malloc (end_mark
- start_mark
);
1075 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
1076 edit_scroll_screen_over_cursor (edit
);
1078 while (count
< end_mark
) {
1079 copy_buf
[end_mark
- count
- 1] = edit_delete (edit
);
1082 edit_scroll_screen_over_cursor (edit
);
1083 edit_cursor_move (edit
,
1084 current
- edit
->curs1
-
1085 (((current
- edit
->curs1
) >
1086 0) ? end_mark
- start_mark
: 0));
1087 edit_scroll_screen_over_cursor (edit
);
1088 while (count
-- > start_mark
)
1089 edit_insert_ahead (edit
, copy_buf
[end_mark
- count
- 1]);
1090 edit_set_markers (edit
, edit
->curs1
,
1091 edit
->curs1
+ end_mark
- start_mark
, 0, 0);
1093 edit_scroll_screen_over_cursor (edit
);
1095 edit
->force
|= REDRAW_PAGE
;
1099 edit_delete_column_of_text (WEdit
* edit
)
1101 long p
, q
, r
, m1
, m2
;
1105 eval_marks (edit
, &m1
, &m2
);
1106 n
= edit_move_forward (edit
, m1
, 0, m2
) + 1;
1107 c
= edit_move_forward3 (edit
, edit_bol (edit
, m1
), 0, m1
);
1108 d
= edit_move_forward3 (edit
, edit_bol (edit
, m2
), 0, m2
);
1114 r
= edit_bol (edit
, edit
->curs1
);
1115 p
= edit_move_forward3 (edit
, r
, b
, 0);
1116 q
= edit_move_forward3 (edit
, r
, c
, 0);
1121 edit_cursor_move (edit
, p
- edit
->curs1
);
1122 while (q
> p
) { /* delete line between margins */
1123 if (edit_get_byte (edit
, edit
->curs1
) != '\n')
1127 if (n
) /* move to next line except on the last delete */
1128 edit_cursor_move (edit
, edit_move_forward (edit
, edit
->curs1
, 1, 0) - edit
->curs1
);
1132 /* if success return 0 */
1134 edit_block_delete (WEdit
*edit
)
1137 long start_mark
, end_mark
;
1138 if (eval_marks (edit
, &start_mark
, &end_mark
))
1140 if (column_highlighting
&& edit
->mark2
< 0)
1141 edit_mark_cmd (edit
, 0);
1142 if ((end_mark
- start_mark
) > option_max_undo
/ 2) {
1143 /* Warning message with a query to continue or cancel the operation */
1144 if (edit_query_dialog2
1147 (" Block is large, you may not be able to undo this action. "),
1148 _("C&ontinue"), _("&Cancel"))) {
1152 edit_push_markers (edit
);
1153 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
1154 edit_scroll_screen_over_cursor (edit
);
1156 if (start_mark
< end_mark
) {
1157 if (column_highlighting
) {
1158 if (edit
->mark2
< 0)
1159 edit_mark_cmd (edit
, 0);
1160 edit_delete_column_of_text (edit
);
1162 while (count
< end_mark
) {
1168 edit_set_markers (edit
, 0, 0, 0, 0);
1169 edit
->force
|= REDRAW_PAGE
;
1173 /* returns 1 if canceelled by user */
1174 int edit_block_delete_cmd (WEdit
* edit
)
1176 long start_mark
, end_mark
;
1177 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
1178 edit_delete_line (edit
);
1181 return edit_block_delete (edit
);
1185 #define INPUT_INDEX 9
1186 #define SEARCH_DLG_WIDTH 58
1187 #define SEARCH_DLG_HEIGHT 10
1188 #define REPLACE_DLG_WIDTH 58
1189 #define REPLACE_DLG_HEIGHT 15
1190 #define CONFIRM_DLG_WIDTH 79
1191 #define CONFIRM_DLG_HEIGTH 6
1192 #define B_REPLACE_ALL (B_USER+1)
1193 #define B_REPLACE_ONE (B_USER+2)
1194 #define B_SKIP_REPLACE (B_USER+3)
1197 edit_replace_prompt (WEdit
* edit
, char *replace_text
, int xpos
, int ypos
)
1199 QuickWidget quick_widgets
[] =
1201 {quick_button
, 63, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Cancel"),
1202 0, B_CANCEL
, 0, 0, NULL
},
1203 {quick_button
, 50, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("O&ne"),
1204 0, B_REPLACE_ONE
, 0, 0, NULL
},
1205 {quick_button
, 37, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("A&ll"),
1206 0, B_REPLACE_ALL
, 0, 0, NULL
},
1207 {quick_button
, 21, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Skip"),
1208 0, B_SKIP_REPLACE
, 0, 0, NULL
},
1209 {quick_button
, 4, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Replace"),
1210 0, B_ENTER
, 0, 0, NULL
},
1211 {quick_label
, 2, CONFIRM_DLG_WIDTH
, 2, CONFIRM_DLG_HEIGTH
, 0,
1215 GString
*label_text
= g_string_new (_(" Replace with: "));
1216 if (*replace_text
) {
1218 label_len
= label_text
->len
;
1219 g_string_append (label_text
, replace_text
);
1220 convert_to_display (label_text
->str
+ label_len
);
1222 quick_widgets
[5].text
= label_text
->str
;
1226 QuickDialog Quick_input
=
1227 {CONFIRM_DLG_WIDTH
, CONFIRM_DLG_HEIGTH
, 0, 0, N_ (" Confirm replace "),
1228 "[Input Line Keys]", 0 /*quick_widgets */, 0 };
1230 Quick_input
.widgets
= quick_widgets
;
1232 Quick_input
.xpos
= xpos
;
1234 /* Sometimes menu can hide replaced text. I don't like it */
1236 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ CONFIRM_DLG_HEIGTH
- 1))
1237 ypos
-= CONFIRM_DLG_HEIGTH
;
1239 Quick_input
.ypos
= ypos
;
1240 retval
= quick_dialog (&Quick_input
);
1241 g_string_free (label_text
, TRUE
);
1247 edit_replace_dialog (WEdit
* edit
, const char *search_default
,
1248 const char *replace_default
, const char *argorder_default
,
1249 /*@out@*/ char **search_text
, /*@out@*/ char **replace_text
,
1250 /*@out@*/ char **arg_order
)
1252 int treplace_scanf
= replace_scanf
;
1253 int treplace_regexp
= replace_regexp
;
1254 int treplace_all
= replace_all
;
1255 int treplace_prompt
= replace_prompt
;
1256 int treplace_backwards
= replace_backwards
;
1257 int treplace_whole
= replace_whole
;
1258 int treplace_case
= replace_case
;
1260 /* Alt-p is in use as hotkey for previous entry; don't use */
1261 QuickWidget quick_widgets
[] =
1263 {quick_button
, 6, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1265 {quick_button
, 2, 10, 12, REPLACE_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1267 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1269 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("replace &All"), 0, 0,
1271 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("pro&Mpt on replace"), 0, 0,
1273 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1275 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1277 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1279 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 8, REPLACE_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1281 {quick_input
, 3, REPLACE_DLG_WIDTH
, 7, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1283 {quick_label
, 2, REPLACE_DLG_WIDTH
, 6, REPLACE_DLG_HEIGHT
, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1285 {quick_input
, 3, REPLACE_DLG_WIDTH
, 5, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1287 {quick_label
, 2, REPLACE_DLG_WIDTH
, 4, REPLACE_DLG_HEIGHT
, N_(" Enter replacement string:"), 0, 0, 0,
1289 {quick_input
, 3, REPLACE_DLG_WIDTH
, 3, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1291 {quick_label
, 2, REPLACE_DLG_WIDTH
, 2, REPLACE_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1297 quick_widgets
[2].result
= &treplace_scanf
;
1298 quick_widgets
[3].result
= &treplace_all
;
1299 quick_widgets
[4].result
= &treplace_prompt
;
1300 quick_widgets
[5].result
= &treplace_backwards
;
1301 quick_widgets
[6].result
= &treplace_regexp
;
1302 quick_widgets
[7].result
= &treplace_whole
;
1303 quick_widgets
[8].result
= &treplace_case
;
1304 quick_widgets
[9].str_result
= arg_order
;
1305 quick_widgets
[9].text
= argorder_default
;
1306 quick_widgets
[11].str_result
= replace_text
;
1307 quick_widgets
[11].text
= replace_default
;
1308 quick_widgets
[13].str_result
= search_text
;
1309 quick_widgets
[13].text
= search_default
;
1311 QuickDialog Quick_input
=
1312 {REPLACE_DLG_WIDTH
, REPLACE_DLG_HEIGHT
, -1, 0, N_(" Replace "),
1313 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1315 Quick_input
.widgets
= quick_widgets
;
1317 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1318 replace_scanf
= treplace_scanf
;
1319 replace_backwards
= treplace_backwards
;
1320 replace_regexp
= treplace_regexp
;
1321 replace_all
= treplace_all
;
1322 replace_prompt
= treplace_prompt
;
1323 replace_whole
= treplace_whole
;
1324 replace_case
= treplace_case
;
1328 *replace_text
= NULL
;
1329 *search_text
= NULL
;
1337 edit_search_dialog (WEdit
* edit
, char **search_text
)
1339 int treplace_scanf
= replace_scanf
;
1340 int treplace_regexp
= replace_regexp
;
1341 int treplace_whole
= replace_whole
;
1342 int treplace_case
= replace_case
;
1343 int treplace_backwards
= replace_backwards
;
1345 QuickWidget quick_widgets
[] =
1347 {quick_button
, 6, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1349 {quick_button
, 2, 10, 7, SEARCH_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1351 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1353 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1355 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1357 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1359 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 4, SEARCH_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1361 {quick_input
, 3, SEARCH_DLG_WIDTH
, 3, SEARCH_DLG_HEIGHT
, "", 52, 0, 0,
1363 {quick_label
, 2, SEARCH_DLG_WIDTH
, 2, SEARCH_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1369 quick_widgets
[2].result
= &treplace_scanf
;
1370 quick_widgets
[3].result
= &treplace_backwards
;
1371 quick_widgets
[4].result
= &treplace_regexp
;
1372 quick_widgets
[5].result
= &treplace_whole
;
1373 quick_widgets
[6].result
= &treplace_case
;
1374 quick_widgets
[7].str_result
= search_text
;
1375 quick_widgets
[7].text
= *search_text
;
1378 QuickDialog Quick_input
=
1379 {SEARCH_DLG_WIDTH
, SEARCH_DLG_HEIGHT
, -1, 0, N_("Search"),
1380 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1382 Quick_input
.widgets
= quick_widgets
;
1384 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1385 replace_scanf
= treplace_scanf
;
1386 replace_backwards
= treplace_backwards
;
1387 replace_regexp
= treplace_regexp
;
1388 replace_whole
= treplace_whole
;
1389 replace_case
= treplace_case
;
1391 *search_text
= NULL
;
1397 static long sargs
[NUM_REPL_ARGS
][256 / sizeof (long)];
1399 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1400 sargs[4], sargs[5], sargs[6], sargs[7], \
1401 sargs[8], sargs[9], sargs[10], sargs[11], \
1402 sargs[12], sargs[13], sargs[14], sargs[15]
1404 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1405 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1406 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1407 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1410 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1411 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1413 string_regexp_search (char *pattern
, char *string
, int match_type
,
1414 int match_bol
, int icase
, int *found_len
, void *d
)
1417 static char *old_pattern
= NULL
;
1418 static int old_type
, old_icase
;
1420 static regmatch_t s
[1];
1422 pmatch
= (regmatch_t
*) d
;
1426 if (!old_pattern
|| strcmp (old_pattern
, pattern
)
1427 || old_type
!= match_type
|| old_icase
!= icase
) {
1430 g_free (old_pattern
);
1433 if (regcomp (&r
, pattern
, REG_EXTENDED
| (icase
? REG_ICASE
: 0) |
1438 old_pattern
= g_strdup (pattern
);
1439 old_type
= match_type
;
1443 (&r
, string
, d
? NUM_REPL_ARGS
: 1, pmatch
,
1445 || match_type
!= match_normal
) ? 0 : REG_NOTBOL
)) != 0) {
1449 *found_len
= pmatch
[0].rm_eo
- pmatch
[0].rm_so
;
1450 return (pmatch
[0].rm_so
);
1453 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1454 (and the above) routines to work properly - paul */
1456 typedef int (*edit_getbyte_fn
) (WEdit
*, long);
1459 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
)
1462 long l
= strlen ((char *) exp
), f
= 0;
1465 for (p
= 0; p
< l
; p
++) /* count conversions... */
1467 if (exp
[++p
] != '%') /* ...except for "%%" */
1470 if (replace_scanf
|| replace_regexp
) {
1473 unsigned char mbuf
[MAX_REPL_LEN
* 2 + 3];
1475 replace_scanf
= (!replace_regexp
); /* can't have both */
1479 if (replace_scanf
) {
1480 unsigned char e
[MAX_REPL_LEN
];
1481 if (n
>= NUM_REPL_ARGS
)
1485 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++)
1486 buf
[p
- start
] = (*get_byte
) (data
, p
);
1488 for (p
= 0; exp
[p
] != 0; p
++)
1489 exp
[p
] = my_lower_case (exp
[p
]);
1490 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++) {
1491 c
= (*get_byte
) (data
, p
);
1492 buf
[p
- start
] = my_lower_case (c
);
1496 buf
[(q
= p
- start
)] = 0;
1497 strcpy ((char *) e
, (char *) exp
);
1498 strcat ((char *) e
, "%n");
1502 *((int *) sargs
[n
]) = 0; /* --> here was the problem - now fixed: good */
1503 if (n
== sscanf ((char *) buf
, (char *) exp
, SCANF_ARGS
)) {
1504 if (*((int *) sargs
[n
])) {
1505 *len
= *((int *) sargs
[n
]);
1511 if (q
+ start
< last_byte
) {
1513 buf
[q
] = (*get_byte
) (data
, q
+ start
);
1515 c
= (*get_byte
) (data
, q
+ start
);
1516 buf
[q
] = my_lower_case (c
);
1522 buf
++; /* move the window along */
1523 if (buf
== mbuf
+ MAX_REPL_LEN
) { /* the window is about to go past the end of array, so... */
1524 memmove (mbuf
, buf
, strlen ((char *) buf
) + 1); /* reset it */
1529 } else { /* regexp matching */
1531 int found_start
, match_bol
, move_win
= 0;
1533 while (start
+ offset
< last_byte
) {
1534 match_bol
= (start
== 0 || (*get_byte
) (data
, start
+ offset
- 1) == '\n');
1539 for (; p
< last_byte
&& q
< MAX_REPL_LEN
; p
++, q
++) {
1540 mbuf
[q
] = (*get_byte
) (data
, p
);
1541 if (mbuf
[q
] == '\n') {
1551 found_start
= string_regexp_search ((char *) exp
, (char *) buf
, match_normal
, match_bol
, !replace_case
, len
, d
);
1553 if (found_start
<= -2) { /* regcomp/regexec error */
1557 else if (found_start
== -1) /* not found: try next line */
1559 else if (*len
== 0) { /* null pattern: try again at next character */
1566 return (start
+ offset
- q
+ found_start
);
1571 if (buf
[q
- 1] != '\n') { /* incomplete line: try to recover */
1572 buf
= mbuf
+ MAX_REPL_LEN
/ 2;
1573 q
= strlen ((const char *) buf
);
1574 memmove (mbuf
, buf
, q
);
1583 *len
= strlen ((const char *) exp
);
1585 for (p
= start
; p
<= last_byte
- l
; p
++) {
1586 if ((*get_byte
) (data
, p
) == (unsigned char)exp
[0]) { /* check if first char matches */
1587 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1588 if ((*get_byte
) (data
, q
+ p
) != (unsigned char)exp
[q
])
1597 for (p
= 0; exp
[p
] != 0; p
++)
1598 exp
[p
] = my_lower_case (exp
[p
]);
1600 for (p
= start
; p
<= last_byte
- l
; p
++) {
1601 if (my_lower_case ((*get_byte
) (data
, p
)) == (unsigned char)exp
[0]) {
1602 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1603 if (my_lower_case ((*get_byte
) (data
, q
+ p
)) != (unsigned char)exp
[q
])
1618 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
)
1619 { /*front end to find_string to check for
1624 while ((p
= edit_find_string (p
, exp
, len
, last_byte
, get_byte
, data
, once_only
, d
)) >= 0) {
1625 if (replace_whole
) {
1626 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1627 if (!strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
- 1))
1628 && !strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
+ *len
)))
1636 p
++; /*not a whole word so continue search. */
1642 edit_find (long search_start
, unsigned char *exp
, int *len
, long last_byte
, edit_getbyte_fn get_byte
, void *data
, void *d
)
1645 if (replace_backwards
) {
1646 while (search_start
>= 0) {
1647 p
= edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 1, d
);
1648 if (p
== search_start
)
1653 return edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 0, d
);
1658 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1660 #define snprint(v) { \
1663 n = snprintf(s,e-s,q1,v); \
1664 if (n >= (size_t) (e - s)) goto nospc; \
1668 /* this function uses the sprintf command to do a vprintf */
1669 /* it takes pointers to arguments instead of the arguments themselves */
1670 /* The return value is the number of bytes written excluding '\0'
1671 if successfull, -1 if the resulting string would be too long and
1672 -2 if the format string is errorneous. */
1673 static int snprintf_p (char *str
, size_t size
, const char *fmt
,...)
1674 __attribute__ ((format (printf
, 3, 4)));
1676 static int snprintf_p (char *str
, size_t size
, const char *fmt
,...)
1681 char *s
= str
, *e
= str
+ size
;
1689 while ((p
= strchr (p
, '%'))) {
1691 if (n
>= (size_t) (e
- s
))
1693 memcpy (s
, q
, n
); /* copy stuff between format specifiers */
1708 /* We were passed only 16 arguments. */
1721 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace field width with a number */
1724 while (is_digit (*p
) && p1
< q1
+ 20)
1733 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace precision with a number */
1736 while (is_digit (*p
) && p1
< q1
+ 32)
1741 /* flags done, now get argument */
1743 snprint (va_arg (ap
, char *));
1744 } else if (*p
== 'h') {
1745 if (strchr ("diouxX", *p
))
1746 snprint (*va_arg (ap
, short *));
1747 } else if (*p
== 'l') {
1749 if (strchr ("diouxX", *p
))
1750 snprint (*va_arg (ap
, long *));
1751 } else if (strchr ("cdiouxX", *p
)) {
1752 snprint (*va_arg (ap
, int *));
1753 } else if (*p
== 'L') {
1755 if (strchr ("EefgG", *p
))
1756 snprint (*va_arg (ap
, double *)); /* should be long double */
1757 } else if (strchr ("EefgG", *p
)) {
1758 snprint (*va_arg (ap
, double *));
1759 } else if (strchr ("DOU", *p
)) {
1760 snprint (*va_arg (ap
, long *));
1761 } else if (*p
== 'p') {
1762 snprint (*va_arg (ap
, void **));
1769 if (n
>= (size_t) (e
- s
))
1771 memcpy (s
, q
, n
+ 1);
1781 static void regexp_error (WEdit
*edit
)
1784 edit_error_dialog (_("Error"), _(" Invalid regular expression, or scanf expression with too many conversions "));
1787 /* call with edit = 0 before shutdown to close memory leaks */
1789 edit_replace_cmd (WEdit
*edit
, int again
)
1791 static regmatch_t pmatch
[NUM_REPL_ARGS
];
1792 /* 1 = search string, 2 = replace with, 3 = argument order */
1793 static char *saved1
= NULL
; /* saved default[123] */
1794 static char *saved2
= NULL
;
1795 static char *saved3
= NULL
;
1796 char *input1
= NULL
; /* user input from the dialog */
1797 char *input2
= NULL
;
1798 char *input3
= NULL
;
1800 int replace_continue
;
1801 int treplace_prompt
= 0;
1802 long times_replaced
= 0, last_search
;
1803 int argord
[NUM_REPL_ARGS
];
1806 g_free (saved1
), saved1
= NULL
;
1807 g_free (saved2
), saved2
= NULL
;
1808 g_free (saved3
), saved3
= NULL
;
1812 last_search
= edit
->last_byte
;
1814 edit
->force
|= REDRAW_COMPLETELY
;
1816 if (again
&& !saved1
&& !saved2
)
1820 input1
= g_strdup (saved1
? saved1
: "");
1821 input2
= g_strdup (saved2
? saved2
: "");
1822 input3
= g_strdup (saved3
? saved3
: "");
1824 char *disp1
= g_strdup (saved1
? saved1
: "");
1825 char *disp2
= g_strdup (saved2
? saved2
: "");
1826 char *disp3
= g_strdup (saved3
? saved3
: "");
1828 convert_to_display (disp1
);
1829 convert_to_display (disp2
);
1830 convert_to_display (disp3
);
1832 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1833 edit_replace_dialog (edit
, disp1
, disp2
, disp3
, &input1
, &input2
,
1840 convert_from_input (input1
);
1841 convert_from_input (input2
);
1842 convert_from_input (input3
);
1844 treplace_prompt
= replace_prompt
;
1845 if (input1
== NULL
|| *input1
== '\0') {
1846 edit
->force
= REDRAW_COMPLETELY
;
1850 g_free (saved1
), saved1
= g_strdup (input1
);
1851 g_free (saved2
), saved2
= g_strdup (input2
);
1852 g_free (saved3
), saved3
= g_strdup (input3
);
1861 for (i
= 0; i
< NUM_REPL_ARGS
; i
++) {
1862 if (s
!= NULL
&& *s
!= '\0') {
1864 if ((ord
> 0) && (ord
<= NUM_REPL_ARGS
))
1865 argord
[i
] = ord
- 1;
1868 s
= strchr (s
, ',');
1876 replace_continue
= replace_all
;
1878 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1
1879 && replace_backwards
)
1880 edit
->search_start
--;
1882 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1
1883 && !replace_backwards
)
1884 edit
->search_start
++;
1890 edit_find (edit
->search_start
, (unsigned char *) input1
, &len
,
1891 last_search
, edit_get_byte
, (void *) edit
, pmatch
);
1892 if (new_start
== -3) {
1893 regexp_error (edit
);
1896 edit
->search_start
= new_start
;
1897 /*returns negative on not found or error in pattern */
1899 if (edit
->search_start
>= 0) {
1902 edit
->found_start
= edit
->search_start
;
1903 i
= edit
->found_len
= len
;
1905 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1906 edit_scroll_screen_over_cursor (edit
);
1910 if (treplace_prompt
) {
1912 l
= edit
->curs_row
- edit
->num_widget_lines
/ 3;
1914 edit_scroll_downward (edit
, l
);
1916 edit_scroll_upward (edit
, -l
);
1918 edit_scroll_screen_over_cursor (edit
);
1919 edit
->force
|= REDRAW_PAGE
;
1920 edit_render_keypress (edit
);
1922 /*so that undo stops at each query */
1923 edit_push_key_press (edit
);
1925 switch (edit_replace_prompt (edit
, input2
, /* and prompt 2/3 down */
1926 (edit
->num_widget_columns
-
1927 CONFIRM_DLG_WIDTH
) / 2,
1928 edit
->num_widget_lines
* 2 /
1932 case B_SKIP_REPLACE
:
1936 treplace_prompt
= 0;
1937 replace_continue
= 1;
1940 replace_continue
= 0;
1944 replace_continue
= 0;
1948 if (replace_yes
) { /* delete then insert new */
1949 if (replace_scanf
) {
1950 char repl_str
[MAX_REPL_LEN
+ 2];
1953 /* we need to fill in sargs just like with scanf */
1954 if (replace_regexp
) {
1957 k
< NUM_REPL_ARGS
&& pmatch
[k
].rm_eo
>= 0;
1961 if (pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
> 255) {
1965 t
= (unsigned char *) &sargs
[k
- 1][0];
1967 j
< pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
1968 && j
< 255; j
++, t
++)
1969 *t
= (unsigned char) edit_get_byte (edit
,
1982 for (; k
<= NUM_REPL_ARGS
; k
++)
1983 sargs
[k
- 1][0] = 0;
1987 snprintf_p (repl_str
, MAX_REPL_LEN
+ 2, input2
,
1993 while (repl_str
[++i
])
1994 edit_insert (edit
, repl_str
[i
]);
1996 edit_error_dialog (_(" Replace "),
2000 (" Error in replacement format string. ")
2001 : _(" Replacement too long. "));
2002 replace_continue
= 0;
2009 edit_insert (edit
, input2
[i
]);
2011 edit
->found_len
= i
;
2013 /* so that we don't find the same string again */
2014 if (replace_backwards
) {
2015 last_search
= edit
->search_start
;
2016 edit
->search_start
--;
2018 edit
->search_start
+= i
;
2019 last_search
= edit
->last_byte
;
2021 edit_scroll_screen_over_cursor (edit
);
2023 const char *msg
= _(" Replace ");
2024 /* try and find from right here for next search */
2025 edit
->search_start
= edit
->curs1
;
2026 edit_update_curs_col (edit
);
2028 edit
->force
|= REDRAW_PAGE
;
2029 edit_render_keypress (edit
);
2030 if (times_replaced
) {
2031 message (D_NORMAL
, msg
, _(" %ld replacements made. "),
2034 query_dialog (msg
, _(" Search string not found "),
2035 D_NORMAL
, 1, _("&OK"));
2036 replace_continue
= 0;
2038 } while (replace_continue
);
2040 edit
->force
= REDRAW_COMPLETELY
;
2041 edit_scroll_screen_over_cursor (edit
);
2051 void edit_search_cmd (WEdit
* edit
, int again
)
2053 static char *old
= NULL
;
2062 exp
= old
? old
: exp
;
2063 if (again
) { /*ctrl-hotkey for search again. */
2066 exp
= g_strdup (old
);
2071 convert_to_display (exp
);
2072 #endif /* HAVE_CHARSET */
2074 edit_search_dialog (edit
, &exp
);
2078 convert_from_input (exp
);
2079 #endif /* HAVE_CHARSET */
2081 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2088 old
= g_strdup (exp
);
2090 if (search_create_bookmark
) {
2091 int found
= 0, books
= 0;
2092 int l
= 0, l_last
= -1;
2095 p
= edit_find (q
, (unsigned char *) exp
, &len
, edit
->last_byte
,
2096 edit_get_byte
, (void *) edit
, 0);
2100 l
+= edit_count_lines (edit
, q
, p
);
2102 book_mark_insert (edit
, l
, BOOK_MARK_FOUND_COLOR
);
2109 /* in response to number of bookmarks added because of string being found %d times */
2110 message (D_NORMAL
, _("Search"), _(" %d items found, %d bookmarks added "), found
, books
);
2112 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2116 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
2117 edit
->search_start
--;
2119 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
2120 edit
->search_start
++;
2122 edit
->search_start
= edit_find (edit
->search_start
, (unsigned char *) exp
, &len
, edit
->last_byte
,
2123 edit_get_byte
, (void *) edit
, 0);
2125 if (edit
->search_start
>= 0) {
2126 edit
->found_start
= edit
->search_start
;
2127 edit
->found_len
= len
;
2129 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
2130 edit_scroll_screen_over_cursor (edit
);
2131 if (replace_backwards
)
2132 edit
->search_start
--;
2134 edit
->search_start
++;
2135 } else if (edit
->search_start
== -3) {
2136 edit
->search_start
= edit
->curs1
;
2137 regexp_error (edit
);
2139 edit
->search_start
= edit
->curs1
;
2140 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2146 edit
->force
|= REDRAW_COMPLETELY
;
2147 edit_scroll_screen_over_cursor (edit
);
2152 * Check if it's OK to close the editor. If there are unsaved changes,
2153 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2156 edit_ok_to_exit (WEdit
*edit
)
2158 if (!edit
->modified
)
2161 switch (edit_query_dialog3
2162 (_("Quit"), _(" File was modified, Save with exit? "),
2163 _("&Cancel quit"), _("&Yes"), _("&No"))) {
2165 edit_push_markers (edit
);
2166 edit_set_markers (edit
, 0, 0, 0, 0);
2167 if (!edit_save_cmd (edit
))
2181 #define TEMP_BUF_LEN 1024
2183 /* Return a null terminated length of text. Result must be g_free'd */
2184 static unsigned char *
2185 edit_get_block (WEdit
*edit
, long start
, long finish
, int *l
)
2187 unsigned char *s
, *r
;
2188 r
= s
= g_malloc (finish
- start
+ 1);
2189 if (column_highlighting
) {
2191 /* copy from buffer, excluding chars that are out of the column 'margins' */
2192 while (start
< finish
) {
2194 x
= edit_move_forward3 (edit
, edit_bol (edit
, start
), 0,
2196 c
= edit_get_byte (edit
, start
);
2197 if ((x
>= edit
->column1
&& x
< edit
->column2
)
2198 || (x
>= edit
->column2
&& x
< edit
->column1
) || c
== '\n') {
2205 *l
= finish
- start
;
2206 while (start
< finish
)
2207 *s
++ = edit_get_byte (edit
, start
++);
2213 /* save block, returns 1 on success */
2215 edit_save_block (WEdit
* edit
, const char *filename
, long start
,
2221 mc_open (filename
, O_CREAT
| O_WRONLY
| O_TRUNC
,
2222 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
| O_BINARY
)) == -1)
2225 if (column_highlighting
) {
2226 unsigned char *block
, *p
;
2228 p
= block
= edit_get_block (edit
, start
, finish
, &len
);
2230 r
= mc_write (file
, p
, len
);
2240 len
= finish
- start
;
2241 buf
= g_malloc (TEMP_BUF_LEN
);
2242 while (start
!= finish
) {
2243 end
= min (finish
, start
+ TEMP_BUF_LEN
);
2244 for (; i
< end
; i
++)
2245 buf
[i
- start
] = edit_get_byte (edit
, i
);
2246 len
-= mc_write (file
, (char *) buf
, end
- start
);
2257 /* copies a block to clipboard file */
2258 static int edit_save_block_to_clip_file (WEdit
* edit
, long start
, long finish
)
2260 return edit_save_block (edit
, catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
), start
, finish
);
2264 void edit_paste_from_history (WEdit
*edit
)
2267 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
2270 int edit_copy_to_X_buf_cmd (WEdit
* edit
)
2272 long start_mark
, end_mark
;
2273 if (eval_marks (edit
, &start_mark
, &end_mark
))
2275 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2276 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2279 edit_mark_cmd (edit
, 1);
2283 int edit_cut_to_X_buf_cmd (WEdit
* edit
)
2285 long start_mark
, end_mark
;
2286 if (eval_marks (edit
, &start_mark
, &end_mark
))
2288 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2289 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2292 edit_block_delete_cmd (edit
);
2293 edit_mark_cmd (edit
, 1);
2297 void edit_paste_from_X_buf_cmd (WEdit
* edit
)
2299 edit_insert_file (edit
, catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
));
2304 * Ask user for the line and go to that line.
2305 * Negative numbers mean line from the end (i.e. -1 is the last line).
2308 edit_goto_cmd (WEdit
*edit
)
2311 static long line
= 0; /* line as typed, saved as default */
2316 g_snprintf (s
, sizeof (s
), "%ld", line
);
2317 f
= input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE
,
2327 l
= strtol (f
, &error
, 0);
2335 l
= edit
->total_lines
+ l
+ 2;
2336 edit_move_display (edit
, l
- edit
->num_widget_lines
/ 2 - 1);
2337 edit_move_to_line (edit
, l
- 1);
2338 edit
->force
|= REDRAW_COMPLETELY
;
2343 /* Return 1 on success */
2345 edit_save_block_cmd (WEdit
*edit
)
2347 long start_mark
, end_mark
;
2349 if (eval_marks (edit
, &start_mark
, &end_mark
))
2352 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2353 MC_HISTORY_EDIT_SAVE_BLOCK
,
2354 catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
));
2355 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2361 if (edit_save_block (edit
, exp
, start_mark
, end_mark
)) {
2363 edit
->force
|= REDRAW_COMPLETELY
;
2367 edit_error_dialog (_(" Save Block "),
2369 (" Cannot save file. ")));
2373 edit
->force
|= REDRAW_COMPLETELY
;
2378 /* returns 1 on success */
2380 edit_insert_file_cmd (WEdit
*edit
)
2382 char *exp
= input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2383 MC_HISTORY_EDIT_INSERT_FILE
,
2384 catstrs (home_dir
, PATH_SEP_STR CLIP_FILE
, (char *) NULL
));
2385 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2391 if (edit_insert_file (edit
, exp
)) {
2393 edit
->force
|= REDRAW_COMPLETELY
;
2397 edit_error_dialog (_(" Insert File "),
2399 (" Cannot insert file. ")));
2403 edit
->force
|= REDRAW_COMPLETELY
;
2407 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2408 int edit_sort_cmd (WEdit
* edit
)
2410 static char *old
= 0;
2412 long start_mark
, end_mark
;
2415 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2416 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2419 edit_save_block (edit
, catstrs (home_dir
, PATH_SEP_STR BLOCK_FILE
, (char *) NULL
), start_mark
, end_mark
);
2421 exp
= input_dialog (_(" Run Sort "),
2422 _(" Enter sort options (see manpage) separated by whitespace: "),
2423 MC_HISTORY_EDIT_SORT
, (old
!= NULL
) ? old
: "");
2430 e
= system (catstrs (" sort ", exp
, " ", home_dir
, PATH_SEP_STR BLOCK_FILE
, " > ", home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2432 if (e
== -1 || e
== 127) {
2433 edit_error_dialog (_(" Sort "),
2434 get_sys_error (_(" Cannot execute sort command ")));
2437 sprintf (q
, "%d ", e
);
2438 edit_error_dialog (_(" Sort "),
2439 catstrs (_(" Sort returned non-zero: "), q
, (char *) NULL
));
2444 edit
->force
|= REDRAW_COMPLETELY
;
2446 if (edit_block_delete_cmd (edit
))
2448 edit_insert_file (edit
, catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2453 * Ask user for a command, execute it and paste its output back to the
2457 edit_ext_cmd (WEdit
*edit
)
2463 input_dialog (_("Paste output of external command"),
2464 _("Enter shell command(s):"),
2465 MC_HISTORY_EDIT_PASTE_EXTCMD
, NULL
);
2470 e
= system (catstrs (exp
, " > ", home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2474 edit_error_dialog (_("External command"),
2475 get_sys_error (_("Cannot execute command")));
2479 edit
->force
|= REDRAW_COMPLETELY
;
2481 edit_insert_file (edit
, catstrs (home_dir
, PATH_SEP_STR TEMP_FILE
, (char *) NULL
));
2485 /* if block is 1, a block must be highlighted and the shell command
2486 processes it. If block is 0 the shell command is a straight system
2487 command, that just produces some output which is to be inserted */
2489 edit_block_process_cmd (WEdit
*edit
, const char *shell_cmd
, int block
)
2491 long start_mark
, end_mark
;
2493 FILE *script_home
= NULL
;
2494 FILE *script_src
= NULL
;
2495 FILE *block_file
= NULL
;
2496 const char *o
= NULL
;
2497 const char *h
= NULL
;
2498 const char *b
= NULL
;
2499 char *quoted_name
= NULL
;
2501 o
= catstrs (mc_home
, shell_cmd
, (char *) NULL
); /* original source script */
2502 h
= catstrs (home_dir
, PATH_SEP_STR EDIT_DIR
, shell_cmd
, (char *) NULL
); /* home script */
2503 b
= catstrs (home_dir
, PATH_SEP_STR BLOCK_FILE
, (char *) NULL
); /* block file */
2505 if (!(script_home
= fopen (h
, "r"))) {
2506 if (!(script_home
= fopen (h
, "w"))) {
2507 edit_error_dialog ("", get_sys_error (catstrs
2509 ("Error creating script:"),
2510 h
, (char *) NULL
)));
2513 if (!(script_src
= fopen (o
, "r"))) {
2514 fclose (script_home
);
2516 edit_error_dialog ("", get_sys_error (catstrs
2517 (_("Error reading script:"),
2518 o
, (char *) NULL
)));
2521 while (fgets (buf
, sizeof (buf
), script_src
))
2522 fputs (buf
, script_home
);
2523 if (fclose (script_home
)) {
2524 edit_error_dialog ("", get_sys_error (catstrs
2526 ("Error closing script:"),
2527 h
, (char *) NULL
)));
2531 edit_error_dialog ("", get_sys_error (catstrs
2532 (_("Script created:"), h
, (char *) NULL
)));
2537 if (block
) { /* for marked block run indent formatter */
2538 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2539 edit_error_dialog (_("Process block"),
2541 (" You must first highlight a block of text. "));
2544 edit_save_block (edit
, b
, start_mark
, end_mark
);
2545 quoted_name
= name_quote (edit
->filename
, 0);
2548 * Initial space is to avoid polluting bash history.
2550 * $1 - name of the edited file (to check its extension etc).
2551 * $2 - file containing the current block.
2552 * $3 - file where error messages should be put
2553 * (for compatibility with old scripts).
2555 system (catstrs (" ", home_dir
, PATH_SEP_STR EDIT_DIR
, shell_cmd
, " ", quoted_name
,
2556 " ", home_dir
, PATH_SEP_STR BLOCK_FILE
" /dev/null", (char *) NULL
));
2560 * No block selected, just execute the command for the file.
2562 * $1 - name of the edited file.
2564 system (catstrs (" ", home_dir
, PATH_SEP_STR EDIT_DIR
, shell_cmd
, " ",
2565 quoted_name
, (char *) NULL
));
2567 g_free (quoted_name
);
2568 close_error_pipe (D_NORMAL
, NULL
);
2570 edit_refresh_cmd (edit
);
2571 edit
->force
|= REDRAW_COMPLETELY
;
2573 /* insert result block */
2575 if (edit_block_delete_cmd (edit
))
2577 edit_insert_file (edit
, b
);
2578 if ((block_file
= fopen (b
, "w")))
2579 fclose (block_file
);
2586 /* prints at the cursor */
2587 /* returns the number of chars printed */
2588 int edit_print_string (WEdit
* e
, const char *s
)
2592 edit_execute_cmd (e
, -1, (unsigned char) s
[i
++]);
2593 e
->force
|= REDRAW_COMPLETELY
;
2594 edit_update_screen (e
);
2599 static void pipe_mail (WEdit
*edit
, char *to
, char *subject
, char *cc
)
2604 to
= name_quote (to
, 0);
2605 subject
= name_quote (subject
, 0);
2606 cc
= name_quote (cc
, 0);
2607 s
= g_strconcat ("mail -s ", subject
, *cc
? " -c " : "" , cc
, " ", to
, (char *) NULL
);
2619 for (i
= 0; i
< edit
->last_byte
; i
++)
2620 fputc (edit_get_byte (edit
, i
), p
);
2625 #define MAIL_DLG_HEIGHT 12
2627 void edit_mail_dialog (WEdit
* edit
)
2630 char *tmail_subject
;
2633 static char *mail_cc_last
= 0;
2634 static char *mail_subject_last
= 0;
2635 static char *mail_to_last
= 0;
2637 QuickDialog Quick_input
=
2638 {50, MAIL_DLG_HEIGHT
, -1, 0, N_(" Mail "),
2639 "[Input Line Keys]", 0, 0};
2641 QuickWidget quick_widgets
[] =
2643 {quick_button
, 6, 10, 9, MAIL_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
2645 {quick_button
, 2, 10, 9, MAIL_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
2647 {quick_input
, 3, 50, 8, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2648 0, "mail-dlg-input"},
2649 {quick_label
, 2, 50, 7, MAIL_DLG_HEIGHT
, N_(" Copies to"), 0, 0, 0,
2651 {quick_input
, 3, 50, 6, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2652 0, "mail-dlg-input-2"},
2653 {quick_label
, 2, 50, 5, MAIL_DLG_HEIGHT
, N_(" Subject"), 0, 0, 0,
2655 {quick_input
, 3, 50, 4, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2656 0, "mail-dlg-input-3"},
2657 {quick_label
, 2, 50, 3, MAIL_DLG_HEIGHT
, N_(" To"), 0, 0, 0,
2659 {quick_label
, 2, 50, 2, MAIL_DLG_HEIGHT
, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2663 quick_widgets
[2].str_result
= &tmail_cc
;
2664 quick_widgets
[2].text
= mail_cc_last
? mail_cc_last
: "";
2665 quick_widgets
[4].str_result
= &tmail_subject
;
2666 quick_widgets
[4].text
= mail_subject_last
? mail_subject_last
: "";
2667 quick_widgets
[6].str_result
= &tmail_to
;
2668 quick_widgets
[6].text
= mail_to_last
? mail_to_last
: "";
2670 Quick_input
.widgets
= quick_widgets
;
2672 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
2673 g_free (mail_cc_last
);
2674 g_free (mail_subject_last
);
2675 g_free (mail_to_last
);
2676 mail_cc_last
= tmail_cc
;
2677 mail_subject_last
= tmail_subject
;
2678 mail_to_last
= tmail_to
;
2679 pipe_mail (edit
, mail_to_last
, mail_subject_last
, mail_cc_last
);
2684 /*******************/
2685 /* Word Completion */
2686 /*******************/
2689 /* find first character of current word */
2690 static int edit_find_word_start (WEdit
*edit
, long *word_start
, int *word_len
)
2694 /* return if at begin of file */
2695 if (edit
->curs1
<= 0)
2698 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- 1);
2699 /* return if not at end or in word */
2700 if (isspace (c
) || !(isalnum (c
) || c
== '_'))
2703 /* search start of word to be completed */
2705 /* return if at begin of file */
2706 if (edit
->curs1
- i
< 0)
2710 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- i
);
2712 if (!(isalnum (c
) || c
== '_')) {
2713 /* return if word starts with digit */
2717 *word_start
= edit
->curs1
- (i
- 1); /* start found */
2727 /* (re)set search parameters to the given values */
2728 static void edit_set_search_parameters (int rs
, int rb
, int rr
, int rw
, int rc
)
2731 replace_backwards
= rb
;
2732 replace_regexp
= rr
;
2738 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2740 /* collect the possible completions */
2742 edit_collect_completions (WEdit
*edit
, long start
, int word_len
,
2743 char *match_expr
, struct selection
*compl,
2746 int len
, max_len
= 0, i
, skip
;
2747 unsigned char *bufpos
;
2749 /* collect max MAX_WORD_COMPLETIONS completions */
2750 while (*num
< MAX_WORD_COMPLETIONS
) {
2751 /* get next match */
2753 edit_find (start
- 1, (unsigned char *) match_expr
, &len
,
2754 edit
->last_byte
, edit_get_byte
, (void *) edit
, 0);
2760 /* add matched completion if not yet added */
2763 buffers1
[start
>> S_EDIT_BUF_SIZE
][start
& M_EDIT_BUF_SIZE
];
2765 for (i
= 0; i
< *num
; i
++) {
2767 ((char *) &compl[i
].text
[word_len
],
2768 (char *) &bufpos
[word_len
], max (len
,
2772 break; /* skip it, already added */
2778 compl[*num
].text
= g_malloc (len
+ 1);
2779 compl[*num
].len
= len
;
2780 for (i
= 0; i
< len
; i
++)
2781 compl[*num
].text
[i
] = *(bufpos
+ i
);
2782 compl[*num
].text
[i
] = '\0';
2785 /* note the maximal length needed for the completion dialog */
2793 /* let the user select its preferred completion */
2795 edit_completion_dialog (WEdit
* edit
, int max_len
, int word_len
,
2796 struct selection
*compl, int num_compl
)
2798 int start_x
, start_y
, offset
, i
;
2800 Dlg_head
*compl_dlg
;
2801 WListbox
*compl_list
;
2802 int compl_dlg_h
; /* completion dialog height */
2803 int compl_dlg_w
; /* completion dialog width */
2805 /* calculate the dialog metrics */
2806 compl_dlg_h
= num_compl
+ 2;
2807 compl_dlg_w
= max_len
+ 4;
2808 start_x
= edit
->curs_col
+ edit
->start_col
- (compl_dlg_w
/ 2);
2809 start_y
= edit
->curs_row
+ EDIT_TEXT_VERTICAL_OFFSET
+ 1;
2813 if (compl_dlg_w
> COLS
)
2815 if (compl_dlg_h
> LINES
- 2)
2816 compl_dlg_h
= LINES
- 2;
2818 offset
= start_x
+ compl_dlg_w
- COLS
;
2821 offset
= start_y
+ compl_dlg_h
- LINES
;
2823 start_y
-= (offset
+ 1);
2825 /* create the dialog */
2827 create_dlg (start_y
, start_x
, compl_dlg_h
, compl_dlg_w
,
2828 dialog_colors
, NULL
, "[Completion]", NULL
,
2831 /* create the listbox */
2833 listbox_new (1, 1, compl_dlg_w
- 2, compl_dlg_h
- 2, NULL
);
2835 /* add the dialog */
2836 add_widget (compl_dlg
, compl_list
);
2838 /* fill the listbox with the completions */
2839 for (i
= 0; i
< num_compl
; i
++)
2840 listbox_add_item (compl_list
, LISTBOX_APPEND_AT_END
, 0,
2841 (char *) compl[i
].text
, NULL
);
2843 /* pop up the dialog */
2844 run_dlg (compl_dlg
);
2846 /* apply the choosen completion */
2847 if (compl_dlg
->ret_value
== B_ENTER
) {
2848 listbox_get_current (compl_list
, &curr
, NULL
);
2850 for (curr
+= word_len
; *curr
; curr
++)
2851 edit_insert (edit
, *curr
);
2854 /* destroy dialog before return */
2855 destroy_dlg (compl_dlg
);
2860 * Complete current word using regular expression search
2861 * backwards beginning at the current cursor position.
2864 edit_complete_word_cmd (WEdit
*edit
)
2866 int word_len
= 0, i
, num_compl
= 0, max_len
;
2867 long word_start
= 0;
2868 unsigned char *bufpos
;
2870 struct selection
compl[MAX_WORD_COMPLETIONS
]; /* completions */
2872 /* don't want to disturb another search */
2873 int old_rs
= replace_scanf
;
2874 int old_rb
= replace_backwards
;
2875 int old_rr
= replace_regexp
;
2876 int old_rw
= replace_whole
;
2877 int old_rc
= replace_case
;
2879 /* search start of word to be completed */
2880 if (!edit_find_word_start (edit
, &word_start
, &word_len
))
2883 /* prepare match expression */
2884 bufpos
= &edit
->buffers1
[word_start
>> S_EDIT_BUF_SIZE
]
2885 [word_start
& M_EDIT_BUF_SIZE
];
2886 match_expr
= g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len
, bufpos
);
2888 /* init search: backward, regexp, whole word, case sensitive */
2889 edit_set_search_parameters (0, 1, 1, 1, 1);
2891 /* collect the possible completions */
2892 /* start search from curs1 down to begin of file */
2894 edit_collect_completions (edit
, word_start
, word_len
, match_expr
,
2895 (struct selection
*) &compl, &num_compl
);
2897 if (num_compl
> 0) {
2898 /* insert completed word if there is only one match */
2899 if (num_compl
== 1) {
2900 for (i
= word_len
; i
< compl[0].len
; i
++)
2901 edit_insert (edit
, *(compl[0].text
+ i
));
2903 /* more than one possible completion => ask the user */
2905 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2906 /* !!! pressed again the selection dialog pops up, but that !!! */
2907 /* !!! seems to require a further internal state !!! */
2910 /* let the user select the preferred completion */
2911 edit_completion_dialog (edit
, max_len
, word_len
,
2912 (struct selection
*) &compl,
2917 g_free (match_expr
);
2918 /* release memory before return */
2919 for (i
= 0; i
< num_compl
; i
++)
2920 g_free (compl[i
].text
);
2922 /* restore search parameters */
2923 edit_set_search_parameters (old_rs
, old_rb
, old_rr
, old_rw
, old_rc
);
2927 edit_select_codepage_cmd (WEdit
*edit
)
2930 do_select_codepage ();
2931 edit
->force
= REDRAW_COMPLETELY
;
2932 edit_refresh_cmd (edit
);
2937 edit_insert_literal_cmd (WEdit
*edit
)
2939 int char_for_insertion
=
2940 edit_raw_key_query (_(" Insert Literal "),
2941 _(" Press any key: "), 0);
2942 edit_execute_key_command (edit
, -1,
2943 ascii_alpha_to_cntrl (char_for_insertion
));
2947 edit_execute_macro_cmd (WEdit
*edit
)
2950 CK_Macro (edit_raw_key_query
2951 (_(" Execute Macro "), _(" Press macro hotkey: "),
2953 if (command
== CK_Macro (0))
2954 command
= CK_Insert_Char
;
2956 edit_execute_key_command (edit
, command
, -1);
2960 edit_begin_end_macro_cmd(WEdit
*edit
)
2964 /* edit is a pointer to the widget */
2968 0 ? CK_Begin_Record_Macro
: CK_End_Record_Macro
;
2969 edit_execute_key_command (edit
, command
, -1);