Removed type SHELL_ESCAPED_STR in favour of plain char*
[midnight-commander.git] / edit / editcmd.c
blob6d3c2ed503dbd481f1f7a3999155ce25eb65c867
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 <mhl/memory.h>
42 #include <mhl/string.h>
44 #include "../src/global.h"
45 #include "../src/history.h"
47 #include "edit.h"
48 #include "editlock.h"
49 #include "editcmddef.h"
50 #include "edit-widget.h"
52 #include "../src/color.h" /* dialog_colors */
53 #include "../src/tty.h" /* LINES */
54 #include "../src/widget.h" /* listbox_new() */
55 #include "../src/layout.h" /* clr_scr() */
56 #include "../src/main.h" /* mc_home */
57 #include "../src/help.h" /* interactive_display() */
58 #include "../src/key.h" /* XCTRL */
59 #include "../src/dialog.h" /* do_refresh() */
60 #include "../src/wtools.h" /* message() */
61 #include "../src/charsets.h"
62 #include "../src/selcodepage.h"
64 struct selection {
65 unsigned char * text;
66 int len;
69 /* globals: */
71 /* search and replace: */
72 static int replace_scanf = 0;
73 static int replace_regexp = 0;
74 static int replace_all = 0;
75 static int replace_prompt = 1;
76 static int replace_whole = 0;
77 static int replace_case = 0;
78 static int replace_backwards = 0;
79 static int search_create_bookmark = 0;
81 /* queries on a save */
82 int edit_confirm_save = 1;
84 #define NUM_REPL_ARGS 64
85 #define MAX_REPL_LEN 1024
87 static int edit_save_cmd (WEdit *edit);
88 static unsigned char *edit_get_block (WEdit *edit, long start,
89 long finish, int *l);
91 static inline int my_lower_case (int c)
93 return tolower(c & 0xFF);
96 static const char *
97 strcasechr (const char *s, int c)
99 for (c = my_lower_case (c); my_lower_case ((int) *s) != c; ++s)
100 if (*s == '\0')
101 return 0;
102 return s;
105 /* #define itoa MY_itoa <---- this line is now in edit.h */
106 static char *
107 MY_itoa (int i)
109 static char t[14];
110 char *s = t + 13;
111 int j = i;
112 *s-- = 0;
113 do {
114 *s-- = i % 10 + '0';
115 } while ((i = i / 10));
116 if (j < 0)
117 *s-- = '-';
118 return ++s;
121 /* Temporary strings */
122 static char *stacked[16];
125 This joins strings end on end and allocates memory for the result.
126 The result is later automatically free'd and must not be free'd
127 by the caller.
129 static const char *
130 catstrs (const char *first,...)
132 static int i = 0;
133 va_list ap;
134 int len;
135 char *data;
137 if (!first)
138 return 0;
140 len = strlen (first);
141 va_start (ap, first);
143 while ((data = va_arg (ap, char *)) != 0)
144 len += strlen (data);
146 len++;
148 i = (i + 1) % 16;
149 g_free (stacked[i]);
151 stacked[i] = g_malloc (len);
152 va_end (ap);
153 va_start (ap, first);
154 strcpy (stacked[i], first);
155 while ((data = va_arg (ap, char *)) != 0)
156 strcat (stacked[i], data);
157 va_end (ap);
159 return stacked[i];
162 /* Free temporary strings */
163 void freestrs(void)
165 size_t i;
167 for (i = 0; i < sizeof(stacked) / sizeof(stacked[0]); i++) {
168 g_free (stacked[i]);
169 stacked[i] = NULL;
173 void edit_help_cmd (WEdit * edit)
175 interactive_display (NULL, "[Internal File Editor]");
176 edit->force |= REDRAW_COMPLETELY;
179 void edit_refresh_cmd (WEdit * edit)
181 #ifndef HAVE_SLANG
182 clr_scr();
183 do_refresh();
184 #else
186 int color;
187 edit_get_syntax_color (edit, -1, &color);
189 touchwin(stdscr);
190 #endif /* !HAVE_SLANG */
191 mc_refresh();
192 doupdate();
195 /* If 0 (quick save) then a) create/truncate <filename> file,
196 b) save to <filename>;
197 if 1 (safe save) then a) save to <tempnam>,
198 b) rename <tempnam> to <filename>;
199 if 2 (do backups) then a) save to <tempnam>,
200 b) rename <filename> to <filename.backup_ext>,
201 c) rename <tempnam> to <filename>. */
203 /* returns 0 on error, -1 on abort */
204 static int
205 edit_save_file (WEdit *edit, const char *filename)
207 char *p;
208 long filelen = 0;
209 char *savename = 0;
210 int this_save_mode, fd = -1;
212 if (!filename)
213 return 0;
214 if (!*filename)
215 return 0;
217 if (*filename != PATH_SEP && edit->dir) {
218 savename = mhl_str_dir_plus_file (edit->dir, filename);
219 filename = catstrs (savename, (char *) NULL);
220 g_free (savename);
223 this_save_mode = option_save_mode;
224 if (this_save_mode != EDIT_QUICK_SAVE) {
225 if (!vfs_file_is_local (filename) ||
226 (fd = mc_open (filename, O_RDONLY | O_BINARY)) == -1) {
228 * The file does not exists yet, so no safe save or
229 * backup are necessary.
231 this_save_mode = EDIT_QUICK_SAVE;
233 if (fd != -1)
234 mc_close (fd);
237 if (this_save_mode == EDIT_QUICK_SAVE &&
238 !edit->skip_detach_prompt) {
239 int rv;
240 struct stat sb;
242 rv = mc_stat (filename, &sb);
243 if (rv == 0 && sb.st_nlink > 1) {
244 rv = edit_query_dialog3 (_("Warning"),
245 _(" File has hard-links. Detach before saving? "),
246 _("&Yes"), _("&No"), _("&Cancel"));
247 switch (rv) {
248 case 0:
249 this_save_mode = EDIT_SAFE_SAVE;
250 /* fallthrough */
251 case 1:
252 edit->skip_detach_prompt = 1;
253 break;
254 default:
255 return -1;
259 /* Prevent overwriting changes from other editor sessions. */
260 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
262 /* The default action is "Cancel". */
263 query_set_sel(1);
265 rv = edit_query_dialog2 (
266 _("Warning"),
267 _("The file has been modified in the meantime. Save anyway?"),
268 _("&Yes"),
269 _("&Cancel"));
270 if (rv != 0)
271 return -1;
275 if (this_save_mode != EDIT_QUICK_SAVE) {
276 char *savedir, *saveprefix;
277 const char *slashpos;
278 slashpos = strrchr (filename, PATH_SEP);
279 if (slashpos) {
280 savedir = mhl_str_dup (filename);
281 savedir[slashpos - filename + 1] = '\0';
282 } else
283 savedir = mhl_str_dup (".");
284 saveprefix = mhl_str_dir_plus_file (savedir, "cooledit");
285 g_free (savedir);
286 fd = mc_mkstemps (&savename, saveprefix, NULL);
287 g_free (saveprefix);
288 if (!savename)
289 return 0;
290 /* FIXME:
291 * Close for now because mc_mkstemps use pure open system call
292 * to create temporary file and it needs to be reopened by
293 * VFS-aware mc_open().
295 close (fd);
296 } else
297 savename = g_strdup (filename);
299 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
300 mc_chmod (savename, edit->stat1.st_mode);
302 if ((fd =
303 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
304 edit->stat1.st_mode)) == -1)
305 goto error_save;
307 /* pipe save */
308 if ((p = edit_get_write_filter (savename, filename))) {
309 FILE *file;
311 mc_close (fd);
312 file = (FILE *) popen (p, "w");
314 if (file) {
315 filelen = edit_write_stream (edit, file);
316 #if 1
317 pclose (file);
318 #else
319 if (pclose (file) != 0) {
320 edit_error_dialog (_("Error"),
321 catstrs (_(" Error writing to pipe: "),
322 p, " ", (char *) NULL));
323 g_free (p);
324 goto error_save;
326 #endif
327 } else {
328 edit_error_dialog (_("Error"),
329 get_sys_error (catstrs
331 (" Cannot open pipe for writing: "),
332 p, " ", (char *) NULL)));
333 g_free (p);
334 goto error_save;
336 g_free (p);
337 } else {
338 long buf;
339 buf = 0;
340 filelen = edit->last_byte;
341 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
342 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
343 != EDIT_BUF_SIZE) {
344 mc_close (fd);
345 goto error_save;
347 buf++;
349 if (mc_write
350 (fd, (char *) edit->buffers1[buf],
351 edit->curs1 & M_EDIT_BUF_SIZE) !=
352 (edit->curs1 & M_EDIT_BUF_SIZE)) {
353 filelen = -1;
354 } else if (edit->curs2) {
355 edit->curs2--;
356 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
357 if (mc_write
358 (fd,
359 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
360 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
361 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
362 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
363 filelen = -1;
364 } else {
365 while (--buf >= 0) {
366 if (mc_write
367 (fd, (char *) edit->buffers2[buf],
368 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
369 filelen = -1;
370 break;
374 edit->curs2++;
376 if (mc_close (fd))
377 goto error_save;
379 /* Update the file information, especially the mtime. */
380 if (mc_stat (savename, &edit->stat1) == -1)
381 goto error_save;
384 if (filelen != edit->last_byte)
385 goto error_save;
387 if (this_save_mode == EDIT_DO_BACKUP) {
388 assert (option_backup_ext != NULL);
389 if (mc_rename (filename, catstrs (filename, option_backup_ext,
390 (char *) NULL)) == -1)
391 goto error_save;
394 if (this_save_mode != EDIT_QUICK_SAVE)
395 if (mc_rename (savename, filename) == -1)
396 goto error_save;
397 g_free (savename);
398 return 1;
399 error_save:
400 /* FIXME: Is this safe ?
401 * if (this_save_mode != EDIT_QUICK_SAVE)
402 * mc_unlink (savename);
404 g_free (savename);
405 return 0;
408 void menu_save_mode_cmd (void)
410 #define DLG_X 38
411 #define DLG_Y 10
412 static char *str_result;
413 static int save_mode_new;
414 static const char *str[] =
416 N_("Quick save "),
417 N_("Safe save "),
418 N_("Do backups -->")};
419 static QuickWidget widgets[] =
421 {quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
422 B_CANCEL, 0, 0, NULL},
423 {quick_button, 6, DLG_X, 7, DLG_Y, N_("&OK"), 0,
424 B_ENTER, 0, 0, NULL},
425 {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
426 0, 0, &str_result, "edit-backup-ext"},
427 {quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
428 0, 0, 0, NULL},
429 {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
430 0, &save_mode_new, (char **) str, NULL},
431 NULL_QuickWidget};
432 static QuickDialog dialog =
433 {DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
434 widgets, 0};
435 static int i18n_flag = 0;
437 if (!i18n_flag) {
438 size_t i;
439 size_t maxlen = 0;
440 int dlg_x;
441 size_t l1;
443 /* OK/Cancel buttons */
444 l1 = strlen (_(widgets[0].text)) + strlen (_(widgets[1].text)) + 5;
445 maxlen = max (maxlen, l1);
447 for (i = 0; i < 3; i++ ) {
448 str[i] = _(str[i]);
449 maxlen = max (maxlen, strlen (str[i]) + 7);
451 i18n_flag = 1;
453 dlg_x = maxlen + strlen (_(widgets[3].text)) + 5 + 1;
454 widgets[2].hotkey_pos = strlen (_(widgets[3].text)); /* input field length */
455 dlg_x = min (COLS, dlg_x);
456 dialog.xlen = dlg_x;
458 i = (dlg_x - l1)/3;
459 widgets[1].relative_x = i;
460 widgets[0].relative_x = i + strlen (_(widgets[1].text)) + i + 4;
462 widgets[2].relative_x = widgets[3].relative_x = maxlen + 2;
464 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
465 widgets[i].x_divisions = dlg_x;
468 assert (option_backup_ext != NULL);
469 widgets[2].text = option_backup_ext;
470 widgets[4].value = option_save_mode;
471 if (quick_dialog (&dialog) != B_ENTER)
472 return;
473 option_save_mode = save_mode_new;
475 g_free (option_backup_ext);
476 option_backup_ext = str_result;
477 str_result = NULL;
480 void
481 edit_set_filename (WEdit *edit, const char *f)
483 g_free (edit->filename);
484 if (!f)
485 f = "";
486 edit->filename = g_strdup (f);
487 if (edit->dir == NULL && *f != PATH_SEP)
488 #ifdef USE_VFS
489 edit->dir = g_strdup (vfs_get_current_dir ());
490 #else
491 edit->dir = g_get_current_dir ();
492 #endif
495 /* Here we want to warn the users of overwriting an existing file,
496 but only if they have made a change to the filename */
497 /* returns 1 on success */
499 edit_save_as_cmd (WEdit *edit)
501 /* This heads the 'Save As' dialog box */
502 char *exp;
503 int save_lock = 0;
504 int different_filename = 0;
506 exp = input_expand_dialog (
507 _(" Save As "), _(" Enter file name: "),MC_HISTORY_EDIT_SAVE_AS, edit->filename);
508 edit_push_action (edit, KEY_PRESS + edit->start_display);
510 if (exp) {
511 if (!*exp) {
512 g_free (exp);
513 edit->force |= REDRAW_COMPLETELY;
514 return 0;
515 } else {
516 int rv;
517 if (strcmp (edit->filename, exp)) {
518 int file;
519 different_filename = 1;
520 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
521 /* the file exists */
522 mc_close (file);
523 /* Overwrite the current file or cancel the operation */
524 if (edit_query_dialog2
525 (_("Warning"),
526 _(" A file already exists with this name. "),
527 _("&Overwrite"), _("&Cancel"))) {
528 edit->force |= REDRAW_COMPLETELY;
529 g_free (exp);
530 return 0;
533 save_lock = edit_lock_file (exp);
534 } else {
535 /* filenames equal, check if already locked */
536 if (!edit->locked && !edit->delete_file)
537 save_lock = edit_lock_file (exp);
540 rv = edit_save_file (edit, exp);
541 switch (rv) {
542 case 1:
543 /* Succesful, so unlock both files */
544 if (different_filename) {
545 if (save_lock)
546 edit_unlock_file (exp);
547 if (edit->locked)
548 edit->locked = edit_unlock_file (edit->filename);
549 } else {
550 if (edit->locked || save_lock)
551 edit->locked = edit_unlock_file (edit->filename);
554 edit_set_filename (edit, exp);
555 g_free (exp);
556 edit->modified = 0;
557 edit->delete_file = 0;
558 if (different_filename)
559 edit_load_syntax (edit, NULL, option_syntax_type);
560 edit->force |= REDRAW_COMPLETELY;
561 return 1;
562 default:
563 edit_error_dialog (_(" Save As "),
564 get_sys_error (_
565 (" Cannot save file. ")));
566 /* fallthrough */
567 case -1:
568 /* Failed, so maintain modify (not save) lock */
569 if (save_lock)
570 edit_unlock_file (exp);
571 g_free (exp);
572 edit->force |= REDRAW_COMPLETELY;
573 return 0;
577 edit->force |= REDRAW_COMPLETELY;
578 return 0;
581 /* {{{ Macro stuff starts here */
583 static cb_ret_t
584 raw_callback (struct Dlg_head *h, dlg_msg_t msg, int parm)
586 switch (msg) {
587 case DLG_KEY:
588 h->running = 0;
589 h->ret_value = parm;
590 return MSG_HANDLED;
591 default:
592 return default_dlg_callback (h, msg, parm);
596 /* gets a raw key from the keyboard. Passing cancel = 1 draws
597 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
598 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
599 and Esc are cannot returned */
601 edit_raw_key_query (const char *heading, const char *query, int cancel)
603 int w = strlen (query) + 7;
604 struct Dlg_head *raw_dlg =
605 create_dlg (0, 0, 7, w, dialog_colors, raw_callback,
606 NULL, heading,
607 DLG_CENTER | DLG_TRYUP | DLG_WANT_TAB);
608 add_widget (raw_dlg,
609 input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0, INPUT_COMPLETE_DEFAULT));
610 add_widget (raw_dlg, label_new (3 - cancel, 2, query));
611 if (cancel)
612 add_widget (raw_dlg,
613 button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON,
614 _("Cancel"), 0));
615 run_dlg (raw_dlg);
616 w = raw_dlg->ret_value;
617 destroy_dlg (raw_dlg);
618 if (cancel) {
619 if (w == XCTRL ('g') || w == XCTRL ('c') || w == ESC_CHAR
620 || w == B_CANCEL)
621 return 0;
624 return w;
627 /* creates a macro file if it doesn't exist */
628 static FILE *edit_open_macro_file (const char *r)
630 const char *filename;
631 int file;
632 filename = catstrs (home_dir, PATH_SEP_STR MACRO_FILE, (char *) NULL);
633 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
634 return 0;
635 close (file);
636 return fopen (filename, r);
639 #define MAX_MACROS 1024
640 static int saved_macro[MAX_MACROS + 1];
641 static int saved_macros_loaded = 0;
644 This is just to stop the macro file be loaded over and over for keys
645 that aren't defined to anything. On slow systems this could be annoying.
647 static int
648 macro_exists (int k)
650 int i;
651 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
652 if (saved_macro[i] == k)
653 return i;
654 return -1;
657 /* returns 1 on error */
658 static int
659 edit_delete_macro (WEdit * edit, int k)
661 struct macro macro[MAX_MACRO_LENGTH];
662 FILE *f, *g;
663 int s, i, n, j = 0;
665 (void) edit;
667 if (saved_macros_loaded)
668 if ((j = macro_exists (k)) < 0)
669 return 0;
670 g = fopen (catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL), "w");
671 if (!g) {
672 edit_error_dialog (_(" Delete macro "),
673 get_sys_error (_(" Cannot open temp file ")));
674 return 1;
676 f = edit_open_macro_file ("r");
677 if (!f) {
678 edit_error_dialog (_(" Delete macro "),
679 get_sys_error (_(" Cannot open macro file ")));
680 fclose (g);
681 return 1;
683 for (;;) {
684 n = fscanf (f, ("key '%d 0': "), &s);
685 if (!n || n == EOF)
686 break;
687 n = 0;
688 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
689 n++;
690 fscanf (f, ";\n");
691 if (s != k) {
692 fprintf (g, ("key '%d 0': "), s);
693 for (i = 0; i < n; i++)
694 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
695 fprintf (g, ";\n");
698 fclose (f);
699 fclose (g);
700 if (rename (catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL), catstrs (home_dir, PATH_SEP_STR MACRO_FILE, (char *) NULL)) == -1) {
701 edit_error_dialog (_(" Delete macro "),
702 get_sys_error (_(" Cannot overwrite macro file ")));
703 return 1;
705 if (saved_macros_loaded)
706 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
707 return 0;
710 /* returns 0 on error */
711 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
713 FILE *f;
714 int s, i;
716 edit_push_action (edit, KEY_PRESS + edit->start_display);
717 s = edit_raw_key_query (_(" Save macro "),
718 _(" Press the macro's new hotkey: "), 1);
719 edit->force |= REDRAW_COMPLETELY;
720 if (s) {
721 if (edit_delete_macro (edit, s))
722 return 0;
723 f = edit_open_macro_file ("a+");
724 if (f) {
725 fprintf (f, ("key '%d 0': "), s);
726 for (i = 0; i < n; i++)
727 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
728 fprintf (f, ";\n");
729 fclose (f);
730 if (saved_macros_loaded) {
731 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
732 saved_macro[i] = s;
734 return 1;
735 } else
736 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
738 return 0;
741 void edit_delete_macro_cmd (WEdit * edit)
743 int command;
745 command = edit_raw_key_query (_ (" Delete macro "),
746 _ (" Press macro hotkey: "), 1);
748 if (!command)
749 return;
751 edit_delete_macro (edit, command);
754 /* return 0 on error */
755 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
757 FILE *f;
758 int s, i = 0, found = 0;
760 (void) edit;
762 if (saved_macros_loaded)
763 if (macro_exists (k) < 0)
764 return 0;
766 if ((f = edit_open_macro_file ("r"))) {
767 struct macro dummy;
768 do {
769 int u;
770 u = fscanf (f, ("key '%d 0': "), &s);
771 if (!u || u == EOF)
772 break;
773 if (!saved_macros_loaded)
774 saved_macro[i++] = s;
775 if (!found) {
776 *n = 0;
777 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
778 (*n)++;
779 } else {
780 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
782 fscanf (f, ";\n");
783 if (s == k)
784 found = 1;
785 } while (!found || !saved_macros_loaded);
786 if (!saved_macros_loaded) {
787 saved_macro[i] = 0;
788 saved_macros_loaded = 1;
790 fclose (f);
791 return found;
792 } else
793 edit_error_dialog (_(" Load macro "),
794 get_sys_error (_(" Cannot open macro file ")));
795 return 0;
798 /* }}} Macro stuff starts here */
800 /* returns 1 on success */
801 int edit_save_confirm_cmd (WEdit * edit)
803 const char *f;
805 if (edit_confirm_save) {
806 f = catstrs (_(" Confirm save file? : "), edit->filename, " ", (char *) NULL);
807 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel")))
808 return 0;
810 return edit_save_cmd (edit);
814 /* returns 1 on success */
815 static int
816 edit_save_cmd (WEdit *edit)
818 int res, save_lock = 0;
820 if (!edit->locked && !edit->delete_file)
821 save_lock = edit_lock_file (edit->filename);
822 res = edit_save_file (edit, edit->filename);
824 /* Maintain modify (not save) lock on failure */
825 if ((res > 0 && edit->locked) || save_lock)
826 edit->locked = edit_unlock_file (edit->filename);
828 /* On failure try 'save as', it does locking on its own */
829 if (!res)
830 return edit_save_as_cmd (edit);
831 edit->force |= REDRAW_COMPLETELY;
832 if (res > 0) {
833 edit->delete_file = 0;
834 edit->modified = 0;
837 return 1;
841 /* returns 1 on success */
842 int edit_new_cmd (WEdit * edit)
844 if (edit->modified) {
845 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
846 edit->force |= REDRAW_COMPLETELY;
847 return 0;
850 edit->force |= REDRAW_COMPLETELY;
852 return edit_renew (edit); /* if this gives an error, something has really screwed up */
855 /* returns 1 on error */
856 static int
857 edit_load_file_from_filename (WEdit * edit, char *exp)
859 int prev_locked = edit->locked;
860 char *prev_filename = g_strdup (edit->filename);
862 if (!edit_reload (edit, exp)) {
863 g_free (prev_filename);
864 return 1;
867 if (prev_locked)
868 edit_unlock_file (prev_filename);
869 g_free (prev_filename);
870 return 0;
874 edit_load_cmd (WEdit *edit)
876 char *exp;
878 if (edit->modified) {
879 if (edit_query_dialog2
880 (_("Warning"),
881 _(" Current text was modified without a file save. \n"
882 " Continue discards these changes. "), _("C&ontinue"),
883 _("&Cancel"))) {
884 edit->force |= REDRAW_COMPLETELY;
885 return 0;
889 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
890 MC_HISTORY_EDIT_LOAD, edit->filename);
892 if (exp) {
893 if (*exp)
894 edit_load_file_from_filename (edit, exp);
895 g_free (exp);
897 edit->force |= REDRAW_COMPLETELY;
898 return 0;
902 if mark2 is -1 then marking is from mark1 to the cursor.
903 Otherwise its between the markers. This handles this.
904 Returns 1 if no text is marked.
906 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
908 if (edit->mark1 != edit->mark2) {
909 if (edit->mark2 >= 0) {
910 *start_mark = min (edit->mark1, edit->mark2);
911 *end_mark = max (edit->mark1, edit->mark2);
912 } else {
913 *start_mark = min (edit->mark1, edit->curs1);
914 *end_mark = max (edit->mark1, edit->curs1);
915 edit->column2 = edit->curs_col;
917 return 0;
918 } else {
919 *start_mark = *end_mark = 0;
920 edit->column2 = edit->column1 = 0;
921 return 1;
925 #define space_width 1
927 static void
928 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
930 long cursor;
931 int i, col;
932 cursor = edit->curs1;
933 col = edit_get_col (edit);
934 for (i = 0; i < size; i++) {
935 if (data[i] == '\n') { /* fill in and move to next line */
936 int l;
937 long p;
938 if (edit_get_byte (edit, edit->curs1) != '\n') {
939 l = width - (edit_get_col (edit) - col);
940 while (l > 0) {
941 edit_insert (edit, ' ');
942 l -= space_width;
945 for (p = edit->curs1;; p++) {
946 if (p == edit->last_byte) {
947 edit_cursor_move (edit, edit->last_byte - edit->curs1);
948 edit_insert_ahead (edit, '\n');
949 p++;
950 break;
952 if (edit_get_byte (edit, p) == '\n') {
953 p++;
954 break;
957 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
958 l = col - edit_get_col (edit);
959 while (l >= space_width) {
960 edit_insert (edit, ' ');
961 l -= space_width;
963 continue;
965 edit_insert (edit, data[i]);
967 edit_cursor_move (edit, cursor - edit->curs1);
971 void
972 edit_block_copy_cmd (WEdit *edit)
974 long start_mark, end_mark, current = edit->curs1;
975 int size;
976 unsigned char *copy_buf;
978 edit_update_curs_col (edit);
979 if (eval_marks (edit, &start_mark, &end_mark))
980 return;
982 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
984 /* all that gets pushed are deletes hence little space is used on the stack */
986 edit_push_markers (edit);
988 if (column_highlighting) {
989 edit_insert_column_of_text (edit, copy_buf, size,
990 abs (edit->column2 - edit->column1));
991 } else {
992 while (size--)
993 edit_insert_ahead (edit, copy_buf[size]);
996 g_free (copy_buf);
997 edit_scroll_screen_over_cursor (edit);
999 if (column_highlighting) {
1000 edit_set_markers (edit, 0, 0, 0, 0);
1001 edit_push_action (edit, COLUMN_ON);
1002 column_highlighting = 0;
1003 } else if (start_mark < current && end_mark > current)
1004 edit_set_markers (edit, start_mark,
1005 end_mark + end_mark - start_mark, 0, 0);
1007 edit->force |= REDRAW_PAGE;
1011 void
1012 edit_block_move_cmd (WEdit *edit)
1014 long count;
1015 long current;
1016 unsigned char *copy_buf;
1017 long start_mark, end_mark;
1018 int deleted = 0;
1019 int x = 0;
1021 if (eval_marks (edit, &start_mark, &end_mark))
1022 return;
1023 if (column_highlighting) {
1024 edit_update_curs_col (edit);
1025 x = edit->curs_col;
1026 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1027 if ((x > edit->column1 && x < edit->column2)
1028 || (x > edit->column2 && x < edit->column1))
1029 return;
1030 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1031 return;
1033 if ((end_mark - start_mark) > option_max_undo / 2)
1034 if (edit_query_dialog2
1035 (_("Warning"),
1037 (" Block is large, you may not be able to undo this action. "),
1038 _("C&ontinue"), _("&Cancel")))
1039 return;
1041 edit_push_markers (edit);
1042 current = edit->curs1;
1043 if (column_highlighting) {
1044 int size, c1, c2, line;
1045 line = edit->curs_line;
1046 if (edit->mark2 < 0)
1047 edit_mark_cmd (edit, 0);
1048 c1 = min (edit->column1, edit->column2);
1049 c2 = max (edit->column1, edit->column2);
1050 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1051 if (x < c2) {
1052 edit_block_delete_cmd (edit);
1053 deleted = 1;
1055 edit_move_to_line (edit, line);
1056 edit_cursor_move (edit,
1057 edit_move_forward3 (edit,
1058 edit_bol (edit, edit->curs1),
1059 x, 0) - edit->curs1);
1060 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1061 if (!deleted) {
1062 line = edit->curs_line;
1063 edit_update_curs_col (edit);
1064 x = edit->curs_col;
1065 edit_block_delete_cmd (edit);
1066 edit_move_to_line (edit, line);
1067 edit_cursor_move (edit,
1068 edit_move_forward3 (edit,
1069 edit_bol (edit,
1070 edit->curs1),
1071 x, 0) - edit->curs1);
1073 edit_set_markers (edit, 0, 0, 0, 0);
1074 edit_push_action (edit, COLUMN_ON);
1075 column_highlighting = 0;
1076 } else {
1077 copy_buf = g_malloc (end_mark - start_mark);
1078 edit_cursor_move (edit, start_mark - edit->curs1);
1079 edit_scroll_screen_over_cursor (edit);
1080 count = start_mark;
1081 while (count < end_mark) {
1082 copy_buf[end_mark - count - 1] = edit_delete (edit);
1083 count++;
1085 edit_scroll_screen_over_cursor (edit);
1086 edit_cursor_move (edit,
1087 current - edit->curs1 -
1088 (((current - edit->curs1) >
1089 0) ? end_mark - start_mark : 0));
1090 edit_scroll_screen_over_cursor (edit);
1091 while (count-- > start_mark)
1092 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1093 edit_set_markers (edit, edit->curs1,
1094 edit->curs1 + end_mark - start_mark, 0, 0);
1096 edit_scroll_screen_over_cursor (edit);
1097 g_free (copy_buf);
1098 edit->force |= REDRAW_PAGE;
1101 static void
1102 edit_delete_column_of_text (WEdit * edit)
1104 long p, q, r, m1, m2;
1105 int b, c, d;
1106 int n;
1108 eval_marks (edit, &m1, &m2);
1109 n = edit_move_forward (edit, m1, 0, m2) + 1;
1110 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1111 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1113 b = min (c, d);
1114 c = max (c, d);
1116 while (n--) {
1117 r = edit_bol (edit, edit->curs1);
1118 p = edit_move_forward3 (edit, r, b, 0);
1119 q = edit_move_forward3 (edit, r, c, 0);
1120 if (p < m1)
1121 p = m1;
1122 if (q > m2)
1123 q = m2;
1124 edit_cursor_move (edit, p - edit->curs1);
1125 while (q > p) { /* delete line between margins */
1126 if (edit_get_byte (edit, edit->curs1) != '\n')
1127 edit_delete (edit);
1128 q--;
1130 if (n) /* move to next line except on the last delete */
1131 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1135 /* if success return 0 */
1136 static int
1137 edit_block_delete (WEdit *edit)
1139 long count;
1140 long start_mark, end_mark;
1141 if (eval_marks (edit, &start_mark, &end_mark))
1142 return 0;
1143 if (column_highlighting && edit->mark2 < 0)
1144 edit_mark_cmd (edit, 0);
1145 if ((end_mark - start_mark) > option_max_undo / 2) {
1146 /* Warning message with a query to continue or cancel the operation */
1147 if (edit_query_dialog2
1148 (_("Warning"),
1150 (" Block is large, you may not be able to undo this action. "),
1151 _("C&ontinue"), _("&Cancel"))) {
1152 return 1;
1155 edit_push_markers (edit);
1156 edit_cursor_move (edit, start_mark - edit->curs1);
1157 edit_scroll_screen_over_cursor (edit);
1158 count = start_mark;
1159 if (start_mark < end_mark) {
1160 if (column_highlighting) {
1161 if (edit->mark2 < 0)
1162 edit_mark_cmd (edit, 0);
1163 edit_delete_column_of_text (edit);
1164 } else {
1165 while (count < end_mark) {
1166 edit_delete (edit);
1167 count++;
1171 edit_set_markers (edit, 0, 0, 0, 0);
1172 edit->force |= REDRAW_PAGE;
1173 return 0;
1176 /* returns 1 if canceelled by user */
1177 int edit_block_delete_cmd (WEdit * edit)
1179 long start_mark, end_mark;
1180 if (eval_marks (edit, &start_mark, &end_mark)) {
1181 edit_delete_line (edit);
1182 return 0;
1184 return edit_block_delete (edit);
1188 #define INPUT_INDEX 9
1189 #define SEARCH_DLG_WIDTH 58
1190 #define SEARCH_DLG_HEIGHT 10
1191 #define REPLACE_DLG_WIDTH 58
1192 #define REPLACE_DLG_HEIGHT 15
1193 #define CONFIRM_DLG_WIDTH 79
1194 #define CONFIRM_DLG_HEIGTH 6
1195 #define B_REPLACE_ALL (B_USER+1)
1196 #define B_REPLACE_ONE (B_USER+2)
1197 #define B_SKIP_REPLACE (B_USER+3)
1199 static int
1200 edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
1202 QuickWidget quick_widgets[] =
1204 {quick_button, 63, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Cancel"),
1205 0, B_CANCEL, 0, 0, NULL},
1206 {quick_button, 50, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("O&ne"),
1207 0, B_REPLACE_ONE, 0, 0, NULL},
1208 {quick_button, 37, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("A&ll"),
1209 0, B_REPLACE_ALL, 0, 0, NULL},
1210 {quick_button, 21, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Skip"),
1211 0, B_SKIP_REPLACE, 0, 0, NULL},
1212 {quick_button, 4, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Replace"),
1213 0, B_ENTER, 0, 0, NULL},
1214 {quick_label, 2, CONFIRM_DLG_WIDTH, 2, CONFIRM_DLG_HEIGTH, 0,
1215 0, 0, 0, 0, 0},
1216 NULL_QuickWidget};
1218 GString *label_text = g_string_new (_(" Replace with: "));
1219 if (*replace_text) {
1220 size_t label_len;
1221 label_len = label_text->len;
1222 g_string_append (label_text, replace_text);
1223 convert_to_display (label_text->str + label_len);
1225 quick_widgets[5].text = label_text->str;
1228 int retval;
1229 QuickDialog Quick_input =
1230 {CONFIRM_DLG_WIDTH, CONFIRM_DLG_HEIGTH, 0, 0, N_ (" Confirm replace "),
1231 "[Input Line Keys]", 0 /*quick_widgets */, 0 };
1233 Quick_input.widgets = quick_widgets;
1235 Quick_input.xpos = xpos;
1237 /* Sometimes menu can hide replaced text. I don't like it */
1239 if ((edit->curs_row >= ypos - 1) && (edit->curs_row <= ypos + CONFIRM_DLG_HEIGTH - 1))
1240 ypos -= CONFIRM_DLG_HEIGTH;
1242 Quick_input.ypos = ypos;
1243 retval = quick_dialog (&Quick_input);
1244 g_string_free (label_text, TRUE);
1245 return retval;
1249 static void
1250 edit_replace_dialog (WEdit * edit, const char *search_default,
1251 const char *replace_default, const char *argorder_default,
1252 /*@out@*/ char **search_text, /*@out@*/ char **replace_text,
1253 /*@out@*/ char **arg_order)
1255 int treplace_scanf = replace_scanf;
1256 int treplace_regexp = replace_regexp;
1257 int treplace_all = replace_all;
1258 int treplace_prompt = replace_prompt;
1259 int treplace_backwards = replace_backwards;
1260 int treplace_whole = replace_whole;
1261 int treplace_case = replace_case;
1263 /* Alt-p is in use as hotkey for previous entry; don't use */
1264 QuickWidget quick_widgets[] =
1266 {quick_button, 6, 10, 12, REPLACE_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1267 0, NULL},
1268 {quick_button, 2, 10, 12, REPLACE_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
1269 0, NULL},
1270 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1271 0, 0, NULL},
1272 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("replace &All"), 0, 0,
1273 0, 0, NULL},
1274 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("pro&Mpt on replace"), 0, 0,
1275 0, 0, NULL},
1276 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1277 0, 0, NULL},
1278 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1279 0, 0, NULL},
1280 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1281 0, 0, NULL},
1282 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 8, REPLACE_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1283 0, 0, NULL},
1284 {quick_input, 3, REPLACE_DLG_WIDTH, 7, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1285 0, "edit-argord"},
1286 {quick_label, 2, REPLACE_DLG_WIDTH, 6, REPLACE_DLG_HEIGHT, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1287 0, 0, 0},
1288 {quick_input, 3, REPLACE_DLG_WIDTH, 5, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1289 0, "edit-replace"},
1290 {quick_label, 2, REPLACE_DLG_WIDTH, 4, REPLACE_DLG_HEIGHT, N_(" Enter replacement string:"), 0, 0, 0,
1291 0, 0},
1292 {quick_input, 3, REPLACE_DLG_WIDTH, 3, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1293 0, "edit-search"},
1294 {quick_label, 2, REPLACE_DLG_WIDTH, 2, REPLACE_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1295 0, 0},
1296 NULL_QuickWidget};
1298 (void) edit;
1300 quick_widgets[2].result = &treplace_scanf;
1301 quick_widgets[3].result = &treplace_all;
1302 quick_widgets[4].result = &treplace_prompt;
1303 quick_widgets[5].result = &treplace_backwards;
1304 quick_widgets[6].result = &treplace_regexp;
1305 quick_widgets[7].result = &treplace_whole;
1306 quick_widgets[8].result = &treplace_case;
1307 quick_widgets[9].str_result = arg_order;
1308 quick_widgets[9].text = argorder_default;
1309 quick_widgets[11].str_result = replace_text;
1310 quick_widgets[11].text = replace_default;
1311 quick_widgets[13].str_result = search_text;
1312 quick_widgets[13].text = search_default;
1314 QuickDialog Quick_input =
1315 {REPLACE_DLG_WIDTH, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "),
1316 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1318 Quick_input.widgets = quick_widgets;
1320 if (quick_dialog (&Quick_input) != B_CANCEL) {
1321 replace_scanf = treplace_scanf;
1322 replace_backwards = treplace_backwards;
1323 replace_regexp = treplace_regexp;
1324 replace_all = treplace_all;
1325 replace_prompt = treplace_prompt;
1326 replace_whole = treplace_whole;
1327 replace_case = treplace_case;
1328 return;
1329 } else {
1330 *arg_order = NULL;
1331 *replace_text = NULL;
1332 *search_text = NULL;
1333 return;
1339 static void
1340 edit_search_dialog (WEdit * edit, char **search_text)
1342 int treplace_scanf = replace_scanf;
1343 int treplace_regexp = replace_regexp;
1344 int treplace_whole = replace_whole;
1345 int treplace_case = replace_case;
1346 int treplace_backwards = replace_backwards;
1348 QuickWidget quick_widgets[] =
1350 {quick_button, 6, 10, 7, SEARCH_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1351 0, NULL},
1352 {quick_button, 2, 10, 7, SEARCH_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
1353 0, NULL},
1354 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1355 0, 0, NULL },
1356 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1357 0, 0, NULL},
1358 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1359 0, 0, NULL},
1360 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1361 0, 0, NULL},
1362 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 4, SEARCH_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1363 0, 0, NULL},
1364 {quick_input, 3, SEARCH_DLG_WIDTH, 3, SEARCH_DLG_HEIGHT, "", 52, 0, 0,
1365 0, "edit-search"},
1366 {quick_label, 2, SEARCH_DLG_WIDTH, 2, SEARCH_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1367 0, 0},
1368 NULL_QuickWidget};
1370 (void) edit;
1372 quick_widgets[2].result = &treplace_scanf;
1373 quick_widgets[3].result = &treplace_backwards;
1374 quick_widgets[4].result = &treplace_regexp;
1375 quick_widgets[5].result = &treplace_whole;
1376 quick_widgets[6].result = &treplace_case;
1377 quick_widgets[7].str_result = search_text;
1378 quick_widgets[7].text = *search_text;
1381 QuickDialog Quick_input =
1382 {SEARCH_DLG_WIDTH, SEARCH_DLG_HEIGHT, -1, 0, N_("Search"),
1383 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1385 Quick_input.widgets = quick_widgets;
1387 if (quick_dialog (&Quick_input) != B_CANCEL) {
1388 replace_scanf = treplace_scanf;
1389 replace_backwards = treplace_backwards;
1390 replace_regexp = treplace_regexp;
1391 replace_whole = treplace_whole;
1392 replace_case = treplace_case;
1393 } else {
1394 *search_text = NULL;
1400 static long sargs[NUM_REPL_ARGS][256 / sizeof (long)];
1402 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1403 sargs[4], sargs[5], sargs[6], sargs[7], \
1404 sargs[8], sargs[9], sargs[10], sargs[11], \
1405 sargs[12], sargs[13], sargs[14], sargs[15]
1407 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1408 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1409 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1410 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1413 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1414 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1415 static int
1416 string_regexp_search (char *pattern, char *string, int match_type,
1417 int match_bol, int icase, int *found_len, void *d)
1419 static regex_t r;
1420 static char *old_pattern = NULL;
1421 static int old_type, old_icase;
1422 regmatch_t *pmatch;
1423 static regmatch_t s[1];
1425 pmatch = (regmatch_t *) d;
1426 if (!pmatch)
1427 pmatch = s;
1429 if (!old_pattern || strcmp (old_pattern, pattern)
1430 || old_type != match_type || old_icase != icase) {
1431 if (old_pattern) {
1432 regfree (&r);
1433 g_free (old_pattern);
1434 old_pattern = 0;
1436 if (regcomp (&r, pattern, REG_EXTENDED | (icase ? REG_ICASE : 0) |
1437 REG_NEWLINE)) {
1438 *found_len = 0;
1439 return -3;
1441 old_pattern = g_strdup (pattern);
1442 old_type = match_type;
1443 old_icase = icase;
1445 if (regexec
1446 (&r, string, d ? NUM_REPL_ARGS : 1, pmatch,
1447 ((match_bol
1448 || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) {
1449 *found_len = 0;
1450 return -1;
1452 *found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
1453 return (pmatch[0].rm_so);
1456 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1457 (and the above) routines to work properly - paul */
1459 typedef int (*edit_getbyte_fn) (WEdit *, long);
1461 static long
1462 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)
1464 long p, q = 0;
1465 long l = strlen ((char *) exp), f = 0;
1466 int n = 0;
1468 for (p = 0; p < l; p++) /* count conversions... */
1469 if (exp[p] == '%')
1470 if (exp[++p] != '%') /* ...except for "%%" */
1471 n++;
1473 if (replace_scanf || replace_regexp) {
1474 int c;
1475 unsigned char *buf;
1476 unsigned char mbuf[MAX_REPL_LEN * 2 + 3];
1478 replace_scanf = (!replace_regexp); /* can't have both */
1480 buf = mbuf;
1482 if (replace_scanf) {
1483 unsigned char e[MAX_REPL_LEN];
1484 if (n >= NUM_REPL_ARGS)
1485 return -3;
1487 if (replace_case) {
1488 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++)
1489 buf[p - start] = (*get_byte) (data, p);
1490 } else {
1491 for (p = 0; exp[p] != 0; p++)
1492 exp[p] = my_lower_case (exp[p]);
1493 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) {
1494 c = (*get_byte) (data, p);
1495 buf[p - start] = my_lower_case (c);
1499 buf[(q = p - start)] = 0;
1500 strcpy ((char *) e, (char *) exp);
1501 strcat ((char *) e, "%n");
1502 exp = e;
1504 while (q) {
1505 *((int *) sargs[n]) = 0; /* --> here was the problem - now fixed: good */
1506 if (n == sscanf ((char *) buf, (char *) exp, SCANF_ARGS)) {
1507 if (*((int *) sargs[n])) {
1508 *len = *((int *) sargs[n]);
1509 return start;
1512 if (once_only)
1513 return -2;
1514 if (q + start < last_byte) {
1515 if (replace_case) {
1516 buf[q] = (*get_byte) (data, q + start);
1517 } else {
1518 c = (*get_byte) (data, q + start);
1519 buf[q] = my_lower_case (c);
1521 q++;
1523 buf[q] = 0;
1524 start++;
1525 buf++; /* move the window along */
1526 if (buf == mbuf + MAX_REPL_LEN) { /* the window is about to go past the end of array, so... */
1527 memmove (mbuf, buf, strlen ((char *) buf) + 1); /* reset it */
1528 buf = mbuf;
1530 q--;
1532 } else { /* regexp matching */
1533 long offset = 0;
1534 int found_start, match_bol, move_win = 0;
1536 while (start + offset < last_byte) {
1537 match_bol = (start == 0 || (*get_byte) (data, start + offset - 1) == '\n');
1538 if (!move_win) {
1539 p = start + offset;
1540 q = 0;
1542 for (; p < last_byte && q < MAX_REPL_LEN; p++, q++) {
1543 mbuf[q] = (*get_byte) (data, p);
1544 if (mbuf[q] == '\n') {
1545 q++;
1546 break;
1549 offset += q;
1550 mbuf[q] = 0;
1552 buf = mbuf;
1553 while (q) {
1554 found_start = string_regexp_search ((char *) exp, (char *) buf, match_normal, match_bol, !replace_case, len, d);
1556 if (found_start <= -2) { /* regcomp/regexec error */
1557 *len = 0;
1558 return -3;
1560 else if (found_start == -1) /* not found: try next line */
1561 break;
1562 else if (*len == 0) { /* null pattern: try again at next character */
1563 q--;
1564 buf++;
1565 match_bol = 0;
1566 continue;
1568 else /* found */
1569 return (start + offset - q + found_start);
1571 if (once_only)
1572 return -2;
1574 if (buf[q - 1] != '\n') { /* incomplete line: try to recover */
1575 buf = mbuf + MAX_REPL_LEN / 2;
1576 q = strlen ((const char *) buf);
1577 memmove (mbuf, buf, q);
1578 p = start + q;
1579 move_win = 1;
1581 else
1582 move_win = 0;
1585 } else {
1586 *len = strlen ((const char *) exp);
1587 if (replace_case) {
1588 for (p = start; p <= last_byte - l; p++) {
1589 if ((*get_byte) (data, p) == (unsigned char)exp[0]) { /* check if first char matches */
1590 for (f = 0, q = 0; q < l && f < 1; q++)
1591 if ((*get_byte) (data, q + p) != (unsigned char)exp[q])
1592 f = 1;
1593 if (f == 0)
1594 return p;
1596 if (once_only)
1597 return -2;
1599 } else {
1600 for (p = 0; exp[p] != 0; p++)
1601 exp[p] = my_lower_case (exp[p]);
1603 for (p = start; p <= last_byte - l; p++) {
1604 if (my_lower_case ((*get_byte) (data, p)) == (unsigned char)exp[0]) {
1605 for (f = 0, q = 0; q < l && f < 1; q++)
1606 if (my_lower_case ((*get_byte) (data, q + p)) != (unsigned char)exp[q])
1607 f = 1;
1608 if (f == 0)
1609 return p;
1611 if (once_only)
1612 return -2;
1616 return -2;
1620 static long
1621 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)
1622 { /*front end to find_string to check for
1623 whole words */
1624 long p;
1625 p = search_start;
1627 while ((p = edit_find_string (p, exp, len, last_byte, get_byte, data, once_only, d)) >= 0) {
1628 if (replace_whole) {
1629 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1630 if (!strcasechr (option_whole_chars_search, (*get_byte) (data, p - 1))
1631 && !strcasechr (option_whole_chars_search, (*get_byte) (data, p + *len)))
1632 return p;
1633 if (once_only)
1634 return -2;
1635 } else
1636 return p;
1637 if (once_only)
1638 break;
1639 p++; /*not a whole word so continue search. */
1641 return p;
1644 static long
1645 edit_find (long search_start, unsigned char *exp, int *len, long last_byte, edit_getbyte_fn get_byte, void *data, void *d)
1647 long p;
1648 if (replace_backwards) {
1649 while (search_start >= 0) {
1650 p = edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 1, d);
1651 if (p == search_start)
1652 return p;
1653 search_start--;
1655 } else {
1656 return edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 0, d);
1658 return -2;
1661 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1663 #define snprint(v) { \
1664 *p1++ = *p++; \
1665 *p1 = '\0'; \
1666 n = snprintf(s,e-s,q1,v); \
1667 if (n >= (size_t) (e - s)) goto nospc; \
1668 s += n; \
1671 /* this function uses the sprintf command to do a vprintf */
1672 /* it takes pointers to arguments instead of the arguments themselves */
1673 /* The return value is the number of bytes written excluding '\0'
1674 if successfull, -1 if the resulting string would be too long and
1675 -2 if the format string is errorneous. */
1676 static int snprintf_p (char *str, size_t size, const char *fmt,...)
1677 __attribute__ ((format (printf, 3, 4)));
1679 static int snprintf_p (char *str, size_t size, const char *fmt,...)
1681 va_list ap;
1682 size_t n;
1683 const char *q, *p;
1684 char *s = str, *e = str + size;
1685 char q1[40];
1686 char *p1;
1687 int nargs = 0;
1689 va_start (ap, fmt);
1690 p = q = fmt;
1692 while ((p = strchr (p, '%'))) {
1693 n = p - q;
1694 if (n >= (size_t) (e - s))
1695 goto nospc;
1696 memcpy (s, q, n); /* copy stuff between format specifiers */
1697 s += n;
1698 q = p;
1699 p1 = q1;
1700 *p1++ = *p++;
1701 if (*p == '%') {
1702 p++;
1703 *s++ = '%';
1704 if (s == e)
1705 goto nospc;
1706 q = p;
1707 continue;
1709 if (*p == 'n')
1710 goto err;
1711 /* We were passed only 16 arguments. */
1712 if (++nargs == 16)
1713 goto err;
1714 if (*p == '#')
1715 *p1++ = *p++;
1716 if (*p == '0')
1717 *p1++ = *p++;
1718 if (*p == '-')
1719 *p1++ = *p++;
1720 if (*p == '+')
1721 *p1++ = *p++;
1722 if (*p == '*') {
1723 p++;
1724 strcpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace field width with a number */
1725 p1 += strlen (p1);
1726 } else {
1727 while (is_digit (*p) && p1 < q1 + 20)
1728 *p1++ = *p++;
1729 if (is_digit (*p))
1730 goto err;
1732 if (*p == '.')
1733 *p1++ = *p++;
1734 if (*p == '*') {
1735 p++;
1736 strcpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace precision with a number */
1737 p1 += strlen (p1);
1738 } else {
1739 while (is_digit (*p) && p1 < q1 + 32)
1740 *p1++ = *p++;
1741 if (is_digit (*p))
1742 goto err;
1744 /* flags done, now get argument */
1745 if (*p == 's') {
1746 snprint (va_arg (ap, char *));
1747 } else if (*p == 'h') {
1748 if (strchr ("diouxX", *p))
1749 snprint (*va_arg (ap, short *));
1750 } else if (*p == 'l') {
1751 *p1++ = *p++;
1752 if (strchr ("diouxX", *p))
1753 snprint (*va_arg (ap, long *));
1754 } else if (strchr ("cdiouxX", *p)) {
1755 snprint (*va_arg (ap, int *));
1756 } else if (*p == 'L') {
1757 *p1++ = *p++;
1758 if (strchr ("EefgG", *p))
1759 snprint (*va_arg (ap, double *)); /* should be long double */
1760 } else if (strchr ("EefgG", *p)) {
1761 snprint (*va_arg (ap, double *));
1762 } else if (strchr ("DOU", *p)) {
1763 snprint (*va_arg (ap, long *));
1764 } else if (*p == 'p') {
1765 snprint (*va_arg (ap, void **));
1766 } else
1767 goto err;
1768 q = p;
1770 va_end (ap);
1771 n = strlen (q);
1772 if (n >= (size_t) (e - s))
1773 return -1;
1774 memcpy (s, q, n + 1);
1775 return s + n - str;
1776 nospc:
1777 va_end (ap);
1778 return -1;
1779 err:
1780 va_end (ap);
1781 return -2;
1784 static void regexp_error (WEdit *edit)
1786 (void) edit;
1787 edit_error_dialog (_("Error"), _(" Invalid regular expression, or scanf expression with too many conversions "));
1790 /* call with edit = 0 before shutdown to close memory leaks */
1791 void
1792 edit_replace_cmd (WEdit *edit, int again)
1794 static regmatch_t pmatch[NUM_REPL_ARGS];
1795 /* 1 = search string, 2 = replace with, 3 = argument order */
1796 static char *saved1 = NULL; /* saved default[123] */
1797 static char *saved2 = NULL;
1798 static char *saved3 = NULL;
1799 char *input1 = NULL; /* user input from the dialog */
1800 char *input2 = NULL;
1801 char *input3 = NULL;
1802 int replace_yes;
1803 int replace_continue;
1804 int treplace_prompt = 0;
1805 long times_replaced = 0, last_search;
1806 int argord[NUM_REPL_ARGS];
1808 if (!edit) {
1809 g_free (saved1), saved1 = NULL;
1810 g_free (saved2), saved2 = NULL;
1811 g_free (saved3), saved3 = NULL;
1812 return;
1815 last_search = edit->last_byte;
1817 edit->force |= REDRAW_COMPLETELY;
1819 if (again && !saved1 && !saved2)
1820 again = 0;
1822 if (again) {
1823 input1 = g_strdup (saved1 ? saved1 : "");
1824 input2 = g_strdup (saved2 ? saved2 : "");
1825 input3 = g_strdup (saved3 ? saved3 : "");
1826 } else {
1827 char *disp1 = g_strdup (saved1 ? saved1 : "");
1828 char *disp2 = g_strdup (saved2 ? saved2 : "");
1829 char *disp3 = g_strdup (saved3 ? saved3 : "");
1831 convert_to_display (disp1);
1832 convert_to_display (disp2);
1833 convert_to_display (disp3);
1835 edit_push_action (edit, KEY_PRESS + edit->start_display);
1836 edit_replace_dialog (edit, disp1, disp2, disp3, &input1, &input2,
1837 &input3);
1839 g_free (disp1);
1840 g_free (disp2);
1841 g_free (disp3);
1843 convert_from_input (input1);
1844 convert_from_input (input2);
1845 convert_from_input (input3);
1847 treplace_prompt = replace_prompt;
1848 if (input1 == NULL || *input1 == '\0') {
1849 edit->force = REDRAW_COMPLETELY;
1850 goto cleanup;
1853 g_free (saved1), saved1 = mhl_str_dup (input1);
1854 g_free (saved2), saved2 = mhl_str_dup (input2);
1855 g_free (saved3), saved3 = mhl_str_dup (input3);
1859 const char *s;
1860 int ord;
1861 size_t i;
1863 s = input3;
1864 for (i = 0; i < NUM_REPL_ARGS; i++) {
1865 if (s != NULL && *s != '\0') {
1866 ord = atoi (s);
1867 if ((ord > 0) && (ord <= NUM_REPL_ARGS))
1868 argord[i] = ord - 1;
1869 else
1870 argord[i] = i;
1871 s = strchr (s, ',');
1872 if (s != NULL)
1873 s++;
1874 } else
1875 argord[i] = i;
1879 replace_continue = replace_all;
1881 if (edit->found_len && edit->search_start == edit->found_start + 1
1882 && replace_backwards)
1883 edit->search_start--;
1885 if (edit->found_len && edit->search_start == edit->found_start - 1
1886 && !replace_backwards)
1887 edit->search_start++;
1889 do {
1890 int len = 0;
1891 long new_start;
1892 new_start =
1893 edit_find (edit->search_start, (unsigned char *) input1, &len,
1894 last_search, edit_get_byte, (void *) edit, pmatch);
1895 if (new_start == -3) {
1896 regexp_error (edit);
1897 break;
1899 edit->search_start = new_start;
1900 /*returns negative on not found or error in pattern */
1902 if (edit->search_start >= 0) {
1903 int i;
1905 edit->found_start = edit->search_start;
1906 i = edit->found_len = len;
1908 edit_cursor_move (edit, edit->search_start - edit->curs1);
1909 edit_scroll_screen_over_cursor (edit);
1911 replace_yes = 1;
1913 if (treplace_prompt) {
1914 int l;
1915 l = edit->curs_row - edit->num_widget_lines / 3;
1916 if (l > 0)
1917 edit_scroll_downward (edit, l);
1918 if (l < 0)
1919 edit_scroll_upward (edit, -l);
1921 edit_scroll_screen_over_cursor (edit);
1922 edit->force |= REDRAW_PAGE;
1923 edit_render_keypress (edit);
1925 /*so that undo stops at each query */
1926 edit_push_key_press (edit);
1928 switch (edit_replace_prompt (edit, input2, /* and prompt 2/3 down */
1929 (edit->num_widget_columns -
1930 CONFIRM_DLG_WIDTH) / 2,
1931 edit->num_widget_lines * 2 /
1932 3)) {
1933 case B_ENTER:
1934 break;
1935 case B_SKIP_REPLACE:
1936 replace_yes = 0;
1937 break;
1938 case B_REPLACE_ALL:
1939 treplace_prompt = 0;
1940 replace_continue = 1;
1941 break;
1942 case B_REPLACE_ONE:
1943 replace_continue = 0;
1944 break;
1945 case B_CANCEL:
1946 replace_yes = 0;
1947 replace_continue = 0;
1948 break;
1951 if (replace_yes) { /* delete then insert new */
1952 if (replace_scanf) {
1953 char repl_str[MAX_REPL_LEN + 2];
1954 int ret = 0;
1956 /* we need to fill in sargs just like with scanf */
1957 if (replace_regexp) {
1958 int k, j;
1959 for (k = 1;
1960 k < NUM_REPL_ARGS && pmatch[k].rm_eo >= 0;
1961 k++) {
1962 unsigned char *t;
1964 if (pmatch[k].rm_eo - pmatch[k].rm_so > 255) {
1965 ret = -1;
1966 break;
1968 t = (unsigned char *) &sargs[k - 1][0];
1969 for (j = 0;
1970 j < pmatch[k].rm_eo - pmatch[k].rm_so
1971 && j < 255; j++, t++)
1972 *t = (unsigned char) edit_get_byte (edit,
1973 edit->
1974 search_start
1976 pmatch
1977 [0].
1978 rm_so +
1979 pmatch
1980 [k].
1981 rm_so +
1983 *t = '\0';
1985 for (; k <= NUM_REPL_ARGS; k++)
1986 sargs[k - 1][0] = 0;
1988 if (!ret)
1989 ret =
1990 snprintf_p (repl_str, MAX_REPL_LEN + 2, input2,
1991 PRINTF_ARGS);
1992 if (ret >= 0) {
1993 times_replaced++;
1994 while (i--)
1995 edit_delete (edit);
1996 while (repl_str[++i])
1997 edit_insert (edit, repl_str[i]);
1998 } else {
1999 edit_error_dialog (_(" Replace "),
2000 ret ==
2001 -2 ?
2003 (" Error in replacement format string. ")
2004 : _(" Replacement too long. "));
2005 replace_continue = 0;
2007 } else {
2008 times_replaced++;
2009 while (i--)
2010 edit_delete (edit);
2011 while (input2[++i])
2012 edit_insert (edit, input2[i]);
2014 edit->found_len = i;
2016 /* so that we don't find the same string again */
2017 if (replace_backwards) {
2018 last_search = edit->search_start;
2019 edit->search_start--;
2020 } else {
2021 edit->search_start += i;
2022 last_search = edit->last_byte;
2024 edit_scroll_screen_over_cursor (edit);
2025 } else {
2026 const char *msg = _(" Replace ");
2027 /* try and find from right here for next search */
2028 edit->search_start = edit->curs1;
2029 edit_update_curs_col (edit);
2031 edit->force |= REDRAW_PAGE;
2032 edit_render_keypress (edit);
2033 if (times_replaced) {
2034 message (D_NORMAL, msg, _(" %ld replacements made. "),
2035 times_replaced);
2036 } else
2037 query_dialog (msg, _(" Search string not found "),
2038 D_NORMAL, 1, _("&OK"));
2039 replace_continue = 0;
2041 } while (replace_continue);
2043 edit->force = REDRAW_COMPLETELY;
2044 edit_scroll_screen_over_cursor (edit);
2045 cleanup:
2046 g_free (input1);
2047 g_free (input2);
2048 g_free (input3);
2054 void edit_search_cmd (WEdit * edit, int again)
2056 static char *old = NULL;
2057 char *exp = "";
2059 if (!edit) {
2060 g_free (old);
2061 old = NULL;
2062 return;
2065 exp = old ? old : exp;
2066 if (again) { /*ctrl-hotkey for search again. */
2067 if (!old)
2068 return;
2069 exp = g_strdup (old);
2070 } else {
2072 #ifdef HAVE_CHARSET
2073 if (exp && *exp)
2074 convert_to_display (exp);
2075 #endif /* HAVE_CHARSET */
2077 edit_search_dialog (edit, &exp);
2079 #ifdef HAVE_CHARSET
2080 if (exp && *exp)
2081 convert_from_input (exp);
2082 #endif /* HAVE_CHARSET */
2084 edit_push_action (edit, KEY_PRESS + edit->start_display);
2087 if (exp) {
2088 if (*exp) {
2089 int len = 0;
2090 g_free (old);
2091 old = g_strdup (exp);
2093 if (search_create_bookmark) {
2094 int found = 0, books = 0;
2095 int l = 0, l_last = -1;
2096 long p, q = 0;
2097 for (;;) {
2098 p = edit_find (q, (unsigned char *) exp, &len, edit->last_byte,
2099 edit_get_byte, (void *) edit, 0);
2100 if (p < 0)
2101 break;
2102 found++;
2103 l += edit_count_lines (edit, q, p);
2104 if (l != l_last) {
2105 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
2106 books++;
2108 l_last = l;
2109 q = p + 1;
2111 if (found) {
2112 /* in response to number of bookmarks added because of string being found %d times */
2113 message (D_NORMAL, _("Search"), _(" %d items found, %d bookmarks added "), found, books);
2114 } else {
2115 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2117 } else {
2119 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
2120 edit->search_start--;
2122 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
2123 edit->search_start++;
2125 edit->search_start = edit_find (edit->search_start, (unsigned char *) exp, &len, edit->last_byte,
2126 edit_get_byte, (void *) edit, 0);
2128 if (edit->search_start >= 0) {
2129 edit->found_start = edit->search_start;
2130 edit->found_len = len;
2132 edit_cursor_move (edit, edit->search_start - edit->curs1);
2133 edit_scroll_screen_over_cursor (edit);
2134 if (replace_backwards)
2135 edit->search_start--;
2136 else
2137 edit->search_start++;
2138 } else if (edit->search_start == -3) {
2139 edit->search_start = edit->curs1;
2140 regexp_error (edit);
2141 } else {
2142 edit->search_start = edit->curs1;
2143 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2147 g_free (exp);
2149 edit->force |= REDRAW_COMPLETELY;
2150 edit_scroll_screen_over_cursor (edit);
2155 * Check if it's OK to close the editor. If there are unsaved changes,
2156 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2159 edit_ok_to_exit (WEdit *edit)
2161 if (!edit->modified)
2162 return 1;
2164 switch (edit_query_dialog3
2165 (_("Quit"), _(" File was modified, Save with exit? "),
2166 _("&Cancel quit"), _("&Yes"), _("&No"))) {
2167 case 1:
2168 edit_push_markers (edit);
2169 edit_set_markers (edit, 0, 0, 0, 0);
2170 if (!edit_save_cmd (edit))
2171 return 0;
2172 break;
2173 case 2:
2174 break;
2175 case 0:
2176 case -1:
2177 return 0;
2180 return 1;
2184 #define TEMP_BUF_LEN 1024
2186 /* Return a null terminated length of text. Result must be g_free'd */
2187 static unsigned char *
2188 edit_get_block (WEdit *edit, long start, long finish, int *l)
2190 unsigned char *s, *r;
2191 r = s = g_malloc (finish - start + 1);
2192 if (column_highlighting) {
2193 *l = 0;
2194 /* copy from buffer, excluding chars that are out of the column 'margins' */
2195 while (start < finish) {
2196 int c, x;
2197 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
2198 start);
2199 c = edit_get_byte (edit, start);
2200 if ((x >= edit->column1 && x < edit->column2)
2201 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
2202 *s++ = c;
2203 (*l)++;
2205 start++;
2207 } else {
2208 *l = finish - start;
2209 while (start < finish)
2210 *s++ = edit_get_byte (edit, start++);
2212 *s = 0;
2213 return r;
2216 /* save block, returns 1 on success */
2218 edit_save_block (WEdit * edit, const char *filename, long start,
2219 long finish)
2221 int len, file;
2223 if ((file =
2224 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
2225 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
2226 return 0;
2228 if (column_highlighting) {
2229 unsigned char *block, *p;
2230 int r;
2231 p = block = edit_get_block (edit, start, finish, &len);
2232 while (len) {
2233 r = mc_write (file, p, len);
2234 if (r < 0)
2235 break;
2236 p += r;
2237 len -= r;
2239 g_free (block);
2240 } else {
2241 unsigned char *buf;
2242 int i = start, end;
2243 len = finish - start;
2244 buf = g_malloc (TEMP_BUF_LEN);
2245 while (start != finish) {
2246 end = min (finish, start + TEMP_BUF_LEN);
2247 for (; i < end; i++)
2248 buf[i - start] = edit_get_byte (edit, i);
2249 len -= mc_write (file, (char *) buf, end - start);
2250 start = end;
2252 g_free (buf);
2254 mc_close (file);
2255 if (len)
2256 return 0;
2257 return 1;
2260 /* copies a block to clipboard file */
2261 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
2263 return edit_save_block (edit, catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL), start, finish);
2267 void edit_paste_from_history (WEdit *edit)
2269 (void) edit;
2270 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
2273 int edit_copy_to_X_buf_cmd (WEdit * edit)
2275 long start_mark, end_mark;
2276 if (eval_marks (edit, &start_mark, &end_mark))
2277 return 0;
2278 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2279 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2280 return 1;
2282 edit_mark_cmd (edit, 1);
2283 return 0;
2286 int edit_cut_to_X_buf_cmd (WEdit * edit)
2288 long start_mark, end_mark;
2289 if (eval_marks (edit, &start_mark, &end_mark))
2290 return 0;
2291 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2292 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2293 return 1;
2295 edit_block_delete_cmd (edit);
2296 edit_mark_cmd (edit, 1);
2297 return 0;
2300 void edit_paste_from_X_buf_cmd (WEdit * edit)
2302 edit_insert_file (edit, catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL));
2307 * Ask user for the line and go to that line.
2308 * Negative numbers mean line from the end (i.e. -1 is the last line).
2310 void
2311 edit_goto_cmd (WEdit *edit)
2313 char *f;
2314 static long line = 0; /* line as typed, saved as default */
2315 long l;
2316 char *error;
2317 char s[32];
2319 g_snprintf (s, sizeof (s), "%ld", line);
2320 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
2321 line ? s : "");
2322 if (!f)
2323 return;
2325 if (!*f) {
2326 g_free (f);
2327 return;
2330 l = strtol (f, &error, 0);
2331 if (*error) {
2332 g_free (f);
2333 return;
2336 line = l;
2337 if (l < 0)
2338 l = edit->total_lines + l + 2;
2339 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2340 edit_move_to_line (edit, l - 1);
2341 edit->force |= REDRAW_COMPLETELY;
2342 g_free (f);
2346 /* Return 1 on success */
2348 edit_save_block_cmd (WEdit *edit)
2350 long start_mark, end_mark;
2351 char *exp;
2352 if (eval_marks (edit, &start_mark, &end_mark))
2353 return 1;
2354 exp =
2355 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2356 MC_HISTORY_EDIT_SAVE_BLOCK,
2357 catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL));
2358 edit_push_action (edit, KEY_PRESS + edit->start_display);
2359 if (exp) {
2360 if (!*exp) {
2361 g_free (exp);
2362 return 0;
2363 } else {
2364 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2365 g_free (exp);
2366 edit->force |= REDRAW_COMPLETELY;
2367 return 1;
2368 } else {
2369 g_free (exp);
2370 edit_error_dialog (_(" Save Block "),
2371 get_sys_error (_
2372 (" Cannot save file. ")));
2376 edit->force |= REDRAW_COMPLETELY;
2377 return 0;
2381 /* returns 1 on success */
2383 edit_insert_file_cmd (WEdit *edit)
2385 char *exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2386 MC_HISTORY_EDIT_INSERT_FILE,
2387 catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL));
2388 edit_push_action (edit, KEY_PRESS + edit->start_display);
2389 if (exp) {
2390 if (!*exp) {
2391 g_free (exp);
2392 return 0;
2393 } else {
2394 if (edit_insert_file (edit, exp)) {
2395 g_free (exp);
2396 edit->force |= REDRAW_COMPLETELY;
2397 return 1;
2398 } else {
2399 g_free (exp);
2400 edit_error_dialog (_(" Insert File "),
2401 get_sys_error (_
2402 (" Cannot insert file. ")));
2406 edit->force |= REDRAW_COMPLETELY;
2407 return 0;
2410 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2411 int edit_sort_cmd (WEdit * edit)
2413 static char *old = 0;
2414 char *exp;
2415 long start_mark, end_mark;
2416 int e;
2418 if (eval_marks (edit, &start_mark, &end_mark)) {
2419 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2420 return 0;
2422 edit_save_block (edit, catstrs (home_dir, PATH_SEP_STR BLOCK_FILE, (char *) NULL), start_mark, end_mark);
2424 exp = input_dialog (_(" Run Sort "),
2425 _(" Enter sort options (see manpage) separated by whitespace: "),
2426 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2428 if (!exp)
2429 return 1;
2430 g_free (old);
2431 old = exp;
2433 e = system (catstrs (" sort ", exp, " ", home_dir, PATH_SEP_STR BLOCK_FILE, " > ", home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2434 if (e) {
2435 if (e == -1 || e == 127) {
2436 edit_error_dialog (_(" Sort "),
2437 get_sys_error (_(" Cannot execute sort command ")));
2438 } else {
2439 char q[8];
2440 sprintf (q, "%d ", e);
2441 edit_error_dialog (_(" Sort "),
2442 catstrs (_(" Sort returned non-zero: "), q, (char *) NULL));
2444 return -1;
2447 edit->force |= REDRAW_COMPLETELY;
2449 if (edit_block_delete_cmd (edit))
2450 return 1;
2451 edit_insert_file (edit, catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2452 return 0;
2456 * Ask user for a command, execute it and paste its output back to the
2457 * editor.
2460 edit_ext_cmd (WEdit *edit)
2462 char *exp;
2463 int e;
2465 exp =
2466 input_dialog (_("Paste output of external command"),
2467 _("Enter shell command(s):"),
2468 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2470 if (!exp)
2471 return 1;
2473 e = system (catstrs (exp, " > ", home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2474 g_free (exp);
2476 if (e) {
2477 edit_error_dialog (_("External command"),
2478 get_sys_error (_("Cannot execute command")));
2479 return -1;
2482 edit->force |= REDRAW_COMPLETELY;
2484 edit_insert_file (edit, catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2485 return 0;
2488 /* if block is 1, a block must be highlighted and the shell command
2489 processes it. If block is 0 the shell command is a straight system
2490 command, that just produces some output which is to be inserted */
2491 void
2492 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2494 long start_mark, end_mark;
2495 char buf[BUFSIZ];
2496 FILE *script_home = NULL;
2497 FILE *script_src = NULL;
2498 FILE *block_file = NULL;
2499 const char *o = NULL;
2500 const char *h = NULL;
2501 const char *b = NULL;
2502 char *quoted_name = NULL;
2504 o = catstrs (mc_home, shell_cmd, (char *) NULL); /* original source script */
2505 h = catstrs (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2506 b = catstrs (home_dir, PATH_SEP_STR BLOCK_FILE, (char *) NULL); /* block file */
2508 if (!(script_home = fopen (h, "r"))) {
2509 if (!(script_home = fopen (h, "w"))) {
2510 edit_error_dialog ("", get_sys_error (catstrs
2512 ("Error creating script:"),
2513 h, (char *) NULL)));
2514 return;
2516 if (!(script_src = fopen (o, "r"))) {
2517 fclose (script_home);
2518 unlink (h);
2519 edit_error_dialog ("", get_sys_error (catstrs
2520 (_("Error reading script:"),
2521 o, (char *) NULL)));
2522 return;
2524 while (fgets (buf, sizeof (buf), script_src))
2525 fputs (buf, script_home);
2526 if (fclose (script_home)) {
2527 edit_error_dialog ("", get_sys_error (catstrs
2529 ("Error closing script:"),
2530 h, (char *) NULL)));
2531 return;
2533 chmod (h, 0700);
2534 edit_error_dialog ("", get_sys_error (catstrs
2535 (_("Script created:"), h, (char *) NULL)));
2538 open_error_pipe ();
2540 if (block) { /* for marked block run indent formatter */
2541 if (eval_marks (edit, &start_mark, &end_mark)) {
2542 edit_error_dialog (_("Process block"),
2544 (" You must first highlight a block of text. "));
2545 return;
2547 edit_save_block (edit, b, start_mark, end_mark);
2548 quoted_name = name_quote (edit->filename, 0);
2550 * Run script.
2551 * Initial space is to avoid polluting bash history.
2552 * Arguments:
2553 * $1 - name of the edited file (to check its extension etc).
2554 * $2 - file containing the current block.
2555 * $3 - file where error messages should be put
2556 * (for compatibility with old scripts).
2558 system (catstrs (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2559 " ", home_dir, PATH_SEP_STR BLOCK_FILE " /dev/null", (char *) NULL));
2561 } else {
2563 * No block selected, just execute the command for the file.
2564 * Arguments:
2565 * $1 - name of the edited file.
2567 system (catstrs (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2568 quoted_name, (char *) NULL));
2570 g_free (quoted_name);
2571 close_error_pipe (D_NORMAL, NULL);
2573 edit_refresh_cmd (edit);
2574 edit->force |= REDRAW_COMPLETELY;
2576 /* insert result block */
2577 if (block) {
2578 if (edit_block_delete_cmd (edit))
2579 return;
2580 edit_insert_file (edit, b);
2581 if ((block_file = fopen (b, "w")))
2582 fclose (block_file);
2583 return;
2586 return;
2589 /* prints at the cursor */
2590 /* returns the number of chars printed */
2591 int edit_print_string (WEdit * e, const char *s)
2593 int i = 0;
2594 while (s[i])
2595 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2596 e->force |= REDRAW_COMPLETELY;
2597 edit_update_screen (e);
2598 return i;
2602 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2604 FILE *p = 0;
2605 char *s;
2607 to = name_quote (to, 0);
2608 subject = name_quote (subject, 0);
2609 cc = name_quote (cc, 0);
2610 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2611 g_free (to);
2612 g_free (subject);
2613 g_free (cc);
2615 if (s) {
2616 p = popen (s, "w");
2617 g_free (s);
2620 if (p) {
2621 long i;
2622 for (i = 0; i < edit->last_byte; i++)
2623 fputc (edit_get_byte (edit, i), p);
2624 pclose (p);
2628 #define MAIL_DLG_HEIGHT 12
2630 void edit_mail_dialog (WEdit * edit)
2632 char *tmail_to;
2633 char *tmail_subject;
2634 char *tmail_cc;
2636 static char *mail_cc_last = 0;
2637 static char *mail_subject_last = 0;
2638 static char *mail_to_last = 0;
2640 QuickDialog Quick_input =
2641 {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
2642 "[Input Line Keys]", 0, 0};
2644 QuickWidget quick_widgets[] =
2646 {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
2647 0, NULL},
2648 {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
2649 0, NULL},
2650 {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2651 0, "mail-dlg-input"},
2652 {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
2653 0, 0},
2654 {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2655 0, "mail-dlg-input-2"},
2656 {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
2657 0, 0},
2658 {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2659 0, "mail-dlg-input-3"},
2660 {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
2661 0, 0},
2662 {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2663 0, 0},
2664 NULL_QuickWidget};
2666 quick_widgets[2].str_result = &tmail_cc;
2667 quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
2668 quick_widgets[4].str_result = &tmail_subject;
2669 quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
2670 quick_widgets[6].str_result = &tmail_to;
2671 quick_widgets[6].text = mail_to_last ? mail_to_last : "";
2673 Quick_input.widgets = quick_widgets;
2675 if (quick_dialog (&Quick_input) != B_CANCEL) {
2676 g_free (mail_cc_last);
2677 g_free (mail_subject_last);
2678 g_free (mail_to_last);
2679 mail_cc_last = tmail_cc;
2680 mail_subject_last = tmail_subject;
2681 mail_to_last = tmail_to;
2682 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2687 /*******************/
2688 /* Word Completion */
2689 /*******************/
2692 /* find first character of current word */
2693 static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len)
2695 int i, c, last;
2697 /* return if at begin of file */
2698 if (edit->curs1 <= 0)
2699 return 0;
2701 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2702 /* return if not at end or in word */
2703 if (isspace (c) || !(isalnum (c) || c == '_'))
2704 return 0;
2706 /* search start of word to be completed */
2707 for (i = 2;; i++) {
2708 /* return if at begin of file */
2709 if (edit->curs1 - i < 0)
2710 return 0;
2712 last = c;
2713 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2715 if (!(isalnum (c) || c == '_')) {
2716 /* return if word starts with digit */
2717 if (isdigit (last))
2718 return 0;
2720 *word_start = edit->curs1 - (i - 1); /* start found */
2721 *word_len = i - 1;
2722 break;
2725 /* success */
2726 return 1;
2730 /* (re)set search parameters to the given values */
2731 static void edit_set_search_parameters (int rs, int rb, int rr, int rw, int rc)
2733 replace_scanf = rs;
2734 replace_backwards = rb;
2735 replace_regexp = rr;
2736 replace_whole = rw;
2737 replace_case = rc;
2741 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2743 /* collect the possible completions */
2744 static int
2745 edit_collect_completions (WEdit *edit, long start, int word_len,
2746 char *match_expr, struct selection *compl,
2747 int *num)
2749 int len, max_len = 0, i, skip;
2750 unsigned char *bufpos;
2752 /* collect max MAX_WORD_COMPLETIONS completions */
2753 while (*num < MAX_WORD_COMPLETIONS) {
2754 /* get next match */
2755 start =
2756 edit_find (start - 1, (unsigned char *) match_expr, &len,
2757 edit->last_byte, edit_get_byte, (void *) edit, 0);
2759 /* not matched */
2760 if (start < 0)
2761 break;
2763 /* add matched completion if not yet added */
2764 bufpos =
2765 &edit->
2766 buffers1[start >> S_EDIT_BUF_SIZE][start & M_EDIT_BUF_SIZE];
2767 skip = 0;
2768 for (i = 0; i < *num; i++) {
2769 if (strncmp
2770 ((char *) &compl[i].text[word_len],
2771 (char *) &bufpos[word_len], max (len,
2772 compl[i].len) -
2773 word_len) == 0) {
2774 skip = 1;
2775 break; /* skip it, already added */
2778 if (skip)
2779 continue;
2781 compl[*num].text = g_malloc (len + 1);
2782 compl[*num].len = len;
2783 for (i = 0; i < len; i++)
2784 compl[*num].text[i] = *(bufpos + i);
2785 compl[*num].text[i] = '\0';
2786 (*num)++;
2788 /* note the maximal length needed for the completion dialog */
2789 if (len > max_len)
2790 max_len = len;
2792 return max_len;
2796 /* let the user select its preferred completion */
2797 static void
2798 edit_completion_dialog (WEdit * edit, int max_len, int word_len,
2799 struct selection *compl, int num_compl)
2801 int start_x, start_y, offset, i;
2802 char *curr = NULL;
2803 Dlg_head *compl_dlg;
2804 WListbox *compl_list;
2805 int compl_dlg_h; /* completion dialog height */
2806 int compl_dlg_w; /* completion dialog width */
2808 /* calculate the dialog metrics */
2809 compl_dlg_h = num_compl + 2;
2810 compl_dlg_w = max_len + 4;
2811 start_x = edit->curs_col + edit->start_col - (compl_dlg_w / 2);
2812 start_y = edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + 1;
2814 if (start_x < 0)
2815 start_x = 0;
2816 if (compl_dlg_w > COLS)
2817 compl_dlg_w = COLS;
2818 if (compl_dlg_h > LINES - 2)
2819 compl_dlg_h = LINES - 2;
2821 offset = start_x + compl_dlg_w - COLS;
2822 if (offset > 0)
2823 start_x -= offset;
2824 offset = start_y + compl_dlg_h - LINES;
2825 if (offset > 0)
2826 start_y -= (offset + 1);
2828 /* create the dialog */
2829 compl_dlg =
2830 create_dlg (start_y, start_x, compl_dlg_h, compl_dlg_w,
2831 dialog_colors, NULL, "[Completion]", NULL,
2832 DLG_COMPACT);
2834 /* create the listbox */
2835 compl_list =
2836 listbox_new (1, 1, compl_dlg_w - 2, compl_dlg_h - 2, NULL);
2838 /* add the dialog */
2839 add_widget (compl_dlg, compl_list);
2841 /* fill the listbox with the completions */
2842 for (i = 0; i < num_compl; i++)
2843 listbox_add_item (compl_list, LISTBOX_APPEND_AT_END, 0,
2844 (char *) compl[i].text, NULL);
2846 /* pop up the dialog */
2847 run_dlg (compl_dlg);
2849 /* apply the choosen completion */
2850 if (compl_dlg->ret_value == B_ENTER) {
2851 listbox_get_current (compl_list, &curr, NULL);
2852 if (curr)
2853 for (curr += word_len; *curr; curr++)
2854 edit_insert (edit, *curr);
2857 /* destroy dialog before return */
2858 destroy_dlg (compl_dlg);
2863 * Complete current word using regular expression search
2864 * backwards beginning at the current cursor position.
2866 void
2867 edit_complete_word_cmd (WEdit *edit)
2869 int word_len = 0, i, num_compl = 0, max_len;
2870 long word_start = 0;
2871 unsigned char *bufpos;
2872 char *match_expr;
2873 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2875 /* don't want to disturb another search */
2876 int old_rs = replace_scanf;
2877 int old_rb = replace_backwards;
2878 int old_rr = replace_regexp;
2879 int old_rw = replace_whole;
2880 int old_rc = replace_case;
2882 /* search start of word to be completed */
2883 if (!edit_find_word_start (edit, &word_start, &word_len))
2884 return;
2886 /* prepare match expression */
2887 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2888 [word_start & M_EDIT_BUF_SIZE];
2889 match_expr = g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len, bufpos);
2891 /* init search: backward, regexp, whole word, case sensitive */
2892 edit_set_search_parameters (0, 1, 1, 1, 1);
2894 /* collect the possible completions */
2895 /* start search from curs1 down to begin of file */
2896 max_len =
2897 edit_collect_completions (edit, word_start, word_len, match_expr,
2898 (struct selection *) &compl, &num_compl);
2900 if (num_compl > 0) {
2901 /* insert completed word if there is only one match */
2902 if (num_compl == 1) {
2903 for (i = word_len; i < compl[0].len; i++)
2904 edit_insert (edit, *(compl[0].text + i));
2906 /* more than one possible completion => ask the user */
2907 else {
2908 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2909 /* !!! pressed again the selection dialog pops up, but that !!! */
2910 /* !!! seems to require a further internal state !!! */
2911 /*beep (); */
2913 /* let the user select the preferred completion */
2914 edit_completion_dialog (edit, max_len, word_len,
2915 (struct selection *) &compl,
2916 num_compl);
2920 g_free (match_expr);
2921 /* release memory before return */
2922 for (i = 0; i < num_compl; i++)
2923 g_free (compl[i].text);
2925 /* restore search parameters */
2926 edit_set_search_parameters (old_rs, old_rb, old_rr, old_rw, old_rc);
2929 void
2930 edit_select_codepage_cmd (WEdit *edit)
2932 #ifdef HAVE_CHARSET
2933 do_select_codepage ();
2934 edit->force = REDRAW_COMPLETELY;
2935 edit_refresh_cmd (edit);
2936 #endif
2939 void
2940 edit_insert_literal_cmd (WEdit *edit)
2942 int char_for_insertion =
2943 edit_raw_key_query (_(" Insert Literal "),
2944 _(" Press any key: "), 0);
2945 edit_execute_key_command (edit, -1,
2946 ascii_alpha_to_cntrl (char_for_insertion));
2949 void
2950 edit_execute_macro_cmd (WEdit *edit)
2952 int command =
2953 CK_Macro (edit_raw_key_query
2954 (_(" Execute Macro "), _(" Press macro hotkey: "),
2955 1));
2956 if (command == CK_Macro (0))
2957 command = CK_Insert_Char;
2959 edit_execute_key_command (edit, command, -1);
2962 void
2963 edit_begin_end_macro_cmd(WEdit *edit)
2965 int command;
2967 /* edit is a pointer to the widget */
2968 if (edit) {
2969 command =
2970 edit->macro_i <
2971 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2972 edit_execute_key_command (edit, command, -1);