src/find.c: Micro fix for 'Skip hidden' shortcut
[kaloumi3.git] / edit / editcmd.c
blob257ab6efe3985308783bb0e57aabd62451ac4505
1 /* editor high level editing commands.
3 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007 Free Software Foundation, Inc.
6 Authors: 1996, 1997 Paul Sheer
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
25 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
27 #include <config.h>
29 #include <assert.h>
30 #include <ctype.h>
32 #include <stdio.h>
33 #include <stdarg.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <sys/stat.h>
39 #include <stdlib.h>
41 #include "../src/global.h"
42 #include "../src/history.h"
44 #include "edit.h"
45 #include "editlock.h"
46 #include "editcmddef.h"
47 #include "edit-widget.h"
49 #include "../src/color.h" /* dialog_colors */
50 #include "../src/tty.h" /* LINES */
51 #include "../src/widget.h" /* listbox_new() */
52 #include "../src/layout.h" /* clr_scr() */
53 #include "../src/main.h" /* mc_home */
54 #include "../src/help.h" /* interactive_display() */
55 #include "../src/key.h" /* XCTRL */
56 #include "../src/dialog.h" /* do_refresh() */
57 #include "../src/wtools.h" /* message() */
58 #include "../src/charsets.h"
59 #include "../src/selcodepage.h"
61 struct selection {
62 unsigned char * text;
63 int len;
66 /* globals: */
68 /* search and replace: */
69 static int replace_scanf = 0;
70 static int replace_regexp = 0;
71 static int replace_all = 0;
72 static int replace_prompt = 1;
73 static int replace_whole = 0;
74 static int replace_case = 0;
75 static int replace_backwards = 0;
76 static int search_create_bookmark = 0;
78 /* queries on a save */
79 int edit_confirm_save = 1;
81 #define NUM_REPL_ARGS 64
82 #define MAX_REPL_LEN 1024
84 static int edit_save_cmd (WEdit *edit);
85 static unsigned char *edit_get_block (WEdit *edit, long start,
86 long finish, int *l);
88 static inline int my_lower_case (int c)
90 return tolower(c & 0xFF);
93 static const char *
94 strcasechr (const char *s, int c)
96 for (c = my_lower_case (c); my_lower_case ((int) *s) != c; ++s)
97 if (*s == '\0')
98 return 0;
99 return s;
102 /* #define itoa MY_itoa <---- this line is now in edit.h */
103 static char *
104 MY_itoa (int i)
106 static char t[14];
107 char *s = t + 13;
108 int j = i;
109 *s-- = 0;
110 do {
111 *s-- = i % 10 + '0';
112 } while ((i = i / 10));
113 if (j < 0)
114 *s-- = '-';
115 return ++s;
118 /* Temporary strings */
119 static char *stacked[16];
122 This joins strings end on end and allocates memory for the result.
123 The result is later automatically free'd and must not be free'd
124 by the caller.
126 static const char *
127 catstrs (const char *first,...)
129 static int i = 0;
130 va_list ap;
131 int len;
132 char *data;
134 if (!first)
135 return 0;
137 len = strlen (first);
138 va_start (ap, first);
140 while ((data = va_arg (ap, char *)) != 0)
141 len += strlen (data);
143 len++;
145 i = (i + 1) % 16;
146 g_free (stacked[i]);
148 stacked[i] = g_malloc (len);
149 va_end (ap);
150 va_start (ap, first);
151 strcpy (stacked[i], first);
152 while ((data = va_arg (ap, char *)) != 0)
153 strcat (stacked[i], data);
154 va_end (ap);
156 return stacked[i];
159 /* Free temporary strings */
160 void freestrs(void)
162 size_t i;
164 for (i = 0; i < sizeof(stacked) / sizeof(stacked[0]); i++) {
165 g_free (stacked[i]);
166 stacked[i] = NULL;
170 void edit_help_cmd (WEdit * edit)
172 interactive_display (NULL, "[Internal File Editor]");
173 edit->force |= REDRAW_COMPLETELY;
176 void edit_refresh_cmd (WEdit * edit)
178 #ifndef HAVE_SLANG
179 clr_scr();
180 do_refresh();
181 #else
183 int color;
184 edit_get_syntax_color (edit, -1, &color);
186 touchwin(stdscr);
187 #endif /* !HAVE_SLANG */
188 mc_refresh();
189 doupdate();
192 /* If 0 (quick save) then a) create/truncate <filename> file,
193 b) save to <filename>;
194 if 1 (safe save) then a) save to <tempnam>,
195 b) rename <tempnam> to <filename>;
196 if 2 (do backups) then a) save to <tempnam>,
197 b) rename <filename> to <filename.backup_ext>,
198 c) rename <tempnam> to <filename>. */
200 /* returns 0 on error, -1 on abort */
201 static int
202 edit_save_file (WEdit *edit, const char *filename)
204 char *p;
205 long filelen = 0;
206 char *savename = 0;
207 int this_save_mode, fd = -1;
209 if (!filename)
210 return 0;
211 if (!*filename)
212 return 0;
214 if (*filename != PATH_SEP && edit->dir) {
215 savename = concat_dir_and_file (edit->dir, filename);
216 filename = catstrs (savename, (char *) NULL);
217 g_free (savename);
220 this_save_mode = option_save_mode;
221 if (this_save_mode != EDIT_QUICK_SAVE) {
222 if (!vfs_file_is_local (filename) ||
223 (fd = mc_open (filename, O_RDONLY | O_BINARY)) == -1) {
225 * The file does not exists yet, so no safe save or
226 * backup are necessary.
228 this_save_mode = EDIT_QUICK_SAVE;
230 if (fd != -1)
231 mc_close (fd);
234 if (this_save_mode == EDIT_QUICK_SAVE &&
235 !edit->skip_detach_prompt) {
236 int rv;
237 struct stat sb;
239 rv = mc_stat (filename, &sb);
240 if (rv == 0 && sb.st_nlink > 1) {
241 rv = edit_query_dialog3 (_("Warning"),
242 _(" File has hard-links. Detach before saving? "),
243 _("&Yes"), _("&No"), _("&Cancel"));
244 switch (rv) {
245 case 0:
246 this_save_mode = EDIT_SAFE_SAVE;
247 /* fallthrough */
248 case 1:
249 edit->skip_detach_prompt = 1;
250 break;
251 default:
252 return -1;
256 /* Prevent overwriting changes from other editor sessions. */
257 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
259 /* The default action is "Cancel". */
260 query_set_sel(1);
262 rv = edit_query_dialog2 (
263 _("Warning"),
264 _("The file has been modified in the meantime. Save anyway?"),
265 _("&Yes"),
266 _("&Cancel"));
267 if (rv != 0)
268 return -1;
272 if (this_save_mode != EDIT_QUICK_SAVE) {
273 char *savedir, *saveprefix;
274 const char *slashpos;
275 slashpos = strrchr (filename, PATH_SEP);
276 if (slashpos) {
277 savedir = g_strdup (filename);
278 savedir[slashpos - filename + 1] = '\0';
279 } else
280 savedir = g_strdup (".");
281 saveprefix = concat_dir_and_file (savedir, "cooledit");
282 g_free (savedir);
283 fd = mc_mkstemps (&savename, saveprefix, NULL);
284 g_free (saveprefix);
285 if (!savename)
286 return 0;
287 /* FIXME:
288 * Close for now because mc_mkstemps use pure open system call
289 * to create temporary file and it needs to be reopened by
290 * VFS-aware mc_open().
292 close (fd);
293 } else
294 savename = g_strdup (filename);
296 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
297 mc_chmod (savename, edit->stat1.st_mode);
299 if ((fd =
300 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
301 edit->stat1.st_mode)) == -1)
302 goto error_save;
304 /* pipe save */
305 if ((p = edit_get_write_filter (savename, filename))) {
306 FILE *file;
308 mc_close (fd);
309 file = (FILE *) popen (p, "w");
311 if (file) {
312 filelen = edit_write_stream (edit, file);
313 #if 1
314 pclose (file);
315 #else
316 if (pclose (file) != 0) {
317 edit_error_dialog (_("Error"),
318 catstrs (_(" Error writing to pipe: "),
319 p, " ", (char *) NULL));
320 g_free (p);
321 goto error_save;
323 #endif
324 } else {
325 edit_error_dialog (_("Error"),
326 get_sys_error (catstrs
328 (" Cannot open pipe for writing: "),
329 p, " ", (char *) NULL)));
330 g_free (p);
331 goto error_save;
333 g_free (p);
334 } else {
335 long buf;
336 buf = 0;
337 filelen = edit->last_byte;
338 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
339 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
340 != EDIT_BUF_SIZE) {
341 mc_close (fd);
342 goto error_save;
344 buf++;
346 if (mc_write
347 (fd, (char *) edit->buffers1[buf],
348 edit->curs1 & M_EDIT_BUF_SIZE) !=
349 (edit->curs1 & M_EDIT_BUF_SIZE)) {
350 filelen = -1;
351 } else if (edit->curs2) {
352 edit->curs2--;
353 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
354 if (mc_write
355 (fd,
356 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
357 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
358 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
359 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
360 filelen = -1;
361 } else {
362 while (--buf >= 0) {
363 if (mc_write
364 (fd, (char *) edit->buffers2[buf],
365 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
366 filelen = -1;
367 break;
371 edit->curs2++;
373 if (mc_close (fd))
374 goto error_save;
376 /* Update the file information, especially the mtime. */
377 if (mc_stat (savename, &edit->stat1) == -1)
378 goto error_save;
381 if (filelen != edit->last_byte)
382 goto error_save;
384 if (this_save_mode == EDIT_DO_BACKUP) {
385 assert (option_backup_ext != NULL);
386 if (mc_rename (filename, catstrs (filename, option_backup_ext,
387 (char *) NULL)) == -1)
388 goto error_save;
391 if (this_save_mode != EDIT_QUICK_SAVE)
392 if (mc_rename (savename, filename) == -1)
393 goto error_save;
394 g_free (savename);
395 return 1;
396 error_save:
397 /* FIXME: Is this safe ?
398 * if (this_save_mode != EDIT_QUICK_SAVE)
399 * mc_unlink (savename);
401 g_free (savename);
402 return 0;
405 void menu_save_mode_cmd (void)
407 #define DLG_X 38
408 #define DLG_Y 10
409 static char *str_result;
410 static int save_mode_new;
411 static const char *str[] =
413 N_("Quick save "),
414 N_("Safe save "),
415 N_("Do backups -->")};
416 static QuickWidget widgets[] =
418 {quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
419 B_CANCEL, 0, 0, NULL},
420 {quick_button, 6, DLG_X, 7, DLG_Y, N_("&OK"), 0,
421 B_ENTER, 0, 0, NULL},
422 {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
423 0, 0, &str_result, "edit-backup-ext"},
424 {quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
425 0, 0, 0, NULL},
426 {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
427 0, &save_mode_new, (char **) str, NULL},
428 NULL_QuickWidget};
429 static QuickDialog dialog =
430 {DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
431 widgets, 0};
432 static int i18n_flag = 0;
434 if (!i18n_flag) {
435 size_t i;
436 size_t maxlen = 0;
437 int dlg_x;
438 size_t l1;
440 /* OK/Cancel buttons */
441 l1 = strlen (_(widgets[0].text)) + strlen (_(widgets[1].text)) + 5;
442 maxlen = max (maxlen, l1);
444 for (i = 0; i < 3; i++ ) {
445 str[i] = _(str[i]);
446 maxlen = max (maxlen, strlen (str[i]) + 7);
448 i18n_flag = 1;
450 dlg_x = maxlen + strlen (_(widgets[3].text)) + 5 + 1;
451 widgets[2].hotkey_pos = strlen (_(widgets[3].text)); /* input field length */
452 dlg_x = min (COLS, dlg_x);
453 dialog.xlen = dlg_x;
455 i = (dlg_x - l1)/3;
456 widgets[1].relative_x = i;
457 widgets[0].relative_x = i + strlen (_(widgets[1].text)) + i + 4;
459 widgets[2].relative_x = widgets[3].relative_x = maxlen + 2;
461 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
462 widgets[i].x_divisions = dlg_x;
465 assert (option_backup_ext != NULL);
466 widgets[2].text = option_backup_ext;
467 widgets[4].value = option_save_mode;
468 if (quick_dialog (&dialog) != B_ENTER)
469 return;
470 option_save_mode = save_mode_new;
472 g_free (option_backup_ext);
473 option_backup_ext = str_result;
474 str_result = NULL;
477 void
478 edit_set_filename (WEdit *edit, const char *f)
480 g_free (edit->filename);
481 if (!f)
482 f = "";
483 edit->filename = g_strdup (f);
484 if (edit->dir == NULL && *f != PATH_SEP)
485 #ifdef USE_VFS
486 edit->dir = g_strdup (vfs_get_current_dir ());
487 #else
488 edit->dir = g_get_current_dir ();
489 #endif
492 /* Here we want to warn the users of overwriting an existing file,
493 but only if they have made a change to the filename */
494 /* returns 1 on success */
496 edit_save_as_cmd (WEdit *edit)
498 /* This heads the 'Save As' dialog box */
499 char *exp;
500 int save_lock = 0;
501 int different_filename = 0;
503 exp = input_expand_dialog (
504 _(" Save As "), _(" Enter file name: "),MC_HISTORY_EDIT_SAVE_AS, edit->filename);
505 edit_push_action (edit, KEY_PRESS + edit->start_display);
507 if (exp) {
508 if (!*exp) {
509 g_free (exp);
510 edit->force |= REDRAW_COMPLETELY;
511 return 0;
512 } else {
513 int rv;
514 if (strcmp (edit->filename, exp)) {
515 int file;
516 different_filename = 1;
517 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
518 /* the file exists */
519 mc_close (file);
520 /* Overwrite the current file or cancel the operation */
521 if (edit_query_dialog2
522 (_("Warning"),
523 _(" A file already exists with this name. "),
524 _("&Overwrite"), _("&Cancel"))) {
525 edit->force |= REDRAW_COMPLETELY;
526 g_free (exp);
527 return 0;
530 save_lock = edit_lock_file (exp);
531 } else {
532 /* filenames equal, check if already locked */
533 if (!edit->locked && !edit->delete_file)
534 save_lock = edit_lock_file (exp);
537 rv = edit_save_file (edit, exp);
538 switch (rv) {
539 case 1:
540 /* Succesful, so unlock both files */
541 if (different_filename) {
542 if (save_lock)
543 edit_unlock_file (exp);
544 if (edit->locked)
545 edit->locked = edit_unlock_file (edit->filename);
546 } else {
547 if (edit->locked || save_lock)
548 edit->locked = edit_unlock_file (edit->filename);
551 edit_set_filename (edit, exp);
552 g_free (exp);
553 edit->modified = 0;
554 edit->delete_file = 0;
555 if (different_filename)
556 edit_load_syntax (edit, NULL, option_syntax_type);
557 edit->force |= REDRAW_COMPLETELY;
558 return 1;
559 default:
560 edit_error_dialog (_(" Save As "),
561 get_sys_error (_
562 (" Cannot save file. ")));
563 /* fallthrough */
564 case -1:
565 /* Failed, so maintain modify (not save) lock */
566 if (save_lock)
567 edit_unlock_file (exp);
568 g_free (exp);
569 edit->force |= REDRAW_COMPLETELY;
570 return 0;
574 edit->force |= REDRAW_COMPLETELY;
575 return 0;
578 /* {{{ Macro stuff starts here */
580 static cb_ret_t
581 raw_callback (struct Dlg_head *h, dlg_msg_t msg, int parm)
583 switch (msg) {
584 case DLG_KEY:
585 h->running = 0;
586 h->ret_value = parm;
587 return MSG_HANDLED;
588 default:
589 return default_dlg_callback (h, msg, parm);
593 /* gets a raw key from the keyboard. Passing cancel = 1 draws
594 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
595 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
596 and Esc are cannot returned */
598 edit_raw_key_query (const char *heading, const char *query, int cancel)
600 int w = strlen (query) + 7;
601 struct Dlg_head *raw_dlg =
602 create_dlg (0, 0, 7, w, dialog_colors, raw_callback,
603 NULL, heading,
604 DLG_CENTER | DLG_TRYUP | DLG_WANT_TAB);
605 add_widget (raw_dlg,
606 input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0, INPUT_COMPLETE_DEFAULT));
607 add_widget (raw_dlg, label_new (3 - cancel, 2, query));
608 if (cancel)
609 add_widget (raw_dlg,
610 button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON,
611 _("Cancel"), 0));
612 run_dlg (raw_dlg);
613 w = raw_dlg->ret_value;
614 destroy_dlg (raw_dlg);
615 if (cancel) {
616 if (w == XCTRL ('g') || w == XCTRL ('c') || w == ESC_CHAR
617 || w == B_CANCEL)
618 return 0;
621 return w;
624 /* creates a macro file if it doesn't exist */
625 static FILE *edit_open_macro_file (const char *r)
627 const char *filename;
628 int file;
629 filename = catstrs (home_dir, PATH_SEP_STR MACRO_FILE, (char *) NULL);
630 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
631 return 0;
632 close (file);
633 return fopen (filename, r);
636 #define MAX_MACROS 1024
637 static int saved_macro[MAX_MACROS + 1];
638 static int saved_macros_loaded = 0;
641 This is just to stop the macro file be loaded over and over for keys
642 that aren't defined to anything. On slow systems this could be annoying.
644 static int
645 macro_exists (int k)
647 int i;
648 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
649 if (saved_macro[i] == k)
650 return i;
651 return -1;
654 /* returns 1 on error */
655 static int
656 edit_delete_macro (WEdit * edit, int k)
658 struct macro macro[MAX_MACRO_LENGTH];
659 FILE *f, *g;
660 int s, i, n, j = 0;
662 (void) edit;
664 if (saved_macros_loaded)
665 if ((j = macro_exists (k)) < 0)
666 return 0;
667 g = fopen (catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL), "w");
668 if (!g) {
669 edit_error_dialog (_(" Delete macro "),
670 get_sys_error (_(" Cannot open temp file ")));
671 return 1;
673 f = edit_open_macro_file ("r");
674 if (!f) {
675 edit_error_dialog (_(" Delete macro "),
676 get_sys_error (_(" Cannot open macro file ")));
677 fclose (g);
678 return 1;
680 for (;;) {
681 n = fscanf (f, ("key '%d 0': "), &s);
682 if (!n || n == EOF)
683 break;
684 n = 0;
685 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
686 n++;
687 fscanf (f, ";\n");
688 if (s != k) {
689 fprintf (g, ("key '%d 0': "), s);
690 for (i = 0; i < n; i++)
691 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
692 fprintf (g, ";\n");
695 fclose (f);
696 fclose (g);
697 if (rename (catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL), catstrs (home_dir, PATH_SEP_STR MACRO_FILE, (char *) NULL)) == -1) {
698 edit_error_dialog (_(" Delete macro "),
699 get_sys_error (_(" Cannot overwrite macro file ")));
700 return 1;
702 if (saved_macros_loaded)
703 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
704 return 0;
707 /* returns 0 on error */
708 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
710 FILE *f;
711 int s, i;
713 edit_push_action (edit, KEY_PRESS + edit->start_display);
714 s = edit_raw_key_query (_(" Save macro "),
715 _(" Press the macro's new hotkey: "), 1);
716 edit->force |= REDRAW_COMPLETELY;
717 if (s) {
718 if (edit_delete_macro (edit, s))
719 return 0;
720 f = edit_open_macro_file ("a+");
721 if (f) {
722 fprintf (f, ("key '%d 0': "), s);
723 for (i = 0; i < n; i++)
724 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
725 fprintf (f, ";\n");
726 fclose (f);
727 if (saved_macros_loaded) {
728 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
729 saved_macro[i] = s;
731 return 1;
732 } else
733 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
735 return 0;
738 void edit_delete_macro_cmd (WEdit * edit)
740 int command;
742 command = edit_raw_key_query (_ (" Delete macro "),
743 _ (" Press macro hotkey: "), 1);
745 if (!command)
746 return;
748 edit_delete_macro (edit, command);
751 /* return 0 on error */
752 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
754 FILE *f;
755 int s, i = 0, found = 0;
757 (void) edit;
759 if (saved_macros_loaded)
760 if (macro_exists (k) < 0)
761 return 0;
763 if ((f = edit_open_macro_file ("r"))) {
764 struct macro dummy;
765 do {
766 int u;
767 u = fscanf (f, ("key '%d 0': "), &s);
768 if (!u || u == EOF)
769 break;
770 if (!saved_macros_loaded)
771 saved_macro[i++] = s;
772 if (!found) {
773 *n = 0;
774 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
775 (*n)++;
776 } else {
777 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
779 fscanf (f, ";\n");
780 if (s == k)
781 found = 1;
782 } while (!found || !saved_macros_loaded);
783 if (!saved_macros_loaded) {
784 saved_macro[i] = 0;
785 saved_macros_loaded = 1;
787 fclose (f);
788 return found;
789 } else
790 edit_error_dialog (_(" Load macro "),
791 get_sys_error (_(" Cannot open macro file ")));
792 return 0;
795 /* }}} Macro stuff starts here */
797 /* returns 1 on success */
798 int edit_save_confirm_cmd (WEdit * edit)
800 const char *f;
802 if (edit_confirm_save) {
803 f = catstrs (_(" Confirm save file? : "), edit->filename, " ", (char *) NULL);
804 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel")))
805 return 0;
807 return edit_save_cmd (edit);
811 /* returns 1 on success */
812 static int
813 edit_save_cmd (WEdit *edit)
815 int res, save_lock = 0;
817 if (!edit->locked && !edit->delete_file)
818 save_lock = edit_lock_file (edit->filename);
819 res = edit_save_file (edit, edit->filename);
821 /* Maintain modify (not save) lock on failure */
822 if ((res > 0 && edit->locked) || save_lock)
823 edit->locked = edit_unlock_file (edit->filename);
825 /* On failure try 'save as', it does locking on its own */
826 if (!res)
827 return edit_save_as_cmd (edit);
828 edit->force |= REDRAW_COMPLETELY;
829 if (res > 0) {
830 edit->delete_file = 0;
831 edit->modified = 0;
834 return 1;
838 /* returns 1 on success */
839 int edit_new_cmd (WEdit * edit)
841 if (edit->modified) {
842 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
843 edit->force |= REDRAW_COMPLETELY;
844 return 0;
847 edit->force |= REDRAW_COMPLETELY;
849 return edit_renew (edit); /* if this gives an error, something has really screwed up */
852 /* returns 1 on error */
853 static int
854 edit_load_file_from_filename (WEdit * edit, char *exp)
856 int prev_locked = edit->locked;
857 char *prev_filename = g_strdup (edit->filename);
859 if (!edit_reload (edit, exp)) {
860 g_free (prev_filename);
861 return 1;
864 if (prev_locked)
865 edit_unlock_file (prev_filename);
866 g_free (prev_filename);
867 return 0;
871 edit_load_cmd (WEdit *edit)
873 char *exp;
875 if (edit->modified) {
876 if (edit_query_dialog2
877 (_("Warning"),
878 _(" Current text was modified without a file save. \n"
879 " Continue discards these changes. "), _("C&ontinue"),
880 _("&Cancel"))) {
881 edit->force |= REDRAW_COMPLETELY;
882 return 0;
886 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
887 MC_HISTORY_EDIT_LOAD, edit->filename);
889 if (exp) {
890 if (*exp)
891 edit_load_file_from_filename (edit, exp);
892 g_free (exp);
894 edit->force |= REDRAW_COMPLETELY;
895 return 0;
899 if mark2 is -1 then marking is from mark1 to the cursor.
900 Otherwise its between the markers. This handles this.
901 Returns 1 if no text is marked.
903 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
905 if (edit->mark1 != edit->mark2) {
906 if (edit->mark2 >= 0) {
907 *start_mark = min (edit->mark1, edit->mark2);
908 *end_mark = max (edit->mark1, edit->mark2);
909 } else {
910 *start_mark = min (edit->mark1, edit->curs1);
911 *end_mark = max (edit->mark1, edit->curs1);
912 edit->column2 = edit->curs_col;
914 return 0;
915 } else {
916 *start_mark = *end_mark = 0;
917 edit->column2 = edit->column1 = 0;
918 return 1;
922 #define space_width 1
924 static void
925 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
927 long cursor;
928 int i, col;
929 cursor = edit->curs1;
930 col = edit_get_col (edit);
931 for (i = 0; i < size; i++) {
932 if (data[i] == '\n') { /* fill in and move to next line */
933 int l;
934 long p;
935 if (edit_get_byte (edit, edit->curs1) != '\n') {
936 l = width - (edit_get_col (edit) - col);
937 while (l > 0) {
938 edit_insert (edit, ' ');
939 l -= space_width;
942 for (p = edit->curs1;; p++) {
943 if (p == edit->last_byte) {
944 edit_cursor_move (edit, edit->last_byte - edit->curs1);
945 edit_insert_ahead (edit, '\n');
946 p++;
947 break;
949 if (edit_get_byte (edit, p) == '\n') {
950 p++;
951 break;
954 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
955 l = col - edit_get_col (edit);
956 while (l >= space_width) {
957 edit_insert (edit, ' ');
958 l -= space_width;
960 continue;
962 edit_insert (edit, data[i]);
964 edit_cursor_move (edit, cursor - edit->curs1);
968 void
969 edit_block_copy_cmd (WEdit *edit)
971 long start_mark, end_mark, current = edit->curs1;
972 int size;
973 unsigned char *copy_buf;
975 edit_update_curs_col (edit);
976 if (eval_marks (edit, &start_mark, &end_mark))
977 return;
979 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
981 /* all that gets pushed are deletes hence little space is used on the stack */
983 edit_push_markers (edit);
985 if (column_highlighting) {
986 edit_insert_column_of_text (edit, copy_buf, size,
987 abs (edit->column2 - edit->column1));
988 } else {
989 while (size--)
990 edit_insert_ahead (edit, copy_buf[size]);
993 g_free (copy_buf);
994 edit_scroll_screen_over_cursor (edit);
996 if (column_highlighting) {
997 edit_set_markers (edit, 0, 0, 0, 0);
998 edit_push_action (edit, COLUMN_ON);
999 column_highlighting = 0;
1000 } else if (start_mark < current && end_mark > current)
1001 edit_set_markers (edit, start_mark,
1002 end_mark + end_mark - start_mark, 0, 0);
1004 edit->force |= REDRAW_PAGE;
1008 void
1009 edit_block_move_cmd (WEdit *edit)
1011 long count;
1012 long current;
1013 unsigned char *copy_buf;
1014 long start_mark, end_mark;
1015 int deleted = 0;
1016 int x = 0;
1018 if (eval_marks (edit, &start_mark, &end_mark))
1019 return;
1020 if (column_highlighting) {
1021 edit_update_curs_col (edit);
1022 x = edit->curs_col;
1023 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1024 if ((x > edit->column1 && x < edit->column2)
1025 || (x > edit->column2 && x < edit->column1))
1026 return;
1027 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1028 return;
1030 if ((end_mark - start_mark) > option_max_undo / 2)
1031 if (edit_query_dialog2
1032 (_("Warning"),
1034 (" Block is large, you may not be able to undo this action. "),
1035 _("C&ontinue"), _("&Cancel")))
1036 return;
1038 edit_push_markers (edit);
1039 current = edit->curs1;
1040 if (column_highlighting) {
1041 int size, c1, c2, line;
1042 line = edit->curs_line;
1043 if (edit->mark2 < 0)
1044 edit_mark_cmd (edit, 0);
1045 c1 = min (edit->column1, edit->column2);
1046 c2 = max (edit->column1, edit->column2);
1047 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1048 if (x < c2) {
1049 edit_block_delete_cmd (edit);
1050 deleted = 1;
1052 edit_move_to_line (edit, line);
1053 edit_cursor_move (edit,
1054 edit_move_forward3 (edit,
1055 edit_bol (edit, edit->curs1),
1056 x, 0) - edit->curs1);
1057 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1058 if (!deleted) {
1059 line = edit->curs_line;
1060 edit_update_curs_col (edit);
1061 x = edit->curs_col;
1062 edit_block_delete_cmd (edit);
1063 edit_move_to_line (edit, line);
1064 edit_cursor_move (edit,
1065 edit_move_forward3 (edit,
1066 edit_bol (edit,
1067 edit->curs1),
1068 x, 0) - edit->curs1);
1070 edit_set_markers (edit, 0, 0, 0, 0);
1071 edit_push_action (edit, COLUMN_ON);
1072 column_highlighting = 0;
1073 } else {
1074 copy_buf = g_malloc (end_mark - start_mark);
1075 edit_cursor_move (edit, start_mark - edit->curs1);
1076 edit_scroll_screen_over_cursor (edit);
1077 count = start_mark;
1078 while (count < end_mark) {
1079 copy_buf[end_mark - count - 1] = edit_delete (edit);
1080 count++;
1082 edit_scroll_screen_over_cursor (edit);
1083 edit_cursor_move (edit,
1084 current - edit->curs1 -
1085 (((current - edit->curs1) >
1086 0) ? end_mark - start_mark : 0));
1087 edit_scroll_screen_over_cursor (edit);
1088 while (count-- > start_mark)
1089 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1090 edit_set_markers (edit, edit->curs1,
1091 edit->curs1 + end_mark - start_mark, 0, 0);
1093 edit_scroll_screen_over_cursor (edit);
1094 g_free (copy_buf);
1095 edit->force |= REDRAW_PAGE;
1098 static void
1099 edit_delete_column_of_text (WEdit * edit)
1101 long p, q, r, m1, m2;
1102 int b, c, d;
1103 int n;
1105 eval_marks (edit, &m1, &m2);
1106 n = edit_move_forward (edit, m1, 0, m2) + 1;
1107 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1108 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1110 b = min (c, d);
1111 c = max (c, d);
1113 while (n--) {
1114 r = edit_bol (edit, edit->curs1);
1115 p = edit_move_forward3 (edit, r, b, 0);
1116 q = edit_move_forward3 (edit, r, c, 0);
1117 if (p < m1)
1118 p = m1;
1119 if (q > m2)
1120 q = m2;
1121 edit_cursor_move (edit, p - edit->curs1);
1122 while (q > p) { /* delete line between margins */
1123 if (edit_get_byte (edit, edit->curs1) != '\n')
1124 edit_delete (edit);
1125 q--;
1127 if (n) /* move to next line except on the last delete */
1128 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1132 /* if success return 0 */
1133 static int
1134 edit_block_delete (WEdit *edit)
1136 long count;
1137 long start_mark, end_mark;
1138 if (eval_marks (edit, &start_mark, &end_mark))
1139 return 0;
1140 if (column_highlighting && edit->mark2 < 0)
1141 edit_mark_cmd (edit, 0);
1142 if ((end_mark - start_mark) > option_max_undo / 2) {
1143 /* Warning message with a query to continue or cancel the operation */
1144 if (edit_query_dialog2
1145 (_("Warning"),
1147 (" Block is large, you may not be able to undo this action. "),
1148 _("C&ontinue"), _("&Cancel"))) {
1149 return 1;
1152 edit_push_markers (edit);
1153 edit_cursor_move (edit, start_mark - edit->curs1);
1154 edit_scroll_screen_over_cursor (edit);
1155 count = start_mark;
1156 if (start_mark < end_mark) {
1157 if (column_highlighting) {
1158 if (edit->mark2 < 0)
1159 edit_mark_cmd (edit, 0);
1160 edit_delete_column_of_text (edit);
1161 } else {
1162 while (count < end_mark) {
1163 edit_delete (edit);
1164 count++;
1168 edit_set_markers (edit, 0, 0, 0, 0);
1169 edit->force |= REDRAW_PAGE;
1170 return 0;
1173 /* returns 1 if canceelled by user */
1174 int edit_block_delete_cmd (WEdit * edit)
1176 long start_mark, end_mark;
1177 if (eval_marks (edit, &start_mark, &end_mark)) {
1178 edit_delete_line (edit);
1179 return 0;
1181 return edit_block_delete (edit);
1185 #define INPUT_INDEX 9
1186 #define SEARCH_DLG_WIDTH 58
1187 #define SEARCH_DLG_HEIGHT 10
1188 #define REPLACE_DLG_WIDTH 58
1189 #define REPLACE_DLG_HEIGHT 15
1190 #define CONFIRM_DLG_WIDTH 79
1191 #define CONFIRM_DLG_HEIGTH 6
1192 #define B_REPLACE_ALL (B_USER+1)
1193 #define B_REPLACE_ONE (B_USER+2)
1194 #define B_SKIP_REPLACE (B_USER+3)
1196 static int
1197 edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
1199 QuickWidget quick_widgets[] =
1201 {quick_button, 63, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Cancel"),
1202 0, B_CANCEL, 0, 0, NULL},
1203 {quick_button, 50, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("O&ne"),
1204 0, B_REPLACE_ONE, 0, 0, NULL},
1205 {quick_button, 37, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("A&ll"),
1206 0, B_REPLACE_ALL, 0, 0, NULL},
1207 {quick_button, 21, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Skip"),
1208 0, B_SKIP_REPLACE, 0, 0, NULL},
1209 {quick_button, 4, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Replace"),
1210 0, B_ENTER, 0, 0, NULL},
1211 {quick_label, 2, CONFIRM_DLG_WIDTH, 2, CONFIRM_DLG_HEIGTH, 0,
1212 0, 0, 0, 0, 0},
1213 NULL_QuickWidget};
1215 GString *label_text = g_string_new (_(" Replace with: "));
1216 if (*replace_text) {
1217 size_t label_len;
1218 label_len = label_text->len;
1219 g_string_append (label_text, replace_text);
1220 convert_to_display (label_text->str + label_len);
1222 quick_widgets[5].text = label_text->str;
1225 int retval;
1226 QuickDialog Quick_input =
1227 {CONFIRM_DLG_WIDTH, CONFIRM_DLG_HEIGTH, 0, 0, N_ (" Confirm replace "),
1228 "[Input Line Keys]", 0 /*quick_widgets */, 0 };
1230 Quick_input.widgets = quick_widgets;
1232 Quick_input.xpos = xpos;
1234 /* Sometimes menu can hide replaced text. I don't like it */
1236 if ((edit->curs_row >= ypos - 1) && (edit->curs_row <= ypos + CONFIRM_DLG_HEIGTH - 1))
1237 ypos -= CONFIRM_DLG_HEIGTH;
1239 Quick_input.ypos = ypos;
1240 retval = quick_dialog (&Quick_input);
1241 g_string_free (label_text, TRUE);
1242 return retval;
1246 static void
1247 edit_replace_dialog (WEdit * edit, const char *search_default,
1248 const char *replace_default, const char *argorder_default,
1249 /*@out@*/ char **search_text, /*@out@*/ char **replace_text,
1250 /*@out@*/ char **arg_order)
1252 int treplace_scanf = replace_scanf;
1253 int treplace_regexp = replace_regexp;
1254 int treplace_all = replace_all;
1255 int treplace_prompt = replace_prompt;
1256 int treplace_backwards = replace_backwards;
1257 int treplace_whole = replace_whole;
1258 int treplace_case = replace_case;
1260 /* Alt-p is in use as hotkey for previous entry; don't use */
1261 QuickWidget quick_widgets[] =
1263 {quick_button, 6, 10, 12, REPLACE_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1264 0, NULL},
1265 {quick_button, 2, 10, 12, REPLACE_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
1266 0, NULL},
1267 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1268 0, 0, NULL},
1269 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("replace &All"), 0, 0,
1270 0, 0, NULL},
1271 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("pro&Mpt on replace"), 0, 0,
1272 0, 0, NULL},
1273 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1274 0, 0, NULL},
1275 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1276 0, 0, NULL},
1277 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1278 0, 0, NULL},
1279 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 8, REPLACE_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1280 0, 0, NULL},
1281 {quick_input, 3, REPLACE_DLG_WIDTH, 7, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1282 0, "edit-argord"},
1283 {quick_label, 2, REPLACE_DLG_WIDTH, 6, REPLACE_DLG_HEIGHT, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1284 0, 0, 0},
1285 {quick_input, 3, REPLACE_DLG_WIDTH, 5, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1286 0, "edit-replace"},
1287 {quick_label, 2, REPLACE_DLG_WIDTH, 4, REPLACE_DLG_HEIGHT, N_(" Enter replacement string:"), 0, 0, 0,
1288 0, 0},
1289 {quick_input, 3, REPLACE_DLG_WIDTH, 3, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1290 0, "edit-search"},
1291 {quick_label, 2, REPLACE_DLG_WIDTH, 2, REPLACE_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1292 0, 0},
1293 NULL_QuickWidget};
1295 (void) edit;
1297 quick_widgets[2].result = &treplace_scanf;
1298 quick_widgets[3].result = &treplace_all;
1299 quick_widgets[4].result = &treplace_prompt;
1300 quick_widgets[5].result = &treplace_backwards;
1301 quick_widgets[6].result = &treplace_regexp;
1302 quick_widgets[7].result = &treplace_whole;
1303 quick_widgets[8].result = &treplace_case;
1304 quick_widgets[9].str_result = arg_order;
1305 quick_widgets[9].text = argorder_default;
1306 quick_widgets[11].str_result = replace_text;
1307 quick_widgets[11].text = replace_default;
1308 quick_widgets[13].str_result = search_text;
1309 quick_widgets[13].text = search_default;
1311 QuickDialog Quick_input =
1312 {REPLACE_DLG_WIDTH, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "),
1313 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1315 Quick_input.widgets = quick_widgets;
1317 if (quick_dialog (&Quick_input) != B_CANCEL) {
1318 replace_scanf = treplace_scanf;
1319 replace_backwards = treplace_backwards;
1320 replace_regexp = treplace_regexp;
1321 replace_all = treplace_all;
1322 replace_prompt = treplace_prompt;
1323 replace_whole = treplace_whole;
1324 replace_case = treplace_case;
1325 return;
1326 } else {
1327 *arg_order = NULL;
1328 *replace_text = NULL;
1329 *search_text = NULL;
1330 return;
1336 static void
1337 edit_search_dialog (WEdit * edit, char **search_text)
1339 int treplace_scanf = replace_scanf;
1340 int treplace_regexp = replace_regexp;
1341 int treplace_whole = replace_whole;
1342 int treplace_case = replace_case;
1343 int treplace_backwards = replace_backwards;
1345 QuickWidget quick_widgets[] =
1347 {quick_button, 6, 10, 7, SEARCH_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1348 0, NULL},
1349 {quick_button, 2, 10, 7, SEARCH_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
1350 0, NULL},
1351 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1352 0, 0, NULL },
1353 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1354 0, 0, NULL},
1355 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1356 0, 0, NULL},
1357 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1358 0, 0, NULL},
1359 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 4, SEARCH_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1360 0, 0, NULL},
1361 {quick_input, 3, SEARCH_DLG_WIDTH, 3, SEARCH_DLG_HEIGHT, "", 52, 0, 0,
1362 0, "edit-search"},
1363 {quick_label, 2, SEARCH_DLG_WIDTH, 2, SEARCH_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1364 0, 0},
1365 NULL_QuickWidget};
1367 (void) edit;
1369 quick_widgets[2].result = &treplace_scanf;
1370 quick_widgets[3].result = &treplace_backwards;
1371 quick_widgets[4].result = &treplace_regexp;
1372 quick_widgets[5].result = &treplace_whole;
1373 quick_widgets[6].result = &treplace_case;
1374 quick_widgets[7].str_result = search_text;
1375 quick_widgets[7].text = *search_text;
1378 QuickDialog Quick_input =
1379 {SEARCH_DLG_WIDTH, SEARCH_DLG_HEIGHT, -1, 0, N_("Search"),
1380 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1382 Quick_input.widgets = quick_widgets;
1384 if (quick_dialog (&Quick_input) != B_CANCEL) {
1385 replace_scanf = treplace_scanf;
1386 replace_backwards = treplace_backwards;
1387 replace_regexp = treplace_regexp;
1388 replace_whole = treplace_whole;
1389 replace_case = treplace_case;
1390 } else {
1391 *search_text = NULL;
1397 static long sargs[NUM_REPL_ARGS][256 / sizeof (long)];
1399 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1400 sargs[4], sargs[5], sargs[6], sargs[7], \
1401 sargs[8], sargs[9], sargs[10], sargs[11], \
1402 sargs[12], sargs[13], sargs[14], sargs[15]
1404 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1405 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1406 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1407 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1410 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1411 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1412 static int
1413 string_regexp_search (char *pattern, char *string, int match_type,
1414 int match_bol, int icase, int *found_len, void *d)
1416 static regex_t r;
1417 static char *old_pattern = NULL;
1418 static int old_type, old_icase;
1419 regmatch_t *pmatch;
1420 static regmatch_t s[1];
1422 pmatch = (regmatch_t *) d;
1423 if (!pmatch)
1424 pmatch = s;
1426 if (!old_pattern || strcmp (old_pattern, pattern)
1427 || old_type != match_type || old_icase != icase) {
1428 if (old_pattern) {
1429 regfree (&r);
1430 g_free (old_pattern);
1431 old_pattern = 0;
1433 if (regcomp (&r, pattern, REG_EXTENDED | (icase ? REG_ICASE : 0) |
1434 REG_NEWLINE)) {
1435 *found_len = 0;
1436 return -3;
1438 old_pattern = g_strdup (pattern);
1439 old_type = match_type;
1440 old_icase = icase;
1442 if (regexec
1443 (&r, string, d ? NUM_REPL_ARGS : 1, pmatch,
1444 ((match_bol
1445 || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) {
1446 *found_len = 0;
1447 return -1;
1449 *found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
1450 return (pmatch[0].rm_so);
1453 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1454 (and the above) routines to work properly - paul */
1456 typedef int (*edit_getbyte_fn) (WEdit *, long);
1458 static long
1459 edit_find_string (long start, unsigned char *exp, int *len, long last_byte, edit_getbyte_fn get_byte, void *data, int once_only, void *d)
1461 long p, q = 0;
1462 long l = strlen ((char *) exp), f = 0;
1463 int n = 0;
1465 for (p = 0; p < l; p++) /* count conversions... */
1466 if (exp[p] == '%')
1467 if (exp[++p] != '%') /* ...except for "%%" */
1468 n++;
1470 if (replace_scanf || replace_regexp) {
1471 int c;
1472 unsigned char *buf;
1473 unsigned char mbuf[MAX_REPL_LEN * 2 + 3];
1475 replace_scanf = (!replace_regexp); /* can't have both */
1477 buf = mbuf;
1479 if (replace_scanf) {
1480 unsigned char e[MAX_REPL_LEN];
1481 if (n >= NUM_REPL_ARGS)
1482 return -3;
1484 if (replace_case) {
1485 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++)
1486 buf[p - start] = (*get_byte) (data, p);
1487 } else {
1488 for (p = 0; exp[p] != 0; p++)
1489 exp[p] = my_lower_case (exp[p]);
1490 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) {
1491 c = (*get_byte) (data, p);
1492 buf[p - start] = my_lower_case (c);
1496 buf[(q = p - start)] = 0;
1497 strcpy ((char *) e, (char *) exp);
1498 strcat ((char *) e, "%n");
1499 exp = e;
1501 while (q) {
1502 *((int *) sargs[n]) = 0; /* --> here was the problem - now fixed: good */
1503 if (n == sscanf ((char *) buf, (char *) exp, SCANF_ARGS)) {
1504 if (*((int *) sargs[n])) {
1505 *len = *((int *) sargs[n]);
1506 return start;
1509 if (once_only)
1510 return -2;
1511 if (q + start < last_byte) {
1512 if (replace_case) {
1513 buf[q] = (*get_byte) (data, q + start);
1514 } else {
1515 c = (*get_byte) (data, q + start);
1516 buf[q] = my_lower_case (c);
1518 q++;
1520 buf[q] = 0;
1521 start++;
1522 buf++; /* move the window along */
1523 if (buf == mbuf + MAX_REPL_LEN) { /* the window is about to go past the end of array, so... */
1524 memmove (mbuf, buf, strlen ((char *) buf) + 1); /* reset it */
1525 buf = mbuf;
1527 q--;
1529 } else { /* regexp matching */
1530 long offset = 0;
1531 int found_start, match_bol, move_win = 0;
1533 while (start + offset < last_byte) {
1534 match_bol = (start == 0 || (*get_byte) (data, start + offset - 1) == '\n');
1535 if (!move_win) {
1536 p = start + offset;
1537 q = 0;
1539 for (; p < last_byte && q < MAX_REPL_LEN; p++, q++) {
1540 mbuf[q] = (*get_byte) (data, p);
1541 if (mbuf[q] == '\n') {
1542 q++;
1543 break;
1546 offset += q;
1547 mbuf[q] = 0;
1549 buf = mbuf;
1550 while (q) {
1551 found_start = string_regexp_search ((char *) exp, (char *) buf, match_normal, match_bol, !replace_case, len, d);
1553 if (found_start <= -2) { /* regcomp/regexec error */
1554 *len = 0;
1555 return -3;
1557 else if (found_start == -1) /* not found: try next line */
1558 break;
1559 else if (*len == 0) { /* null pattern: try again at next character */
1560 q--;
1561 buf++;
1562 match_bol = 0;
1563 continue;
1565 else /* found */
1566 return (start + offset - q + found_start);
1568 if (once_only)
1569 return -2;
1571 if (buf[q - 1] != '\n') { /* incomplete line: try to recover */
1572 buf = mbuf + MAX_REPL_LEN / 2;
1573 q = strlen ((const char *) buf);
1574 memmove (mbuf, buf, q);
1575 p = start + q;
1576 move_win = 1;
1578 else
1579 move_win = 0;
1582 } else {
1583 *len = strlen ((const char *) exp);
1584 if (replace_case) {
1585 for (p = start; p <= last_byte - l; p++) {
1586 if ((*get_byte) (data, p) == (unsigned char)exp[0]) { /* check if first char matches */
1587 for (f = 0, q = 0; q < l && f < 1; q++)
1588 if ((*get_byte) (data, q + p) != (unsigned char)exp[q])
1589 f = 1;
1590 if (f == 0)
1591 return p;
1593 if (once_only)
1594 return -2;
1596 } else {
1597 for (p = 0; exp[p] != 0; p++)
1598 exp[p] = my_lower_case (exp[p]);
1600 for (p = start; p <= last_byte - l; p++) {
1601 if (my_lower_case ((*get_byte) (data, p)) == (unsigned char)exp[0]) {
1602 for (f = 0, q = 0; q < l && f < 1; q++)
1603 if (my_lower_case ((*get_byte) (data, q + p)) != (unsigned char)exp[q])
1604 f = 1;
1605 if (f == 0)
1606 return p;
1608 if (once_only)
1609 return -2;
1613 return -2;
1617 static long
1618 edit_find_forwards (long search_start, unsigned char *exp, int *len, long last_byte, edit_getbyte_fn get_byte, void *data, int once_only, void *d)
1619 { /*front end to find_string to check for
1620 whole words */
1621 long p;
1622 p = search_start;
1624 while ((p = edit_find_string (p, exp, len, last_byte, get_byte, data, once_only, d)) >= 0) {
1625 if (replace_whole) {
1626 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1627 if (!strcasechr (option_whole_chars_search, (*get_byte) (data, p - 1))
1628 && !strcasechr (option_whole_chars_search, (*get_byte) (data, p + *len)))
1629 return p;
1630 if (once_only)
1631 return -2;
1632 } else
1633 return p;
1634 if (once_only)
1635 break;
1636 p++; /*not a whole word so continue search. */
1638 return p;
1641 static long
1642 edit_find (long search_start, unsigned char *exp, int *len, long last_byte, edit_getbyte_fn get_byte, void *data, void *d)
1644 long p;
1645 if (replace_backwards) {
1646 while (search_start >= 0) {
1647 p = edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 1, d);
1648 if (p == search_start)
1649 return p;
1650 search_start--;
1652 } else {
1653 return edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 0, d);
1655 return -2;
1658 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1660 #define snprint(v) { \
1661 *p1++ = *p++; \
1662 *p1 = '\0'; \
1663 n = snprintf(s,e-s,q1,v); \
1664 if (n >= (size_t) (e - s)) goto nospc; \
1665 s += n; \
1668 /* this function uses the sprintf command to do a vprintf */
1669 /* it takes pointers to arguments instead of the arguments themselves */
1670 /* The return value is the number of bytes written excluding '\0'
1671 if successfull, -1 if the resulting string would be too long and
1672 -2 if the format string is errorneous. */
1673 static int snprintf_p (char *str, size_t size, const char *fmt,...)
1674 __attribute__ ((format (printf, 3, 4)));
1676 static int snprintf_p (char *str, size_t size, const char *fmt,...)
1678 va_list ap;
1679 size_t n;
1680 const char *q, *p;
1681 char *s = str, *e = str + size;
1682 char q1[40];
1683 char *p1;
1684 int nargs = 0;
1686 va_start (ap, fmt);
1687 p = q = fmt;
1689 while ((p = strchr (p, '%'))) {
1690 n = p - q;
1691 if (n >= (size_t) (e - s))
1692 goto nospc;
1693 memcpy (s, q, n); /* copy stuff between format specifiers */
1694 s += n;
1695 q = p;
1696 p1 = q1;
1697 *p1++ = *p++;
1698 if (*p == '%') {
1699 p++;
1700 *s++ = '%';
1701 if (s == e)
1702 goto nospc;
1703 q = p;
1704 continue;
1706 if (*p == 'n')
1707 goto err;
1708 /* We were passed only 16 arguments. */
1709 if (++nargs == 16)
1710 goto err;
1711 if (*p == '#')
1712 *p1++ = *p++;
1713 if (*p == '0')
1714 *p1++ = *p++;
1715 if (*p == '-')
1716 *p1++ = *p++;
1717 if (*p == '+')
1718 *p1++ = *p++;
1719 if (*p == '*') {
1720 p++;
1721 strcpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace field width with a number */
1722 p1 += strlen (p1);
1723 } else {
1724 while (is_digit (*p) && p1 < q1 + 20)
1725 *p1++ = *p++;
1726 if (is_digit (*p))
1727 goto err;
1729 if (*p == '.')
1730 *p1++ = *p++;
1731 if (*p == '*') {
1732 p++;
1733 strcpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace precision with a number */
1734 p1 += strlen (p1);
1735 } else {
1736 while (is_digit (*p) && p1 < q1 + 32)
1737 *p1++ = *p++;
1738 if (is_digit (*p))
1739 goto err;
1741 /* flags done, now get argument */
1742 if (*p == 's') {
1743 snprint (va_arg (ap, char *));
1744 } else if (*p == 'h') {
1745 if (strchr ("diouxX", *p))
1746 snprint (*va_arg (ap, short *));
1747 } else if (*p == 'l') {
1748 *p1++ = *p++;
1749 if (strchr ("diouxX", *p))
1750 snprint (*va_arg (ap, long *));
1751 } else if (strchr ("cdiouxX", *p)) {
1752 snprint (*va_arg (ap, int *));
1753 } else if (*p == 'L') {
1754 *p1++ = *p++;
1755 if (strchr ("EefgG", *p))
1756 snprint (*va_arg (ap, double *)); /* should be long double */
1757 } else if (strchr ("EefgG", *p)) {
1758 snprint (*va_arg (ap, double *));
1759 } else if (strchr ("DOU", *p)) {
1760 snprint (*va_arg (ap, long *));
1761 } else if (*p == 'p') {
1762 snprint (*va_arg (ap, void **));
1763 } else
1764 goto err;
1765 q = p;
1767 va_end (ap);
1768 n = strlen (q);
1769 if (n >= (size_t) (e - s))
1770 return -1;
1771 memcpy (s, q, n + 1);
1772 return s + n - str;
1773 nospc:
1774 va_end (ap);
1775 return -1;
1776 err:
1777 va_end (ap);
1778 return -2;
1781 static void regexp_error (WEdit *edit)
1783 (void) edit;
1784 edit_error_dialog (_("Error"), _(" Invalid regular expression, or scanf expression with too many conversions "));
1787 /* call with edit = 0 before shutdown to close memory leaks */
1788 void
1789 edit_replace_cmd (WEdit *edit, int again)
1791 static regmatch_t pmatch[NUM_REPL_ARGS];
1792 /* 1 = search string, 2 = replace with, 3 = argument order */
1793 static char *saved1 = NULL; /* saved default[123] */
1794 static char *saved2 = NULL;
1795 static char *saved3 = NULL;
1796 char *input1 = NULL; /* user input from the dialog */
1797 char *input2 = NULL;
1798 char *input3 = NULL;
1799 int replace_yes;
1800 int replace_continue;
1801 int treplace_prompt = 0;
1802 long times_replaced = 0, last_search;
1803 int argord[NUM_REPL_ARGS];
1805 if (!edit) {
1806 g_free (saved1), saved1 = NULL;
1807 g_free (saved2), saved2 = NULL;
1808 g_free (saved3), saved3 = NULL;
1809 return;
1812 last_search = edit->last_byte;
1814 edit->force |= REDRAW_COMPLETELY;
1816 if (again && !saved1 && !saved2)
1817 again = 0;
1819 if (again) {
1820 input1 = g_strdup (saved1 ? saved1 : "");
1821 input2 = g_strdup (saved2 ? saved2 : "");
1822 input3 = g_strdup (saved3 ? saved3 : "");
1823 } else {
1824 char *disp1 = g_strdup (saved1 ? saved1 : "");
1825 char *disp2 = g_strdup (saved2 ? saved2 : "");
1826 char *disp3 = g_strdup (saved3 ? saved3 : "");
1828 convert_to_display (disp1);
1829 convert_to_display (disp2);
1830 convert_to_display (disp3);
1832 edit_push_action (edit, KEY_PRESS + edit->start_display);
1833 edit_replace_dialog (edit, disp1, disp2, disp3, &input1, &input2,
1834 &input3);
1836 g_free (disp1);
1837 g_free (disp2);
1838 g_free (disp3);
1840 convert_from_input (input1);
1841 convert_from_input (input2);
1842 convert_from_input (input3);
1844 treplace_prompt = replace_prompt;
1845 if (input1 == NULL || *input1 == '\0') {
1846 edit->force = REDRAW_COMPLETELY;
1847 goto cleanup;
1850 g_free (saved1), saved1 = g_strdup (input1);
1851 g_free (saved2), saved2 = g_strdup (input2);
1852 g_free (saved3), saved3 = g_strdup (input3);
1856 const char *s;
1857 int ord;
1858 size_t i;
1860 s = input3;
1861 for (i = 0; i < NUM_REPL_ARGS; i++) {
1862 if (s != NULL && *s != '\0') {
1863 ord = atoi (s);
1864 if ((ord > 0) && (ord <= NUM_REPL_ARGS))
1865 argord[i] = ord - 1;
1866 else
1867 argord[i] = i;
1868 s = strchr (s, ',');
1869 if (s != NULL)
1870 s++;
1871 } else
1872 argord[i] = i;
1876 replace_continue = replace_all;
1878 if (edit->found_len && edit->search_start == edit->found_start + 1
1879 && replace_backwards)
1880 edit->search_start--;
1882 if (edit->found_len && edit->search_start == edit->found_start - 1
1883 && !replace_backwards)
1884 edit->search_start++;
1886 do {
1887 int len = 0;
1888 long new_start;
1889 new_start =
1890 edit_find (edit->search_start, (unsigned char *) input1, &len,
1891 last_search, edit_get_byte, (void *) edit, pmatch);
1892 if (new_start == -3) {
1893 regexp_error (edit);
1894 break;
1896 edit->search_start = new_start;
1897 /*returns negative on not found or error in pattern */
1899 if (edit->search_start >= 0) {
1900 int i;
1902 edit->found_start = edit->search_start;
1903 i = edit->found_len = len;
1905 edit_cursor_move (edit, edit->search_start - edit->curs1);
1906 edit_scroll_screen_over_cursor (edit);
1908 replace_yes = 1;
1910 if (treplace_prompt) {
1911 int l;
1912 l = edit->curs_row - edit->num_widget_lines / 3;
1913 if (l > 0)
1914 edit_scroll_downward (edit, l);
1915 if (l < 0)
1916 edit_scroll_upward (edit, -l);
1918 edit_scroll_screen_over_cursor (edit);
1919 edit->force |= REDRAW_PAGE;
1920 edit_render_keypress (edit);
1922 /*so that undo stops at each query */
1923 edit_push_key_press (edit);
1925 switch (edit_replace_prompt (edit, input2, /* and prompt 2/3 down */
1926 (edit->num_widget_columns -
1927 CONFIRM_DLG_WIDTH) / 2,
1928 edit->num_widget_lines * 2 /
1929 3)) {
1930 case B_ENTER:
1931 break;
1932 case B_SKIP_REPLACE:
1933 replace_yes = 0;
1934 break;
1935 case B_REPLACE_ALL:
1936 treplace_prompt = 0;
1937 replace_continue = 1;
1938 break;
1939 case B_REPLACE_ONE:
1940 replace_continue = 0;
1941 break;
1942 case B_CANCEL:
1943 replace_yes = 0;
1944 replace_continue = 0;
1945 break;
1948 if (replace_yes) { /* delete then insert new */
1949 if (replace_scanf) {
1950 char repl_str[MAX_REPL_LEN + 2];
1951 int ret = 0;
1953 /* we need to fill in sargs just like with scanf */
1954 if (replace_regexp) {
1955 int k, j;
1956 for (k = 1;
1957 k < NUM_REPL_ARGS && pmatch[k].rm_eo >= 0;
1958 k++) {
1959 unsigned char *t;
1961 if (pmatch[k].rm_eo - pmatch[k].rm_so > 255) {
1962 ret = -1;
1963 break;
1965 t = (unsigned char *) &sargs[k - 1][0];
1966 for (j = 0;
1967 j < pmatch[k].rm_eo - pmatch[k].rm_so
1968 && j < 255; j++, t++)
1969 *t = (unsigned char) edit_get_byte (edit,
1970 edit->
1971 search_start
1973 pmatch
1974 [0].
1975 rm_so +
1976 pmatch
1977 [k].
1978 rm_so +
1980 *t = '\0';
1982 for (; k <= NUM_REPL_ARGS; k++)
1983 sargs[k - 1][0] = 0;
1985 if (!ret)
1986 ret =
1987 snprintf_p (repl_str, MAX_REPL_LEN + 2, input2,
1988 PRINTF_ARGS);
1989 if (ret >= 0) {
1990 times_replaced++;
1991 while (i--)
1992 edit_delete (edit);
1993 while (repl_str[++i])
1994 edit_insert (edit, repl_str[i]);
1995 } else {
1996 edit_error_dialog (_(" Replace "),
1997 ret ==
1998 -2 ?
2000 (" Error in replacement format string. ")
2001 : _(" Replacement too long. "));
2002 replace_continue = 0;
2004 } else {
2005 times_replaced++;
2006 while (i--)
2007 edit_delete (edit);
2008 while (input2[++i])
2009 edit_insert (edit, input2[i]);
2011 edit->found_len = i;
2013 /* so that we don't find the same string again */
2014 if (replace_backwards) {
2015 last_search = edit->search_start;
2016 edit->search_start--;
2017 } else {
2018 edit->search_start += i;
2019 last_search = edit->last_byte;
2021 edit_scroll_screen_over_cursor (edit);
2022 } else {
2023 const char *msg = _(" Replace ");
2024 /* try and find from right here for next search */
2025 edit->search_start = edit->curs1;
2026 edit_update_curs_col (edit);
2028 edit->force |= REDRAW_PAGE;
2029 edit_render_keypress (edit);
2030 if (times_replaced) {
2031 message (D_NORMAL, msg, _(" %ld replacements made. "),
2032 times_replaced);
2033 } else
2034 query_dialog (msg, _(" Search string not found "),
2035 D_NORMAL, 1, _("&OK"));
2036 replace_continue = 0;
2038 } while (replace_continue);
2040 edit->force = REDRAW_COMPLETELY;
2041 edit_scroll_screen_over_cursor (edit);
2042 cleanup:
2043 g_free (input1);
2044 g_free (input2);
2045 g_free (input3);
2051 void edit_search_cmd (WEdit * edit, int again)
2053 static char *old = NULL;
2054 char *exp = "";
2056 if (!edit) {
2057 g_free (old);
2058 old = NULL;
2059 return;
2062 exp = old ? old : exp;
2063 if (again) { /*ctrl-hotkey for search again. */
2064 if (!old)
2065 return;
2066 exp = g_strdup (old);
2067 } else {
2069 #ifdef HAVE_CHARSET
2070 if (exp && *exp)
2071 convert_to_display (exp);
2072 #endif /* HAVE_CHARSET */
2074 edit_search_dialog (edit, &exp);
2076 #ifdef HAVE_CHARSET
2077 if (exp && *exp)
2078 convert_from_input (exp);
2079 #endif /* HAVE_CHARSET */
2081 edit_push_action (edit, KEY_PRESS + edit->start_display);
2084 if (exp) {
2085 if (*exp) {
2086 int len = 0;
2087 g_free (old);
2088 old = g_strdup (exp);
2090 if (search_create_bookmark) {
2091 int found = 0, books = 0;
2092 int l = 0, l_last = -1;
2093 long p, q = 0;
2094 for (;;) {
2095 p = edit_find (q, (unsigned char *) exp, &len, edit->last_byte,
2096 edit_get_byte, (void *) edit, 0);
2097 if (p < 0)
2098 break;
2099 found++;
2100 l += edit_count_lines (edit, q, p);
2101 if (l != l_last) {
2102 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
2103 books++;
2105 l_last = l;
2106 q = p + 1;
2108 if (found) {
2109 /* in response to number of bookmarks added because of string being found %d times */
2110 message (D_NORMAL, _("Search"), _(" %d items found, %d bookmarks added "), found, books);
2111 } else {
2112 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2114 } else {
2116 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
2117 edit->search_start--;
2119 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
2120 edit->search_start++;
2122 edit->search_start = edit_find (edit->search_start, (unsigned char *) exp, &len, edit->last_byte,
2123 edit_get_byte, (void *) edit, 0);
2125 if (edit->search_start >= 0) {
2126 edit->found_start = edit->search_start;
2127 edit->found_len = len;
2129 edit_cursor_move (edit, edit->search_start - edit->curs1);
2130 edit_scroll_screen_over_cursor (edit);
2131 if (replace_backwards)
2132 edit->search_start--;
2133 else
2134 edit->search_start++;
2135 } else if (edit->search_start == -3) {
2136 edit->search_start = edit->curs1;
2137 regexp_error (edit);
2138 } else {
2139 edit->search_start = edit->curs1;
2140 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2144 g_free (exp);
2146 edit->force |= REDRAW_COMPLETELY;
2147 edit_scroll_screen_over_cursor (edit);
2152 * Check if it's OK to close the editor. If there are unsaved changes,
2153 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2156 edit_ok_to_exit (WEdit *edit)
2158 if (!edit->modified)
2159 return 1;
2161 switch (edit_query_dialog3
2162 (_("Quit"), _(" File was modified, Save with exit? "),
2163 _("&Cancel quit"), _("&Yes"), _("&No"))) {
2164 case 1:
2165 edit_push_markers (edit);
2166 edit_set_markers (edit, 0, 0, 0, 0);
2167 if (!edit_save_cmd (edit))
2168 return 0;
2169 break;
2170 case 2:
2171 break;
2172 case 0:
2173 case -1:
2174 return 0;
2177 return 1;
2181 #define TEMP_BUF_LEN 1024
2183 /* Return a null terminated length of text. Result must be g_free'd */
2184 static unsigned char *
2185 edit_get_block (WEdit *edit, long start, long finish, int *l)
2187 unsigned char *s, *r;
2188 r = s = g_malloc (finish - start + 1);
2189 if (column_highlighting) {
2190 *l = 0;
2191 /* copy from buffer, excluding chars that are out of the column 'margins' */
2192 while (start < finish) {
2193 int c, x;
2194 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
2195 start);
2196 c = edit_get_byte (edit, start);
2197 if ((x >= edit->column1 && x < edit->column2)
2198 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
2199 *s++ = c;
2200 (*l)++;
2202 start++;
2204 } else {
2205 *l = finish - start;
2206 while (start < finish)
2207 *s++ = edit_get_byte (edit, start++);
2209 *s = 0;
2210 return r;
2213 /* save block, returns 1 on success */
2215 edit_save_block (WEdit * edit, const char *filename, long start,
2216 long finish)
2218 int len, file;
2220 if ((file =
2221 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
2222 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
2223 return 0;
2225 if (column_highlighting) {
2226 unsigned char *block, *p;
2227 int r;
2228 p = block = edit_get_block (edit, start, finish, &len);
2229 while (len) {
2230 r = mc_write (file, p, len);
2231 if (r < 0)
2232 break;
2233 p += r;
2234 len -= r;
2236 g_free (block);
2237 } else {
2238 unsigned char *buf;
2239 int i = start, end;
2240 len = finish - start;
2241 buf = g_malloc (TEMP_BUF_LEN);
2242 while (start != finish) {
2243 end = min (finish, start + TEMP_BUF_LEN);
2244 for (; i < end; i++)
2245 buf[i - start] = edit_get_byte (edit, i);
2246 len -= mc_write (file, (char *) buf, end - start);
2247 start = end;
2249 g_free (buf);
2251 mc_close (file);
2252 if (len)
2253 return 0;
2254 return 1;
2257 /* copies a block to clipboard file */
2258 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
2260 return edit_save_block (edit, catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL), start, finish);
2264 void edit_paste_from_history (WEdit *edit)
2266 (void) edit;
2267 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
2270 int edit_copy_to_X_buf_cmd (WEdit * edit)
2272 long start_mark, end_mark;
2273 if (eval_marks (edit, &start_mark, &end_mark))
2274 return 0;
2275 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2276 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2277 return 1;
2279 edit_mark_cmd (edit, 1);
2280 return 0;
2283 int edit_cut_to_X_buf_cmd (WEdit * edit)
2285 long start_mark, end_mark;
2286 if (eval_marks (edit, &start_mark, &end_mark))
2287 return 0;
2288 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2289 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2290 return 1;
2292 edit_block_delete_cmd (edit);
2293 edit_mark_cmd (edit, 1);
2294 return 0;
2297 void edit_paste_from_X_buf_cmd (WEdit * edit)
2299 edit_insert_file (edit, catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL));
2304 * Ask user for the line and go to that line.
2305 * Negative numbers mean line from the end (i.e. -1 is the last line).
2307 void
2308 edit_goto_cmd (WEdit *edit)
2310 char *f;
2311 static long line = 0; /* line as typed, saved as default */
2312 long l;
2313 char *error;
2314 char s[32];
2316 g_snprintf (s, sizeof (s), "%ld", line);
2317 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
2318 line ? s : "");
2319 if (!f)
2320 return;
2322 if (!*f) {
2323 g_free (f);
2324 return;
2327 l = strtol (f, &error, 0);
2328 if (*error) {
2329 g_free (f);
2330 return;
2333 line = l;
2334 if (l < 0)
2335 l = edit->total_lines + l + 2;
2336 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2337 edit_move_to_line (edit, l - 1);
2338 edit->force |= REDRAW_COMPLETELY;
2339 g_free (f);
2343 /* Return 1 on success */
2345 edit_save_block_cmd (WEdit *edit)
2347 long start_mark, end_mark;
2348 char *exp;
2349 if (eval_marks (edit, &start_mark, &end_mark))
2350 return 1;
2351 exp =
2352 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2353 MC_HISTORY_EDIT_SAVE_BLOCK,
2354 catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL));
2355 edit_push_action (edit, KEY_PRESS + edit->start_display);
2356 if (exp) {
2357 if (!*exp) {
2358 g_free (exp);
2359 return 0;
2360 } else {
2361 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2362 g_free (exp);
2363 edit->force |= REDRAW_COMPLETELY;
2364 return 1;
2365 } else {
2366 g_free (exp);
2367 edit_error_dialog (_(" Save Block "),
2368 get_sys_error (_
2369 (" Cannot save file. ")));
2373 edit->force |= REDRAW_COMPLETELY;
2374 return 0;
2378 /* returns 1 on success */
2380 edit_insert_file_cmd (WEdit *edit)
2382 char *exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2383 MC_HISTORY_EDIT_INSERT_FILE,
2384 catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL));
2385 edit_push_action (edit, KEY_PRESS + edit->start_display);
2386 if (exp) {
2387 if (!*exp) {
2388 g_free (exp);
2389 return 0;
2390 } else {
2391 if (edit_insert_file (edit, exp)) {
2392 g_free (exp);
2393 edit->force |= REDRAW_COMPLETELY;
2394 return 1;
2395 } else {
2396 g_free (exp);
2397 edit_error_dialog (_(" Insert File "),
2398 get_sys_error (_
2399 (" Cannot insert file. ")));
2403 edit->force |= REDRAW_COMPLETELY;
2404 return 0;
2407 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2408 int edit_sort_cmd (WEdit * edit)
2410 static char *old = 0;
2411 char *exp;
2412 long start_mark, end_mark;
2413 int e;
2415 if (eval_marks (edit, &start_mark, &end_mark)) {
2416 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2417 return 0;
2419 edit_save_block (edit, catstrs (home_dir, PATH_SEP_STR BLOCK_FILE, (char *) NULL), start_mark, end_mark);
2421 exp = input_dialog (_(" Run Sort "),
2422 _(" Enter sort options (see manpage) separated by whitespace: "),
2423 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2425 if (!exp)
2426 return 1;
2427 g_free (old);
2428 old = exp;
2430 e = system (catstrs (" sort ", exp, " ", home_dir, PATH_SEP_STR BLOCK_FILE, " > ", home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2431 if (e) {
2432 if (e == -1 || e == 127) {
2433 edit_error_dialog (_(" Sort "),
2434 get_sys_error (_(" Cannot execute sort command ")));
2435 } else {
2436 char q[8];
2437 sprintf (q, "%d ", e);
2438 edit_error_dialog (_(" Sort "),
2439 catstrs (_(" Sort returned non-zero: "), q, (char *) NULL));
2441 return -1;
2444 edit->force |= REDRAW_COMPLETELY;
2446 if (edit_block_delete_cmd (edit))
2447 return 1;
2448 edit_insert_file (edit, catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2449 return 0;
2453 * Ask user for a command, execute it and paste its output back to the
2454 * editor.
2457 edit_ext_cmd (WEdit *edit)
2459 char *exp;
2460 int e;
2462 exp =
2463 input_dialog (_("Paste output of external command"),
2464 _("Enter shell command(s):"),
2465 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2467 if (!exp)
2468 return 1;
2470 e = system (catstrs (exp, " > ", home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2471 g_free (exp);
2473 if (e) {
2474 edit_error_dialog (_("External command"),
2475 get_sys_error (_("Cannot execute command")));
2476 return -1;
2479 edit->force |= REDRAW_COMPLETELY;
2481 edit_insert_file (edit, catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2482 return 0;
2485 /* if block is 1, a block must be highlighted and the shell command
2486 processes it. If block is 0 the shell command is a straight system
2487 command, that just produces some output which is to be inserted */
2488 void
2489 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2491 long start_mark, end_mark;
2492 char buf[BUFSIZ];
2493 FILE *script_home = NULL;
2494 FILE *script_src = NULL;
2495 FILE *block_file = NULL;
2496 const char *o = NULL;
2497 const char *h = NULL;
2498 const char *b = NULL;
2499 char *quoted_name = NULL;
2501 o = catstrs (mc_home, shell_cmd, (char *) NULL); /* original source script */
2502 h = catstrs (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2503 b = catstrs (home_dir, PATH_SEP_STR BLOCK_FILE, (char *) NULL); /* block file */
2505 if (!(script_home = fopen (h, "r"))) {
2506 if (!(script_home = fopen (h, "w"))) {
2507 edit_error_dialog ("", get_sys_error (catstrs
2509 ("Error creating script:"),
2510 h, (char *) NULL)));
2511 return;
2513 if (!(script_src = fopen (o, "r"))) {
2514 fclose (script_home);
2515 unlink (h);
2516 edit_error_dialog ("", get_sys_error (catstrs
2517 (_("Error reading script:"),
2518 o, (char *) NULL)));
2519 return;
2521 while (fgets (buf, sizeof (buf), script_src))
2522 fputs (buf, script_home);
2523 if (fclose (script_home)) {
2524 edit_error_dialog ("", get_sys_error (catstrs
2526 ("Error closing script:"),
2527 h, (char *) NULL)));
2528 return;
2530 chmod (h, 0700);
2531 edit_error_dialog ("", get_sys_error (catstrs
2532 (_("Script created:"), h, (char *) NULL)));
2535 open_error_pipe ();
2537 if (block) { /* for marked block run indent formatter */
2538 if (eval_marks (edit, &start_mark, &end_mark)) {
2539 edit_error_dialog (_("Process block"),
2541 (" You must first highlight a block of text. "));
2542 return;
2544 edit_save_block (edit, b, start_mark, end_mark);
2545 quoted_name = name_quote (edit->filename, 0);
2547 * Run script.
2548 * Initial space is to avoid polluting bash history.
2549 * Arguments:
2550 * $1 - name of the edited file (to check its extension etc).
2551 * $2 - file containing the current block.
2552 * $3 - file where error messages should be put
2553 * (for compatibility with old scripts).
2555 system (catstrs (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2556 " ", home_dir, PATH_SEP_STR BLOCK_FILE " /dev/null", (char *) NULL));
2558 } else {
2560 * No block selected, just execute the command for the file.
2561 * Arguments:
2562 * $1 - name of the edited file.
2564 system (catstrs (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2565 quoted_name, (char *) NULL));
2567 g_free (quoted_name);
2568 close_error_pipe (D_NORMAL, NULL);
2570 edit_refresh_cmd (edit);
2571 edit->force |= REDRAW_COMPLETELY;
2573 /* insert result block */
2574 if (block) {
2575 if (edit_block_delete_cmd (edit))
2576 return;
2577 edit_insert_file (edit, b);
2578 if ((block_file = fopen (b, "w")))
2579 fclose (block_file);
2580 return;
2583 return;
2586 /* prints at the cursor */
2587 /* returns the number of chars printed */
2588 int edit_print_string (WEdit * e, const char *s)
2590 int i = 0;
2591 while (s[i])
2592 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2593 e->force |= REDRAW_COMPLETELY;
2594 edit_update_screen (e);
2595 return i;
2599 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2601 FILE *p = 0;
2602 char *s;
2604 to = name_quote (to, 0);
2605 subject = name_quote (subject, 0);
2606 cc = name_quote (cc, 0);
2607 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2608 g_free (to);
2609 g_free (subject);
2610 g_free (cc);
2612 if (s) {
2613 p = popen (s, "w");
2614 g_free (s);
2617 if (p) {
2618 long i;
2619 for (i = 0; i < edit->last_byte; i++)
2620 fputc (edit_get_byte (edit, i), p);
2621 pclose (p);
2625 #define MAIL_DLG_HEIGHT 12
2627 void edit_mail_dialog (WEdit * edit)
2629 char *tmail_to;
2630 char *tmail_subject;
2631 char *tmail_cc;
2633 static char *mail_cc_last = 0;
2634 static char *mail_subject_last = 0;
2635 static char *mail_to_last = 0;
2637 QuickDialog Quick_input =
2638 {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
2639 "[Input Line Keys]", 0, 0};
2641 QuickWidget quick_widgets[] =
2643 {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
2644 0, NULL},
2645 {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
2646 0, NULL},
2647 {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2648 0, "mail-dlg-input"},
2649 {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
2650 0, 0},
2651 {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2652 0, "mail-dlg-input-2"},
2653 {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
2654 0, 0},
2655 {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2656 0, "mail-dlg-input-3"},
2657 {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
2658 0, 0},
2659 {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2660 0, 0},
2661 NULL_QuickWidget};
2663 quick_widgets[2].str_result = &tmail_cc;
2664 quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
2665 quick_widgets[4].str_result = &tmail_subject;
2666 quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
2667 quick_widgets[6].str_result = &tmail_to;
2668 quick_widgets[6].text = mail_to_last ? mail_to_last : "";
2670 Quick_input.widgets = quick_widgets;
2672 if (quick_dialog (&Quick_input) != B_CANCEL) {
2673 g_free (mail_cc_last);
2674 g_free (mail_subject_last);
2675 g_free (mail_to_last);
2676 mail_cc_last = tmail_cc;
2677 mail_subject_last = tmail_subject;
2678 mail_to_last = tmail_to;
2679 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2684 /*******************/
2685 /* Word Completion */
2686 /*******************/
2689 /* find first character of current word */
2690 static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len)
2692 int i, c, last;
2694 /* return if at begin of file */
2695 if (edit->curs1 <= 0)
2696 return 0;
2698 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2699 /* return if not at end or in word */
2700 if (isspace (c) || !(isalnum (c) || c == '_'))
2701 return 0;
2703 /* search start of word to be completed */
2704 for (i = 2;; i++) {
2705 /* return if at begin of file */
2706 if (edit->curs1 - i < 0)
2707 return 0;
2709 last = c;
2710 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2712 if (!(isalnum (c) || c == '_')) {
2713 /* return if word starts with digit */
2714 if (isdigit (last))
2715 return 0;
2717 *word_start = edit->curs1 - (i - 1); /* start found */
2718 *word_len = i - 1;
2719 break;
2722 /* success */
2723 return 1;
2727 /* (re)set search parameters to the given values */
2728 static void edit_set_search_parameters (int rs, int rb, int rr, int rw, int rc)
2730 replace_scanf = rs;
2731 replace_backwards = rb;
2732 replace_regexp = rr;
2733 replace_whole = rw;
2734 replace_case = rc;
2738 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2740 /* collect the possible completions */
2741 static int
2742 edit_collect_completions (WEdit *edit, long start, int word_len,
2743 char *match_expr, struct selection *compl,
2744 int *num)
2746 int len, max_len = 0, i, skip;
2747 unsigned char *bufpos;
2749 /* collect max MAX_WORD_COMPLETIONS completions */
2750 while (*num < MAX_WORD_COMPLETIONS) {
2751 /* get next match */
2752 start =
2753 edit_find (start - 1, (unsigned char *) match_expr, &len,
2754 edit->last_byte, edit_get_byte, (void *) edit, 0);
2756 /* not matched */
2757 if (start < 0)
2758 break;
2760 /* add matched completion if not yet added */
2761 bufpos =
2762 &edit->
2763 buffers1[start >> S_EDIT_BUF_SIZE][start & M_EDIT_BUF_SIZE];
2764 skip = 0;
2765 for (i = 0; i < *num; i++) {
2766 if (strncmp
2767 ((char *) &compl[i].text[word_len],
2768 (char *) &bufpos[word_len], max (len,
2769 compl[i].len) -
2770 word_len) == 0) {
2771 skip = 1;
2772 break; /* skip it, already added */
2775 if (skip)
2776 continue;
2778 compl[*num].text = g_malloc (len + 1);
2779 compl[*num].len = len;
2780 for (i = 0; i < len; i++)
2781 compl[*num].text[i] = *(bufpos + i);
2782 compl[*num].text[i] = '\0';
2783 (*num)++;
2785 /* note the maximal length needed for the completion dialog */
2786 if (len > max_len)
2787 max_len = len;
2789 return max_len;
2793 /* let the user select its preferred completion */
2794 static void
2795 edit_completion_dialog (WEdit * edit, int max_len, int word_len,
2796 struct selection *compl, int num_compl)
2798 int start_x, start_y, offset, i;
2799 char *curr = NULL;
2800 Dlg_head *compl_dlg;
2801 WListbox *compl_list;
2802 int compl_dlg_h; /* completion dialog height */
2803 int compl_dlg_w; /* completion dialog width */
2805 /* calculate the dialog metrics */
2806 compl_dlg_h = num_compl + 2;
2807 compl_dlg_w = max_len + 4;
2808 start_x = edit->curs_col + edit->start_col - (compl_dlg_w / 2);
2809 start_y = edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + 1;
2811 if (start_x < 0)
2812 start_x = 0;
2813 if (compl_dlg_w > COLS)
2814 compl_dlg_w = COLS;
2815 if (compl_dlg_h > LINES - 2)
2816 compl_dlg_h = LINES - 2;
2818 offset = start_x + compl_dlg_w - COLS;
2819 if (offset > 0)
2820 start_x -= offset;
2821 offset = start_y + compl_dlg_h - LINES;
2822 if (offset > 0)
2823 start_y -= (offset + 1);
2825 /* create the dialog */
2826 compl_dlg =
2827 create_dlg (start_y, start_x, compl_dlg_h, compl_dlg_w,
2828 dialog_colors, NULL, "[Completion]", NULL,
2829 DLG_COMPACT);
2831 /* create the listbox */
2832 compl_list =
2833 listbox_new (1, 1, compl_dlg_w - 2, compl_dlg_h - 2, NULL);
2835 /* add the dialog */
2836 add_widget (compl_dlg, compl_list);
2838 /* fill the listbox with the completions */
2839 for (i = 0; i < num_compl; i++)
2840 listbox_add_item (compl_list, LISTBOX_APPEND_AT_END, 0,
2841 (char *) compl[i].text, NULL);
2843 /* pop up the dialog */
2844 run_dlg (compl_dlg);
2846 /* apply the choosen completion */
2847 if (compl_dlg->ret_value == B_ENTER) {
2848 listbox_get_current (compl_list, &curr, NULL);
2849 if (curr)
2850 for (curr += word_len; *curr; curr++)
2851 edit_insert (edit, *curr);
2854 /* destroy dialog before return */
2855 destroy_dlg (compl_dlg);
2860 * Complete current word using regular expression search
2861 * backwards beginning at the current cursor position.
2863 void
2864 edit_complete_word_cmd (WEdit *edit)
2866 int word_len = 0, i, num_compl = 0, max_len;
2867 long word_start = 0;
2868 unsigned char *bufpos;
2869 char *match_expr;
2870 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2872 /* don't want to disturb another search */
2873 int old_rs = replace_scanf;
2874 int old_rb = replace_backwards;
2875 int old_rr = replace_regexp;
2876 int old_rw = replace_whole;
2877 int old_rc = replace_case;
2879 /* search start of word to be completed */
2880 if (!edit_find_word_start (edit, &word_start, &word_len))
2881 return;
2883 /* prepare match expression */
2884 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2885 [word_start & M_EDIT_BUF_SIZE];
2886 match_expr = g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len, bufpos);
2888 /* init search: backward, regexp, whole word, case sensitive */
2889 edit_set_search_parameters (0, 1, 1, 1, 1);
2891 /* collect the possible completions */
2892 /* start search from curs1 down to begin of file */
2893 max_len =
2894 edit_collect_completions (edit, word_start, word_len, match_expr,
2895 (struct selection *) &compl, &num_compl);
2897 if (num_compl > 0) {
2898 /* insert completed word if there is only one match */
2899 if (num_compl == 1) {
2900 for (i = word_len; i < compl[0].len; i++)
2901 edit_insert (edit, *(compl[0].text + i));
2903 /* more than one possible completion => ask the user */
2904 else {
2905 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2906 /* !!! pressed again the selection dialog pops up, but that !!! */
2907 /* !!! seems to require a further internal state !!! */
2908 /*beep (); */
2910 /* let the user select the preferred completion */
2911 edit_completion_dialog (edit, max_len, word_len,
2912 (struct selection *) &compl,
2913 num_compl);
2917 g_free (match_expr);
2918 /* release memory before return */
2919 for (i = 0; i < num_compl; i++)
2920 g_free (compl[i].text);
2922 /* restore search parameters */
2923 edit_set_search_parameters (old_rs, old_rb, old_rr, old_rw, old_rc);
2926 void
2927 edit_select_codepage_cmd (WEdit *edit)
2929 #ifdef HAVE_CHARSET
2930 do_select_codepage ();
2931 edit->force = REDRAW_COMPLETELY;
2932 edit_refresh_cmd (edit);
2933 #endif
2936 void
2937 edit_insert_literal_cmd (WEdit *edit)
2939 int char_for_insertion =
2940 edit_raw_key_query (_(" Insert Literal "),
2941 _(" Press any key: "), 0);
2942 edit_execute_key_command (edit, -1,
2943 ascii_alpha_to_cntrl (char_for_insertion));
2946 void
2947 edit_execute_macro_cmd (WEdit *edit)
2949 int command =
2950 CK_Macro (edit_raw_key_query
2951 (_(" Execute Macro "), _(" Press macro hotkey: "),
2952 1));
2953 if (command == CK_Macro (0))
2954 command = CK_Insert_Char;
2956 edit_execute_key_command (edit, command, -1);
2959 void
2960 edit_begin_end_macro_cmd(WEdit *edit)
2962 int command;
2964 /* edit is a pointer to the widget */
2965 if (edit) {
2966 command =
2967 edit->macro_i <
2968 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2969 edit_execute_key_command (edit, command, -1);