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 "editcmddef.h"
32 #include "edit-widget.h"
34 #include "src/color.h" /* dialog_colors */
35 #include "src/tty.h" /* LINES */
36 #include "src/widget.h" /* listbox_new() */
37 #include "src/main.h" /* mc_home */
38 #include "src/help.h" /* interactive_display() */
39 #include "src/key.h" /* XCTRL */
40 #include "src/dialog.h" /* do_refresh() */
41 #include "src/wtools.h" /* message() */
42 #include "src/charsets.h"
44 #define edit_get_load_file(f,h) input_dialog (h, _(" Enter file name: "), f)
45 #define edit_get_save_file(f,h) input_dialog (h, _(" Enter file name: "), f)
49 /* search and replace: */
50 int replace_scanf
= 0;
51 int replace_regexp
= 0;
53 int replace_prompt
= 1;
54 int replace_whole
= 0;
56 int replace_backwards
= 0;
57 int search_create_bookmark
= 0;
59 /* queries on a save */
60 int edit_confirm_save
= 1;
62 #define NUM_REPL_ARGS 64
63 #define MAX_REPL_LEN 1024
65 static inline int my_lower_case (int c
)
67 return tolower(c
& 0xFF);
70 char *strcasechr (const unsigned char *s
, int c
)
72 for (c
= my_lower_case (c
); my_lower_case ((int) *s
) != c
; ++s
)
80 static void *memmove (void *dest
, const void *src
, size_t n
)
90 t
= (char *) dest
+ n
;
97 #endif /* !HAVE_MEMMOVE */
99 /* #define itoa MY_itoa <---- this line is now in edit.h */
109 } while ((i
= i
/ 10));
115 /* Temporary strings */
116 static char *stacked
[16];
119 This joins strings end on end and allocates memory for the result.
120 The result is later automatically free'd and must not be free'd
123 char *catstrs (const char *first
,...)
133 len
= strlen (first
);
134 va_start (ap
, first
);
136 while ((data
= va_arg (ap
, char *)) != 0)
137 len
+= strlen (data
);
144 stacked
[i
] = g_malloc (len
);
146 va_start (ap
, first
);
147 strcpy (stacked
[i
], first
);
148 while ((data
= va_arg (ap
, char *)) != 0)
149 strcat (stacked
[i
], data
);
155 /* Free temporary strings */
160 for (i
= 0; i
< sizeof(stacked
) / sizeof(stacked
[0]); i
++) {
166 void edit_help_cmd (WEdit
* edit
)
168 interactive_display (NULL
, "[Internal File Editor]");
169 edit
->force
|= REDRAW_COMPLETELY
;
172 void edit_refresh_cmd (WEdit
* edit
)
180 edit_get_syntax_color (edit
, -1, &color
);
183 #endif /* !HAVE_SLANG */
188 /* If 0 (quick save) then a) create/truncate <filename> file,
189 b) save to <filename>;
190 if 1 (safe save) then a) save to <tempnam>,
191 b) rename <tempnam> to <filename>;
192 if 2 (do backups) then a) save to <tempnam>,
193 b) rename <filename> to <filename.backup_ext>,
194 c) rename <tempnam> to <filename>. */
196 /* returns 0 on error */
198 edit_save_file (WEdit
*edit
, const char *filename
)
203 int this_save_mode
, fd
;
210 if ((fd
= mc_open (filename
, O_WRONLY
| O_BINARY
)) == -1) {
212 * The file does not exists yet, so no safe save or
213 * backup are necessary.
215 this_save_mode
= EDIT_QUICK_SAVE
;
218 this_save_mode
= option_save_mode
;
221 if (this_save_mode
!= EDIT_QUICK_SAVE
) {
222 char *savedir
, *slashpos
, *saveprefix
;
223 slashpos
= strrchr (filename
, PATH_SEP
);
225 savedir
= g_strdup (filename
);
226 savedir
[slashpos
- filename
+ 1] = '\0';
228 savedir
= g_strdup (".");
229 saveprefix
= concat_dir_and_file (savedir
, "cooledit");
231 fd
= mc_mkstemps (&savename
, saveprefix
, NULL
);
236 * Close for now because mc_mkstemps use pure open system call
237 * to create temporary file and it needs to be reopened by
238 * VFS-aware mc_open().
242 savename
= g_strdup (filename
);
244 mc_chown (savename
, edit
->stat1
.st_uid
, edit
->stat1
.st_gid
);
245 mc_chmod (savename
, edit
->stat1
.st_mode
);
248 mc_open (savename
, O_CREAT
| O_WRONLY
| O_TRUNC
| O_BINARY
,
249 edit
->stat1
.st_mode
)) == -1)
253 if ((p
= edit_get_write_filter (savename
, filename
))) {
257 file
= (FILE *) popen (p
, "w");
260 filelen
= edit_write_stream (edit
, file
);
264 if (pclose (file
) != 0) {
265 edit_error_dialog (_("Error"),
266 catstrs (_(" Error writing to pipe: "),
273 edit_error_dialog (_("Error"),
274 get_sys_error (catstrs
276 (" Cannot open pipe for writing: "),
285 filelen
= edit
->last_byte
;
286 while (buf
<= (edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1) {
287 if (mc_write (fd
, (char *) edit
->buffers1
[buf
], EDIT_BUF_SIZE
)
295 (fd
, (char *) edit
->buffers1
[buf
],
296 edit
->curs1
& M_EDIT_BUF_SIZE
) !=
297 (edit
->curs1
& M_EDIT_BUF_SIZE
)) {
299 } else if (edit
->curs2
) {
301 buf
= (edit
->curs2
>> S_EDIT_BUF_SIZE
);
304 (char *) edit
->buffers2
[buf
] + EDIT_BUF_SIZE
-
305 (edit
->curs2
& M_EDIT_BUF_SIZE
) - 1,
306 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) !=
307 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) {
312 (fd
, (char *) edit
->buffers2
[buf
],
313 EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
325 if (filelen
!= edit
->last_byte
)
327 if (this_save_mode
== EDIT_DO_BACKUP
)
328 if (mc_rename (filename
, catstrs (filename
, option_backup_ext
, 0))
331 if (this_save_mode
!= EDIT_QUICK_SAVE
)
332 if (mc_rename (savename
, filename
) == -1)
337 /* FIXME: Is this safe ?
338 * if (this_save_mode != EDIT_QUICK_SAVE)
339 * mc_unlink (savename);
346 I changed this from Oleg's original routine so
347 that option_backup_ext works with coolwidgets as well. This
348 does mean there is a memory leak - paul.
350 void menu_save_mode_cmd (void)
354 static char *str_result
;
355 static int save_mode_new
;
360 N_("Do backups -->")};
361 static QuickWidget widgets
[] =
363 {quick_button
, 18, DLG_X
, 7, DLG_Y
, N_("&Cancel"), 0,
364 B_CANCEL
, 0, 0, "c"},
365 {quick_button
, 6, DLG_X
, 7, DLG_Y
, N_("&OK"), 0,
367 {quick_input
, 23, DLG_X
, 5, DLG_Y
, 0, 9,
368 0, 0, &str_result
, "edit-backup-ext"},
369 {quick_label
, 22, DLG_X
, 4, DLG_Y
, N_("Extension:"), 0,
370 0, 0, 0, "savemext"},
371 {quick_radio
, 4, DLG_X
, 3, DLG_Y
, "", 3,
372 0, &save_mode_new
, str
, "t"},
374 static QuickDialog dialog
=
375 {DLG_X
, DLG_Y
, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
377 static int i18n_flag
= 0;
385 /* OK/Cancel buttons */
386 l1
= strlen (_(widgets
[0].text
)) + strlen (_(widgets
[1].text
)) + 5;
387 maxlen
= max (maxlen
, l1
);
389 for (i
= 0; i
< 3; i
++ ) {
391 maxlen
= max (maxlen
, strlen (str
[i
]) + 7);
395 dlg_x
= maxlen
+ strlen (_(widgets
[3].text
)) + 5 + 1;
396 widgets
[2].hotkey_pos
= strlen (_(widgets
[3].text
)); /* input field length */
397 dlg_x
= min (COLS
, dlg_x
);
401 widgets
[1].relative_x
= i
;
402 widgets
[0].relative_x
= i
+ strlen (_(widgets
[1].text
)) + i
+ 4;
404 widgets
[2].relative_x
= widgets
[3].relative_x
= maxlen
+ 2;
406 for (i
= 0; i
< sizeof (widgets
)/sizeof (widgets
[0]); i
++)
407 widgets
[i
].x_divisions
= dlg_x
;
410 widgets
[2].text
= option_backup_ext
;
411 widgets
[4].value
= option_save_mode
;
412 if (quick_dialog (&dialog
) != B_ENTER
)
414 option_save_mode
= save_mode_new
;
415 option_backup_ext
= str_result
; /* this is a memory leak */
416 option_backup_ext_int
= 0;
417 str_result
[min (strlen (str_result
), sizeof (int))] = '\0';
418 memcpy ((char *) &option_backup_ext_int
, str_result
, strlen (option_backup_ext
));
422 edit_set_filename (WEdit
*edit
, const char *f
)
425 g_free (edit
->filename
);
428 edit
->filename
= g_strdup (f
);
431 /* Here we want to warn the users of overwriting an existing file,
432 but only if they have made a change to the filename */
433 /* returns 1 on success */
435 edit_save_as_cmd (WEdit
*edit
)
437 /* This heads the 'Save As' dialog box */
440 int different_filename
= 0;
442 exp
= edit_get_save_file (edit
->filename
, _(" Save As "));
443 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
448 edit
->force
|= REDRAW_COMPLETELY
;
451 if (strcmp (edit
->filename
, exp
)) {
453 different_filename
= 1;
454 if ((file
= mc_open (exp
, O_RDONLY
| O_BINARY
)) != -1) {
455 /* the file exists */
457 /* Overwrite the current file or cancel the operation */
458 if (edit_query_dialog2
460 _(" A file already exists with this name. "),
461 _("Overwrite"), _("Cancel"))) {
462 edit
->force
|= REDRAW_COMPLETELY
;
467 save_lock
= edit_lock_file (exp
);
469 /* filenames equal, check if already locked */
470 if (!edit
->locked
&& !edit
->delete_file
)
471 save_lock
= edit_lock_file (exp
);
474 if (edit_save_file (edit
, exp
)) {
475 /* Succesful, so unlock both files */
476 if (strcmp (edit
->filename
, exp
)) {
478 edit_unlock_file (exp
);
480 edit
->locked
= edit_unlock_file (edit
->filename
);
482 if (edit
->locked
|| save_lock
)
483 edit
->locked
= edit_unlock_file (edit
->filename
);
486 edit_set_filename (edit
, exp
);
489 edit
->delete_file
= 0;
490 if (different_filename
&& !edit
->explicit_syntax
)
491 edit_load_syntax (edit
, 0, 0);
492 edit
->force
|= REDRAW_COMPLETELY
;
495 /* Failed, so maintain modify (not save) lock */
496 if (strcmp (edit
->filename
, exp
) && save_lock
)
497 edit_unlock_file (exp
);
499 edit
->locked
= edit_unlock_file (edit
->filename
);
501 edit_error_dialog (_(" Save As "),
503 (" Cannot save file. ")));
504 edit
->force
|= REDRAW_COMPLETELY
;
509 edit
->force
|= REDRAW_COMPLETELY
;
513 /* {{{ Macro stuff starts here */
516 raw_callback (struct Dlg_head
*h
, int key
, int Msg
)
524 return default_dlg_callback (h
, key
, Msg
);;
527 /* gets a raw key from the keyboard. Passing cancel = 1 draws
528 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
529 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
530 and Esc are cannot returned */
532 edit_raw_key_query (char *heading
, char *query
, int cancel
)
534 int w
= strlen (query
) + 7;
535 struct Dlg_head
*raw_dlg
=
536 create_dlg (0, 0, 7, w
, dialog_colors
, raw_callback
,
538 DLG_CENTER
| DLG_TRYUP
| DLG_WANT_TAB
);
541 button_new (4, w
/ 2 - 5, B_CANCEL
, NORMAL_BUTTON
,
542 _("Cancel"), 0, 0, 0));
543 add_widget (raw_dlg
, label_new (3 - cancel
, 2, query
, 0));
545 input_new (3 - cancel
, w
- 5, INPUT_COLOR
, 2, "", 0));
547 w
= raw_dlg
->ret_value
;
548 destroy_dlg (raw_dlg
);
550 if (w
== XCTRL ('g') || w
== XCTRL ('c') || w
== ESC_CHAR
558 /* creates a macro file if it doesn't exist */
559 static FILE *edit_open_macro_file (const char *r
)
563 filename
= catstrs (home_dir
, MACRO_FILE
, 0);
564 if ((file
= open (filename
, O_CREAT
| O_RDWR
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
567 return fopen (filename
, r
);
570 #define MAX_MACROS 1024
571 static int saved_macro
[MAX_MACROS
+ 1];
572 static int saved_macros_loaded
= 0;
575 This is just to stop the macro file be loaded over and over for keys
576 that aren't defined to anything. On slow systems this could be annoying.
582 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++)
583 if (saved_macro
[i
] == k
)
588 /* returns 1 on error */
590 edit_delete_macro (WEdit
* edit
, int k
)
592 struct macro macro
[MAX_MACRO_LENGTH
];
596 if (saved_macros_loaded
)
597 if ((j
= macro_exists (k
)) < 0)
599 g
= fopen (catstrs (home_dir
, TEMP_FILE
, 0), "w");
601 /* This heads the delete macro error dialog box */
602 edit_error_dialog (_(" Delete macro "),
603 /* 'Open' = load temp file */
604 get_sys_error (_(" Cannot open temp file ")));
607 f
= edit_open_macro_file ("r");
609 /* This heads the delete macro error dialog box */
610 edit_error_dialog (_(" Delete macro "),
611 /* 'Open' = load temp file */
612 get_sys_error (_(" Cannot open macro file ")));
617 n
= fscanf (f
, ("key '%d 0': "), &s
);
621 while (fscanf (f
, "%hd %hd, ", ¯o
[n
].command
, ¯o
[n
].ch
))
625 fprintf (g
, ("key '%d 0': "), s
);
626 for (i
= 0; i
< n
; i
++)
627 fprintf (g
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
633 if (rename (catstrs (home_dir
, TEMP_FILE
, 0), catstrs (home_dir
, MACRO_FILE
, 0)) == -1) {
634 /* This heads the delete macro error dialog box */
635 edit_error_dialog (_(" Delete macro "),
636 get_sys_error (_(" Cannot overwrite macro file ")));
639 if (saved_macros_loaded
)
640 memmove (saved_macro
+ j
, saved_macro
+ j
+ 1, sizeof (int) * (MAX_MACROS
- j
- 1));
644 /* returns 0 on error */
645 int edit_save_macro_cmd (WEdit
* edit
, struct macro macro
[], int n
)
650 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
651 /* This heads the 'Macro' dialog box */
652 s
= edit_raw_key_query (_(" Save macro "),
653 /* Input line for a single key press follows the ':' */
654 _(" Press the macro's new hotkey: "), 1);
655 edit
->force
|= REDRAW_COMPLETELY
;
657 if (edit_delete_macro (edit
, s
))
659 f
= edit_open_macro_file ("a+");
661 fprintf (f
, ("key '%d 0': "), s
);
662 for (i
= 0; i
< n
; i
++)
663 fprintf (f
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
666 if (saved_macros_loaded
) {
667 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++);
672 /* This heads the 'Save Macro' dialog box */
673 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
678 void edit_delete_macro_cmd (WEdit
* edit
)
682 command
= edit_raw_key_query (_ (" Delete macro "),
683 _ (" Press macro hotkey: "), 1);
688 edit_delete_macro (edit
, command
);
691 /* return 0 on error */
692 int edit_load_macro_cmd (WEdit
* edit
, struct macro macro
[], int *n
, int k
)
695 int s
, i
= 0, found
= 0;
697 if (saved_macros_loaded
)
698 if (macro_exists (k
) < 0)
701 if ((f
= edit_open_macro_file ("r"))) {
705 u
= fscanf (f
, ("key '%d 0': "), &s
);
708 if (!saved_macros_loaded
)
709 saved_macro
[i
++] = s
;
712 while (*n
< MAX_MACRO_LENGTH
&& 2 == fscanf (f
, "%hd %hd, ", ¯o
[*n
].command
, ¯o
[*n
].ch
))
715 while (2 == fscanf (f
, "%hd %hd, ", &dummy
.command
, &dummy
.ch
));
720 } while (!found
|| !saved_macros_loaded
);
721 if (!saved_macros_loaded
) {
723 saved_macros_loaded
= 1;
728 /* This heads the 'Load Macro' dialog box */
729 edit_error_dialog (_(" Load macro "),
730 get_sys_error (_(" Cannot open macro file ")));
734 /* }}} Macro stuff starts here */
736 /* returns 1 on success */
737 int edit_save_confirm_cmd (WEdit
* edit
)
741 if (edit_confirm_save
) {
742 f
= catstrs (_(" Confirm save file? : "), edit
->filename
, " ", 0);
743 /* Buttons to 'Confirm save file' query */
744 if (edit_query_dialog2 (_(" Save file "), f
, _("Save"), _("Cancel")))
747 return edit_save_cmd (edit
);
751 /* returns 1 on success */
752 int edit_save_cmd (WEdit
* edit
)
754 int res
, save_lock
= 0;
756 if (!edit
->locked
&& !edit
->delete_file
)
757 save_lock
= edit_lock_file (edit
->filename
);
758 res
= edit_save_file (edit
, edit
->filename
);
760 /* Maintain modify (not save) lock on failure */
761 if ((res
&& edit
->locked
) || save_lock
)
762 edit
->locked
= edit_unlock_file (edit
->filename
);
764 /* On failure try 'save as', it does locking on its own */
766 return edit_save_as_cmd (edit
);
767 edit
->force
|= REDRAW_COMPLETELY
;
768 edit
->delete_file
= 0;
775 /* returns 1 on success */
776 int edit_new_cmd (WEdit
* edit
)
778 if (edit
->modified
) {
779 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
780 edit
->force
|= REDRAW_COMPLETELY
;
784 edit
->force
|= REDRAW_COMPLETELY
;
787 edit
->locked
= edit_unlock_file (edit
->filename
);
788 return edit_renew (edit
); /* if this gives an error, something has really screwed up */
791 /* returns 1 on error */
793 edit_load_file_from_filename (WEdit
* edit
, char *exp
)
795 int prev_locked
= edit
->locked
;
796 char *prev_filename
= g_strdup (edit
->filename
);
798 if (!edit_reload (edit
, exp
)) {
799 g_free (prev_filename
);
804 edit_unlock_file (prev_filename
);
805 g_free (prev_filename
);
810 edit_load_cmd (WEdit
*edit
)
814 if (edit
->modified
) {
815 if (edit_query_dialog2
817 _(" Current text was modified without a file save. \n"
818 " Continue discards these changes. "), _("Continue"),
820 edit
->force
|= REDRAW_COMPLETELY
;
825 exp
= edit_get_load_file (edit
->filename
, _(" Load "));
829 edit_load_file_from_filename (edit
, exp
);
832 edit
->force
|= REDRAW_COMPLETELY
;
837 if mark2 is -1 then marking is from mark1 to the cursor.
838 Otherwise its between the markers. This handles this.
839 Returns 1 if no text is marked.
841 int eval_marks (WEdit
* edit
, long *start_mark
, long *end_mark
)
843 if (edit
->mark1
!= edit
->mark2
) {
844 if (edit
->mark2
>= 0) {
845 *start_mark
= min (edit
->mark1
, edit
->mark2
);
846 *end_mark
= max (edit
->mark1
, edit
->mark2
);
848 *start_mark
= min (edit
->mark1
, edit
->curs1
);
849 *end_mark
= max (edit
->mark1
, edit
->curs1
);
850 edit
->column2
= edit
->curs_col
;
854 *start_mark
= *end_mark
= 0;
855 edit
->column2
= edit
->column1
= 0;
860 #define space_width 1
863 edit_insert_column_of_text (WEdit
* edit
, unsigned char *data
, int size
, int width
)
867 cursor
= edit
->curs1
;
868 col
= edit_get_col (edit
);
869 for (i
= 0; i
< size
; i
++) {
870 if (data
[i
] == '\n') { /* fill in and move to next line */
873 if (edit_get_byte (edit
, edit
->curs1
) != '\n') {
874 l
= width
- (edit_get_col (edit
) - col
);
876 edit_insert (edit
, ' ');
880 for (p
= edit
->curs1
;; p
++) {
881 if (p
== edit
->last_byte
) {
882 edit_cursor_move (edit
, edit
->last_byte
- edit
->curs1
);
883 edit_insert_ahead (edit
, '\n');
887 if (edit_get_byte (edit
, p
) == '\n') {
892 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, col
, 0) - edit
->curs1
);
893 l
= col
- edit_get_col (edit
);
894 while (l
>= space_width
) {
895 edit_insert (edit
, ' ');
900 edit_insert (edit
, data
[i
]);
902 edit_cursor_move (edit
, cursor
- edit
->curs1
);
907 edit_block_copy_cmd (WEdit
*edit
)
909 long start_mark
, end_mark
, current
= edit
->curs1
;
911 unsigned char *copy_buf
;
913 edit_update_curs_col (edit
);
915 if (eval_marks (edit
, &start_mark
, &end_mark
))
917 if (column_highlighting
)
918 if ((x
>= edit
->column1
&& x
< edit
->column2
)
919 || (x
> edit
->column2
&& x
<= edit
->column1
))
922 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
924 /* all that gets pushed are deletes hence little space is used on the stack */
926 edit_push_markers (edit
);
928 if (column_highlighting
) {
929 edit_insert_column_of_text (edit
, copy_buf
, size
,
930 abs (edit
->column2
- edit
->column1
));
933 edit_insert_ahead (edit
, copy_buf
[size
]);
937 edit_scroll_screen_over_cursor (edit
);
939 if (column_highlighting
) {
940 edit_set_markers (edit
, 0, 0, 0, 0);
941 edit_push_action (edit
, COLUMN_ON
);
942 column_highlighting
= 0;
943 } else if (start_mark
< current
&& end_mark
> current
)
944 edit_set_markers (edit
, start_mark
,
945 end_mark
+ end_mark
- start_mark
, 0, 0);
947 edit
->force
|= REDRAW_PAGE
;
952 edit_block_move_cmd (WEdit
*edit
)
956 unsigned char *copy_buf
;
957 long start_mark
, end_mark
;
961 if (eval_marks (edit
, &start_mark
, &end_mark
))
963 if (column_highlighting
) {
964 edit_update_curs_col (edit
);
966 if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
967 if ((x
> edit
->column1
&& x
< edit
->column2
)
968 || (x
> edit
->column2
&& x
< edit
->column1
))
970 } else if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
973 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
974 if (edit_query_dialog2
977 (" Block is large, you may not be able to undo this action. "),
978 _("Continue"), _("Cancel")))
981 edit_push_markers (edit
);
982 current
= edit
->curs1
;
983 if (column_highlighting
) {
984 int size
, c1
, c2
, line
;
985 line
= edit
->curs_line
;
987 edit_mark_cmd (edit
, 0);
988 c1
= min (edit
->column1
, edit
->column2
);
989 c2
= max (edit
->column1
, edit
->column2
);
990 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
992 edit_block_delete_cmd (edit
);
995 edit_move_to_line (edit
, line
);
996 edit_cursor_move (edit
,
997 edit_move_forward3 (edit
,
998 edit_bol (edit
, edit
->curs1
),
999 x
, 0) - edit
->curs1
);
1000 edit_insert_column_of_text (edit
, copy_buf
, size
, c2
- c1
);
1002 line
= edit
->curs_line
;
1003 edit_update_curs_col (edit
);
1005 edit_block_delete_cmd (edit
);
1006 edit_move_to_line (edit
, line
);
1007 edit_cursor_move (edit
,
1008 edit_move_forward3 (edit
,
1011 x
, 0) - edit
->curs1
);
1013 edit_set_markers (edit
, 0, 0, 0, 0);
1014 edit_push_action (edit
, COLUMN_ON
);
1015 column_highlighting
= 0;
1017 copy_buf
= g_malloc (end_mark
- start_mark
);
1018 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
1019 edit_scroll_screen_over_cursor (edit
);
1021 while (count
< end_mark
) {
1022 copy_buf
[end_mark
- count
- 1] = edit_delete (edit
);
1025 edit_scroll_screen_over_cursor (edit
);
1026 edit_cursor_move (edit
,
1027 current
- edit
->curs1
-
1028 (((current
- edit
->curs1
) >
1029 0) ? end_mark
- start_mark
: 0));
1030 edit_scroll_screen_over_cursor (edit
);
1031 while (count
-- > start_mark
)
1032 edit_insert_ahead (edit
, copy_buf
[end_mark
- count
- 1]);
1033 edit_set_markers (edit
, edit
->curs1
,
1034 edit
->curs1
+ end_mark
- start_mark
, 0, 0);
1036 edit_scroll_screen_over_cursor (edit
);
1038 edit
->force
|= REDRAW_PAGE
;
1042 edit_delete_column_of_text (WEdit
* edit
)
1044 long p
, q
, r
, m1
, m2
;
1048 eval_marks (edit
, &m1
, &m2
);
1049 n
= edit_move_forward (edit
, m1
, 0, m2
) + 1;
1050 c
= edit_move_forward3 (edit
, edit_bol (edit
, m1
), 0, m1
);
1051 d
= edit_move_forward3 (edit
, edit_bol (edit
, m2
), 0, m2
);
1057 r
= edit_bol (edit
, edit
->curs1
);
1058 p
= edit_move_forward3 (edit
, r
, b
, 0);
1059 q
= edit_move_forward3 (edit
, r
, c
, 0);
1064 edit_cursor_move (edit
, p
- edit
->curs1
);
1065 while (q
> p
) { /* delete line between margins */
1066 if (edit_get_byte (edit
, edit
->curs1
) != '\n')
1070 if (n
) /* move to next line except on the last delete */
1071 edit_cursor_move (edit
, edit_move_forward (edit
, edit
->curs1
, 1, 0) - edit
->curs1
);
1075 /* if success return 0 */
1077 edit_block_delete (WEdit
*edit
)
1080 long start_mark
, end_mark
;
1081 if (eval_marks (edit
, &start_mark
, &end_mark
))
1083 if (column_highlighting
&& edit
->mark2
< 0)
1084 edit_mark_cmd (edit
, 0);
1085 if ((end_mark
- start_mark
) > option_max_undo
/ 2) {
1086 /* Warning message with a query to continue or cancel the operation */
1087 if (edit_query_dialog2
1090 (" Block is large, you may not be able to undo this action. "),
1091 _("Continue"), _("Cancel"))) {
1095 edit_push_markers (edit
);
1096 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
1097 edit_scroll_screen_over_cursor (edit
);
1099 if (start_mark
< end_mark
) {
1100 if (column_highlighting
) {
1101 if (edit
->mark2
< 0)
1102 edit_mark_cmd (edit
, 0);
1103 edit_delete_column_of_text (edit
);
1105 while (count
< end_mark
) {
1111 edit_set_markers (edit
, 0, 0, 0, 0);
1112 edit
->force
|= REDRAW_PAGE
;
1116 /* returns 1 if canceelled by user */
1117 int edit_block_delete_cmd (WEdit
* edit
)
1119 long start_mark
, end_mark
;
1120 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
1121 edit_delete_line (edit
);
1124 return edit_block_delete (edit
);
1128 #define INPUT_INDEX 9
1129 #define SEARCH_DLG_WIDTH 58
1130 #define SEARCH_DLG_HEIGHT 10
1131 #define REPLACE_DLG_WIDTH 58
1132 #define REPLACE_DLG_HEIGHT 15
1133 #define CONFIRM_DLG_WIDTH 79
1134 #define CONFIRM_DLG_HEIGTH 6
1135 #define B_REPLACE_ALL B_USER+1
1136 #define B_REPLACE_ONE B_USER+2
1137 #define B_SKIP_REPLACE B_USER+3
1140 edit_replace_prompt (WEdit
* edit
, char *replace_text
, int xpos
, int ypos
)
1142 QuickWidget quick_widgets
[] =
1144 {quick_button
, 63, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Cancel"),
1145 0, B_CANCEL
, 0, 0, NULL
},
1146 {quick_button
, 50, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("O&ne"),
1147 0, B_REPLACE_ONE
, 0, 0, NULL
},
1148 {quick_button
, 37, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("A&ll"),
1149 0, B_REPLACE_ALL
, 0, 0, NULL
},
1150 {quick_button
, 21, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Skip"),
1151 0, B_SKIP_REPLACE
, 0, 0, NULL
},
1152 {quick_button
, 4, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Replace"),
1153 0, B_ENTER
, 0, 0, NULL
},
1154 {quick_label
, 2, CONFIRM_DLG_WIDTH
, 2, CONFIRM_DLG_HEIGTH
, 0,
1159 char *msg
= _(" Replace with: ");
1161 quick_widgets
[5].text
= catstrs (msg
, replace_text
, 0);
1164 convert_to_display (quick_widgets
[5].text
+ strlen (msg
));
1166 quick_widgets
[5].text
= catstrs (_ (" Replace with: "), replace_text
, 0);
1167 #endif /* !HAVE_CHARSET */
1170 QuickDialog Quick_input
=
1171 {CONFIRM_DLG_WIDTH
, CONFIRM_DLG_HEIGTH
, 0, 0, N_ (" Confirm replace "),
1172 "[Input Line Keys]", 0 /*quick_widgets */ };
1174 Quick_input
.widgets
= quick_widgets
;
1176 Quick_input
.xpos
= xpos
;
1178 /* Sometimes menu can hide replaced text. I don't like it */
1180 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ CONFIRM_DLG_HEIGTH
- 1))
1181 ypos
-= CONFIRM_DLG_HEIGTH
;
1183 Quick_input
.ypos
= ypos
;
1184 return quick_dialog (&Quick_input
);
1189 edit_replace_dialog (WEdit
* edit
, char **search_text
, char **replace_text
, char **arg_order
)
1191 int treplace_scanf
= replace_scanf
;
1192 int treplace_regexp
= replace_regexp
;
1193 int treplace_all
= replace_all
;
1194 int treplace_prompt
= replace_prompt
;
1195 int treplace_backwards
= replace_backwards
;
1196 int treplace_whole
= replace_whole
;
1197 int treplace_case
= replace_case
;
1199 QuickWidget quick_widgets
[] =
1201 {quick_button
, 6, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1203 {quick_button
, 2, 10, 12, REPLACE_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1205 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1207 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("replace &All"), 0, 0,
1209 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("pr&Ompt on replace"), 0, 0,
1211 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1213 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1215 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1217 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 8, REPLACE_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1219 {quick_input
, 3, REPLACE_DLG_WIDTH
, 7, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1221 {quick_label
, 2, REPLACE_DLG_WIDTH
, 6, REPLACE_DLG_HEIGHT
, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1223 {quick_input
, 3, REPLACE_DLG_WIDTH
, 5, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1225 {quick_label
, 2, REPLACE_DLG_WIDTH
, 4, REPLACE_DLG_HEIGHT
, N_(" Enter replacement string:"), 0, 0, 0,
1227 {quick_input
, 3, REPLACE_DLG_WIDTH
, 3, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1229 {quick_label
, 2, REPLACE_DLG_WIDTH
, 2, REPLACE_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1233 quick_widgets
[2].result
= &treplace_scanf
;
1234 quick_widgets
[3].result
= &treplace_all
;
1235 quick_widgets
[4].result
= &treplace_prompt
;
1236 quick_widgets
[5].result
= &treplace_backwards
;
1237 quick_widgets
[6].result
= &treplace_regexp
;
1238 quick_widgets
[7].result
= &treplace_whole
;
1239 quick_widgets
[8].result
= &treplace_case
;
1240 quick_widgets
[9].str_result
= arg_order
;
1241 quick_widgets
[9].text
= *arg_order
;
1242 quick_widgets
[11].str_result
= replace_text
;
1243 quick_widgets
[11].text
= *replace_text
;
1244 quick_widgets
[13].str_result
= search_text
;
1245 quick_widgets
[13].text
= *search_text
;
1247 QuickDialog Quick_input
=
1248 {REPLACE_DLG_WIDTH
, REPLACE_DLG_HEIGHT
, -1, 0, N_(" Replace "),
1249 "[Input Line Keys]", 0 /*quick_widgets */ };
1251 Quick_input
.widgets
= quick_widgets
;
1253 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1254 replace_scanf
= treplace_scanf
;
1255 replace_backwards
= treplace_backwards
;
1256 replace_regexp
= treplace_regexp
;
1257 replace_all
= treplace_all
;
1258 replace_prompt
= treplace_prompt
;
1259 replace_whole
= treplace_whole
;
1260 replace_case
= treplace_case
;
1264 *replace_text
= NULL
;
1265 *search_text
= NULL
;
1273 edit_search_dialog (WEdit
* edit
, char **search_text
)
1275 int treplace_scanf
= replace_scanf
;
1276 int treplace_regexp
= replace_regexp
;
1277 int treplace_whole
= replace_whole
;
1278 int treplace_case
= replace_case
;
1279 int treplace_backwards
= replace_backwards
;
1281 QuickWidget quick_widgets
[] =
1283 {quick_button
, 6, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1285 {quick_button
, 2, 10, 7, SEARCH_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1287 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1289 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1291 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1293 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1295 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 4, SEARCH_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1297 {quick_input
, 3, SEARCH_DLG_WIDTH
, 3, SEARCH_DLG_HEIGHT
, "", 52, 0, 0,
1299 {quick_label
, 2, SEARCH_DLG_WIDTH
, 2, SEARCH_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1303 quick_widgets
[2].result
= &treplace_scanf
;
1304 quick_widgets
[3].result
= &treplace_backwards
;
1305 quick_widgets
[4].result
= &treplace_regexp
;
1306 quick_widgets
[5].result
= &treplace_whole
;
1307 quick_widgets
[6].result
= &treplace_case
;
1308 quick_widgets
[7].str_result
= search_text
;
1309 quick_widgets
[7].text
= *search_text
;
1312 QuickDialog Quick_input
=
1313 {SEARCH_DLG_WIDTH
, SEARCH_DLG_HEIGHT
, -1, 0, N_("Search"),
1314 "[Input Line Keys]", 0 /*quick_widgets */ };
1316 Quick_input
.widgets
= quick_widgets
;
1318 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1319 replace_scanf
= treplace_scanf
;
1320 replace_backwards
= treplace_backwards
;
1321 replace_regexp
= treplace_regexp
;
1322 replace_whole
= treplace_whole
;
1323 replace_case
= treplace_case
;
1325 *search_text
= NULL
;
1331 static long sargs
[NUM_REPL_ARGS
][256 / sizeof (long)];
1333 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1334 sargs[4], sargs[5], sargs[6], sargs[7], \
1335 sargs[8], sargs[9], sargs[10], sargs[11], \
1336 sargs[12], sargs[13], sargs[14], sargs[15]
1338 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1339 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1340 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1341 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1344 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1345 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1347 string_regexp_search (char *pattern
, char *string
, int len
, int match_type
,
1348 int match_bol
, int icase
, int *found_len
, void *d
)
1351 static char *old_pattern
= NULL
;
1352 static int old_type
, old_icase
;
1354 static regmatch_t s
[1];
1356 pmatch
= (regmatch_t
*) d
;
1360 if (!old_pattern
|| strcmp (old_pattern
, pattern
)
1361 || old_type
!= match_type
|| old_icase
!= icase
) {
1364 g_free (old_pattern
);
1367 if (regcomp (&r
, pattern
, REG_EXTENDED
| (icase
? REG_ICASE
: 0))) {
1371 old_pattern
= g_strdup (pattern
);
1372 old_type
= match_type
;
1376 (&r
, string
, d
? NUM_REPL_ARGS
: 1, pmatch
,
1378 || match_type
!= match_normal
) ? 0 : REG_NOTBOL
)) != 0) {
1382 *found_len
= pmatch
[0].rm_eo
- pmatch
[0].rm_so
;
1383 return (pmatch
[0].rm_so
);
1386 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1387 (and the above) routines to work properly - paul */
1390 edit_find_string (long start
, unsigned char *exp
, int *len
, long last_byte
, int (*get_byte
) (void *, long), void *data
, int once_only
, void *d
)
1393 long l
= strlen ((char *) exp
), f
= 0;
1396 for (p
= 0; p
< l
; p
++) /* count conversions... */
1398 if (exp
[++p
] != '%') /* ...except for "%%" */
1401 if (replace_scanf
|| replace_regexp
) {
1404 unsigned char mbuf
[MAX_REPL_LEN
* 2 + 3];
1406 replace_scanf
= (!replace_regexp
); /* can't have both */
1410 if (replace_scanf
) {
1411 unsigned char e
[MAX_REPL_LEN
];
1412 if (n
>= NUM_REPL_ARGS
)
1416 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++)
1417 buf
[p
- start
] = (*get_byte
) (data
, p
);
1419 for (p
= 0; exp
[p
] != 0; p
++)
1420 exp
[p
] = my_lower_case (exp
[p
]);
1421 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++) {
1422 c
= (*get_byte
) (data
, p
);
1423 buf
[p
- start
] = my_lower_case (c
);
1427 buf
[(q
= p
- start
)] = 0;
1428 strcpy ((char *) e
, (char *) exp
);
1429 strcat ((char *) e
, "%n");
1433 *((int *) sargs
[n
]) = 0; /* --> here was the problem - now fixed: good */
1434 if (n
== sscanf ((char *) buf
, (char *) exp
, SCANF_ARGS
)) {
1435 if (*((int *) sargs
[n
])) {
1436 *len
= *((int *) sargs
[n
]);
1442 if (q
+ start
< last_byte
) {
1444 buf
[q
] = (*get_byte
) (data
, q
+ start
);
1446 c
= (*get_byte
) (data
, q
+ start
);
1447 buf
[q
] = my_lower_case (c
);
1453 buf
++; /* move the window along */
1454 if (buf
== mbuf
+ MAX_REPL_LEN
) { /* the window is about to go past the end of array, so... */
1455 memmove (mbuf
, buf
, strlen ((char *) buf
) + 1); /* reset it */
1460 } else { /* regexp matching */
1462 int found_start
, match_bol
, move_win
= 0;
1464 while (start
+ offset
< last_byte
) {
1465 match_bol
= (offset
== 0 || (*get_byte
) (data
, start
+ offset
- 1) == '\n');
1470 for (; p
< last_byte
&& q
< MAX_REPL_LEN
; p
++, q
++) {
1471 mbuf
[q
] = (*get_byte
) (data
, p
);
1472 if (mbuf
[q
] == '\n')
1481 found_start
= string_regexp_search ((char *) exp
, (char *) buf
, q
, match_normal
, match_bol
, !replace_case
, len
, d
);
1483 if (found_start
<= -2) { /* regcomp/regexec error */
1487 else if (found_start
== -1) /* not found: try next line */
1489 else if (*len
== 0) { /* null pattern: try again at next character */
1496 return (start
+ offset
- q
+ found_start
);
1501 if (buf
[q
- 1] != '\n') { /* incomplete line: try to recover */
1502 buf
= mbuf
+ MAX_REPL_LEN
/ 2;
1503 q
= strlen ((char *) buf
);
1504 memmove (mbuf
, buf
, q
);
1513 *len
= strlen ((char *) exp
);
1515 for (p
= start
; p
<= last_byte
- l
; p
++) {
1516 if ((*get_byte
) (data
, p
) == (unsigned char)exp
[0]) { /* check if first char matches */
1517 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1518 if ((*get_byte
) (data
, q
+ p
) != (unsigned char)exp
[q
])
1527 for (p
= 0; exp
[p
] != 0; p
++)
1528 exp
[p
] = my_lower_case (exp
[p
]);
1530 for (p
= start
; p
<= last_byte
- l
; p
++) {
1531 if (my_lower_case ((*get_byte
) (data
, p
)) == (unsigned char)exp
[0]) {
1532 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1533 if (my_lower_case ((*get_byte
) (data
, q
+ p
)) != (unsigned char)exp
[q
])
1548 edit_find_forwards (long search_start
, unsigned char *exp
, int *len
, long last_byte
, int (*get_byte
) (void *, long), void *data
, int once_only
, void *d
)
1549 { /*front end to find_string to check for
1554 while ((p
= edit_find_string (p
, exp
, len
, last_byte
, get_byte
, data
, once_only
, d
)) >= 0) {
1555 if (replace_whole
) {
1556 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1557 if (!strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
- 1))
1558 && !strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
+ *len
)))
1566 p
++; /*not a whole word so continue search. */
1572 edit_find (long search_start
, unsigned char *exp
, int *len
, long last_byte
, int (*get_byte
) (void *, long), void *data
, void *d
)
1575 if (replace_backwards
) {
1576 while (search_start
>= 0) {
1577 p
= edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 1, d
);
1578 if (p
== search_start
)
1583 return edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 0, d
);
1588 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1590 #define snprintf(v) { \
1595 sprintf(s,q1,v,&n); \
1599 /* this function uses the sprintf command to do a vprintf */
1600 /* it takes pointers to arguments instead of the arguments themselves */
1601 static int sprintf_p (char *str
, const char *fmt
,...)
1602 __attribute__ ((format (printf
, 2, 3)));
1604 static int sprintf_p (char *str
, const char *fmt
,...)
1608 char *q
, *p
, *s
= str
;
1613 p
= q
= (char *) fmt
;
1615 while ((p
= strchr (p
, '%'))) {
1617 strncpy (s
, q
, n
); /* copy stuff between format specifiers */
1645 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace field width with a number */
1648 while (is_digit (*p
))
1655 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace precision with a number */
1658 while (is_digit (*p
))
1661 /* flags done, now get argument */
1663 snprintf (va_arg (ap
, char *));
1664 } else if (*p
== 'h') {
1665 if (strchr ("diouxX", *p
))
1666 snprintf (*va_arg (ap
, short *));
1667 } else if (*p
== 'l') {
1669 if (strchr ("diouxX", *p
))
1670 snprintf (*va_arg (ap
, long *));
1671 } else if (strchr ("cdiouxX", *p
)) {
1672 snprintf (*va_arg (ap
, int *));
1673 } else if (*p
== 'L') {
1675 if (strchr ("EefgG", *p
))
1676 snprintf (*va_arg (ap
, double *)); /* should be long double */
1677 } else if (strchr ("EefgG", *p
)) {
1678 snprintf (*va_arg (ap
, double *));
1679 } else if (strchr ("DOU", *p
)) {
1680 snprintf (*va_arg (ap
, long *));
1681 } else if (*p
== 'p') {
1682 snprintf (*va_arg (ap
, void **));
1687 sprintf (s
, q
); /* print trailing leftover */
1688 return s
- str
+ strlen (s
);
1691 static void regexp_error (WEdit
*edit
)
1693 /* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */
1694 edit_error_dialog (_("Error"), _(" Invalid regular expression, or scanf expression with to many conversions "));
1697 /* call with edit = 0 before shutdown to close memory leaks */
1699 edit_replace_cmd (WEdit
*edit
, int again
)
1701 static regmatch_t pmatch
[NUM_REPL_ARGS
];
1702 static char *old1
= NULL
;
1703 static char *old2
= NULL
;
1704 static char *old3
= NULL
;
1709 int replace_continue
;
1710 int treplace_prompt
= 0;
1712 long times_replaced
= 0, last_search
;
1713 int argord
[NUM_REPL_ARGS
];
1730 last_search
= edit
->last_byte
;
1732 edit
->force
|= REDRAW_COMPLETELY
;
1734 exp1
= old1
? old1
: exp1
;
1735 exp2
= old2
? old2
: exp2
;
1736 exp3
= old3
? old3
: exp3
;
1741 exp1
= g_strdup (old1
);
1742 exp2
= g_strdup (old2
);
1743 exp3
= g_strdup (old3
);
1745 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1747 convert_to_display (exp1
);
1748 convert_to_display (exp2
);
1750 edit_replace_dialog (edit
, &exp1
, &exp2
, &exp3
);
1752 convert_from_input (exp1
);
1753 convert_from_input (exp2
);
1755 treplace_prompt
= replace_prompt
;
1758 if (!exp1
|| !*exp1
) {
1759 edit
->force
= REDRAW_COMPLETELY
;
1768 old1
= g_strdup (exp1
);
1769 old2
= g_strdup (exp2
);
1770 old3
= g_strdup (exp3
);
1775 while ((s
= strchr (exp3
, ' ')))
1776 memmove (s
, s
+ 1, strlen (s
));
1778 for (i
= 0; i
< NUM_REPL_ARGS
; i
++) {
1779 if (s
!= (char *) 1 && *s
) {
1781 if ((ord
> 0) && (ord
< NUM_REPL_ARGS
))
1782 argord
[i
] = ord
- 1;
1785 s
= strchr (s
, ',') + 1;
1791 replace_continue
= replace_all
;
1793 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1
1794 && replace_backwards
)
1795 edit
->search_start
--;
1797 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1
1798 && !replace_backwards
)
1799 edit
->search_start
++;
1805 edit_find (edit
->search_start
, (unsigned char *) exp1
, &len
,
1806 last_search
, (int (*)(void *, long)) edit_get_byte
,
1807 (void *) edit
, pmatch
);
1808 if (new_start
== -3) {
1809 regexp_error (edit
);
1812 edit
->search_start
= new_start
;
1813 /*returns negative on not found or error in pattern */
1815 if (edit
->search_start
>= 0) {
1816 edit
->found_start
= edit
->search_start
;
1817 i
= edit
->found_len
= len
;
1819 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1820 edit_scroll_screen_over_cursor (edit
);
1824 if (treplace_prompt
) {
1826 l
= edit
->curs_row
- edit
->num_widget_lines
/ 3;
1828 edit_scroll_downward (edit
, l
);
1830 edit_scroll_upward (edit
, -l
);
1832 edit_scroll_screen_over_cursor (edit
);
1833 edit
->force
|= REDRAW_PAGE
;
1834 edit_render_keypress (edit
);
1836 /*so that undo stops at each query */
1837 edit_push_key_press (edit
);
1839 switch (edit_replace_prompt (edit
, exp2
, /* and prompt 2/3 down */
1840 (edit
->num_widget_columns
-
1841 CONFIRM_DLG_WIDTH
) / 2,
1842 edit
->num_widget_lines
* 2 /
1846 case B_SKIP_REPLACE
:
1850 treplace_prompt
= 0;
1851 replace_continue
= 1;
1854 replace_continue
= 0;
1858 replace_continue
= 0;
1862 if (replace_yes
) { /* delete then insert new */
1863 if (replace_scanf
|| replace_regexp
) {
1864 char repl_str
[MAX_REPL_LEN
+ 2];
1866 /* we need to fill in sargs just like with scanf */
1867 if (replace_regexp
) {
1870 k
< NUM_REPL_ARGS
&& pmatch
[k
].rm_eo
>= 0;
1873 t
= (unsigned char *) &sargs
[k
- 1][0];
1875 j
< pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
1876 && j
< 255; j
++, t
++)
1877 *t
= (unsigned char) edit_get_byte (edit
,
1890 for (; k
<= NUM_REPL_ARGS
; k
++)
1891 sargs
[k
- 1][0] = 0;
1893 if (sprintf_p (repl_str
, exp2
, PRINTF_ARGS
) >= 0) {
1897 while (repl_str
[++i
])
1898 edit_insert (edit
, repl_str
[i
]);
1900 edit_error_dialog (_(" Replace "),
1902 (" Error in replacement format string. "));
1903 replace_continue
= 0;
1910 edit_insert (edit
, exp2
[i
]);
1912 edit
->found_len
= i
;
1914 /* so that we don't find the same string again */
1915 if (replace_backwards
) {
1916 last_search
= edit
->search_start
;
1917 edit
->search_start
--;
1919 edit
->search_start
+= i
;
1920 last_search
= edit
->last_byte
;
1922 edit_scroll_screen_over_cursor (edit
);
1924 char *msg
= _(" Replace ");
1925 /* try and find from right here for next search */
1926 edit
->search_start
= edit
->curs1
;
1927 edit_update_curs_col (edit
);
1929 edit
->force
|= REDRAW_PAGE
;
1930 edit_render_keypress (edit
);
1931 if (times_replaced
) {
1932 message (0, msg
, _(" %ld replacements made. "),
1935 edit_message_dialog (msg
, _(" Search string not found "));
1936 replace_continue
= 0;
1938 } while (replace_continue
);
1943 edit
->force
= REDRAW_COMPLETELY
;
1944 edit_scroll_screen_over_cursor (edit
);
1950 void edit_search_cmd (WEdit
* edit
, int again
)
1952 static char *old
= NULL
;
1962 exp
= old
? old
: exp
;
1963 if (again
) { /*ctrl-hotkey for search again. */
1966 exp
= g_strdup (old
);
1971 convert_to_display (exp
);
1972 #endif /* HAVE_CHARSET */
1974 edit_search_dialog (edit
, &exp
);
1978 convert_from_input (exp
);
1979 #endif /* HAVE_CHARSET */
1981 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1989 old
= g_strdup (exp
);
1991 if (search_create_bookmark
) {
1992 int found
= 0, books
= 0;
1993 int l
= 0, l_last
= -1;
1996 p
= edit_find (q
, (unsigned char *) exp
, &len
, edit
->last_byte
,
1997 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, 0);
2001 l
+= edit_count_lines (edit
, q
, p
);
2003 book_mark_insert (edit
, l
, BOOK_MARK_FOUND_COLOR
);
2010 /* in response to number of bookmarks added because of string being found %d times */
2011 message (0, _("Search"), _(" %d finds made, %d bookmarks added "), found
, books
);
2013 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2017 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
2018 edit
->search_start
--;
2020 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
2021 edit
->search_start
++;
2023 edit
->search_start
= edit_find (edit
->search_start
, (unsigned char *) exp
, &len
, edit
->last_byte
,
2024 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, 0);
2026 if (edit
->search_start
>= 0) {
2027 edit
->found_start
= edit
->search_start
;
2028 edit
->found_len
= len
;
2030 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
2031 edit_scroll_screen_over_cursor (edit
);
2032 if (replace_backwards
)
2033 edit
->search_start
--;
2035 edit
->search_start
++;
2036 } else if (edit
->search_start
== -3) {
2037 edit
->search_start
= edit
->curs1
;
2038 regexp_error (edit
);
2040 edit
->search_start
= edit
->curs1
;
2041 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2047 edit
->force
|= REDRAW_COMPLETELY
;
2048 edit_scroll_screen_over_cursor (edit
);
2052 /* Real edit only */
2053 void edit_quit_cmd (WEdit
* edit
)
2055 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2057 edit
->force
|= REDRAW_COMPLETELY
;
2058 if (edit
->modified
) {
2059 switch (edit_query_dialog3 (_ ("Quit"), _ (" File was modified, Save with exit? "), _ ("Cancel quit"), _ ("&Yes"), _ ("&No"))) {
2061 edit_push_markers (edit
);
2062 edit_set_markers (edit
, 0, 0, 0, 0);
2063 if (!edit_save_cmd (edit
))
2068 edit
->locked
= edit_unlock_file (edit
->filename
);
2069 if (edit
->delete_file
)
2070 unlink (edit
->filename
);
2077 else if (edit
->delete_file
)
2078 unlink (edit
->filename
);
2079 dlg_stop (edit
->widget
.parent
);
2082 #define TEMP_BUF_LEN 1024
2084 /* Return a null terminated length of text. Result must be g_free'd */
2086 edit_get_block (WEdit
*edit
, long start
, long finish
, int *l
)
2088 unsigned char *s
, *r
;
2089 r
= s
= g_malloc (finish
- start
+ 1);
2090 if (column_highlighting
) {
2092 /* copy from buffer, excluding chars that are out of the column 'margins' */
2093 while (start
< finish
) {
2095 x
= edit_move_forward3 (edit
, edit_bol (edit
, start
), 0,
2097 c
= edit_get_byte (edit
, start
);
2098 if ((x
>= edit
->column1
&& x
< edit
->column2
)
2099 || (x
>= edit
->column2
&& x
< edit
->column1
) || c
== '\n') {
2106 *l
= finish
- start
;
2107 while (start
< finish
)
2108 *s
++ = edit_get_byte (edit
, start
++);
2114 /* save block, returns 1 on success */
2116 edit_save_block (WEdit
* edit
, const char *filename
, long start
,
2122 mc_open (filename
, O_CREAT
| O_WRONLY
| O_TRUNC
,
2123 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
| O_BINARY
)) == -1)
2126 if (column_highlighting
) {
2127 unsigned char *block
, *p
;
2129 p
= block
= edit_get_block (edit
, start
, finish
, &len
);
2131 r
= mc_write (file
, p
, len
);
2141 len
= finish
- start
;
2142 buf
= g_malloc (TEMP_BUF_LEN
);
2143 while (start
!= finish
) {
2144 end
= min (finish
, start
+ TEMP_BUF_LEN
);
2145 for (; i
< end
; i
++)
2146 buf
[i
- start
] = edit_get_byte (edit
, i
);
2147 len
-= mc_write (file
, (char *) buf
, end
- start
);
2158 /* copies a block to clipboard file */
2159 static int edit_save_block_to_clip_file (WEdit
* edit
, long start
, long finish
)
2161 return edit_save_block (edit
, catstrs (home_dir
, CLIP_FILE
, 0), start
, finish
);
2165 void edit_paste_from_history (WEdit
*edit
)
2169 int edit_copy_to_X_buf_cmd (WEdit
* edit
)
2171 long start_mark
, end_mark
;
2172 if (eval_marks (edit
, &start_mark
, &end_mark
))
2174 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2175 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2178 edit_mark_cmd (edit
, 1);
2182 int edit_cut_to_X_buf_cmd (WEdit
* edit
)
2184 long start_mark
, end_mark
;
2185 if (eval_marks (edit
, &start_mark
, &end_mark
))
2187 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2188 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2191 edit_block_delete_cmd (edit
);
2192 edit_mark_cmd (edit
, 1);
2196 void edit_paste_from_X_buf_cmd (WEdit
* edit
)
2198 edit_insert_file (edit
, catstrs (home_dir
, CLIP_FILE
, 0));
2203 * Ask user for the line and go to that line.
2204 * Negative numbers mean line from the end (i.e. -1 is the last line).
2207 edit_goto_cmd (WEdit
*edit
)
2210 static long line
= 0; /* line as typed, saved as default */
2215 g_snprintf (s
, sizeof (s
), "%ld", line
);
2216 f
= input_dialog (_(" Goto line "), _(" Enter line: "), line
? s
: "");
2225 l
= strtol (f
, &error
, 0);
2233 l
= edit
->total_lines
+ l
+ 2;
2234 edit_move_display (edit
, l
- edit
->num_widget_lines
/ 2 - 1);
2235 edit_move_to_line (edit
, l
- 1);
2236 edit
->force
|= REDRAW_COMPLETELY
;
2241 /* Return 1 on success */
2243 edit_save_block_cmd (WEdit
*edit
)
2245 long start_mark
, end_mark
;
2247 if (eval_marks (edit
, &start_mark
, &end_mark
))
2250 edit_get_save_file (catstrs (home_dir
, CLIP_FILE
, 0),
2252 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2258 if (edit_save_block (edit
, exp
, start_mark
, end_mark
)) {
2260 edit
->force
|= REDRAW_COMPLETELY
;
2264 edit_error_dialog (_(" Save Block "),
2266 (" Cannot save file. ")));
2270 edit
->force
|= REDRAW_COMPLETELY
;
2275 /* returns 1 on success */
2277 edit_insert_file_cmd (WEdit
*edit
)
2279 char *exp
= edit_get_load_file (catstrs (home_dir
, CLIP_FILE
, 0),
2280 _(" Insert File "));
2281 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2287 if (edit_insert_file (edit
, exp
)) {
2289 edit
->force
|= REDRAW_COMPLETELY
;
2293 edit_error_dialog (_(" Insert File "),
2295 (" Cannot insert file. ")));
2299 edit
->force
|= REDRAW_COMPLETELY
;
2303 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2304 int edit_sort_cmd (WEdit
* edit
)
2306 static char *old
= 0;
2308 long start_mark
, end_mark
;
2311 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2312 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2315 edit_save_block (edit
, catstrs (home_dir
, BLOCK_FILE
, 0), start_mark
, end_mark
);
2317 exp
= old
? old
: "";
2319 exp
= input_dialog (_(" Run Sort "),
2320 _(" Enter sort options (see manpage) separated by whitespace: "), exp
);
2328 e
= system (catstrs (" sort ", exp
, " ", home_dir
, BLOCK_FILE
, " > ", home_dir
, TEMP_FILE
, 0));
2330 if (e
== -1 || e
== 127) {
2331 edit_error_dialog (_(" Sort "),
2332 get_sys_error (_(" Cannot execute sort command ")));
2335 sprintf (q
, "%d ", e
);
2336 edit_error_dialog (_(" Sort "),
2337 catstrs (_(" Sort returned non-zero: "), q
, 0));
2342 edit
->force
|= REDRAW_COMPLETELY
;
2344 if (edit_block_delete_cmd (edit
))
2346 edit_insert_file (edit
, catstrs (home_dir
, TEMP_FILE
, 0));
2351 * Ask user for a command, execute it and paste its output back to the
2355 edit_ext_cmd (WEdit
*edit
)
2361 input_dialog (_("Paste output of external command"),
2362 _("Enter shell command(s):"), NULL
);
2367 e
= system (catstrs (exp
, " > ", home_dir
, TEMP_FILE
, 0));
2371 edit_error_dialog (_("External command"),
2372 get_sys_error (_("Cannot execute command")));
2376 edit
->force
|= REDRAW_COMPLETELY
;
2378 edit_insert_file (edit
, catstrs (home_dir
, TEMP_FILE
, 0));
2382 /* if block is 1, a block must be highlighted and the shell command
2383 processes it. If block is 0 the shell command is a straight system
2384 command, that just produces some output which is to be inserted */
2386 edit_block_process_cmd (WEdit
*edit
, const char *shell_cmd
, int block
)
2388 long start_mark
, end_mark
;
2390 FILE *script_home
= NULL
;
2391 FILE *script_src
= NULL
;
2392 FILE *block_file
= NULL
;
2396 char *quoted_name
= NULL
;
2398 o
= catstrs (mc_home
, shell_cmd
, 0); /* original source script */
2399 h
= catstrs (home_dir
, EDIT_DIR
, shell_cmd
, 0); /* home script */
2400 b
= catstrs (home_dir
, BLOCK_FILE
, 0); /* block file */
2402 if (!(script_home
= fopen (h
, "r"))) {
2403 if (!(script_home
= fopen (h
, "w"))) {
2404 edit_error_dialog ("", get_sys_error (catstrs
2406 ("Error creating script:"),
2410 if (!(script_src
= fopen (o
, "r"))) {
2411 fclose (script_home
);
2413 edit_error_dialog ("", get_sys_error (catstrs
2414 (_("Error reading script:"),
2418 while (fgets (buf
, sizeof (buf
), script_src
))
2419 fputs (buf
, script_home
);
2420 if (fclose (script_home
)) {
2421 edit_error_dialog ("", get_sys_error (catstrs
2423 ("Error closing script:"),
2428 edit_error_dialog ("", get_sys_error (catstrs
2429 (_("Script created:"), h
, 0)));
2434 if (block
) { /* for marked block run indent formatter */
2435 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2436 edit_error_dialog (_("Process block"),
2438 (" You must first highlight a block of text. "));
2441 edit_save_block (edit
, b
, start_mark
, end_mark
);
2442 quoted_name
= name_quote (edit
->filename
, 0);
2445 * Initial space is to avoid polluting bash history.
2447 * $1 - name of the edited file (to check its extension etc).
2448 * $2 - file containing the current block.
2449 * $3 - file where error messages should be put
2450 * (for compatibility with old scripts).
2452 system (catstrs (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ", quoted_name
,
2453 " ", home_dir
, BLOCK_FILE
" /dev/null", NULL
));
2457 * No block selected, just execute the command for the file.
2459 * $1 - name of the edited file.
2461 system (catstrs (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ",
2462 quoted_name
, NULL
));
2464 g_free (quoted_name
);
2465 close_error_pipe (0, 0);
2467 edit_refresh_cmd (edit
);
2468 edit
->force
|= REDRAW_COMPLETELY
;
2470 /* insert result block */
2472 if (edit_block_delete_cmd (edit
))
2474 edit_insert_file (edit
, b
);
2475 if ((block_file
= fopen (b
, "w")))
2476 fclose (block_file
);
2483 /* prints at the cursor */
2484 /* returns the number of chars printed */
2485 int edit_print_string (WEdit
* e
, const char *s
)
2489 edit_execute_cmd (e
, -1, (unsigned char) s
[i
++]);
2490 e
->force
|= REDRAW_COMPLETELY
;
2491 edit_update_screen (e
);
2495 int edit_printf (WEdit
* e
, const char *fmt
, ...)
2501 g_vsnprintf (s
, sizeof (s
), fmt
, pa
);
2502 i
= edit_print_string (e
, s
);
2507 /* FIXME: does this function break NT_OS2 ? */
2509 static void pipe_mail (WEdit
*edit
, char *to
, char *subject
, char *cc
)
2514 to
= name_quote (to
, 0);
2515 subject
= name_quote (subject
, 0);
2516 cc
= name_quote (cc
, 0);
2517 s
= g_strdup_printf ("mail -s %s -c %s %s", subject
, cc
, to
);
2529 for (i
= 0; i
< edit
->last_byte
; i
++)
2530 fputc (edit_get_byte (edit
, i
), p
);
2535 #define MAIL_DLG_HEIGHT 12
2537 void edit_mail_dialog (WEdit
* edit
)
2540 char *tmail_subject
;
2543 static char *mail_cc_last
= 0;
2544 static char *mail_subject_last
= 0;
2545 static char *mail_to_last
= 0;
2547 QuickDialog Quick_input
=
2548 {50, MAIL_DLG_HEIGHT
, -1, 0, N_(" Mail "),
2549 "[Input Line Keys]", 0};
2551 QuickWidget quick_widgets
[] =
2553 {quick_button
, 6, 10, 9, MAIL_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
2555 {quick_button
, 2, 10, 9, MAIL_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
2557 {quick_input
, 3, 50, 8, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2558 0, "mail-dlg-input"},
2559 {quick_label
, 2, 50, 7, MAIL_DLG_HEIGHT
, N_(" Copies to"), 0, 0, 0,
2561 {quick_input
, 3, 50, 6, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2562 0, "mail-dlg-input-2"},
2563 {quick_label
, 2, 50, 5, MAIL_DLG_HEIGHT
, N_(" Subject"), 0, 0, 0,
2565 {quick_input
, 3, 50, 4, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2566 0, "mail-dlg-input-3"},
2567 {quick_label
, 2, 50, 3, MAIL_DLG_HEIGHT
, N_(" To"), 0, 0, 0,
2569 {quick_label
, 2, 50, 2, MAIL_DLG_HEIGHT
, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2573 quick_widgets
[2].str_result
= &tmail_cc
;
2574 quick_widgets
[2].text
= mail_cc_last
? mail_cc_last
: "";
2575 quick_widgets
[4].str_result
= &tmail_subject
;
2576 quick_widgets
[4].text
= mail_subject_last
? mail_subject_last
: "";
2577 quick_widgets
[6].str_result
= &tmail_to
;
2578 quick_widgets
[6].text
= mail_to_last
? mail_to_last
: "";
2580 Quick_input
.widgets
= quick_widgets
;
2582 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
2584 g_free (mail_cc_last
);
2585 if (mail_subject_last
)
2586 g_free (mail_subject_last
);
2588 g_free (mail_to_last
);
2589 mail_cc_last
= *(quick_widgets
[2].str_result
);
2590 mail_subject_last
= *(quick_widgets
[4].str_result
);
2591 mail_to_last
= *(quick_widgets
[6].str_result
);
2592 pipe_mail (edit
, mail_to_last
, mail_subject_last
, mail_cc_last
);
2597 /*******************/
2598 /* Word Completion */
2599 /*******************/
2602 /* find first character of current word */
2603 static int edit_find_word_start (WEdit
*edit
, long *word_start
, int *word_len
)
2607 /* return if at begin of file */
2608 if (edit
->curs1
<= 0)
2611 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- 1);
2612 /* return if not at end or in word */
2613 if (isspace (c
) || !(isalnum (c
) || c
== '_'))
2616 /* search start of word to be completed */
2618 /* return if at begin of file */
2619 if (edit
->curs1
- i
< 0)
2623 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- i
);
2625 if (!(isalnum (c
) || c
== '_')) {
2626 /* return if word starts with digit */
2630 *word_start
= edit
->curs1
- (i
- 1); /* start found */
2640 /* (re)set search parameters to the given values */
2641 static void edit_set_search_parameters (int rs
, int rb
, int rr
, int rw
, int rc
)
2644 replace_backwards
= rb
;
2645 replace_regexp
= rr
;
2651 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2653 /* collect the possible completions */
2655 edit_collect_completions (WEdit
*edit
, long start
, int word_len
,
2656 char *match_expr
, struct selection
*compl,
2659 int len
, max_len
= 0, i
, skip
;
2662 /* collect max MAX_WORD_COMPLETIONS completions */
2663 while (*num
< MAX_WORD_COMPLETIONS
) {
2664 /* get next match */
2666 edit_find (start
- 1, (unsigned char *) match_expr
, &len
,
2668 (int (*)(void *, long)) edit_get_byte
,
2675 /* add matched completion if not yet added */
2678 buffers1
[start
>> S_EDIT_BUF_SIZE
][start
& M_EDIT_BUF_SIZE
];
2680 for (i
= 0; i
< *num
; i
++) {
2682 (&compl[i
].text
[word_len
], &bufpos
[word_len
],
2683 max (len
, compl[i
].len
) - word_len
) == 0) {
2685 break; /* skip it, already added */
2691 compl[*num
].text
= g_malloc (len
+ 1);
2692 compl[*num
].len
= len
;
2693 for (i
= 0; i
< len
; i
++)
2694 compl[*num
].text
[i
] = *(bufpos
+ i
);
2695 compl[*num
].text
[i
] = '\0';
2698 /* note the maximal length needed for the completion dialog */
2707 compllist_callback (void *data
)
2713 /* let the user select its preferred completion */
2715 edit_completion_dialog (WEdit
*edit
, int max_len
, int word_len
,
2716 struct selection
*compl, int num_compl
)
2718 int start_x
, start_y
, offset
, i
;
2720 Dlg_head
*compl_dlg
;
2721 WListbox
*compl_list
;
2722 unsigned int compl_dlg_h
; /* completion dialog height */
2723 unsigned int compl_dlg_w
; /* completion dialog width */
2725 /* calculate the dialog metrics */
2726 compl_dlg_h
= num_compl
+ 2;
2727 compl_dlg_w
= max_len
+ 4;
2728 start_x
= edit
->curs_col
+ edit
->start_col
- (compl_dlg_w
/ 2);
2729 start_y
= edit
->curs_row
+ EDIT_TEXT_VERTICAL_OFFSET
+ 1;
2733 if (compl_dlg_w
> COLS
)
2735 if (compl_dlg_h
> LINES
- 2)
2736 compl_dlg_h
= LINES
- 2;
2738 offset
= start_x
+ compl_dlg_w
- COLS
;
2741 offset
= start_y
+ compl_dlg_h
- LINES
;
2743 start_y
-= (offset
+ 1);
2745 /* create the dialog */
2747 create_dlg (start_y
, start_x
, compl_dlg_h
, compl_dlg_w
,
2748 dialog_colors
, NULL
, "[Completion]", NULL
,
2751 /* create the listbox */
2753 listbox_new (1, 1, compl_dlg_w
- 2, compl_dlg_h
- 2, 0,
2754 compllist_callback
, NULL
);
2756 /* add the dialog */
2757 add_widget (compl_dlg
, compl_list
);
2759 /* fill the listbox with the completions */
2760 for (i
= 0; i
< num_compl
; i
++)
2761 listbox_add_item (compl_list
, 0, 0, compl[i
].text
, NULL
);
2763 /* pop up the dialog */
2764 run_dlg (compl_dlg
);
2766 /* apply the choosen completion */
2767 if (compl_dlg
->ret_value
== B_ENTER
) {
2768 listbox_get_current (compl_list
, &curr
, NULL
);
2770 for (curr
+= word_len
; *curr
; curr
++)
2771 edit_insert (edit
, *curr
);
2774 /* destroy dialog before return */
2775 destroy_dlg (compl_dlg
);
2780 * Complete current word using regular expression search
2781 * backwards beginning at the current cursor position.
2784 edit_complete_word_cmd (WEdit
*edit
)
2786 int word_len
= 0, i
, num_compl
= 0, max_len
;
2787 long word_start
= 0;
2789 char match_expr
[MAX_REPL_LEN
];
2790 struct selection
compl[MAX_WORD_COMPLETIONS
]; /* completions */
2792 /* don't want to disturb another search */
2793 int old_rs
= replace_scanf
;
2794 int old_rb
= replace_backwards
;
2795 int old_rr
= replace_regexp
;
2796 int old_rw
= replace_whole
;
2797 int old_rc
= replace_case
;
2799 /* search start of word to be completed */
2800 if (!edit_find_word_start (edit
, &word_start
, &word_len
))
2803 /* prepare match expression */
2804 bufpos
= &edit
->buffers1
[word_start
>> S_EDIT_BUF_SIZE
]
2805 [word_start
& M_EDIT_BUF_SIZE
];
2806 strncpy (match_expr
, bufpos
, word_len
);
2807 match_expr
[word_len
] = '\0';
2808 strcat (match_expr
, "[a-zA-Z_0-9]+");
2810 /* init search: backward, regexp, whole word, case sensitive */
2811 edit_set_search_parameters (0, 1, 1, 1, 1);
2813 /* collect the possible completions */
2814 /* start search from curs1 down to begin of file */
2816 edit_collect_completions (edit
, word_start
, word_len
, match_expr
,
2817 (struct selection
*) &compl, &num_compl
);
2819 if (num_compl
> 0) {
2820 /* insert completed word if there is only one match */
2821 if (num_compl
== 1) {
2822 for (i
= word_len
; i
< compl[0].len
; i
++)
2823 edit_insert (edit
, *(compl[0].text
+ i
));
2825 /* more than one possible completion => ask the user */
2827 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2828 /* !!! pressed again the selection dialog pops up, but that !!! */
2829 /* !!! seems to require a further internal state !!! */
2832 /* let the user select the preferred completion */
2833 edit_completion_dialog (edit
, max_len
, word_len
,
2834 (struct selection
*) &compl,
2839 /* release memory before return */
2840 for (i
= 0; i
< num_compl
; i
++)
2841 g_free (compl[i
].text
);
2843 /* restore search parameters */
2844 edit_set_search_parameters (old_rs
, old_rb
, old_rr
, old_rw
, old_rc
);