1 /* editor high level editing commands.
3 Copyright (C) 1996, 1997 the Free Software Foundation
5 Authors: 1996, 1997 Paul Sheer
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
31 #include <sys/types.h>
41 #include "../src/global.h"
45 #include "editcmddef.h"
46 #include "edit-widget.h"
48 #include "../src/color.h" /* dialog_colors */
49 #include "../src/tty.h" /* LINES */
50 #include "../src/widget.h" /* listbox_new() */
51 #include "../src/layout.h" /* clr_scr() */
52 #include "../src/main.h" /* mc_home */
53 #include "../src/help.h" /* interactive_display() */
54 #include "../src/key.h" /* XCTRL */
55 #include "../src/dialog.h" /* do_refresh() */
56 #include "../src/wtools.h" /* message() */
57 #include "../src/charsets.h"
59 #define edit_get_load_file(f,h) input_expand_dialog (h, _(" Enter file name: "), f)
60 #define edit_get_save_file(f,h) input_expand_dialog (h, _(" Enter file name: "), f)
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);
94 static const char *strcasechr (const unsigned char *s
, int c
)
96 for (c
= my_lower_case (c
); my_lower_case ((int) *s
) != c
; ++s
)
99 return (const char *) s
;
104 static void *memmove (void *dest
, const void *src
, size_t n
)
111 s
= (const char *) src
;
115 t
= (char *) dest
+ n
;
116 s
= (const char *) src
+ n
;
122 #endif /* !HAVE_MEMMOVE */
124 /* #define itoa MY_itoa <---- this line is now in edit.h */
134 } while ((i
= i
/ 10));
140 /* Temporary strings */
141 static char *stacked
[16];
144 This joins strings end on end and allocates memory for the result.
145 The result is later automatically free'd and must not be free'd
149 catstrs (const char *first
,...)
159 len
= strlen (first
);
160 va_start (ap
, first
);
162 while ((data
= va_arg (ap
, char *)) != 0)
163 len
+= strlen (data
);
170 stacked
[i
] = g_malloc (len
);
172 va_start (ap
, first
);
173 strcpy (stacked
[i
], first
);
174 while ((data
= va_arg (ap
, char *)) != 0)
175 strcat (stacked
[i
], data
);
181 /* Free temporary strings */
186 for (i
= 0; i
< sizeof(stacked
) / sizeof(stacked
[0]); i
++) {
192 void edit_help_cmd (WEdit
* edit
)
194 interactive_display (NULL
, "[Internal File Editor]");
195 edit
->force
|= REDRAW_COMPLETELY
;
198 void edit_refresh_cmd (WEdit
* edit
)
206 edit_get_syntax_color (edit
, -1, &color
);
209 #endif /* !HAVE_SLANG */
214 /* If 0 (quick save) then a) create/truncate <filename> file,
215 b) save to <filename>;
216 if 1 (safe save) then a) save to <tempnam>,
217 b) rename <tempnam> to <filename>;
218 if 2 (do backups) then a) save to <tempnam>,
219 b) rename <filename> to <filename.backup_ext>,
220 c) rename <tempnam> to <filename>. */
222 /* returns 0 on error */
224 edit_save_file (WEdit
*edit
, const char *filename
)
229 int this_save_mode
, fd
;
236 if (*filename
!= PATH_SEP
&& edit
->dir
) {
237 savename
= concat_dir_and_file (edit
->dir
, filename
);
238 filename
= catstrs (savename
, (char *) NULL
);
242 if (!vfs_file_is_local (filename
) ||
243 (fd
= mc_open (filename
, O_WRONLY
| O_BINARY
)) == -1) {
245 * The file does not exists yet, so no safe save or
246 * backup are necessary.
248 this_save_mode
= EDIT_QUICK_SAVE
;
251 this_save_mode
= option_save_mode
;
254 if (this_save_mode
!= EDIT_QUICK_SAVE
) {
255 char *savedir
, *saveprefix
;
256 const char *slashpos
;
257 slashpos
= strrchr (filename
, PATH_SEP
);
259 savedir
= g_strdup (filename
);
260 savedir
[slashpos
- filename
+ 1] = '\0';
262 savedir
= g_strdup (".");
263 saveprefix
= concat_dir_and_file (savedir
, "cooledit");
265 fd
= mc_mkstemps (&savename
, saveprefix
, NULL
);
270 * Close for now because mc_mkstemps use pure open system call
271 * to create temporary file and it needs to be reopened by
272 * VFS-aware mc_open().
276 savename
= g_strdup (filename
);
278 mc_chown (savename
, edit
->stat1
.st_uid
, edit
->stat1
.st_gid
);
279 mc_chmod (savename
, edit
->stat1
.st_mode
);
282 mc_open (savename
, O_CREAT
| O_WRONLY
| O_TRUNC
| O_BINARY
,
283 edit
->stat1
.st_mode
)) == -1)
287 if ((p
= edit_get_write_filter (savename
, filename
))) {
291 file
= (FILE *) popen (p
, "w");
294 filelen
= edit_write_stream (edit
, file
);
298 if (pclose (file
) != 0) {
299 edit_error_dialog (_("Error"),
300 catstrs (_(" Error writing to pipe: "),
301 p
, " ", (char *) NULL
));
307 edit_error_dialog (_("Error"),
308 get_sys_error (catstrs
310 (" Cannot open pipe for writing: "),
311 p
, " ", (char *) NULL
)));
319 filelen
= edit
->last_byte
;
320 while (buf
<= (edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1) {
321 if (mc_write (fd
, (char *) edit
->buffers1
[buf
], EDIT_BUF_SIZE
)
329 (fd
, (char *) edit
->buffers1
[buf
],
330 edit
->curs1
& M_EDIT_BUF_SIZE
) !=
331 (edit
->curs1
& M_EDIT_BUF_SIZE
)) {
333 } else if (edit
->curs2
) {
335 buf
= (edit
->curs2
>> S_EDIT_BUF_SIZE
);
338 (char *) edit
->buffers2
[buf
] + EDIT_BUF_SIZE
-
339 (edit
->curs2
& M_EDIT_BUF_SIZE
) - 1,
340 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) !=
341 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) {
346 (fd
, (char *) edit
->buffers2
[buf
],
347 EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
359 if (filelen
!= edit
->last_byte
)
361 if (this_save_mode
== EDIT_DO_BACKUP
)
362 if (mc_rename (filename
, catstrs (filename
, option_backup_ext
, (char *) NULL
))
365 if (this_save_mode
!= EDIT_QUICK_SAVE
)
366 if (mc_rename (savename
, filename
) == -1)
371 /* FIXME: Is this safe ?
372 * if (this_save_mode != EDIT_QUICK_SAVE)
373 * mc_unlink (savename);
380 I changed this from Oleg's original routine so
381 that option_backup_ext works with coolwidgets as well. This
382 does mean there is a memory leak - paul.
384 void menu_save_mode_cmd (void)
388 static char *str_result
;
389 static int save_mode_new
;
390 static const char *str
[] =
394 N_("Do backups -->")};
395 static QuickWidget widgets
[] =
397 {quick_button
, 18, DLG_X
, 7, DLG_Y
, N_("&Cancel"), 0,
398 B_CANCEL
, 0, 0, "c"},
399 {quick_button
, 6, DLG_X
, 7, DLG_Y
, N_("&OK"), 0,
401 {quick_input
, 23, DLG_X
, 5, DLG_Y
, 0, 9,
402 0, 0, &str_result
, "edit-backup-ext"},
403 {quick_label
, 22, DLG_X
, 4, DLG_Y
, N_("Extension:"), 0,
404 0, 0, 0, "savemext"},
405 {quick_radio
, 4, DLG_X
, 3, DLG_Y
, "", 3,
406 0, &save_mode_new
, (char **) str
, "t"},
408 static QuickDialog dialog
=
409 {DLG_X
, DLG_Y
, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
411 static int i18n_flag
= 0;
419 /* OK/Cancel buttons */
420 l1
= strlen (_(widgets
[0].text
)) + strlen (_(widgets
[1].text
)) + 5;
421 maxlen
= max (maxlen
, l1
);
423 for (i
= 0; i
< 3; i
++ ) {
425 maxlen
= max (maxlen
, strlen (str
[i
]) + 7);
429 dlg_x
= maxlen
+ strlen (_(widgets
[3].text
)) + 5 + 1;
430 widgets
[2].hotkey_pos
= strlen (_(widgets
[3].text
)); /* input field length */
431 dlg_x
= min (COLS
, dlg_x
);
435 widgets
[1].relative_x
= i
;
436 widgets
[0].relative_x
= i
+ strlen (_(widgets
[1].text
)) + i
+ 4;
438 widgets
[2].relative_x
= widgets
[3].relative_x
= maxlen
+ 2;
440 for (i
= 0; i
< sizeof (widgets
)/sizeof (widgets
[0]); i
++)
441 widgets
[i
].x_divisions
= dlg_x
;
444 widgets
[2].text
= option_backup_ext
;
445 widgets
[4].value
= option_save_mode
;
446 if (quick_dialog (&dialog
) != B_ENTER
)
448 option_save_mode
= save_mode_new
;
449 option_backup_ext
= str_result
; /* this is a memory leak */
450 option_backup_ext_int
= 0;
451 str_result
[min (strlen (str_result
), sizeof (int))] = '\0';
452 memcpy (&option_backup_ext_int
, str_result
, strlen (option_backup_ext
));
456 edit_set_filename (WEdit
*edit
, const char *f
)
458 g_free (edit
->filename
);
461 edit
->filename
= g_strdup (f
);
462 if (edit
->dir
== NULL
&& *f
!= PATH_SEP
)
464 edit
->dir
= g_strdup (vfs_get_current_dir ());
466 edit
->dir
= g_get_current_dir ();
470 /* Here we want to warn the users of overwriting an existing file,
471 but only if they have made a change to the filename */
472 /* returns 1 on success */
474 edit_save_as_cmd (WEdit
*edit
)
476 /* This heads the 'Save As' dialog box */
479 int different_filename
= 0;
481 exp
= edit_get_save_file (edit
->filename
, _(" Save As "));
482 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
487 edit
->force
|= REDRAW_COMPLETELY
;
490 if (strcmp (edit
->filename
, exp
)) {
492 different_filename
= 1;
493 if ((file
= mc_open (exp
, O_RDONLY
| O_BINARY
)) != -1) {
494 /* the file exists */
496 /* Overwrite the current file or cancel the operation */
497 if (edit_query_dialog2
499 _(" A file already exists with this name. "),
500 _("&Overwrite"), _("&Cancel"))) {
501 edit
->force
|= REDRAW_COMPLETELY
;
506 save_lock
= edit_lock_file (exp
);
508 /* filenames equal, check if already locked */
509 if (!edit
->locked
&& !edit
->delete_file
)
510 save_lock
= edit_lock_file (exp
);
513 if (edit_save_file (edit
, exp
)) {
514 /* Succesful, so unlock both files */
515 if (strcmp (edit
->filename
, exp
)) {
517 edit_unlock_file (exp
);
519 edit
->locked
= edit_unlock_file (edit
->filename
);
521 if (edit
->locked
|| save_lock
)
522 edit
->locked
= edit_unlock_file (edit
->filename
);
525 edit_set_filename (edit
, exp
);
528 edit
->delete_file
= 0;
529 if (different_filename
)
530 edit_load_syntax (edit
, 0, 0);
531 edit
->force
|= REDRAW_COMPLETELY
;
534 /* Failed, so maintain modify (not save) lock */
535 if (strcmp (edit
->filename
, exp
) && save_lock
)
536 edit_unlock_file (exp
);
538 edit
->locked
= edit_unlock_file (edit
->filename
);
540 edit_error_dialog (_(" Save As "),
542 (" Cannot save file. ")));
543 edit
->force
|= REDRAW_COMPLETELY
;
548 edit
->force
|= REDRAW_COMPLETELY
;
552 /* {{{ Macro stuff starts here */
555 raw_callback (struct Dlg_head
*h
, dlg_msg_t msg
, int parm
)
563 return default_dlg_callback (h
, msg
, parm
);
567 /* gets a raw key from the keyboard. Passing cancel = 1 draws
568 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
569 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
570 and Esc are cannot returned */
572 edit_raw_key_query (const char *heading
, const char *query
, int cancel
)
574 int w
= strlen (query
) + 7;
575 struct Dlg_head
*raw_dlg
=
576 create_dlg (0, 0, 7, w
, dialog_colors
, raw_callback
,
578 DLG_CENTER
| DLG_TRYUP
| DLG_WANT_TAB
);
580 input_new (3 - cancel
, w
- 5, INPUT_COLOR
, 2, "", 0));
581 add_widget (raw_dlg
, label_new (3 - cancel
, 2, query
));
584 button_new (4, w
/ 2 - 5, B_CANCEL
, NORMAL_BUTTON
,
587 w
= raw_dlg
->ret_value
;
588 destroy_dlg (raw_dlg
);
590 if (w
== XCTRL ('g') || w
== XCTRL ('c') || w
== ESC_CHAR
598 /* creates a macro file if it doesn't exist */
599 static FILE *edit_open_macro_file (const char *r
)
601 const char *filename
;
603 filename
= catstrs (home_dir
, MACRO_FILE
, (char *) NULL
);
604 if ((file
= open (filename
, O_CREAT
| O_RDWR
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
607 return fopen (filename
, r
);
610 #define MAX_MACROS 1024
611 static int saved_macro
[MAX_MACROS
+ 1];
612 static int saved_macros_loaded
= 0;
615 This is just to stop the macro file be loaded over and over for keys
616 that aren't defined to anything. On slow systems this could be annoying.
622 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++)
623 if (saved_macro
[i
] == k
)
628 /* returns 1 on error */
630 edit_delete_macro (WEdit
* edit
, int k
)
632 struct macro macro
[MAX_MACRO_LENGTH
];
638 if (saved_macros_loaded
)
639 if ((j
= macro_exists (k
)) < 0)
641 g
= fopen (catstrs (home_dir
, TEMP_FILE
, (char *) NULL
), "w");
643 edit_error_dialog (_(" Delete macro "),
644 get_sys_error (_(" Cannot open temp file ")));
647 f
= edit_open_macro_file ("r");
649 edit_error_dialog (_(" Delete macro "),
650 get_sys_error (_(" Cannot open macro file ")));
655 n
= fscanf (f
, ("key '%d 0': "), &s
);
659 while (fscanf (f
, "%hd %hd, ", ¯o
[n
].command
, ¯o
[n
].ch
))
663 fprintf (g
, ("key '%d 0': "), s
);
664 for (i
= 0; i
< n
; i
++)
665 fprintf (g
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
671 if (rename (catstrs (home_dir
, TEMP_FILE
, (char *) NULL
), catstrs (home_dir
, MACRO_FILE
, (char *) NULL
)) == -1) {
672 edit_error_dialog (_(" Delete macro "),
673 get_sys_error (_(" Cannot overwrite macro file ")));
676 if (saved_macros_loaded
)
677 memmove (saved_macro
+ j
, saved_macro
+ j
+ 1, sizeof (int) * (MAX_MACROS
- j
- 1));
681 /* returns 0 on error */
682 int edit_save_macro_cmd (WEdit
* edit
, struct macro macro
[], int n
)
687 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
688 s
= edit_raw_key_query (_(" Save macro "),
689 _(" Press the macro's new hotkey: "), 1);
690 edit
->force
|= REDRAW_COMPLETELY
;
692 if (edit_delete_macro (edit
, s
))
694 f
= edit_open_macro_file ("a+");
696 fprintf (f
, ("key '%d 0': "), s
);
697 for (i
= 0; i
< n
; i
++)
698 fprintf (f
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
701 if (saved_macros_loaded
) {
702 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++);
707 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
712 void edit_delete_macro_cmd (WEdit
* edit
)
716 command
= edit_raw_key_query (_ (" Delete macro "),
717 _ (" Press macro hotkey: "), 1);
722 edit_delete_macro (edit
, command
);
725 /* return 0 on error */
726 int edit_load_macro_cmd (WEdit
* edit
, struct macro macro
[], int *n
, int k
)
729 int s
, i
= 0, found
= 0;
733 if (saved_macros_loaded
)
734 if (macro_exists (k
) < 0)
737 if ((f
= edit_open_macro_file ("r"))) {
741 u
= fscanf (f
, ("key '%d 0': "), &s
);
744 if (!saved_macros_loaded
)
745 saved_macro
[i
++] = s
;
748 while (*n
< MAX_MACRO_LENGTH
&& 2 == fscanf (f
, "%hd %hd, ", ¯o
[*n
].command
, ¯o
[*n
].ch
))
751 while (2 == fscanf (f
, "%hd %hd, ", &dummy
.command
, &dummy
.ch
));
756 } while (!found
|| !saved_macros_loaded
);
757 if (!saved_macros_loaded
) {
759 saved_macros_loaded
= 1;
764 edit_error_dialog (_(" Load macro "),
765 get_sys_error (_(" Cannot open macro file ")));
769 /* }}} Macro stuff starts here */
771 /* returns 1 on success */
772 int edit_save_confirm_cmd (WEdit
* edit
)
776 if (edit_confirm_save
) {
777 f
= catstrs (_(" Confirm save file? : "), edit
->filename
, " ", (char *) NULL
);
778 if (edit_query_dialog2 (_(" Save file "), f
, _("&Save"), _("&Cancel")))
781 return edit_save_cmd (edit
);
785 /* returns 1 on success */
787 edit_save_cmd (WEdit
*edit
)
789 int res
, save_lock
= 0;
791 if (!edit
->locked
&& !edit
->delete_file
)
792 save_lock
= edit_lock_file (edit
->filename
);
793 res
= edit_save_file (edit
, edit
->filename
);
795 /* Maintain modify (not save) lock on failure */
796 if ((res
&& edit
->locked
) || save_lock
)
797 edit
->locked
= edit_unlock_file (edit
->filename
);
799 /* On failure try 'save as', it does locking on its own */
801 return edit_save_as_cmd (edit
);
802 edit
->force
|= REDRAW_COMPLETELY
;
803 edit
->delete_file
= 0;
810 /* returns 1 on success */
811 int edit_new_cmd (WEdit
* edit
)
813 if (edit
->modified
) {
814 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
815 edit
->force
|= REDRAW_COMPLETELY
;
819 edit
->force
|= REDRAW_COMPLETELY
;
822 edit
->locked
= edit_unlock_file (edit
->filename
);
823 return edit_renew (edit
); /* if this gives an error, something has really screwed up */
826 /* returns 1 on error */
828 edit_load_file_from_filename (WEdit
* edit
, char *exp
)
830 int prev_locked
= edit
->locked
;
831 char *prev_filename
= g_strdup (edit
->filename
);
833 if (!edit_reload (edit
, exp
)) {
834 g_free (prev_filename
);
839 edit_unlock_file (prev_filename
);
840 g_free (prev_filename
);
845 edit_load_cmd (WEdit
*edit
)
849 if (edit
->modified
) {
850 if (edit_query_dialog2
852 _(" Current text was modified without a file save. \n"
853 " Continue discards these changes. "), _("C&ontinue"),
855 edit
->force
|= REDRAW_COMPLETELY
;
860 exp
= edit_get_load_file (edit
->filename
, _(" Load "));
864 edit_load_file_from_filename (edit
, exp
);
867 edit
->force
|= REDRAW_COMPLETELY
;
872 if mark2 is -1 then marking is from mark1 to the cursor.
873 Otherwise its between the markers. This handles this.
874 Returns 1 if no text is marked.
876 int eval_marks (WEdit
* edit
, long *start_mark
, long *end_mark
)
878 if (edit
->mark1
!= edit
->mark2
) {
879 if (edit
->mark2
>= 0) {
880 *start_mark
= min (edit
->mark1
, edit
->mark2
);
881 *end_mark
= max (edit
->mark1
, edit
->mark2
);
883 *start_mark
= min (edit
->mark1
, edit
->curs1
);
884 *end_mark
= max (edit
->mark1
, edit
->curs1
);
885 edit
->column2
= edit
->curs_col
;
889 *start_mark
= *end_mark
= 0;
890 edit
->column2
= edit
->column1
= 0;
895 #define space_width 1
898 edit_insert_column_of_text (WEdit
* edit
, unsigned char *data
, int size
, int width
)
902 cursor
= edit
->curs1
;
903 col
= edit_get_col (edit
);
904 for (i
= 0; i
< size
; i
++) {
905 if (data
[i
] == '\n') { /* fill in and move to next line */
908 if (edit_get_byte (edit
, edit
->curs1
) != '\n') {
909 l
= width
- (edit_get_col (edit
) - col
);
911 edit_insert (edit
, ' ');
915 for (p
= edit
->curs1
;; p
++) {
916 if (p
== edit
->last_byte
) {
917 edit_cursor_move (edit
, edit
->last_byte
- edit
->curs1
);
918 edit_insert_ahead (edit
, '\n');
922 if (edit_get_byte (edit
, p
) == '\n') {
927 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, col
, 0) - edit
->curs1
);
928 l
= col
- edit_get_col (edit
);
929 while (l
>= space_width
) {
930 edit_insert (edit
, ' ');
935 edit_insert (edit
, data
[i
]);
937 edit_cursor_move (edit
, cursor
- edit
->curs1
);
942 edit_block_copy_cmd (WEdit
*edit
)
944 long start_mark
, end_mark
, current
= edit
->curs1
;
946 unsigned char *copy_buf
;
948 edit_update_curs_col (edit
);
950 if (eval_marks (edit
, &start_mark
, &end_mark
))
952 if (column_highlighting
)
953 if ((x
>= edit
->column1
&& x
< edit
->column2
)
954 || (x
> edit
->column2
&& x
<= edit
->column1
))
957 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
959 /* all that gets pushed are deletes hence little space is used on the stack */
961 edit_push_markers (edit
);
963 if (column_highlighting
) {
964 edit_insert_column_of_text (edit
, copy_buf
, size
,
965 abs (edit
->column2
- edit
->column1
));
968 edit_insert_ahead (edit
, copy_buf
[size
]);
972 edit_scroll_screen_over_cursor (edit
);
974 if (column_highlighting
) {
975 edit_set_markers (edit
, 0, 0, 0, 0);
976 edit_push_action (edit
, COLUMN_ON
);
977 column_highlighting
= 0;
978 } else if (start_mark
< current
&& end_mark
> current
)
979 edit_set_markers (edit
, start_mark
,
980 end_mark
+ end_mark
- start_mark
, 0, 0);
982 edit
->force
|= REDRAW_PAGE
;
987 edit_block_move_cmd (WEdit
*edit
)
991 unsigned char *copy_buf
;
992 long start_mark
, end_mark
;
996 if (eval_marks (edit
, &start_mark
, &end_mark
))
998 if (column_highlighting
) {
999 edit_update_curs_col (edit
);
1001 if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
1002 if ((x
> edit
->column1
&& x
< edit
->column2
)
1003 || (x
> edit
->column2
&& x
< edit
->column1
))
1005 } else if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
1008 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
1009 if (edit_query_dialog2
1012 (" Block is large, you may not be able to undo this action. "),
1013 _("C&ontinue"), _("&Cancel")))
1016 edit_push_markers (edit
);
1017 current
= edit
->curs1
;
1018 if (column_highlighting
) {
1019 int size
, c1
, c2
, line
;
1020 line
= edit
->curs_line
;
1021 if (edit
->mark2
< 0)
1022 edit_mark_cmd (edit
, 0);
1023 c1
= min (edit
->column1
, edit
->column2
);
1024 c2
= max (edit
->column1
, edit
->column2
);
1025 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
1027 edit_block_delete_cmd (edit
);
1030 edit_move_to_line (edit
, line
);
1031 edit_cursor_move (edit
,
1032 edit_move_forward3 (edit
,
1033 edit_bol (edit
, edit
->curs1
),
1034 x
, 0) - edit
->curs1
);
1035 edit_insert_column_of_text (edit
, copy_buf
, size
, c2
- c1
);
1037 line
= edit
->curs_line
;
1038 edit_update_curs_col (edit
);
1040 edit_block_delete_cmd (edit
);
1041 edit_move_to_line (edit
, line
);
1042 edit_cursor_move (edit
,
1043 edit_move_forward3 (edit
,
1046 x
, 0) - edit
->curs1
);
1048 edit_set_markers (edit
, 0, 0, 0, 0);
1049 edit_push_action (edit
, COLUMN_ON
);
1050 column_highlighting
= 0;
1052 copy_buf
= g_malloc (end_mark
- start_mark
);
1053 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
1054 edit_scroll_screen_over_cursor (edit
);
1056 while (count
< end_mark
) {
1057 copy_buf
[end_mark
- count
- 1] = edit_delete (edit
);
1060 edit_scroll_screen_over_cursor (edit
);
1061 edit_cursor_move (edit
,
1062 current
- edit
->curs1
-
1063 (((current
- edit
->curs1
) >
1064 0) ? end_mark
- start_mark
: 0));
1065 edit_scroll_screen_over_cursor (edit
);
1066 while (count
-- > start_mark
)
1067 edit_insert_ahead (edit
, copy_buf
[end_mark
- count
- 1]);
1068 edit_set_markers (edit
, edit
->curs1
,
1069 edit
->curs1
+ end_mark
- start_mark
, 0, 0);
1071 edit_scroll_screen_over_cursor (edit
);
1073 edit
->force
|= REDRAW_PAGE
;
1077 edit_delete_column_of_text (WEdit
* edit
)
1079 long p
, q
, r
, m1
, m2
;
1083 eval_marks (edit
, &m1
, &m2
);
1084 n
= edit_move_forward (edit
, m1
, 0, m2
) + 1;
1085 c
= edit_move_forward3 (edit
, edit_bol (edit
, m1
), 0, m1
);
1086 d
= edit_move_forward3 (edit
, edit_bol (edit
, m2
), 0, m2
);
1092 r
= edit_bol (edit
, edit
->curs1
);
1093 p
= edit_move_forward3 (edit
, r
, b
, 0);
1094 q
= edit_move_forward3 (edit
, r
, c
, 0);
1099 edit_cursor_move (edit
, p
- edit
->curs1
);
1100 while (q
> p
) { /* delete line between margins */
1101 if (edit_get_byte (edit
, edit
->curs1
) != '\n')
1105 if (n
) /* move to next line except on the last delete */
1106 edit_cursor_move (edit
, edit_move_forward (edit
, edit
->curs1
, 1, 0) - edit
->curs1
);
1110 /* if success return 0 */
1112 edit_block_delete (WEdit
*edit
)
1115 long start_mark
, end_mark
;
1116 if (eval_marks (edit
, &start_mark
, &end_mark
))
1118 if (column_highlighting
&& edit
->mark2
< 0)
1119 edit_mark_cmd (edit
, 0);
1120 if ((end_mark
- start_mark
) > option_max_undo
/ 2) {
1121 /* Warning message with a query to continue or cancel the operation */
1122 if (edit_query_dialog2
1125 (" Block is large, you may not be able to undo this action. "),
1126 _("C&ontinue"), _("&Cancel"))) {
1130 edit_push_markers (edit
);
1131 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
1132 edit_scroll_screen_over_cursor (edit
);
1134 if (start_mark
< end_mark
) {
1135 if (column_highlighting
) {
1136 if (edit
->mark2
< 0)
1137 edit_mark_cmd (edit
, 0);
1138 edit_delete_column_of_text (edit
);
1140 while (count
< end_mark
) {
1146 edit_set_markers (edit
, 0, 0, 0, 0);
1147 edit
->force
|= REDRAW_PAGE
;
1151 /* returns 1 if canceelled by user */
1152 int edit_block_delete_cmd (WEdit
* edit
)
1154 long start_mark
, end_mark
;
1155 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
1156 edit_delete_line (edit
);
1159 return edit_block_delete (edit
);
1163 #define INPUT_INDEX 9
1164 #define SEARCH_DLG_WIDTH 58
1165 #define SEARCH_DLG_HEIGHT 10
1166 #define REPLACE_DLG_WIDTH 58
1167 #define REPLACE_DLG_HEIGHT 15
1168 #define CONFIRM_DLG_WIDTH 79
1169 #define CONFIRM_DLG_HEIGTH 6
1170 #define B_REPLACE_ALL (B_USER+1)
1171 #define B_REPLACE_ONE (B_USER+2)
1172 #define B_SKIP_REPLACE (B_USER+3)
1175 edit_replace_prompt (WEdit
* edit
, char *replace_text
, int xpos
, int ypos
)
1177 QuickWidget quick_widgets
[] =
1179 {quick_button
, 63, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Cancel"),
1180 0, B_CANCEL
, 0, 0, NULL
},
1181 {quick_button
, 50, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("O&ne"),
1182 0, B_REPLACE_ONE
, 0, 0, NULL
},
1183 {quick_button
, 37, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("A&ll"),
1184 0, B_REPLACE_ALL
, 0, 0, NULL
},
1185 {quick_button
, 21, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Skip"),
1186 0, B_SKIP_REPLACE
, 0, 0, NULL
},
1187 {quick_button
, 4, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Replace"),
1188 0, B_ENTER
, 0, 0, NULL
},
1189 {quick_label
, 2, CONFIRM_DLG_WIDTH
, 2, CONFIRM_DLG_HEIGTH
, 0,
1193 GString
*label_text
= g_string_new (_(" Replace with: "));
1194 if (*replace_text
) {
1196 label_len
= label_text
->len
;
1197 g_string_append (label_text
, replace_text
);
1198 convert_to_display (label_text
->str
+ label_len
);
1200 quick_widgets
[5].text
= label_text
->str
;
1204 QuickDialog Quick_input
=
1205 {CONFIRM_DLG_WIDTH
, CONFIRM_DLG_HEIGTH
, 0, 0, N_ (" Confirm replace "),
1206 "[Input Line Keys]", 0 /*quick_widgets */, 0 };
1208 Quick_input
.widgets
= quick_widgets
;
1210 Quick_input
.xpos
= xpos
;
1212 /* Sometimes menu can hide replaced text. I don't like it */
1214 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ CONFIRM_DLG_HEIGTH
- 1))
1215 ypos
-= CONFIRM_DLG_HEIGTH
;
1217 Quick_input
.ypos
= ypos
;
1218 retval
= quick_dialog (&Quick_input
);
1219 g_string_free (label_text
, TRUE
);
1225 edit_replace_dialog (WEdit
* edit
, const char *search_default
,
1226 const char *replace_default
, const char *argorder_default
,
1227 /*@out@*/ char **search_text
, /*@out@*/ char **replace_text
,
1228 /*@out@*/ char **arg_order
)
1230 int treplace_scanf
= replace_scanf
;
1231 int treplace_regexp
= replace_regexp
;
1232 int treplace_all
= replace_all
;
1233 int treplace_prompt
= replace_prompt
;
1234 int treplace_backwards
= replace_backwards
;
1235 int treplace_whole
= replace_whole
;
1236 int treplace_case
= replace_case
;
1238 QuickWidget quick_widgets
[] =
1240 {quick_button
, 6, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1242 {quick_button
, 2, 10, 12, REPLACE_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1244 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1246 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("replace &All"), 0, 0,
1248 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("pr&Ompt on replace"), 0, 0,
1250 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1252 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1254 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1256 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 8, REPLACE_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1258 {quick_input
, 3, REPLACE_DLG_WIDTH
, 7, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1260 {quick_label
, 2, REPLACE_DLG_WIDTH
, 6, REPLACE_DLG_HEIGHT
, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1262 {quick_input
, 3, REPLACE_DLG_WIDTH
, 5, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1264 {quick_label
, 2, REPLACE_DLG_WIDTH
, 4, REPLACE_DLG_HEIGHT
, N_(" Enter replacement string:"), 0, 0, 0,
1266 {quick_input
, 3, REPLACE_DLG_WIDTH
, 3, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1268 {quick_label
, 2, REPLACE_DLG_WIDTH
, 2, REPLACE_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1274 quick_widgets
[2].result
= &treplace_scanf
;
1275 quick_widgets
[3].result
= &treplace_all
;
1276 quick_widgets
[4].result
= &treplace_prompt
;
1277 quick_widgets
[5].result
= &treplace_backwards
;
1278 quick_widgets
[6].result
= &treplace_regexp
;
1279 quick_widgets
[7].result
= &treplace_whole
;
1280 quick_widgets
[8].result
= &treplace_case
;
1281 quick_widgets
[9].str_result
= arg_order
;
1282 quick_widgets
[9].text
= argorder_default
;
1283 quick_widgets
[11].str_result
= replace_text
;
1284 quick_widgets
[11].text
= replace_default
;
1285 quick_widgets
[13].str_result
= search_text
;
1286 quick_widgets
[13].text
= search_default
;
1288 QuickDialog Quick_input
=
1289 {REPLACE_DLG_WIDTH
, REPLACE_DLG_HEIGHT
, -1, 0, N_(" Replace "),
1290 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1292 Quick_input
.widgets
= quick_widgets
;
1294 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1295 replace_scanf
= treplace_scanf
;
1296 replace_backwards
= treplace_backwards
;
1297 replace_regexp
= treplace_regexp
;
1298 replace_all
= treplace_all
;
1299 replace_prompt
= treplace_prompt
;
1300 replace_whole
= treplace_whole
;
1301 replace_case
= treplace_case
;
1305 *replace_text
= NULL
;
1306 *search_text
= NULL
;
1314 edit_search_dialog (WEdit
* edit
, char **search_text
)
1316 int treplace_scanf
= replace_scanf
;
1317 int treplace_regexp
= replace_regexp
;
1318 int treplace_whole
= replace_whole
;
1319 int treplace_case
= replace_case
;
1320 int treplace_backwards
= replace_backwards
;
1322 QuickWidget quick_widgets
[] =
1324 {quick_button
, 6, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1326 {quick_button
, 2, 10, 7, SEARCH_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1328 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1330 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1332 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1334 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1336 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 4, SEARCH_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1338 {quick_input
, 3, SEARCH_DLG_WIDTH
, 3, SEARCH_DLG_HEIGHT
, "", 52, 0, 0,
1340 {quick_label
, 2, SEARCH_DLG_WIDTH
, 2, SEARCH_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1346 quick_widgets
[2].result
= &treplace_scanf
;
1347 quick_widgets
[3].result
= &treplace_backwards
;
1348 quick_widgets
[4].result
= &treplace_regexp
;
1349 quick_widgets
[5].result
= &treplace_whole
;
1350 quick_widgets
[6].result
= &treplace_case
;
1351 quick_widgets
[7].str_result
= search_text
;
1352 quick_widgets
[7].text
= *search_text
;
1355 QuickDialog Quick_input
=
1356 {SEARCH_DLG_WIDTH
, SEARCH_DLG_HEIGHT
, -1, 0, N_("Search"),
1357 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1359 Quick_input
.widgets
= quick_widgets
;
1361 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1362 replace_scanf
= treplace_scanf
;
1363 replace_backwards
= treplace_backwards
;
1364 replace_regexp
= treplace_regexp
;
1365 replace_whole
= treplace_whole
;
1366 replace_case
= treplace_case
;
1368 *search_text
= NULL
;
1374 static long sargs
[NUM_REPL_ARGS
][256 / sizeof (long)];
1376 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1377 sargs[4], sargs[5], sargs[6], sargs[7], \
1378 sargs[8], sargs[9], sargs[10], sargs[11], \
1379 sargs[12], sargs[13], sargs[14], sargs[15]
1381 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1382 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1383 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1384 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1387 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1388 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1390 string_regexp_search (char *pattern
, char *string
, int match_type
,
1391 int match_bol
, int icase
, int *found_len
, void *d
)
1394 static char *old_pattern
= NULL
;
1395 static int old_type
, old_icase
;
1397 static regmatch_t s
[1];
1399 pmatch
= (regmatch_t
*) d
;
1403 if (!old_pattern
|| strcmp (old_pattern
, pattern
)
1404 || old_type
!= match_type
|| old_icase
!= icase
) {
1407 g_free (old_pattern
);
1410 if (regcomp (&r
, pattern
, REG_EXTENDED
| (icase
? REG_ICASE
: 0))) {
1414 old_pattern
= g_strdup (pattern
);
1415 old_type
= match_type
;
1419 (&r
, string
, d
? NUM_REPL_ARGS
: 1, pmatch
,
1421 || match_type
!= match_normal
) ? 0 : REG_NOTBOL
)) != 0) {
1425 *found_len
= pmatch
[0].rm_eo
- pmatch
[0].rm_so
;
1426 return (pmatch
[0].rm_so
);
1429 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1430 (and the above) routines to work properly - paul */
1432 typedef int (*edit_getbyte_fn
) (WEdit
*, long);
1435 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
)
1438 long l
= strlen ((char *) exp
), f
= 0;
1441 for (p
= 0; p
< l
; p
++) /* count conversions... */
1443 if (exp
[++p
] != '%') /* ...except for "%%" */
1446 if (replace_scanf
|| replace_regexp
) {
1449 unsigned char mbuf
[MAX_REPL_LEN
* 2 + 3];
1451 replace_scanf
= (!replace_regexp
); /* can't have both */
1455 if (replace_scanf
) {
1456 unsigned char e
[MAX_REPL_LEN
];
1457 if (n
>= NUM_REPL_ARGS
)
1461 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++)
1462 buf
[p
- start
] = (*get_byte
) (data
, p
);
1464 for (p
= 0; exp
[p
] != 0; p
++)
1465 exp
[p
] = my_lower_case (exp
[p
]);
1466 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++) {
1467 c
= (*get_byte
) (data
, p
);
1468 buf
[p
- start
] = my_lower_case (c
);
1472 buf
[(q
= p
- start
)] = 0;
1473 strcpy ((char *) e
, (char *) exp
);
1474 strcat ((char *) e
, "%n");
1478 *((int *) sargs
[n
]) = 0; /* --> here was the problem - now fixed: good */
1479 if (n
== sscanf ((char *) buf
, (char *) exp
, SCANF_ARGS
)) {
1480 if (*((int *) sargs
[n
])) {
1481 *len
= *((int *) sargs
[n
]);
1487 if (q
+ start
< last_byte
) {
1489 buf
[q
] = (*get_byte
) (data
, q
+ start
);
1491 c
= (*get_byte
) (data
, q
+ start
);
1492 buf
[q
] = my_lower_case (c
);
1498 buf
++; /* move the window along */
1499 if (buf
== mbuf
+ MAX_REPL_LEN
) { /* the window is about to go past the end of array, so... */
1500 memmove (mbuf
, buf
, strlen ((char *) buf
) + 1); /* reset it */
1505 } else { /* regexp matching */
1507 int found_start
, match_bol
, move_win
= 0;
1509 while (start
+ offset
< last_byte
) {
1510 match_bol
= (offset
== 0 || (*get_byte
) (data
, start
+ offset
- 1) == '\n');
1515 for (; p
< last_byte
&& q
< MAX_REPL_LEN
; p
++, q
++) {
1516 mbuf
[q
] = (*get_byte
) (data
, p
);
1517 if (mbuf
[q
] == '\n')
1526 found_start
= string_regexp_search ((char *) exp
, (char *) buf
, match_normal
, match_bol
, !replace_case
, len
, d
);
1528 if (found_start
<= -2) { /* regcomp/regexec error */
1532 else if (found_start
== -1) /* not found: try next line */
1534 else if (*len
== 0) { /* null pattern: try again at next character */
1541 return (start
+ offset
- q
+ found_start
);
1546 if (buf
[q
- 1] != '\n') { /* incomplete line: try to recover */
1547 buf
= mbuf
+ MAX_REPL_LEN
/ 2;
1548 q
= strlen ((const char *) buf
);
1549 memmove (mbuf
, buf
, q
);
1558 *len
= strlen ((const char *) exp
);
1560 for (p
= start
; p
<= last_byte
- l
; p
++) {
1561 if ((*get_byte
) (data
, p
) == (unsigned char)exp
[0]) { /* check if first char matches */
1562 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1563 if ((*get_byte
) (data
, q
+ p
) != (unsigned char)exp
[q
])
1572 for (p
= 0; exp
[p
] != 0; p
++)
1573 exp
[p
] = my_lower_case (exp
[p
]);
1575 for (p
= start
; p
<= last_byte
- l
; p
++) {
1576 if (my_lower_case ((*get_byte
) (data
, p
)) == (unsigned char)exp
[0]) {
1577 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1578 if (my_lower_case ((*get_byte
) (data
, q
+ p
)) != (unsigned char)exp
[q
])
1593 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
)
1594 { /*front end to find_string to check for
1599 while ((p
= edit_find_string (p
, exp
, len
, last_byte
, get_byte
, data
, once_only
, d
)) >= 0) {
1600 if (replace_whole
) {
1601 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1602 if (!strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
- 1))
1603 && !strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
+ *len
)))
1611 p
++; /*not a whole word so continue search. */
1617 edit_find (long search_start
, unsigned char *exp
, int *len
, long last_byte
, edit_getbyte_fn get_byte
, void *data
, void *d
)
1620 if (replace_backwards
) {
1621 while (search_start
>= 0) {
1622 p
= edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 1, d
);
1623 if (p
== search_start
)
1628 return edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 0, d
);
1633 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1635 #define snprint(v) { \
1638 n = snprintf(s,e-s,q1,v); \
1639 if (n >= (size_t) (e - s)) goto nospc; \
1643 /* this function uses the sprintf command to do a vprintf */
1644 /* it takes pointers to arguments instead of the arguments themselves */
1645 /* The return value is the number of bytes written excluding '\0'
1646 if successfull, -1 if the resulting string would be too long and
1647 -2 if the format string is errorneous. */
1648 static int snprintf_p (char *str
, size_t size
, const char *fmt
,...)
1649 __attribute__ ((format (printf
, 3, 4)));
1651 static int snprintf_p (char *str
, size_t size
, const char *fmt
,...)
1656 char *s
= str
, *e
= str
+ size
;
1664 while ((p
= strchr (p
, '%'))) {
1666 if (n
>= (size_t) (e
- s
))
1668 memcpy (s
, q
, n
); /* copy stuff between format specifiers */
1683 /* We were passed only 16 arguments. */
1696 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace field width with a number */
1699 while (is_digit (*p
) && p1
< q1
+ 20)
1708 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace precision with a number */
1711 while (is_digit (*p
) && p1
< q1
+ 32)
1716 /* flags done, now get argument */
1718 snprint (va_arg (ap
, char *));
1719 } else if (*p
== 'h') {
1720 if (strchr ("diouxX", *p
))
1721 snprint (*va_arg (ap
, short *));
1722 } else if (*p
== 'l') {
1724 if (strchr ("diouxX", *p
))
1725 snprint (*va_arg (ap
, long *));
1726 } else if (strchr ("cdiouxX", *p
)) {
1727 snprint (*va_arg (ap
, int *));
1728 } else if (*p
== 'L') {
1730 if (strchr ("EefgG", *p
))
1731 snprint (*va_arg (ap
, double *)); /* should be long double */
1732 } else if (strchr ("EefgG", *p
)) {
1733 snprint (*va_arg (ap
, double *));
1734 } else if (strchr ("DOU", *p
)) {
1735 snprint (*va_arg (ap
, long *));
1736 } else if (*p
== 'p') {
1737 snprint (*va_arg (ap
, void **));
1744 if (n
>= (size_t) (e
- s
))
1746 memcpy (s
, q
, n
+ 1);
1756 static void regexp_error (WEdit
*edit
)
1759 edit_error_dialog (_("Error"), _(" Invalid regular expression, or scanf expression with too many conversions "));
1762 /* call with edit = 0 before shutdown to close memory leaks */
1764 edit_replace_cmd (WEdit
*edit
, int again
)
1766 static regmatch_t pmatch
[NUM_REPL_ARGS
];
1767 /* 1 = search string, 2 = replace with, 3 = argument order */
1768 static char *saved1
= NULL
; /* saved default[123] */
1769 static char *saved2
= NULL
;
1770 static char *saved3
= NULL
;
1771 char *input1
= NULL
; /* user input from the dialog */
1772 char *input2
= NULL
;
1773 char *input3
= NULL
;
1775 int replace_continue
;
1776 int treplace_prompt
= 0;
1777 long times_replaced
= 0, last_search
;
1778 int argord
[NUM_REPL_ARGS
];
1781 g_free (saved1
), saved1
= NULL
;
1782 g_free (saved2
), saved2
= NULL
;
1783 g_free (saved3
), saved3
= NULL
;
1787 last_search
= edit
->last_byte
;
1789 edit
->force
|= REDRAW_COMPLETELY
;
1791 if (again
&& !saved1
&& !saved2
)
1795 input1
= g_strdup (saved1
? saved1
: "");
1796 input2
= g_strdup (saved2
? saved2
: "");
1797 input3
= g_strdup (saved3
? saved3
: "");
1799 char *disp1
= g_strdup (saved1
? saved1
: "");
1800 char *disp2
= g_strdup (saved2
? saved2
: "");
1801 char *disp3
= g_strdup (saved3
? saved3
: "");
1803 convert_to_display (disp1
);
1804 convert_to_display (disp2
);
1805 convert_to_display (disp3
);
1807 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1808 edit_replace_dialog (edit
, disp1
, disp2
, disp3
, &input1
, &input2
,
1815 convert_from_input (input1
);
1816 convert_from_input (input2
);
1817 convert_from_input (input3
);
1819 treplace_prompt
= replace_prompt
;
1820 if (input1
== NULL
|| *input1
== '\0') {
1821 edit
->force
= REDRAW_COMPLETELY
;
1825 g_free (saved1
), saved1
= g_strdup (input1
);
1826 g_free (saved2
), saved2
= g_strdup (input2
);
1827 g_free (saved3
), saved3
= g_strdup (input3
);
1837 for (i
= 0; i
< NUM_REPL_ARGS
; i
++) {
1838 if (s
!= NULL
&& *s
!= '\0') {
1840 if ((ord
> 0) && (ord
<= NUM_REPL_ARGS
))
1841 argord
[i
] = ord
- 1;
1844 s
= strchr (s
, ',');
1852 replace_continue
= replace_all
;
1854 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1
1855 && replace_backwards
)
1856 edit
->search_start
--;
1858 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1
1859 && !replace_backwards
)
1860 edit
->search_start
++;
1866 edit_find (edit
->search_start
, (unsigned char *) input1
, &len
,
1867 last_search
, edit_get_byte
, (void *) edit
, pmatch
);
1868 if (new_start
== -3) {
1869 regexp_error (edit
);
1872 edit
->search_start
= new_start
;
1873 /*returns negative on not found or error in pattern */
1875 if (edit
->search_start
>= 0) {
1878 edit
->found_start
= edit
->search_start
;
1879 i
= edit
->found_len
= len
;
1881 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1882 edit_scroll_screen_over_cursor (edit
);
1886 if (treplace_prompt
) {
1888 l
= edit
->curs_row
- edit
->num_widget_lines
/ 3;
1890 edit_scroll_downward (edit
, l
);
1892 edit_scroll_upward (edit
, -l
);
1894 edit_scroll_screen_over_cursor (edit
);
1895 edit
->force
|= REDRAW_PAGE
;
1896 edit_render_keypress (edit
);
1898 /*so that undo stops at each query */
1899 edit_push_key_press (edit
);
1901 switch (edit_replace_prompt (edit
, input2
, /* and prompt 2/3 down */
1902 (edit
->num_widget_columns
-
1903 CONFIRM_DLG_WIDTH
) / 2,
1904 edit
->num_widget_lines
* 2 /
1908 case B_SKIP_REPLACE
:
1912 treplace_prompt
= 0;
1913 replace_continue
= 1;
1916 replace_continue
= 0;
1920 replace_continue
= 0;
1924 if (replace_yes
) { /* delete then insert new */
1925 if (replace_scanf
|| replace_regexp
) {
1926 char repl_str
[MAX_REPL_LEN
+ 2];
1929 /* we need to fill in sargs just like with scanf */
1930 if (replace_regexp
) {
1933 k
< NUM_REPL_ARGS
&& pmatch
[k
].rm_eo
>= 0;
1937 if (pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
> 255) {
1941 t
= (unsigned char *) &sargs
[k
- 1][0];
1943 j
< pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
1944 && j
< 255; j
++, t
++)
1945 *t
= (unsigned char) edit_get_byte (edit
,
1958 for (; k
<= NUM_REPL_ARGS
; k
++)
1959 sargs
[k
- 1][0] = 0;
1963 snprintf_p (repl_str
, MAX_REPL_LEN
+ 2, input2
,
1969 while (repl_str
[++i
])
1970 edit_insert (edit
, repl_str
[i
]);
1972 edit_error_dialog (_(" Replace "),
1976 (" Error in replacement format string. ")
1977 : _(" Replacement too long. "));
1978 replace_continue
= 0;
1985 edit_insert (edit
, input2
[i
]);
1987 edit
->found_len
= i
;
1989 /* so that we don't find the same string again */
1990 if (replace_backwards
) {
1991 last_search
= edit
->search_start
;
1992 edit
->search_start
--;
1994 edit
->search_start
+= i
;
1995 last_search
= edit
->last_byte
;
1997 edit_scroll_screen_over_cursor (edit
);
1999 const char *msg
= _(" Replace ");
2000 /* try and find from right here for next search */
2001 edit
->search_start
= edit
->curs1
;
2002 edit_update_curs_col (edit
);
2004 edit
->force
|= REDRAW_PAGE
;
2005 edit_render_keypress (edit
);
2006 if (times_replaced
) {
2007 message (0, msg
, _(" %ld replacements made. "),
2010 edit_message_dialog (msg
, _(" Search string not found "));
2011 replace_continue
= 0;
2013 } while (replace_continue
);
2015 edit
->force
= REDRAW_COMPLETELY
;
2016 edit_scroll_screen_over_cursor (edit
);
2026 void edit_search_cmd (WEdit
* edit
, int again
)
2028 static char *old
= NULL
;
2036 exp
= old
? old
: exp
;
2037 if (again
) { /*ctrl-hotkey for search again. */
2040 exp
= g_strdup (old
);
2045 convert_to_display (exp
);
2046 #endif /* HAVE_CHARSET */
2048 edit_search_dialog (edit
, &exp
);
2052 convert_from_input (exp
);
2053 #endif /* HAVE_CHARSET */
2055 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2062 old
= g_strdup (exp
);
2064 if (search_create_bookmark
) {
2065 int found
= 0, books
= 0;
2066 int l
= 0, l_last
= -1;
2069 p
= edit_find (q
, (unsigned char *) exp
, &len
, edit
->last_byte
,
2070 edit_get_byte
, (void *) edit
, 0);
2074 l
+= edit_count_lines (edit
, q
, p
);
2076 book_mark_insert (edit
, l
, BOOK_MARK_FOUND_COLOR
);
2083 /* in response to number of bookmarks added because of string being found %d times */
2084 message (0, _("Search"), _(" %d items found, %d bookmarks added "), found
, books
);
2086 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2090 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
2091 edit
->search_start
--;
2093 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
2094 edit
->search_start
++;
2096 edit
->search_start
= edit_find (edit
->search_start
, (unsigned char *) exp
, &len
, edit
->last_byte
,
2097 edit_get_byte
, (void *) edit
, 0);
2099 if (edit
->search_start
>= 0) {
2100 edit
->found_start
= edit
->search_start
;
2101 edit
->found_len
= len
;
2103 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
2104 edit_scroll_screen_over_cursor (edit
);
2105 if (replace_backwards
)
2106 edit
->search_start
--;
2108 edit
->search_start
++;
2109 } else if (edit
->search_start
== -3) {
2110 edit
->search_start
= edit
->curs1
;
2111 regexp_error (edit
);
2113 edit
->search_start
= edit
->curs1
;
2114 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2120 edit
->force
|= REDRAW_COMPLETELY
;
2121 edit_scroll_screen_over_cursor (edit
);
2126 * Check if it's OK to close the editor. If there are unsaved changes,
2127 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2130 edit_ok_to_exit (WEdit
*edit
)
2132 if (!edit
->modified
)
2135 switch (edit_query_dialog3
2136 (_("Quit"), _(" File was modified, Save with exit? "),
2137 _("&Cancel quit"), _("&Yes"), _("&No"))) {
2139 edit_push_markers (edit
);
2140 edit_set_markers (edit
, 0, 0, 0, 0);
2141 if (!edit_save_cmd (edit
))
2146 edit
->locked
= edit_unlock_file (edit
->filename
);
2157 #define TEMP_BUF_LEN 1024
2159 /* Return a null terminated length of text. Result must be g_free'd */
2160 static unsigned char *
2161 edit_get_block (WEdit
*edit
, long start
, long finish
, int *l
)
2163 unsigned char *s
, *r
;
2164 r
= s
= g_malloc (finish
- start
+ 1);
2165 if (column_highlighting
) {
2167 /* copy from buffer, excluding chars that are out of the column 'margins' */
2168 while (start
< finish
) {
2170 x
= edit_move_forward3 (edit
, edit_bol (edit
, start
), 0,
2172 c
= edit_get_byte (edit
, start
);
2173 if ((x
>= edit
->column1
&& x
< edit
->column2
)
2174 || (x
>= edit
->column2
&& x
< edit
->column1
) || c
== '\n') {
2181 *l
= finish
- start
;
2182 while (start
< finish
)
2183 *s
++ = edit_get_byte (edit
, start
++);
2189 /* save block, returns 1 on success */
2191 edit_save_block (WEdit
* edit
, const char *filename
, long start
,
2197 mc_open (filename
, O_CREAT
| O_WRONLY
| O_TRUNC
,
2198 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
| O_BINARY
)) == -1)
2201 if (column_highlighting
) {
2202 unsigned char *block
, *p
;
2204 p
= block
= edit_get_block (edit
, start
, finish
, &len
);
2206 r
= mc_write (file
, p
, len
);
2216 len
= finish
- start
;
2217 buf
= g_malloc (TEMP_BUF_LEN
);
2218 while (start
!= finish
) {
2219 end
= min (finish
, start
+ TEMP_BUF_LEN
);
2220 for (; i
< end
; i
++)
2221 buf
[i
- start
] = edit_get_byte (edit
, i
);
2222 len
-= mc_write (file
, (char *) buf
, end
- start
);
2233 /* copies a block to clipboard file */
2234 static int edit_save_block_to_clip_file (WEdit
* edit
, long start
, long finish
)
2236 return edit_save_block (edit
, catstrs (home_dir
, CLIP_FILE
, (char *) NULL
), start
, finish
);
2240 void edit_paste_from_history (WEdit
*edit
)
2243 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
2246 int edit_copy_to_X_buf_cmd (WEdit
* edit
)
2248 long start_mark
, end_mark
;
2249 if (eval_marks (edit
, &start_mark
, &end_mark
))
2251 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2252 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2255 edit_mark_cmd (edit
, 1);
2259 int edit_cut_to_X_buf_cmd (WEdit
* edit
)
2261 long start_mark
, end_mark
;
2262 if (eval_marks (edit
, &start_mark
, &end_mark
))
2264 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2265 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2268 edit_block_delete_cmd (edit
);
2269 edit_mark_cmd (edit
, 1);
2273 void edit_paste_from_X_buf_cmd (WEdit
* edit
)
2275 edit_insert_file (edit
, catstrs (home_dir
, CLIP_FILE
, (char *) NULL
));
2280 * Ask user for the line and go to that line.
2281 * Negative numbers mean line from the end (i.e. -1 is the last line).
2284 edit_goto_cmd (WEdit
*edit
)
2287 static long line
= 0; /* line as typed, saved as default */
2292 g_snprintf (s
, sizeof (s
), "%ld", line
);
2293 f
= input_dialog (_(" Goto line "), _(" Enter line: "), line
? s
: "");
2302 l
= strtol (f
, &error
, 0);
2310 l
= edit
->total_lines
+ l
+ 2;
2311 edit_move_display (edit
, l
- edit
->num_widget_lines
/ 2 - 1);
2312 edit_move_to_line (edit
, l
- 1);
2313 edit
->force
|= REDRAW_COMPLETELY
;
2318 /* Return 1 on success */
2320 edit_save_block_cmd (WEdit
*edit
)
2322 long start_mark
, end_mark
;
2324 if (eval_marks (edit
, &start_mark
, &end_mark
))
2327 edit_get_save_file (catstrs (home_dir
, CLIP_FILE
, (char *) NULL
),
2329 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2335 if (edit_save_block (edit
, exp
, start_mark
, end_mark
)) {
2337 edit
->force
|= REDRAW_COMPLETELY
;
2341 edit_error_dialog (_(" Save Block "),
2343 (" Cannot save file. ")));
2347 edit
->force
|= REDRAW_COMPLETELY
;
2352 /* returns 1 on success */
2354 edit_insert_file_cmd (WEdit
*edit
)
2356 char *exp
= edit_get_load_file (catstrs (home_dir
, CLIP_FILE
, (char *) NULL
),
2357 _(" Insert File "));
2358 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2364 if (edit_insert_file (edit
, exp
)) {
2366 edit
->force
|= REDRAW_COMPLETELY
;
2370 edit_error_dialog (_(" Insert File "),
2372 (" Cannot insert file. ")));
2376 edit
->force
|= REDRAW_COMPLETELY
;
2380 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2381 int edit_sort_cmd (WEdit
* edit
)
2383 static char *old
= 0;
2385 long start_mark
, end_mark
;
2388 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2389 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2392 edit_save_block (edit
, catstrs (home_dir
, BLOCK_FILE
, (char *) NULL
), start_mark
, end_mark
);
2394 exp
= old
? old
: "";
2396 exp
= input_dialog (_(" Run Sort "),
2397 _(" Enter sort options (see manpage) separated by whitespace: "), exp
);
2404 e
= system (catstrs (" sort ", exp
, " ", home_dir
, BLOCK_FILE
, " > ", home_dir
, TEMP_FILE
, (char *) NULL
));
2406 if (e
== -1 || e
== 127) {
2407 edit_error_dialog (_(" Sort "),
2408 get_sys_error (_(" Cannot execute sort command ")));
2411 sprintf (q
, "%d ", e
);
2412 edit_error_dialog (_(" Sort "),
2413 catstrs (_(" Sort returned non-zero: "), q
, (char *) NULL
));
2418 edit
->force
|= REDRAW_COMPLETELY
;
2420 if (edit_block_delete_cmd (edit
))
2422 edit_insert_file (edit
, catstrs (home_dir
, TEMP_FILE
, (char *) NULL
));
2427 * Ask user for a command, execute it and paste its output back to the
2431 edit_ext_cmd (WEdit
*edit
)
2437 input_dialog (_("Paste output of external command"),
2438 _("Enter shell command(s):"), NULL
);
2443 e
= system (catstrs (exp
, " > ", home_dir
, TEMP_FILE
, (char *) NULL
));
2447 edit_error_dialog (_("External command"),
2448 get_sys_error (_("Cannot execute command")));
2452 edit
->force
|= REDRAW_COMPLETELY
;
2454 edit_insert_file (edit
, catstrs (home_dir
, TEMP_FILE
, (char *) NULL
));
2458 /* if block is 1, a block must be highlighted and the shell command
2459 processes it. If block is 0 the shell command is a straight system
2460 command, that just produces some output which is to be inserted */
2462 edit_block_process_cmd (WEdit
*edit
, const char *shell_cmd
, int block
)
2464 long start_mark
, end_mark
;
2466 FILE *script_home
= NULL
;
2467 FILE *script_src
= NULL
;
2468 FILE *block_file
= NULL
;
2469 const char *o
= NULL
;
2470 const char *h
= NULL
;
2471 const char *b
= NULL
;
2472 char *quoted_name
= NULL
;
2474 o
= catstrs (mc_home
, shell_cmd
, (char *) NULL
); /* original source script */
2475 h
= catstrs (home_dir
, EDIT_DIR
, shell_cmd
, (char *) NULL
); /* home script */
2476 b
= catstrs (home_dir
, BLOCK_FILE
, (char *) NULL
); /* block file */
2478 if (!(script_home
= fopen (h
, "r"))) {
2479 if (!(script_home
= fopen (h
, "w"))) {
2480 edit_error_dialog ("", get_sys_error (catstrs
2482 ("Error creating script:"),
2483 h
, (char *) NULL
)));
2486 if (!(script_src
= fopen (o
, "r"))) {
2487 fclose (script_home
);
2489 edit_error_dialog ("", get_sys_error (catstrs
2490 (_("Error reading script:"),
2491 o
, (char *) NULL
)));
2494 while (fgets (buf
, sizeof (buf
), script_src
))
2495 fputs (buf
, script_home
);
2496 if (fclose (script_home
)) {
2497 edit_error_dialog ("", get_sys_error (catstrs
2499 ("Error closing script:"),
2500 h
, (char *) NULL
)));
2504 edit_error_dialog ("", get_sys_error (catstrs
2505 (_("Script created:"), h
, (char *) NULL
)));
2510 if (block
) { /* for marked block run indent formatter */
2511 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2512 edit_error_dialog (_("Process block"),
2514 (" You must first highlight a block of text. "));
2517 edit_save_block (edit
, b
, start_mark
, end_mark
);
2518 quoted_name
= name_quote (edit
->filename
, 0);
2521 * Initial space is to avoid polluting bash history.
2523 * $1 - name of the edited file (to check its extension etc).
2524 * $2 - file containing the current block.
2525 * $3 - file where error messages should be put
2526 * (for compatibility with old scripts).
2528 system (catstrs (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ", quoted_name
,
2529 " ", home_dir
, BLOCK_FILE
" /dev/null", (char *) NULL
));
2533 * No block selected, just execute the command for the file.
2535 * $1 - name of the edited file.
2537 system (catstrs (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ",
2538 quoted_name
, (char *) NULL
));
2540 g_free (quoted_name
);
2541 close_error_pipe (0, 0);
2543 edit_refresh_cmd (edit
);
2544 edit
->force
|= REDRAW_COMPLETELY
;
2546 /* insert result block */
2548 if (edit_block_delete_cmd (edit
))
2550 edit_insert_file (edit
, b
);
2551 if ((block_file
= fopen (b
, "w")))
2552 fclose (block_file
);
2559 /* prints at the cursor */
2560 /* returns the number of chars printed */
2561 int edit_print_string (WEdit
* e
, const char *s
)
2565 edit_execute_cmd (e
, -1, (unsigned char) s
[i
++]);
2566 e
->force
|= REDRAW_COMPLETELY
;
2567 edit_update_screen (e
);
2572 static void pipe_mail (WEdit
*edit
, char *to
, char *subject
, char *cc
)
2577 to
= name_quote (to
, 0);
2578 subject
= name_quote (subject
, 0);
2579 cc
= name_quote (cc
, 0);
2580 s
= g_strconcat ("mail -s ", subject
, *cc
? " -c " : "" , cc
, " ", to
, (char *) NULL
);
2592 for (i
= 0; i
< edit
->last_byte
; i
++)
2593 fputc (edit_get_byte (edit
, i
), p
);
2598 #define MAIL_DLG_HEIGHT 12
2600 void edit_mail_dialog (WEdit
* edit
)
2603 char *tmail_subject
;
2606 static char *mail_cc_last
= 0;
2607 static char *mail_subject_last
= 0;
2608 static char *mail_to_last
= 0;
2610 QuickDialog Quick_input
=
2611 {50, MAIL_DLG_HEIGHT
, -1, 0, N_(" Mail "),
2612 "[Input Line Keys]", 0, 0};
2614 QuickWidget quick_widgets
[] =
2616 {quick_button
, 6, 10, 9, MAIL_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
2618 {quick_button
, 2, 10, 9, MAIL_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
2620 {quick_input
, 3, 50, 8, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2621 0, "mail-dlg-input"},
2622 {quick_label
, 2, 50, 7, MAIL_DLG_HEIGHT
, N_(" Copies to"), 0, 0, 0,
2624 {quick_input
, 3, 50, 6, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2625 0, "mail-dlg-input-2"},
2626 {quick_label
, 2, 50, 5, MAIL_DLG_HEIGHT
, N_(" Subject"), 0, 0, 0,
2628 {quick_input
, 3, 50, 4, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2629 0, "mail-dlg-input-3"},
2630 {quick_label
, 2, 50, 3, MAIL_DLG_HEIGHT
, N_(" To"), 0, 0, 0,
2632 {quick_label
, 2, 50, 2, MAIL_DLG_HEIGHT
, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2636 quick_widgets
[2].str_result
= &tmail_cc
;
2637 quick_widgets
[2].text
= mail_cc_last
? mail_cc_last
: "";
2638 quick_widgets
[4].str_result
= &tmail_subject
;
2639 quick_widgets
[4].text
= mail_subject_last
? mail_subject_last
: "";
2640 quick_widgets
[6].str_result
= &tmail_to
;
2641 quick_widgets
[6].text
= mail_to_last
? mail_to_last
: "";
2643 Quick_input
.widgets
= quick_widgets
;
2645 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
2646 g_free (mail_cc_last
);
2647 g_free (mail_subject_last
);
2648 g_free (mail_to_last
);
2649 mail_cc_last
= tmail_cc
;
2650 mail_subject_last
= tmail_subject
;
2651 mail_to_last
= tmail_to
;
2652 pipe_mail (edit
, mail_to_last
, mail_subject_last
, mail_cc_last
);
2657 /*******************/
2658 /* Word Completion */
2659 /*******************/
2662 /* find first character of current word */
2663 static int edit_find_word_start (WEdit
*edit
, long *word_start
, int *word_len
)
2667 /* return if at begin of file */
2668 if (edit
->curs1
<= 0)
2671 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- 1);
2672 /* return if not at end or in word */
2673 if (isspace (c
) || !(isalnum (c
) || c
== '_'))
2676 /* search start of word to be completed */
2678 /* return if at begin of file */
2679 if (edit
->curs1
- i
< 0)
2683 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- i
);
2685 if (!(isalnum (c
) || c
== '_')) {
2686 /* return if word starts with digit */
2690 *word_start
= edit
->curs1
- (i
- 1); /* start found */
2700 /* (re)set search parameters to the given values */
2701 static void edit_set_search_parameters (int rs
, int rb
, int rr
, int rw
, int rc
)
2704 replace_backwards
= rb
;
2705 replace_regexp
= rr
;
2711 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2713 /* collect the possible completions */
2715 edit_collect_completions (WEdit
*edit
, long start
, int word_len
,
2716 char *match_expr
, struct selection
*compl,
2719 int len
, max_len
= 0, i
, skip
;
2722 /* collect max MAX_WORD_COMPLETIONS completions */
2723 while (*num
< MAX_WORD_COMPLETIONS
) {
2724 /* get next match */
2726 edit_find (start
- 1, (unsigned char *) match_expr
, &len
,
2735 /* add matched completion if not yet added */
2738 buffers1
[start
>> S_EDIT_BUF_SIZE
][start
& M_EDIT_BUF_SIZE
];
2740 for (i
= 0; i
< *num
; i
++) {
2742 (&compl[i
].text
[word_len
], &bufpos
[word_len
],
2743 max (len
, compl[i
].len
) - word_len
) == 0) {
2745 break; /* skip it, already added */
2751 compl[*num
].text
= g_malloc (len
+ 1);
2752 compl[*num
].len
= len
;
2753 for (i
= 0; i
< len
; i
++)
2754 compl[*num
].text
[i
] = *(bufpos
+ i
);
2755 compl[*num
].text
[i
] = '\0';
2758 /* note the maximal length needed for the completion dialog */
2766 /* let the user select its preferred completion */
2768 edit_completion_dialog (WEdit
*edit
, int max_len
, int word_len
,
2769 struct selection
*compl, int num_compl
)
2771 int start_x
, start_y
, offset
, i
;
2773 Dlg_head
*compl_dlg
;
2774 WListbox
*compl_list
;
2775 int compl_dlg_h
; /* completion dialog height */
2776 int compl_dlg_w
; /* completion dialog width */
2778 /* calculate the dialog metrics */
2779 compl_dlg_h
= num_compl
+ 2;
2780 compl_dlg_w
= max_len
+ 4;
2781 start_x
= edit
->curs_col
+ edit
->start_col
- (compl_dlg_w
/ 2);
2782 start_y
= edit
->curs_row
+ EDIT_TEXT_VERTICAL_OFFSET
+ 1;
2786 if (compl_dlg_w
> COLS
)
2788 if (compl_dlg_h
> LINES
- 2)
2789 compl_dlg_h
= LINES
- 2;
2791 offset
= start_x
+ compl_dlg_w
- COLS
;
2794 offset
= start_y
+ compl_dlg_h
- LINES
;
2796 start_y
-= (offset
+ 1);
2798 /* create the dialog */
2800 create_dlg (start_y
, start_x
, compl_dlg_h
, compl_dlg_w
,
2801 dialog_colors
, NULL
, "[Completion]", NULL
,
2804 /* create the listbox */
2806 listbox_new (1, 1, compl_dlg_w
- 2, compl_dlg_h
- 2, NULL
);
2808 /* add the dialog */
2809 add_widget (compl_dlg
, compl_list
);
2811 /* fill the listbox with the completions */
2812 for (i
= 0; i
< num_compl
; i
++)
2813 listbox_add_item (compl_list
, 0, 0, compl[i
].text
, NULL
);
2815 /* pop up the dialog */
2816 run_dlg (compl_dlg
);
2818 /* apply the choosen completion */
2819 if (compl_dlg
->ret_value
== B_ENTER
) {
2820 listbox_get_current (compl_list
, &curr
, NULL
);
2822 for (curr
+= word_len
; *curr
; curr
++)
2823 edit_insert (edit
, *curr
);
2826 /* destroy dialog before return */
2827 destroy_dlg (compl_dlg
);
2832 * Complete current word using regular expression search
2833 * backwards beginning at the current cursor position.
2836 edit_complete_word_cmd (WEdit
*edit
)
2838 int word_len
= 0, i
, num_compl
= 0, max_len
;
2839 long word_start
= 0;
2842 struct selection
compl[MAX_WORD_COMPLETIONS
]; /* completions */
2844 /* don't want to disturb another search */
2845 int old_rs
= replace_scanf
;
2846 int old_rb
= replace_backwards
;
2847 int old_rr
= replace_regexp
;
2848 int old_rw
= replace_whole
;
2849 int old_rc
= replace_case
;
2851 /* search start of word to be completed */
2852 if (!edit_find_word_start (edit
, &word_start
, &word_len
))
2855 /* prepare match expression */
2856 bufpos
= &edit
->buffers1
[word_start
>> S_EDIT_BUF_SIZE
]
2857 [word_start
& M_EDIT_BUF_SIZE
];
2858 match_expr
= g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len
, bufpos
);
2860 /* init search: backward, regexp, whole word, case sensitive */
2861 edit_set_search_parameters (0, 1, 1, 1, 1);
2863 /* collect the possible completions */
2864 /* start search from curs1 down to begin of file */
2866 edit_collect_completions (edit
, word_start
, word_len
, match_expr
,
2867 (struct selection
*) &compl, &num_compl
);
2869 if (num_compl
> 0) {
2870 /* insert completed word if there is only one match */
2871 if (num_compl
== 1) {
2872 for (i
= word_len
; i
< compl[0].len
; i
++)
2873 edit_insert (edit
, *(compl[0].text
+ i
));
2875 /* more than one possible completion => ask the user */
2877 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2878 /* !!! pressed again the selection dialog pops up, but that !!! */
2879 /* !!! seems to require a further internal state !!! */
2882 /* let the user select the preferred completion */
2883 edit_completion_dialog (edit
, max_len
, word_len
,
2884 (struct selection
*) &compl,
2889 g_free (match_expr
);
2890 /* release memory before return */
2891 for (i
= 0; i
< num_compl
; i
++)
2892 g_free (compl[i
].text
);
2894 /* restore search parameters */
2895 edit_set_search_parameters (old_rs
, old_rb
, old_rr
, old_rw
, old_rc
);