Changes in directory listing format:
[midnight-commander.git] / edit / editcmd.c
blobde8cf79f45154ae01e16b6ebd4d5242072308f48
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>
40 #include <stdlib.h>
42 #include "../src/global.h"
43 #include "../src/history.h"
45 #include "edit.h"
46 #include "editlock.h"
47 #include "editcmddef.h"
48 #include "edit-widget.h"
50 #include "../src/color.h" /* dialog_colors */
51 #include "../src/tty.h" /* LINES */
52 #include "../src/widget.h" /* listbox_new() */
53 #include "../src/layout.h" /* clr_scr() */
54 #include "../src/main.h" /* mc_home */
55 #include "../src/help.h" /* interactive_display() */
56 #include "../src/key.h" /* XCTRL */
57 #include "../src/dialog.h" /* do_refresh() */
58 #include "../src/wtools.h" /* message() */
59 #include "../src/charsets.h"
60 #include "../src/selcodepage.h"
62 struct selection {
63 unsigned char * text;
64 int len;
67 /* globals: */
69 /* search and replace: */
70 static int replace_scanf = 0;
71 static int replace_regexp = 0;
72 static int replace_all = 0;
73 static int replace_prompt = 1;
74 static int replace_whole = 0;
75 static int replace_case = 0;
76 static int replace_backwards = 0;
77 static int search_create_bookmark = 0;
79 /* queries on a save */
80 int edit_confirm_save = 1;
82 #define NUM_REPL_ARGS 64
83 #define MAX_REPL_LEN 1024
85 static int edit_save_cmd (WEdit *edit);
86 static unsigned char *edit_get_block (WEdit *edit, long start,
87 long finish, int *l);
89 static inline int my_lower_case (int c)
91 return tolower(c & 0xFF);
94 static const char *
95 strcasechr (const char *s, int c)
97 for (c = my_lower_case (c); my_lower_case ((int) *s) != c; ++s)
98 if (*s == '\0')
99 return 0;
100 return s;
103 #ifndef HAVE_MEMMOVE
104 /* for Christophe */
105 static void *memmove (void *dest, const void *src, size_t n)
107 char *t;
108 const char *s;
110 if (dest <= src) {
111 t = (char *) dest;
112 s = (const char *) src;
113 while (n--)
114 *t++ = *s++;
115 } else {
116 t = (char *) dest + n;
117 s = (const char *) src + n;
118 while (n--)
119 *--t = *--s;
121 return dest;
123 #endif /* !HAVE_MEMMOVE */
125 /* #define itoa MY_itoa <---- this line is now in edit.h */
126 static char *
127 MY_itoa (int i)
129 static char t[14];
130 char *s = t + 13;
131 int j = i;
132 *s-- = 0;
133 do {
134 *s-- = i % 10 + '0';
135 } while ((i = i / 10));
136 if (j < 0)
137 *s-- = '-';
138 return ++s;
141 /* Temporary strings */
142 static char *stacked[16];
145 This joins strings end on end and allocates memory for the result.
146 The result is later automatically free'd and must not be free'd
147 by the caller.
149 static const char *
150 catstrs (const char *first,...)
152 static int i = 0;
153 va_list ap;
154 int len;
155 char *data;
157 if (!first)
158 return 0;
160 len = strlen (first);
161 va_start (ap, first);
163 while ((data = va_arg (ap, char *)) != 0)
164 len += strlen (data);
166 len++;
168 i = (i + 1) % 16;
169 g_free (stacked[i]);
171 stacked[i] = g_malloc (len);
172 va_end (ap);
173 va_start (ap, first);
174 strcpy (stacked[i], first);
175 while ((data = va_arg (ap, char *)) != 0)
176 strcat (stacked[i], data);
177 va_end (ap);
179 return stacked[i];
182 /* Free temporary strings */
183 void freestrs(void)
185 size_t i;
187 for (i = 0; i < sizeof(stacked) / sizeof(stacked[0]); i++) {
188 g_free (stacked[i]);
189 stacked[i] = NULL;
193 void edit_help_cmd (WEdit * edit)
195 interactive_display (NULL, "[Internal File Editor]");
196 edit->force |= REDRAW_COMPLETELY;
199 void edit_refresh_cmd (WEdit * edit)
201 #ifndef HAVE_SLANG
202 clr_scr();
203 do_refresh();
204 #else
206 int color;
207 edit_get_syntax_color (edit, -1, &color);
209 touchwin(stdscr);
210 #endif /* !HAVE_SLANG */
211 mc_refresh();
212 doupdate();
215 /* If 0 (quick save) then a) create/truncate <filename> file,
216 b) save to <filename>;
217 if 1 (safe save) then a) save to <tempnam>,
218 b) rename <tempnam> to <filename>;
219 if 2 (do backups) then a) save to <tempnam>,
220 b) rename <filename> to <filename.backup_ext>,
221 c) rename <tempnam> to <filename>. */
223 /* returns 0 on error, -1 on abort */
224 static int
225 edit_save_file (WEdit *edit, const char *filename)
227 char *p;
228 long filelen = 0;
229 char *savename = 0;
230 int this_save_mode, fd = -1;
232 if (!filename)
233 return 0;
234 if (!*filename)
235 return 0;
237 if (*filename != PATH_SEP && edit->dir) {
238 savename = concat_dir_and_file (edit->dir, filename);
239 filename = catstrs (savename, (char *) NULL);
240 g_free (savename);
243 this_save_mode = option_save_mode;
244 if (this_save_mode != EDIT_QUICK_SAVE) {
245 if (!vfs_file_is_local (filename) ||
246 (fd = mc_open (filename, O_RDONLY | O_BINARY)) == -1) {
248 * The file does not exists yet, so no safe save or
249 * backup are necessary.
251 this_save_mode = EDIT_QUICK_SAVE;
253 if (fd != -1)
254 mc_close (fd);
257 if (this_save_mode == EDIT_QUICK_SAVE &&
258 !edit->skip_detach_prompt) {
259 int rv;
260 struct stat sb;
262 rv = mc_stat (filename, &sb);
263 if (rv == 0 && sb.st_nlink > 1) {
264 rv = edit_query_dialog3 (_("Warning"),
265 _(" File has hard-links. Detach before saving? "),
266 _("&Yes"), _("&No"), _("&Cancel"));
267 switch (rv) {
268 case 0:
269 this_save_mode = EDIT_SAFE_SAVE;
270 /* fallthrough */
271 case 1:
272 edit->skip_detach_prompt = 1;
273 break;
274 default:
275 return -1;
279 /* Prevent overwriting changes from other editor sessions. */
280 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
282 /* The default action is "Cancel". */
283 query_set_sel(1);
285 rv = edit_query_dialog2 (
286 _("Warning"),
287 _("The file has been modified in the meantime. Save anyway?"),
288 _("&Yes"),
289 _("&Cancel"));
290 if (rv != 0)
291 return -1;
295 if (this_save_mode != EDIT_QUICK_SAVE) {
296 char *savedir, *saveprefix;
297 const char *slashpos;
298 slashpos = strrchr (filename, PATH_SEP);
299 if (slashpos) {
300 savedir = g_strdup (filename);
301 savedir[slashpos - filename + 1] = '\0';
302 } else
303 savedir = g_strdup (".");
304 saveprefix = concat_dir_and_file (savedir, "cooledit");
305 g_free (savedir);
306 fd = mc_mkstemps (&savename, saveprefix, NULL);
307 g_free (saveprefix);
308 if (!savename)
309 return 0;
310 /* FIXME:
311 * Close for now because mc_mkstemps use pure open system call
312 * to create temporary file and it needs to be reopened by
313 * VFS-aware mc_open().
315 close (fd);
316 } else
317 savename = g_strdup (filename);
319 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
320 mc_chmod (savename, edit->stat1.st_mode);
322 if ((fd =
323 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
324 edit->stat1.st_mode)) == -1)
325 goto error_save;
327 /* pipe save */
328 if ((p = edit_get_write_filter (savename, filename))) {
329 FILE *file;
331 mc_close (fd);
332 file = (FILE *) popen (p, "w");
334 if (file) {
335 filelen = edit_write_stream (edit, file);
336 #if 1
337 pclose (file);
338 #else
339 if (pclose (file) != 0) {
340 edit_error_dialog (_("Error"),
341 catstrs (_(" Error writing to pipe: "),
342 p, " ", (char *) NULL));
343 g_free (p);
344 goto error_save;
346 #endif
347 } else {
348 edit_error_dialog (_("Error"),
349 get_sys_error (catstrs
351 (" Cannot open pipe for writing: "),
352 p, " ", (char *) NULL)));
353 g_free (p);
354 goto error_save;
356 g_free (p);
357 } else {
358 long buf;
359 buf = 0;
360 filelen = edit->last_byte;
361 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
362 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
363 != EDIT_BUF_SIZE) {
364 mc_close (fd);
365 goto error_save;
367 buf++;
369 if (mc_write
370 (fd, (char *) edit->buffers1[buf],
371 edit->curs1 & M_EDIT_BUF_SIZE) !=
372 (edit->curs1 & M_EDIT_BUF_SIZE)) {
373 filelen = -1;
374 } else if (edit->curs2) {
375 edit->curs2--;
376 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
377 if (mc_write
378 (fd,
379 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
380 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
381 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
382 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
383 filelen = -1;
384 } else {
385 while (--buf >= 0) {
386 if (mc_write
387 (fd, (char *) edit->buffers2[buf],
388 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
389 filelen = -1;
390 break;
394 edit->curs2++;
396 if (mc_close (fd))
397 goto error_save;
399 /* Update the file information, especially the mtime. */
400 if (mc_stat (savename, &edit->stat1) == -1)
401 goto error_save;
404 if (filelen != edit->last_byte)
405 goto error_save;
407 if (this_save_mode == EDIT_DO_BACKUP) {
408 assert (option_backup_ext != NULL);
409 if (mc_rename (filename, catstrs (filename, option_backup_ext,
410 (char *) NULL)) == -1)
411 goto error_save;
414 if (this_save_mode != EDIT_QUICK_SAVE)
415 if (mc_rename (savename, filename) == -1)
416 goto error_save;
417 g_free (savename);
418 return 1;
419 error_save:
420 /* FIXME: Is this safe ?
421 * if (this_save_mode != EDIT_QUICK_SAVE)
422 * mc_unlink (savename);
424 g_free (savename);
425 return 0;
428 void menu_save_mode_cmd (void)
430 #define DLG_X 38
431 #define DLG_Y 10
432 static char *str_result;
433 static int save_mode_new;
434 static const char *str[] =
436 N_("Quick save "),
437 N_("Safe save "),
438 N_("Do backups -->")};
439 static QuickWidget widgets[] =
441 {quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
442 B_CANCEL, 0, 0, NULL},
443 {quick_button, 6, DLG_X, 7, DLG_Y, N_("&OK"), 0,
444 B_ENTER, 0, 0, NULL},
445 {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
446 0, 0, &str_result, "edit-backup-ext"},
447 {quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
448 0, 0, 0, NULL},
449 {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
450 0, &save_mode_new, (char **) str, NULL},
451 NULL_QuickWidget};
452 static QuickDialog dialog =
453 {DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
454 widgets, 0};
455 static int i18n_flag = 0;
457 if (!i18n_flag) {
458 size_t i;
459 size_t maxlen = 0;
460 int dlg_x;
461 size_t l1;
463 /* OK/Cancel buttons */
464 l1 = strlen (_(widgets[0].text)) + strlen (_(widgets[1].text)) + 5;
465 maxlen = max (maxlen, l1);
467 for (i = 0; i < 3; i++ ) {
468 str[i] = _(str[i]);
469 maxlen = max (maxlen, strlen (str[i]) + 7);
471 i18n_flag = 1;
473 dlg_x = maxlen + strlen (_(widgets[3].text)) + 5 + 1;
474 widgets[2].hotkey_pos = strlen (_(widgets[3].text)); /* input field length */
475 dlg_x = min (COLS, dlg_x);
476 dialog.xlen = dlg_x;
478 i = (dlg_x - l1)/3;
479 widgets[1].relative_x = i;
480 widgets[0].relative_x = i + strlen (_(widgets[1].text)) + i + 4;
482 widgets[2].relative_x = widgets[3].relative_x = maxlen + 2;
484 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
485 widgets[i].x_divisions = dlg_x;
488 assert (option_backup_ext != NULL);
489 widgets[2].text = option_backup_ext;
490 widgets[4].value = option_save_mode;
491 if (quick_dialog (&dialog) != B_ENTER)
492 return;
493 option_save_mode = save_mode_new;
495 g_free (option_backup_ext);
496 option_backup_ext = str_result;
497 str_result = NULL;
500 void
501 edit_set_filename (WEdit *edit, const char *f)
503 g_free (edit->filename);
504 if (!f)
505 f = "";
506 edit->filename = g_strdup (f);
507 if (edit->dir == NULL && *f != PATH_SEP)
508 #ifdef USE_VFS
509 edit->dir = g_strdup (vfs_get_current_dir ());
510 #else
511 edit->dir = g_get_current_dir ();
512 #endif
515 /* Here we want to warn the users of overwriting an existing file,
516 but only if they have made a change to the filename */
517 /* returns 1 on success */
519 edit_save_as_cmd (WEdit *edit)
521 /* This heads the 'Save As' dialog box */
522 char *exp;
523 int save_lock = 0;
524 int different_filename = 0;
526 exp = input_expand_dialog (
527 _(" Save As "), _(" Enter file name: "),MC_HISTORY_EDIT_SAVE_AS, edit->filename);
528 edit_push_action (edit, KEY_PRESS + edit->start_display);
530 if (exp) {
531 if (!*exp) {
532 g_free (exp);
533 edit->force |= REDRAW_COMPLETELY;
534 return 0;
535 } else {
536 int rv;
537 if (strcmp (edit->filename, exp)) {
538 int file;
539 different_filename = 1;
540 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
541 /* the file exists */
542 mc_close (file);
543 /* Overwrite the current file or cancel the operation */
544 if (edit_query_dialog2
545 (_("Warning"),
546 _(" A file already exists with this name. "),
547 _("&Overwrite"), _("&Cancel"))) {
548 edit->force |= REDRAW_COMPLETELY;
549 g_free (exp);
550 return 0;
553 save_lock = edit_lock_file (exp);
554 } else {
555 /* filenames equal, check if already locked */
556 if (!edit->locked && !edit->delete_file)
557 save_lock = edit_lock_file (exp);
560 rv = edit_save_file (edit, exp);
561 switch (rv) {
562 case 1:
563 /* Succesful, so unlock both files */
564 if (different_filename) {
565 if (save_lock)
566 edit_unlock_file (exp);
567 if (edit->locked)
568 edit->locked = edit_unlock_file (edit->filename);
569 } else {
570 if (edit->locked || save_lock)
571 edit->locked = edit_unlock_file (edit->filename);
574 edit_set_filename (edit, exp);
575 g_free (exp);
576 edit->modified = 0;
577 edit->delete_file = 0;
578 if (different_filename)
579 edit_load_syntax (edit, NULL, option_syntax_type);
580 edit->force |= REDRAW_COMPLETELY;
581 return 1;
582 default:
583 edit_error_dialog (_(" Save As "),
584 get_sys_error (_
585 (" Cannot save file. ")));
586 /* fallthrough */
587 case -1:
588 /* Failed, so maintain modify (not save) lock */
589 if (save_lock)
590 edit_unlock_file (exp);
591 g_free (exp);
592 edit->force |= REDRAW_COMPLETELY;
593 return 0;
597 edit->force |= REDRAW_COMPLETELY;
598 return 0;
601 /* {{{ Macro stuff starts here */
603 static cb_ret_t
604 raw_callback (struct Dlg_head *h, dlg_msg_t msg, int parm)
606 switch (msg) {
607 case DLG_KEY:
608 h->running = 0;
609 h->ret_value = parm;
610 return MSG_HANDLED;
611 default:
612 return default_dlg_callback (h, msg, parm);
616 /* gets a raw key from the keyboard. Passing cancel = 1 draws
617 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
618 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
619 and Esc are cannot returned */
621 edit_raw_key_query (const char *heading, const char *query, int cancel)
623 int w = strlen (query) + 7;
624 struct Dlg_head *raw_dlg =
625 create_dlg (0, 0, 7, w, dialog_colors, raw_callback,
626 NULL, heading,
627 DLG_CENTER | DLG_TRYUP | DLG_WANT_TAB);
628 add_widget (raw_dlg,
629 input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0));
630 add_widget (raw_dlg, label_new (3 - cancel, 2, query));
631 if (cancel)
632 add_widget (raw_dlg,
633 button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON,
634 _("Cancel"), 0));
635 run_dlg (raw_dlg);
636 w = raw_dlg->ret_value;
637 destroy_dlg (raw_dlg);
638 if (cancel) {
639 if (w == XCTRL ('g') || w == XCTRL ('c') || w == ESC_CHAR
640 || w == B_CANCEL)
641 return 0;
644 return w;
647 /* creates a macro file if it doesn't exist */
648 static FILE *edit_open_macro_file (const char *r)
650 const char *filename;
651 int file;
652 filename = catstrs (home_dir, PATH_SEP_STR MACRO_FILE, (char *) NULL);
653 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
654 return 0;
655 close (file);
656 return fopen (filename, r);
659 #define MAX_MACROS 1024
660 static int saved_macro[MAX_MACROS + 1];
661 static int saved_macros_loaded = 0;
664 This is just to stop the macro file be loaded over and over for keys
665 that aren't defined to anything. On slow systems this could be annoying.
667 static int
668 macro_exists (int k)
670 int i;
671 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
672 if (saved_macro[i] == k)
673 return i;
674 return -1;
677 /* returns 1 on error */
678 static int
679 edit_delete_macro (WEdit * edit, int k)
681 struct macro macro[MAX_MACRO_LENGTH];
682 FILE *f, *g;
683 int s, i, n, j = 0;
685 (void) edit;
687 if (saved_macros_loaded)
688 if ((j = macro_exists (k)) < 0)
689 return 0;
690 g = fopen (catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL), "w");
691 if (!g) {
692 edit_error_dialog (_(" Delete macro "),
693 get_sys_error (_(" Cannot open temp file ")));
694 return 1;
696 f = edit_open_macro_file ("r");
697 if (!f) {
698 edit_error_dialog (_(" Delete macro "),
699 get_sys_error (_(" Cannot open macro file ")));
700 fclose (g);
701 return 1;
703 for (;;) {
704 n = fscanf (f, ("key '%d 0': "), &s);
705 if (!n || n == EOF)
706 break;
707 n = 0;
708 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
709 n++;
710 fscanf (f, ";\n");
711 if (s != k) {
712 fprintf (g, ("key '%d 0': "), s);
713 for (i = 0; i < n; i++)
714 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
715 fprintf (g, ";\n");
718 fclose (f);
719 fclose (g);
720 if (rename (catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL), catstrs (home_dir, PATH_SEP_STR MACRO_FILE, (char *) NULL)) == -1) {
721 edit_error_dialog (_(" Delete macro "),
722 get_sys_error (_(" Cannot overwrite macro file ")));
723 return 1;
725 if (saved_macros_loaded)
726 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
727 return 0;
730 /* returns 0 on error */
731 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
733 FILE *f;
734 int s, i;
736 edit_push_action (edit, KEY_PRESS + edit->start_display);
737 s = edit_raw_key_query (_(" Save macro "),
738 _(" Press the macro's new hotkey: "), 1);
739 edit->force |= REDRAW_COMPLETELY;
740 if (s) {
741 if (edit_delete_macro (edit, s))
742 return 0;
743 f = edit_open_macro_file ("a+");
744 if (f) {
745 fprintf (f, ("key '%d 0': "), s);
746 for (i = 0; i < n; i++)
747 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
748 fprintf (f, ";\n");
749 fclose (f);
750 if (saved_macros_loaded) {
751 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
752 saved_macro[i] = s;
754 return 1;
755 } else
756 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
758 return 0;
761 void edit_delete_macro_cmd (WEdit * edit)
763 int command;
765 command = edit_raw_key_query (_ (" Delete macro "),
766 _ (" Press macro hotkey: "), 1);
768 if (!command)
769 return;
771 edit_delete_macro (edit, command);
774 /* return 0 on error */
775 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
777 FILE *f;
778 int s, i = 0, found = 0;
780 (void) edit;
782 if (saved_macros_loaded)
783 if (macro_exists (k) < 0)
784 return 0;
786 if ((f = edit_open_macro_file ("r"))) {
787 struct macro dummy;
788 do {
789 int u;
790 u = fscanf (f, ("key '%d 0': "), &s);
791 if (!u || u == EOF)
792 break;
793 if (!saved_macros_loaded)
794 saved_macro[i++] = s;
795 if (!found) {
796 *n = 0;
797 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
798 (*n)++;
799 } else {
800 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
802 fscanf (f, ";\n");
803 if (s == k)
804 found = 1;
805 } while (!found || !saved_macros_loaded);
806 if (!saved_macros_loaded) {
807 saved_macro[i] = 0;
808 saved_macros_loaded = 1;
810 fclose (f);
811 return found;
812 } else
813 edit_error_dialog (_(" Load macro "),
814 get_sys_error (_(" Cannot open macro file ")));
815 return 0;
818 /* }}} Macro stuff starts here */
820 /* returns 1 on success */
821 int edit_save_confirm_cmd (WEdit * edit)
823 const char *f;
825 if (edit_confirm_save) {
826 f = catstrs (_(" Confirm save file? : "), edit->filename, " ", (char *) NULL);
827 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel")))
828 return 0;
830 return edit_save_cmd (edit);
834 /* returns 1 on success */
835 static int
836 edit_save_cmd (WEdit *edit)
838 int res, save_lock = 0;
840 if (!edit->locked && !edit->delete_file)
841 save_lock = edit_lock_file (edit->filename);
842 res = edit_save_file (edit, edit->filename);
844 /* Maintain modify (not save) lock on failure */
845 if ((res > 0 && edit->locked) || save_lock)
846 edit->locked = edit_unlock_file (edit->filename);
848 /* On failure try 'save as', it does locking on its own */
849 if (!res)
850 return edit_save_as_cmd (edit);
851 edit->force |= REDRAW_COMPLETELY;
852 if (res > 0) {
853 edit->delete_file = 0;
854 edit->modified = 0;
857 return 1;
861 /* returns 1 on success */
862 int edit_new_cmd (WEdit * edit)
864 if (edit->modified) {
865 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
866 edit->force |= REDRAW_COMPLETELY;
867 return 0;
870 edit->force |= REDRAW_COMPLETELY;
872 return edit_renew (edit); /* if this gives an error, something has really screwed up */
875 /* returns 1 on error */
876 static int
877 edit_load_file_from_filename (WEdit * edit, char *exp)
879 int prev_locked = edit->locked;
880 char *prev_filename = g_strdup (edit->filename);
882 if (!edit_reload (edit, exp)) {
883 g_free (prev_filename);
884 return 1;
887 if (prev_locked)
888 edit_unlock_file (prev_filename);
889 g_free (prev_filename);
890 return 0;
894 edit_load_cmd (WEdit *edit)
896 char *exp;
898 if (edit->modified) {
899 if (edit_query_dialog2
900 (_("Warning"),
901 _(" Current text was modified without a file save. \n"
902 " Continue discards these changes. "), _("C&ontinue"),
903 _("&Cancel"))) {
904 edit->force |= REDRAW_COMPLETELY;
905 return 0;
909 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
910 MC_HISTORY_EDIT_LOAD, edit->filename);
912 if (exp) {
913 if (*exp)
914 edit_load_file_from_filename (edit, exp);
915 g_free (exp);
917 edit->force |= REDRAW_COMPLETELY;
918 return 0;
922 if mark2 is -1 then marking is from mark1 to the cursor.
923 Otherwise its between the markers. This handles this.
924 Returns 1 if no text is marked.
926 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
928 if (edit->mark1 != edit->mark2) {
929 if (edit->mark2 >= 0) {
930 *start_mark = min (edit->mark1, edit->mark2);
931 *end_mark = max (edit->mark1, edit->mark2);
932 } else {
933 *start_mark = min (edit->mark1, edit->curs1);
934 *end_mark = max (edit->mark1, edit->curs1);
935 edit->column2 = edit->curs_col;
937 return 0;
938 } else {
939 *start_mark = *end_mark = 0;
940 edit->column2 = edit->column1 = 0;
941 return 1;
945 #define space_width 1
947 static void
948 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
950 long cursor;
951 int i, col;
952 cursor = edit->curs1;
953 col = edit_get_col (edit);
954 for (i = 0; i < size; i++) {
955 if (data[i] == '\n') { /* fill in and move to next line */
956 int l;
957 long p;
958 if (edit_get_byte (edit, edit->curs1) != '\n') {
959 l = width - (edit_get_col (edit) - col);
960 while (l > 0) {
961 edit_insert (edit, ' ');
962 l -= space_width;
965 for (p = edit->curs1;; p++) {
966 if (p == edit->last_byte) {
967 edit_cursor_move (edit, edit->last_byte - edit->curs1);
968 edit_insert_ahead (edit, '\n');
969 p++;
970 break;
972 if (edit_get_byte (edit, p) == '\n') {
973 p++;
974 break;
977 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
978 l = col - edit_get_col (edit);
979 while (l >= space_width) {
980 edit_insert (edit, ' ');
981 l -= space_width;
983 continue;
985 edit_insert (edit, data[i]);
987 edit_cursor_move (edit, cursor - edit->curs1);
991 void
992 edit_block_copy_cmd (WEdit *edit)
994 long start_mark, end_mark, current = edit->curs1;
995 int size;
996 unsigned char *copy_buf;
998 edit_update_curs_col (edit);
999 if (eval_marks (edit, &start_mark, &end_mark))
1000 return;
1002 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1004 /* all that gets pushed are deletes hence little space is used on the stack */
1006 edit_push_markers (edit);
1008 if (column_highlighting) {
1009 edit_insert_column_of_text (edit, copy_buf, size,
1010 abs (edit->column2 - edit->column1));
1011 } else {
1012 while (size--)
1013 edit_insert_ahead (edit, copy_buf[size]);
1016 g_free (copy_buf);
1017 edit_scroll_screen_over_cursor (edit);
1019 if (column_highlighting) {
1020 edit_set_markers (edit, 0, 0, 0, 0);
1021 edit_push_action (edit, COLUMN_ON);
1022 column_highlighting = 0;
1023 } else if (start_mark < current && end_mark > current)
1024 edit_set_markers (edit, start_mark,
1025 end_mark + end_mark - start_mark, 0, 0);
1027 edit->force |= REDRAW_PAGE;
1031 void
1032 edit_block_move_cmd (WEdit *edit)
1034 long count;
1035 long current;
1036 unsigned char *copy_buf;
1037 long start_mark, end_mark;
1038 int deleted = 0;
1039 int x = 0;
1041 if (eval_marks (edit, &start_mark, &end_mark))
1042 return;
1043 if (column_highlighting) {
1044 edit_update_curs_col (edit);
1045 x = edit->curs_col;
1046 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1047 if ((x > edit->column1 && x < edit->column2)
1048 || (x > edit->column2 && x < edit->column1))
1049 return;
1050 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1051 return;
1053 if ((end_mark - start_mark) > option_max_undo / 2)
1054 if (edit_query_dialog2
1055 (_("Warning"),
1057 (" Block is large, you may not be able to undo this action. "),
1058 _("C&ontinue"), _("&Cancel")))
1059 return;
1061 edit_push_markers (edit);
1062 current = edit->curs1;
1063 if (column_highlighting) {
1064 int size, c1, c2, line;
1065 line = edit->curs_line;
1066 if (edit->mark2 < 0)
1067 edit_mark_cmd (edit, 0);
1068 c1 = min (edit->column1, edit->column2);
1069 c2 = max (edit->column1, edit->column2);
1070 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1071 if (x < c2) {
1072 edit_block_delete_cmd (edit);
1073 deleted = 1;
1075 edit_move_to_line (edit, line);
1076 edit_cursor_move (edit,
1077 edit_move_forward3 (edit,
1078 edit_bol (edit, edit->curs1),
1079 x, 0) - edit->curs1);
1080 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1081 if (!deleted) {
1082 line = edit->curs_line;
1083 edit_update_curs_col (edit);
1084 x = edit->curs_col;
1085 edit_block_delete_cmd (edit);
1086 edit_move_to_line (edit, line);
1087 edit_cursor_move (edit,
1088 edit_move_forward3 (edit,
1089 edit_bol (edit,
1090 edit->curs1),
1091 x, 0) - edit->curs1);
1093 edit_set_markers (edit, 0, 0, 0, 0);
1094 edit_push_action (edit, COLUMN_ON);
1095 column_highlighting = 0;
1096 } else {
1097 copy_buf = g_malloc (end_mark - start_mark);
1098 edit_cursor_move (edit, start_mark - edit->curs1);
1099 edit_scroll_screen_over_cursor (edit);
1100 count = start_mark;
1101 while (count < end_mark) {
1102 copy_buf[end_mark - count - 1] = edit_delete (edit);
1103 count++;
1105 edit_scroll_screen_over_cursor (edit);
1106 edit_cursor_move (edit,
1107 current - edit->curs1 -
1108 (((current - edit->curs1) >
1109 0) ? end_mark - start_mark : 0));
1110 edit_scroll_screen_over_cursor (edit);
1111 while (count-- > start_mark)
1112 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1113 edit_set_markers (edit, edit->curs1,
1114 edit->curs1 + end_mark - start_mark, 0, 0);
1116 edit_scroll_screen_over_cursor (edit);
1117 g_free (copy_buf);
1118 edit->force |= REDRAW_PAGE;
1121 static void
1122 edit_delete_column_of_text (WEdit * edit)
1124 long p, q, r, m1, m2;
1125 int b, c, d;
1126 int n;
1128 eval_marks (edit, &m1, &m2);
1129 n = edit_move_forward (edit, m1, 0, m2) + 1;
1130 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1131 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1133 b = min (c, d);
1134 c = max (c, d);
1136 while (n--) {
1137 r = edit_bol (edit, edit->curs1);
1138 p = edit_move_forward3 (edit, r, b, 0);
1139 q = edit_move_forward3 (edit, r, c, 0);
1140 if (p < m1)
1141 p = m1;
1142 if (q > m2)
1143 q = m2;
1144 edit_cursor_move (edit, p - edit->curs1);
1145 while (q > p) { /* delete line between margins */
1146 if (edit_get_byte (edit, edit->curs1) != '\n')
1147 edit_delete (edit);
1148 q--;
1150 if (n) /* move to next line except on the last delete */
1151 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1155 /* if success return 0 */
1156 static int
1157 edit_block_delete (WEdit *edit)
1159 long count;
1160 long start_mark, end_mark;
1161 if (eval_marks (edit, &start_mark, &end_mark))
1162 return 0;
1163 if (column_highlighting && edit->mark2 < 0)
1164 edit_mark_cmd (edit, 0);
1165 if ((end_mark - start_mark) > option_max_undo / 2) {
1166 /* Warning message with a query to continue or cancel the operation */
1167 if (edit_query_dialog2
1168 (_("Warning"),
1170 (" Block is large, you may not be able to undo this action. "),
1171 _("C&ontinue"), _("&Cancel"))) {
1172 return 1;
1175 edit_push_markers (edit);
1176 edit_cursor_move (edit, start_mark - edit->curs1);
1177 edit_scroll_screen_over_cursor (edit);
1178 count = start_mark;
1179 if (start_mark < end_mark) {
1180 if (column_highlighting) {
1181 if (edit->mark2 < 0)
1182 edit_mark_cmd (edit, 0);
1183 edit_delete_column_of_text (edit);
1184 } else {
1185 while (count < end_mark) {
1186 edit_delete (edit);
1187 count++;
1191 edit_set_markers (edit, 0, 0, 0, 0);
1192 edit->force |= REDRAW_PAGE;
1193 return 0;
1196 /* returns 1 if canceelled by user */
1197 int edit_block_delete_cmd (WEdit * edit)
1199 long start_mark, end_mark;
1200 if (eval_marks (edit, &start_mark, &end_mark)) {
1201 edit_delete_line (edit);
1202 return 0;
1204 return edit_block_delete (edit);
1208 #define INPUT_INDEX 9
1209 #define SEARCH_DLG_WIDTH 58
1210 #define SEARCH_DLG_HEIGHT 10
1211 #define REPLACE_DLG_WIDTH 58
1212 #define REPLACE_DLG_HEIGHT 15
1213 #define CONFIRM_DLG_WIDTH 79
1214 #define CONFIRM_DLG_HEIGTH 6
1215 #define B_REPLACE_ALL (B_USER+1)
1216 #define B_REPLACE_ONE (B_USER+2)
1217 #define B_SKIP_REPLACE (B_USER+3)
1219 static int
1220 edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
1222 QuickWidget quick_widgets[] =
1224 {quick_button, 63, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Cancel"),
1225 0, B_CANCEL, 0, 0, NULL},
1226 {quick_button, 50, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("O&ne"),
1227 0, B_REPLACE_ONE, 0, 0, NULL},
1228 {quick_button, 37, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("A&ll"),
1229 0, B_REPLACE_ALL, 0, 0, NULL},
1230 {quick_button, 21, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Skip"),
1231 0, B_SKIP_REPLACE, 0, 0, NULL},
1232 {quick_button, 4, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Replace"),
1233 0, B_ENTER, 0, 0, NULL},
1234 {quick_label, 2, CONFIRM_DLG_WIDTH, 2, CONFIRM_DLG_HEIGTH, 0,
1235 0, 0, 0, 0, 0},
1236 NULL_QuickWidget};
1238 GString *label_text = g_string_new (_(" Replace with: "));
1239 if (*replace_text) {
1240 size_t label_len;
1241 label_len = label_text->len;
1242 g_string_append (label_text, replace_text);
1243 convert_to_display (label_text->str + label_len);
1245 quick_widgets[5].text = label_text->str;
1248 int retval;
1249 QuickDialog Quick_input =
1250 {CONFIRM_DLG_WIDTH, CONFIRM_DLG_HEIGTH, 0, 0, N_ (" Confirm replace "),
1251 "[Input Line Keys]", 0 /*quick_widgets */, 0 };
1253 Quick_input.widgets = quick_widgets;
1255 Quick_input.xpos = xpos;
1257 /* Sometimes menu can hide replaced text. I don't like it */
1259 if ((edit->curs_row >= ypos - 1) && (edit->curs_row <= ypos + CONFIRM_DLG_HEIGTH - 1))
1260 ypos -= CONFIRM_DLG_HEIGTH;
1262 Quick_input.ypos = ypos;
1263 retval = quick_dialog (&Quick_input);
1264 g_string_free (label_text, TRUE);
1265 return retval;
1269 static void
1270 edit_replace_dialog (WEdit * edit, const char *search_default,
1271 const char *replace_default, const char *argorder_default,
1272 /*@out@*/ char **search_text, /*@out@*/ char **replace_text,
1273 /*@out@*/ char **arg_order)
1275 int treplace_scanf = replace_scanf;
1276 int treplace_regexp = replace_regexp;
1277 int treplace_all = replace_all;
1278 int treplace_prompt = replace_prompt;
1279 int treplace_backwards = replace_backwards;
1280 int treplace_whole = replace_whole;
1281 int treplace_case = replace_case;
1283 /* Alt-p is in use as hotkey for previous entry; don't use */
1284 QuickWidget quick_widgets[] =
1286 {quick_button, 6, 10, 12, REPLACE_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1287 0, NULL},
1288 {quick_button, 2, 10, 12, REPLACE_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
1289 0, NULL},
1290 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1291 0, 0, NULL},
1292 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("replace &All"), 0, 0,
1293 0, 0, NULL},
1294 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("pro&Mpt on replace"), 0, 0,
1295 0, 0, NULL},
1296 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1297 0, 0, NULL},
1298 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1299 0, 0, NULL},
1300 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1301 0, 0, NULL},
1302 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 8, REPLACE_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1303 0, 0, NULL},
1304 {quick_input, 3, REPLACE_DLG_WIDTH, 7, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1305 0, "edit-argord"},
1306 {quick_label, 2, REPLACE_DLG_WIDTH, 6, REPLACE_DLG_HEIGHT, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1307 0, 0, 0},
1308 {quick_input, 3, REPLACE_DLG_WIDTH, 5, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1309 0, "edit-replace"},
1310 {quick_label, 2, REPLACE_DLG_WIDTH, 4, REPLACE_DLG_HEIGHT, N_(" Enter replacement string:"), 0, 0, 0,
1311 0, 0},
1312 {quick_input, 3, REPLACE_DLG_WIDTH, 3, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1313 0, "edit-search"},
1314 {quick_label, 2, REPLACE_DLG_WIDTH, 2, REPLACE_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1315 0, 0},
1316 NULL_QuickWidget};
1318 (void) edit;
1320 quick_widgets[2].result = &treplace_scanf;
1321 quick_widgets[3].result = &treplace_all;
1322 quick_widgets[4].result = &treplace_prompt;
1323 quick_widgets[5].result = &treplace_backwards;
1324 quick_widgets[6].result = &treplace_regexp;
1325 quick_widgets[7].result = &treplace_whole;
1326 quick_widgets[8].result = &treplace_case;
1327 quick_widgets[9].str_result = arg_order;
1328 quick_widgets[9].text = argorder_default;
1329 quick_widgets[11].str_result = replace_text;
1330 quick_widgets[11].text = replace_default;
1331 quick_widgets[13].str_result = search_text;
1332 quick_widgets[13].text = search_default;
1334 QuickDialog Quick_input =
1335 {REPLACE_DLG_WIDTH, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "),
1336 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1338 Quick_input.widgets = quick_widgets;
1340 if (quick_dialog (&Quick_input) != B_CANCEL) {
1341 replace_scanf = treplace_scanf;
1342 replace_backwards = treplace_backwards;
1343 replace_regexp = treplace_regexp;
1344 replace_all = treplace_all;
1345 replace_prompt = treplace_prompt;
1346 replace_whole = treplace_whole;
1347 replace_case = treplace_case;
1348 return;
1349 } else {
1350 *arg_order = NULL;
1351 *replace_text = NULL;
1352 *search_text = NULL;
1353 return;
1359 static void
1360 edit_search_dialog (WEdit * edit, char **search_text)
1362 int treplace_scanf = replace_scanf;
1363 int treplace_regexp = replace_regexp;
1364 int treplace_whole = replace_whole;
1365 int treplace_case = replace_case;
1366 int treplace_backwards = replace_backwards;
1368 QuickWidget quick_widgets[] =
1370 {quick_button, 6, 10, 7, SEARCH_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1371 0, NULL},
1372 {quick_button, 2, 10, 7, SEARCH_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
1373 0, NULL},
1374 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1375 0, 0, NULL },
1376 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1377 0, 0, NULL},
1378 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1379 0, 0, NULL},
1380 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1381 0, 0, NULL},
1382 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 4, SEARCH_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1383 0, 0, NULL},
1384 {quick_input, 3, SEARCH_DLG_WIDTH, 3, SEARCH_DLG_HEIGHT, "", 52, 0, 0,
1385 0, "edit-search"},
1386 {quick_label, 2, SEARCH_DLG_WIDTH, 2, SEARCH_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1387 0, 0},
1388 NULL_QuickWidget};
1390 (void) edit;
1392 quick_widgets[2].result = &treplace_scanf;
1393 quick_widgets[3].result = &treplace_backwards;
1394 quick_widgets[4].result = &treplace_regexp;
1395 quick_widgets[5].result = &treplace_whole;
1396 quick_widgets[6].result = &treplace_case;
1397 quick_widgets[7].str_result = search_text;
1398 quick_widgets[7].text = *search_text;
1401 QuickDialog Quick_input =
1402 {SEARCH_DLG_WIDTH, SEARCH_DLG_HEIGHT, -1, 0, N_("Search"),
1403 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1405 Quick_input.widgets = quick_widgets;
1407 if (quick_dialog (&Quick_input) != B_CANCEL) {
1408 replace_scanf = treplace_scanf;
1409 replace_backwards = treplace_backwards;
1410 replace_regexp = treplace_regexp;
1411 replace_whole = treplace_whole;
1412 replace_case = treplace_case;
1413 } else {
1414 *search_text = NULL;
1420 static long sargs[NUM_REPL_ARGS][256 / sizeof (long)];
1422 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1423 sargs[4], sargs[5], sargs[6], sargs[7], \
1424 sargs[8], sargs[9], sargs[10], sargs[11], \
1425 sargs[12], sargs[13], sargs[14], sargs[15]
1427 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1428 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1429 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1430 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1433 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1434 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1435 static int
1436 string_regexp_search (char *pattern, char *string, int match_type,
1437 int match_bol, int icase, int *found_len, void *d)
1439 static regex_t r;
1440 static char *old_pattern = NULL;
1441 static int old_type, old_icase;
1442 regmatch_t *pmatch;
1443 static regmatch_t s[1];
1445 pmatch = (regmatch_t *) d;
1446 if (!pmatch)
1447 pmatch = s;
1449 if (!old_pattern || strcmp (old_pattern, pattern)
1450 || old_type != match_type || old_icase != icase) {
1451 if (old_pattern) {
1452 regfree (&r);
1453 g_free (old_pattern);
1454 old_pattern = 0;
1456 if (regcomp (&r, pattern, REG_EXTENDED | (icase ? REG_ICASE : 0) |
1457 REG_NEWLINE)) {
1458 *found_len = 0;
1459 return -3;
1461 old_pattern = g_strdup (pattern);
1462 old_type = match_type;
1463 old_icase = icase;
1465 if (regexec
1466 (&r, string, d ? NUM_REPL_ARGS : 1, pmatch,
1467 ((match_bol
1468 || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) {
1469 *found_len = 0;
1470 return -1;
1472 *found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
1473 return (pmatch[0].rm_so);
1476 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1477 (and the above) routines to work properly - paul */
1479 typedef int (*edit_getbyte_fn) (WEdit *, long);
1481 static long
1482 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)
1484 long p, q = 0;
1485 long l = strlen ((char *) exp), f = 0;
1486 int n = 0;
1488 for (p = 0; p < l; p++) /* count conversions... */
1489 if (exp[p] == '%')
1490 if (exp[++p] != '%') /* ...except for "%%" */
1491 n++;
1493 if (replace_scanf || replace_regexp) {
1494 int c;
1495 unsigned char *buf;
1496 unsigned char mbuf[MAX_REPL_LEN * 2 + 3];
1498 replace_scanf = (!replace_regexp); /* can't have both */
1500 buf = mbuf;
1502 if (replace_scanf) {
1503 unsigned char e[MAX_REPL_LEN];
1504 if (n >= NUM_REPL_ARGS)
1505 return -3;
1507 if (replace_case) {
1508 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++)
1509 buf[p - start] = (*get_byte) (data, p);
1510 } else {
1511 for (p = 0; exp[p] != 0; p++)
1512 exp[p] = my_lower_case (exp[p]);
1513 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) {
1514 c = (*get_byte) (data, p);
1515 buf[p - start] = my_lower_case (c);
1519 buf[(q = p - start)] = 0;
1520 strcpy ((char *) e, (char *) exp);
1521 strcat ((char *) e, "%n");
1522 exp = e;
1524 while (q) {
1525 *((int *) sargs[n]) = 0; /* --> here was the problem - now fixed: good */
1526 if (n == sscanf ((char *) buf, (char *) exp, SCANF_ARGS)) {
1527 if (*((int *) sargs[n])) {
1528 *len = *((int *) sargs[n]);
1529 return start;
1532 if (once_only)
1533 return -2;
1534 if (q + start < last_byte) {
1535 if (replace_case) {
1536 buf[q] = (*get_byte) (data, q + start);
1537 } else {
1538 c = (*get_byte) (data, q + start);
1539 buf[q] = my_lower_case (c);
1541 q++;
1543 buf[q] = 0;
1544 start++;
1545 buf++; /* move the window along */
1546 if (buf == mbuf + MAX_REPL_LEN) { /* the window is about to go past the end of array, so... */
1547 memmove (mbuf, buf, strlen ((char *) buf) + 1); /* reset it */
1548 buf = mbuf;
1550 q--;
1552 } else { /* regexp matching */
1553 long offset = 0;
1554 int found_start, match_bol, move_win = 0;
1556 while (start + offset < last_byte) {
1557 match_bol = (start == 0 || (*get_byte) (data, start + offset - 1) == '\n');
1558 if (!move_win) {
1559 p = start + offset;
1560 q = 0;
1562 for (; p < last_byte && q < MAX_REPL_LEN; p++, q++) {
1563 mbuf[q] = (*get_byte) (data, p);
1564 if (mbuf[q] == '\n') {
1565 q++;
1566 break;
1569 offset += q;
1570 mbuf[q] = 0;
1572 buf = mbuf;
1573 while (q) {
1574 found_start = string_regexp_search ((char *) exp, (char *) buf, match_normal, match_bol, !replace_case, len, d);
1576 if (found_start <= -2) { /* regcomp/regexec error */
1577 *len = 0;
1578 return -3;
1580 else if (found_start == -1) /* not found: try next line */
1581 break;
1582 else if (*len == 0) { /* null pattern: try again at next character */
1583 q--;
1584 buf++;
1585 match_bol = 0;
1586 continue;
1588 else /* found */
1589 return (start + offset - q + found_start);
1591 if (once_only)
1592 return -2;
1594 if (buf[q - 1] != '\n') { /* incomplete line: try to recover */
1595 buf = mbuf + MAX_REPL_LEN / 2;
1596 q = strlen ((const char *) buf);
1597 memmove (mbuf, buf, q);
1598 p = start + q;
1599 move_win = 1;
1601 else
1602 move_win = 0;
1605 } else {
1606 *len = strlen ((const char *) exp);
1607 if (replace_case) {
1608 for (p = start; p <= last_byte - l; p++) {
1609 if ((*get_byte) (data, p) == (unsigned char)exp[0]) { /* check if first char matches */
1610 for (f = 0, q = 0; q < l && f < 1; q++)
1611 if ((*get_byte) (data, q + p) != (unsigned char)exp[q])
1612 f = 1;
1613 if (f == 0)
1614 return p;
1616 if (once_only)
1617 return -2;
1619 } else {
1620 for (p = 0; exp[p] != 0; p++)
1621 exp[p] = my_lower_case (exp[p]);
1623 for (p = start; p <= last_byte - l; p++) {
1624 if (my_lower_case ((*get_byte) (data, p)) == (unsigned char)exp[0]) {
1625 for (f = 0, q = 0; q < l && f < 1; q++)
1626 if (my_lower_case ((*get_byte) (data, q + p)) != (unsigned char)exp[q])
1627 f = 1;
1628 if (f == 0)
1629 return p;
1631 if (once_only)
1632 return -2;
1636 return -2;
1640 static long
1641 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)
1642 { /*front end to find_string to check for
1643 whole words */
1644 long p;
1645 p = search_start;
1647 while ((p = edit_find_string (p, exp, len, last_byte, get_byte, data, once_only, d)) >= 0) {
1648 if (replace_whole) {
1649 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1650 if (!strcasechr (option_whole_chars_search, (*get_byte) (data, p - 1))
1651 && !strcasechr (option_whole_chars_search, (*get_byte) (data, p + *len)))
1652 return p;
1653 if (once_only)
1654 return -2;
1655 } else
1656 return p;
1657 if (once_only)
1658 break;
1659 p++; /*not a whole word so continue search. */
1661 return p;
1664 static long
1665 edit_find (long search_start, unsigned char *exp, int *len, long last_byte, edit_getbyte_fn get_byte, void *data, void *d)
1667 long p;
1668 if (replace_backwards) {
1669 while (search_start >= 0) {
1670 p = edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 1, d);
1671 if (p == search_start)
1672 return p;
1673 search_start--;
1675 } else {
1676 return edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 0, d);
1678 return -2;
1681 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1683 #define snprint(v) { \
1684 *p1++ = *p++; \
1685 *p1 = '\0'; \
1686 n = snprintf(s,e-s,q1,v); \
1687 if (n >= (size_t) (e - s)) goto nospc; \
1688 s += n; \
1691 /* this function uses the sprintf command to do a vprintf */
1692 /* it takes pointers to arguments instead of the arguments themselves */
1693 /* The return value is the number of bytes written excluding '\0'
1694 if successfull, -1 if the resulting string would be too long and
1695 -2 if the format string is errorneous. */
1696 static int snprintf_p (char *str, size_t size, const char *fmt,...)
1697 __attribute__ ((format (printf, 3, 4)));
1699 static int snprintf_p (char *str, size_t size, const char *fmt,...)
1701 va_list ap;
1702 size_t n;
1703 const char *q, *p;
1704 char *s = str, *e = str + size;
1705 char q1[40];
1706 char *p1;
1707 int nargs = 0;
1709 va_start (ap, fmt);
1710 p = q = fmt;
1712 while ((p = strchr (p, '%'))) {
1713 n = p - q;
1714 if (n >= (size_t) (e - s))
1715 goto nospc;
1716 memcpy (s, q, n); /* copy stuff between format specifiers */
1717 s += n;
1718 q = p;
1719 p1 = q1;
1720 *p1++ = *p++;
1721 if (*p == '%') {
1722 p++;
1723 *s++ = '%';
1724 if (s == e)
1725 goto nospc;
1726 q = p;
1727 continue;
1729 if (*p == 'n')
1730 goto err;
1731 /* We were passed only 16 arguments. */
1732 if (++nargs == 16)
1733 goto err;
1734 if (*p == '#')
1735 *p1++ = *p++;
1736 if (*p == '0')
1737 *p1++ = *p++;
1738 if (*p == '-')
1739 *p1++ = *p++;
1740 if (*p == '+')
1741 *p1++ = *p++;
1742 if (*p == '*') {
1743 p++;
1744 strcpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace field width with a number */
1745 p1 += strlen (p1);
1746 } else {
1747 while (is_digit (*p) && p1 < q1 + 20)
1748 *p1++ = *p++;
1749 if (is_digit (*p))
1750 goto err;
1752 if (*p == '.')
1753 *p1++ = *p++;
1754 if (*p == '*') {
1755 p++;
1756 strcpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace precision with a number */
1757 p1 += strlen (p1);
1758 } else {
1759 while (is_digit (*p) && p1 < q1 + 32)
1760 *p1++ = *p++;
1761 if (is_digit (*p))
1762 goto err;
1764 /* flags done, now get argument */
1765 if (*p == 's') {
1766 snprint (va_arg (ap, char *));
1767 } else if (*p == 'h') {
1768 if (strchr ("diouxX", *p))
1769 snprint (*va_arg (ap, short *));
1770 } else if (*p == 'l') {
1771 *p1++ = *p++;
1772 if (strchr ("diouxX", *p))
1773 snprint (*va_arg (ap, long *));
1774 } else if (strchr ("cdiouxX", *p)) {
1775 snprint (*va_arg (ap, int *));
1776 } else if (*p == 'L') {
1777 *p1++ = *p++;
1778 if (strchr ("EefgG", *p))
1779 snprint (*va_arg (ap, double *)); /* should be long double */
1780 } else if (strchr ("EefgG", *p)) {
1781 snprint (*va_arg (ap, double *));
1782 } else if (strchr ("DOU", *p)) {
1783 snprint (*va_arg (ap, long *));
1784 } else if (*p == 'p') {
1785 snprint (*va_arg (ap, void **));
1786 } else
1787 goto err;
1788 q = p;
1790 va_end (ap);
1791 n = strlen (q);
1792 if (n >= (size_t) (e - s))
1793 return -1;
1794 memcpy (s, q, n + 1);
1795 return s + n - str;
1796 nospc:
1797 va_end (ap);
1798 return -1;
1799 err:
1800 va_end (ap);
1801 return -2;
1804 static void regexp_error (WEdit *edit)
1806 (void) edit;
1807 edit_error_dialog (_("Error"), _(" Invalid regular expression, or scanf expression with too many conversions "));
1810 /* call with edit = 0 before shutdown to close memory leaks */
1811 void
1812 edit_replace_cmd (WEdit *edit, int again)
1814 static regmatch_t pmatch[NUM_REPL_ARGS];
1815 /* 1 = search string, 2 = replace with, 3 = argument order */
1816 static char *saved1 = NULL; /* saved default[123] */
1817 static char *saved2 = NULL;
1818 static char *saved3 = NULL;
1819 char *input1 = NULL; /* user input from the dialog */
1820 char *input2 = NULL;
1821 char *input3 = NULL;
1822 int replace_yes;
1823 int replace_continue;
1824 int treplace_prompt = 0;
1825 long times_replaced = 0, last_search;
1826 int argord[NUM_REPL_ARGS];
1828 if (!edit) {
1829 g_free (saved1), saved1 = NULL;
1830 g_free (saved2), saved2 = NULL;
1831 g_free (saved3), saved3 = NULL;
1832 return;
1835 last_search = edit->last_byte;
1837 edit->force |= REDRAW_COMPLETELY;
1839 if (again && !saved1 && !saved2)
1840 again = 0;
1842 if (again) {
1843 input1 = g_strdup (saved1 ? saved1 : "");
1844 input2 = g_strdup (saved2 ? saved2 : "");
1845 input3 = g_strdup (saved3 ? saved3 : "");
1846 } else {
1847 char *disp1 = g_strdup (saved1 ? saved1 : "");
1848 char *disp2 = g_strdup (saved2 ? saved2 : "");
1849 char *disp3 = g_strdup (saved3 ? saved3 : "");
1851 convert_to_display (disp1);
1852 convert_to_display (disp2);
1853 convert_to_display (disp3);
1855 edit_push_action (edit, KEY_PRESS + edit->start_display);
1856 edit_replace_dialog (edit, disp1, disp2, disp3, &input1, &input2,
1857 &input3);
1859 g_free (disp1);
1860 g_free (disp2);
1861 g_free (disp3);
1863 convert_from_input (input1);
1864 convert_from_input (input2);
1865 convert_from_input (input3);
1867 treplace_prompt = replace_prompt;
1868 if (input1 == NULL || *input1 == '\0') {
1869 edit->force = REDRAW_COMPLETELY;
1870 goto cleanup;
1873 g_free (saved1), saved1 = g_strdup (input1);
1874 g_free (saved2), saved2 = g_strdup (input2);
1875 g_free (saved3), saved3 = g_strdup (input3);
1880 const char *s;
1881 int ord;
1882 size_t i;
1884 s = input3;
1885 for (i = 0; i < NUM_REPL_ARGS; i++) {
1886 if (s != NULL && *s != '\0') {
1887 ord = atoi (s);
1888 if ((ord > 0) && (ord <= NUM_REPL_ARGS))
1889 argord[i] = ord - 1;
1890 else
1891 argord[i] = i;
1892 s = strchr (s, ',');
1893 if (s != NULL)
1894 s++;
1895 } else
1896 argord[i] = i;
1900 replace_continue = replace_all;
1902 if (edit->found_len && edit->search_start == edit->found_start + 1
1903 && replace_backwards)
1904 edit->search_start--;
1906 if (edit->found_len && edit->search_start == edit->found_start - 1
1907 && !replace_backwards)
1908 edit->search_start++;
1910 do {
1911 int len = 0;
1912 long new_start;
1913 new_start =
1914 edit_find (edit->search_start, (unsigned char *) input1, &len,
1915 last_search, edit_get_byte, (void *) edit, pmatch);
1916 if (new_start == -3) {
1917 regexp_error (edit);
1918 break;
1920 edit->search_start = new_start;
1921 /*returns negative on not found or error in pattern */
1923 if (edit->search_start >= 0) {
1924 int i;
1926 edit->found_start = edit->search_start;
1927 i = edit->found_len = len;
1929 edit_cursor_move (edit, edit->search_start - edit->curs1);
1930 edit_scroll_screen_over_cursor (edit);
1932 replace_yes = 1;
1934 if (treplace_prompt) {
1935 int l;
1936 l = edit->curs_row - edit->num_widget_lines / 3;
1937 if (l > 0)
1938 edit_scroll_downward (edit, l);
1939 if (l < 0)
1940 edit_scroll_upward (edit, -l);
1942 edit_scroll_screen_over_cursor (edit);
1943 edit->force |= REDRAW_PAGE;
1944 edit_render_keypress (edit);
1946 /*so that undo stops at each query */
1947 edit_push_key_press (edit);
1949 switch (edit_replace_prompt (edit, input2, /* and prompt 2/3 down */
1950 (edit->num_widget_columns -
1951 CONFIRM_DLG_WIDTH) / 2,
1952 edit->num_widget_lines * 2 /
1953 3)) {
1954 case B_ENTER:
1955 break;
1956 case B_SKIP_REPLACE:
1957 replace_yes = 0;
1958 break;
1959 case B_REPLACE_ALL:
1960 treplace_prompt = 0;
1961 replace_continue = 1;
1962 break;
1963 case B_REPLACE_ONE:
1964 replace_continue = 0;
1965 break;
1966 case B_CANCEL:
1967 replace_yes = 0;
1968 replace_continue = 0;
1969 break;
1972 if (replace_yes) { /* delete then insert new */
1973 if (replace_scanf) {
1974 char repl_str[MAX_REPL_LEN + 2];
1975 int ret = 0;
1977 /* we need to fill in sargs just like with scanf */
1978 if (replace_regexp) {
1979 int k, j;
1980 for (k = 1;
1981 k < NUM_REPL_ARGS && pmatch[k].rm_eo >= 0;
1982 k++) {
1983 unsigned char *t;
1985 if (pmatch[k].rm_eo - pmatch[k].rm_so > 255) {
1986 ret = -1;
1987 break;
1989 t = (unsigned char *) &sargs[k - 1][0];
1990 for (j = 0;
1991 j < pmatch[k].rm_eo - pmatch[k].rm_so
1992 && j < 255; j++, t++)
1993 *t = (unsigned char) edit_get_byte (edit,
1994 edit->
1995 search_start
1997 pmatch
1998 [0].
1999 rm_so +
2000 pmatch
2001 [k].
2002 rm_so +
2004 *t = '\0';
2006 for (; k <= NUM_REPL_ARGS; k++)
2007 sargs[k - 1][0] = 0;
2009 if (!ret)
2010 ret =
2011 snprintf_p (repl_str, MAX_REPL_LEN + 2, input2,
2012 PRINTF_ARGS);
2013 if (ret >= 0) {
2014 times_replaced++;
2015 while (i--)
2016 edit_delete (edit);
2017 while (repl_str[++i])
2018 edit_insert (edit, repl_str[i]);
2019 } else {
2020 edit_error_dialog (_(" Replace "),
2021 ret ==
2022 -2 ?
2024 (" Error in replacement format string. ")
2025 : _(" Replacement too long. "));
2026 replace_continue = 0;
2028 } else {
2029 times_replaced++;
2030 while (i--)
2031 edit_delete (edit);
2032 while (input2[++i])
2033 edit_insert (edit, input2[i]);
2035 edit->found_len = i;
2037 /* so that we don't find the same string again */
2038 if (replace_backwards) {
2039 last_search = edit->search_start;
2040 edit->search_start--;
2041 } else {
2042 edit->search_start += i;
2043 last_search = edit->last_byte;
2045 edit_scroll_screen_over_cursor (edit);
2046 } else {
2047 const char *msg = _(" Replace ");
2048 /* try and find from right here for next search */
2049 edit->search_start = edit->curs1;
2050 edit_update_curs_col (edit);
2052 edit->force |= REDRAW_PAGE;
2053 edit_render_keypress (edit);
2054 if (times_replaced) {
2055 message (0, msg, _(" %ld replacements made. "),
2056 times_replaced);
2057 } else
2058 query_dialog (msg, _(" Search string not found "),
2059 D_NORMAL, 1, _("&OK"));
2060 replace_continue = 0;
2062 } while (replace_continue);
2064 edit->force = REDRAW_COMPLETELY;
2065 edit_scroll_screen_over_cursor (edit);
2066 cleanup:
2067 g_free (input1);
2068 g_free (input2);
2069 g_free (input3);
2075 void edit_search_cmd (WEdit * edit, int again)
2077 static char *old = NULL;
2078 char *exp = "";
2080 if (!edit) {
2081 g_free (old);
2082 old = NULL;
2083 return;
2086 exp = old ? old : exp;
2087 if (again) { /*ctrl-hotkey for search again. */
2088 if (!old)
2089 return;
2090 exp = g_strdup (old);
2091 } else {
2093 #ifdef HAVE_CHARSET
2094 if (exp && *exp)
2095 convert_to_display (exp);
2096 #endif /* HAVE_CHARSET */
2098 edit_search_dialog (edit, &exp);
2100 #ifdef HAVE_CHARSET
2101 if (exp && *exp)
2102 convert_from_input (exp);
2103 #endif /* HAVE_CHARSET */
2105 edit_push_action (edit, KEY_PRESS + edit->start_display);
2108 if (exp) {
2109 if (*exp) {
2110 int len = 0;
2111 g_free (old);
2112 old = g_strdup (exp);
2114 if (search_create_bookmark) {
2115 int found = 0, books = 0;
2116 int l = 0, l_last = -1;
2117 long p, q = 0;
2118 for (;;) {
2119 p = edit_find (q, (unsigned char *) exp, &len, edit->last_byte,
2120 edit_get_byte, (void *) edit, 0);
2121 if (p < 0)
2122 break;
2123 found++;
2124 l += edit_count_lines (edit, q, p);
2125 if (l != l_last) {
2126 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
2127 books++;
2129 l_last = l;
2130 q = p + 1;
2132 if (found) {
2133 /* in response to number of bookmarks added because of string being found %d times */
2134 message (0, _("Search"), _(" %d items found, %d bookmarks added "), found, books);
2135 } else {
2136 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2138 } else {
2140 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
2141 edit->search_start--;
2143 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
2144 edit->search_start++;
2146 edit->search_start = edit_find (edit->search_start, (unsigned char *) exp, &len, edit->last_byte,
2147 edit_get_byte, (void *) edit, 0);
2149 if (edit->search_start >= 0) {
2150 edit->found_start = edit->search_start;
2151 edit->found_len = len;
2153 edit_cursor_move (edit, edit->search_start - edit->curs1);
2154 edit_scroll_screen_over_cursor (edit);
2155 if (replace_backwards)
2156 edit->search_start--;
2157 else
2158 edit->search_start++;
2159 } else if (edit->search_start == -3) {
2160 edit->search_start = edit->curs1;
2161 regexp_error (edit);
2162 } else {
2163 edit->search_start = edit->curs1;
2164 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2168 g_free (exp);
2170 edit->force |= REDRAW_COMPLETELY;
2171 edit_scroll_screen_over_cursor (edit);
2176 * Check if it's OK to close the editor. If there are unsaved changes,
2177 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2180 edit_ok_to_exit (WEdit *edit)
2182 if (!edit->modified)
2183 return 1;
2185 switch (edit_query_dialog3
2186 (_("Quit"), _(" File was modified, Save with exit? "),
2187 _("&Cancel quit"), _("&Yes"), _("&No"))) {
2188 case 1:
2189 edit_push_markers (edit);
2190 edit_set_markers (edit, 0, 0, 0, 0);
2191 if (!edit_save_cmd (edit))
2192 return 0;
2193 break;
2194 case 2:
2195 break;
2196 case 0:
2197 case -1:
2198 return 0;
2201 return 1;
2205 #define TEMP_BUF_LEN 1024
2207 /* Return a null terminated length of text. Result must be g_free'd */
2208 static unsigned char *
2209 edit_get_block (WEdit *edit, long start, long finish, int *l)
2211 unsigned char *s, *r;
2212 r = s = g_malloc (finish - start + 1);
2213 if (column_highlighting) {
2214 *l = 0;
2215 /* copy from buffer, excluding chars that are out of the column 'margins' */
2216 while (start < finish) {
2217 int c, x;
2218 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
2219 start);
2220 c = edit_get_byte (edit, start);
2221 if ((x >= edit->column1 && x < edit->column2)
2222 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
2223 *s++ = c;
2224 (*l)++;
2226 start++;
2228 } else {
2229 *l = finish - start;
2230 while (start < finish)
2231 *s++ = edit_get_byte (edit, start++);
2233 *s = 0;
2234 return r;
2237 /* save block, returns 1 on success */
2239 edit_save_block (WEdit * edit, const char *filename, long start,
2240 long finish)
2242 int len, file;
2244 if ((file =
2245 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
2246 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
2247 return 0;
2249 if (column_highlighting) {
2250 unsigned char *block, *p;
2251 int r;
2252 p = block = edit_get_block (edit, start, finish, &len);
2253 while (len) {
2254 r = mc_write (file, p, len);
2255 if (r < 0)
2256 break;
2257 p += r;
2258 len -= r;
2260 g_free (block);
2261 } else {
2262 unsigned char *buf;
2263 int i = start, end;
2264 len = finish - start;
2265 buf = g_malloc (TEMP_BUF_LEN);
2266 while (start != finish) {
2267 end = min (finish, start + TEMP_BUF_LEN);
2268 for (; i < end; i++)
2269 buf[i - start] = edit_get_byte (edit, i);
2270 len -= mc_write (file, (char *) buf, end - start);
2271 start = end;
2273 g_free (buf);
2275 mc_close (file);
2276 if (len)
2277 return 0;
2278 return 1;
2281 /* copies a block to clipboard file */
2282 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
2284 return edit_save_block (edit, catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL), start, finish);
2288 void edit_paste_from_history (WEdit *edit)
2290 (void) edit;
2291 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
2294 int edit_copy_to_X_buf_cmd (WEdit * edit)
2296 long start_mark, end_mark;
2297 if (eval_marks (edit, &start_mark, &end_mark))
2298 return 0;
2299 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2300 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2301 return 1;
2303 edit_mark_cmd (edit, 1);
2304 return 0;
2307 int edit_cut_to_X_buf_cmd (WEdit * edit)
2309 long start_mark, end_mark;
2310 if (eval_marks (edit, &start_mark, &end_mark))
2311 return 0;
2312 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2313 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2314 return 1;
2316 edit_block_delete_cmd (edit);
2317 edit_mark_cmd (edit, 1);
2318 return 0;
2321 void edit_paste_from_X_buf_cmd (WEdit * edit)
2323 edit_insert_file (edit, catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL));
2328 * Ask user for the line and go to that line.
2329 * Negative numbers mean line from the end (i.e. -1 is the last line).
2331 void
2332 edit_goto_cmd (WEdit *edit)
2334 char *f;
2335 static long line = 0; /* line as typed, saved as default */
2336 long l;
2337 char *error;
2338 char s[32];
2340 g_snprintf (s, sizeof (s), "%ld", line);
2341 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
2342 line ? s : "");
2343 if (!f)
2344 return;
2346 if (!*f) {
2347 g_free (f);
2348 return;
2351 l = strtol (f, &error, 0);
2352 if (*error) {
2353 g_free (f);
2354 return;
2357 line = l;
2358 if (l < 0)
2359 l = edit->total_lines + l + 2;
2360 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2361 edit_move_to_line (edit, l - 1);
2362 edit->force |= REDRAW_COMPLETELY;
2363 g_free (f);
2367 /* Return 1 on success */
2369 edit_save_block_cmd (WEdit *edit)
2371 long start_mark, end_mark;
2372 char *exp;
2373 if (eval_marks (edit, &start_mark, &end_mark))
2374 return 1;
2375 exp =
2376 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2377 MC_HISTORY_EDIT_SAVE_BLOCK,
2378 catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL));
2379 edit_push_action (edit, KEY_PRESS + edit->start_display);
2380 if (exp) {
2381 if (!*exp) {
2382 g_free (exp);
2383 return 0;
2384 } else {
2385 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2386 g_free (exp);
2387 edit->force |= REDRAW_COMPLETELY;
2388 return 1;
2389 } else {
2390 g_free (exp);
2391 edit_error_dialog (_(" Save Block "),
2392 get_sys_error (_
2393 (" Cannot save file. ")));
2397 edit->force |= REDRAW_COMPLETELY;
2398 return 0;
2402 /* returns 1 on success */
2404 edit_insert_file_cmd (WEdit *edit)
2406 char *exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2407 MC_HISTORY_EDIT_INSERT_FILE,
2408 catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL));
2409 edit_push_action (edit, KEY_PRESS + edit->start_display);
2410 if (exp) {
2411 if (!*exp) {
2412 g_free (exp);
2413 return 0;
2414 } else {
2415 if (edit_insert_file (edit, exp)) {
2416 g_free (exp);
2417 edit->force |= REDRAW_COMPLETELY;
2418 return 1;
2419 } else {
2420 g_free (exp);
2421 edit_error_dialog (_(" Insert File "),
2422 get_sys_error (_
2423 (" Cannot insert file. ")));
2427 edit->force |= REDRAW_COMPLETELY;
2428 return 0;
2431 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2432 int edit_sort_cmd (WEdit * edit)
2434 static char *old = 0;
2435 char *exp;
2436 long start_mark, end_mark;
2437 int e;
2439 if (eval_marks (edit, &start_mark, &end_mark)) {
2440 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2441 return 0;
2443 edit_save_block (edit, catstrs (home_dir, PATH_SEP_STR BLOCK_FILE, (char *) NULL), start_mark, end_mark);
2445 exp = input_dialog (_(" Run Sort "),
2446 _(" Enter sort options (see manpage) separated by whitespace: "),
2447 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2449 if (!exp)
2450 return 1;
2451 g_free (old);
2452 old = exp;
2454 e = system (catstrs (" sort ", exp, " ", home_dir, PATH_SEP_STR BLOCK_FILE, " > ", home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2455 if (e) {
2456 if (e == -1 || e == 127) {
2457 edit_error_dialog (_(" Sort "),
2458 get_sys_error (_(" Cannot execute sort command ")));
2459 } else {
2460 char q[8];
2461 sprintf (q, "%d ", e);
2462 edit_error_dialog (_(" Sort "),
2463 catstrs (_(" Sort returned non-zero: "), q, (char *) NULL));
2465 return -1;
2468 edit->force |= REDRAW_COMPLETELY;
2470 if (edit_block_delete_cmd (edit))
2471 return 1;
2472 edit_insert_file (edit, catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2473 return 0;
2477 * Ask user for a command, execute it and paste its output back to the
2478 * editor.
2481 edit_ext_cmd (WEdit *edit)
2483 char *exp;
2484 int e;
2486 exp =
2487 input_dialog (_("Paste output of external command"),
2488 _("Enter shell command(s):"),
2489 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2491 if (!exp)
2492 return 1;
2494 e = system (catstrs (exp, " > ", home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2495 g_free (exp);
2497 if (e) {
2498 edit_error_dialog (_("External command"),
2499 get_sys_error (_("Cannot execute command")));
2500 return -1;
2503 edit->force |= REDRAW_COMPLETELY;
2505 edit_insert_file (edit, catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2506 return 0;
2509 /* if block is 1, a block must be highlighted and the shell command
2510 processes it. If block is 0 the shell command is a straight system
2511 command, that just produces some output which is to be inserted */
2512 void
2513 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2515 long start_mark, end_mark;
2516 char buf[BUFSIZ];
2517 FILE *script_home = NULL;
2518 FILE *script_src = NULL;
2519 FILE *block_file = NULL;
2520 const char *o = NULL;
2521 const char *h = NULL;
2522 const char *b = NULL;
2523 char *quoted_name = NULL;
2525 o = catstrs (mc_home, shell_cmd, (char *) NULL); /* original source script */
2526 h = catstrs (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2527 b = catstrs (home_dir, PATH_SEP_STR BLOCK_FILE, (char *) NULL); /* block file */
2529 if (!(script_home = fopen (h, "r"))) {
2530 if (!(script_home = fopen (h, "w"))) {
2531 edit_error_dialog ("", get_sys_error (catstrs
2533 ("Error creating script:"),
2534 h, (char *) NULL)));
2535 return;
2537 if (!(script_src = fopen (o, "r"))) {
2538 fclose (script_home);
2539 unlink (h);
2540 edit_error_dialog ("", get_sys_error (catstrs
2541 (_("Error reading script:"),
2542 o, (char *) NULL)));
2543 return;
2545 while (fgets (buf, sizeof (buf), script_src))
2546 fputs (buf, script_home);
2547 if (fclose (script_home)) {
2548 edit_error_dialog ("", get_sys_error (catstrs
2550 ("Error closing script:"),
2551 h, (char *) NULL)));
2552 return;
2554 chmod (h, 0700);
2555 edit_error_dialog ("", get_sys_error (catstrs
2556 (_("Script created:"), h, (char *) NULL)));
2559 open_error_pipe ();
2561 if (block) { /* for marked block run indent formatter */
2562 if (eval_marks (edit, &start_mark, &end_mark)) {
2563 edit_error_dialog (_("Process block"),
2565 (" You must first highlight a block of text. "));
2566 return;
2568 edit_save_block (edit, b, start_mark, end_mark);
2569 quoted_name = name_quote (edit->filename, 0);
2571 * Run script.
2572 * Initial space is to avoid polluting bash history.
2573 * Arguments:
2574 * $1 - name of the edited file (to check its extension etc).
2575 * $2 - file containing the current block.
2576 * $3 - file where error messages should be put
2577 * (for compatibility with old scripts).
2579 system (catstrs (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2580 " ", home_dir, PATH_SEP_STR BLOCK_FILE " /dev/null", (char *) NULL));
2582 } else {
2584 * No block selected, just execute the command for the file.
2585 * Arguments:
2586 * $1 - name of the edited file.
2588 system (catstrs (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2589 quoted_name, (char *) NULL));
2591 g_free (quoted_name);
2592 close_error_pipe (0, 0);
2594 edit_refresh_cmd (edit);
2595 edit->force |= REDRAW_COMPLETELY;
2597 /* insert result block */
2598 if (block) {
2599 if (edit_block_delete_cmd (edit))
2600 return;
2601 edit_insert_file (edit, b);
2602 if ((block_file = fopen (b, "w")))
2603 fclose (block_file);
2604 return;
2607 return;
2610 /* prints at the cursor */
2611 /* returns the number of chars printed */
2612 int edit_print_string (WEdit * e, const char *s)
2614 int i = 0;
2615 while (s[i])
2616 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2617 e->force |= REDRAW_COMPLETELY;
2618 edit_update_screen (e);
2619 return i;
2623 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2625 FILE *p = 0;
2626 char *s;
2628 to = name_quote (to, 0);
2629 subject = name_quote (subject, 0);
2630 cc = name_quote (cc, 0);
2631 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2632 g_free (to);
2633 g_free (subject);
2634 g_free (cc);
2636 if (s) {
2637 p = popen (s, "w");
2638 g_free (s);
2641 if (p) {
2642 long i;
2643 for (i = 0; i < edit->last_byte; i++)
2644 fputc (edit_get_byte (edit, i), p);
2645 pclose (p);
2649 #define MAIL_DLG_HEIGHT 12
2651 void edit_mail_dialog (WEdit * edit)
2653 char *tmail_to;
2654 char *tmail_subject;
2655 char *tmail_cc;
2657 static char *mail_cc_last = 0;
2658 static char *mail_subject_last = 0;
2659 static char *mail_to_last = 0;
2661 QuickDialog Quick_input =
2662 {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
2663 "[Input Line Keys]", 0, 0};
2665 QuickWidget quick_widgets[] =
2667 {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
2668 0, NULL},
2669 {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
2670 0, NULL},
2671 {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2672 0, "mail-dlg-input"},
2673 {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
2674 0, 0},
2675 {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2676 0, "mail-dlg-input-2"},
2677 {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
2678 0, 0},
2679 {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2680 0, "mail-dlg-input-3"},
2681 {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
2682 0, 0},
2683 {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2684 0, 0},
2685 NULL_QuickWidget};
2687 quick_widgets[2].str_result = &tmail_cc;
2688 quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
2689 quick_widgets[4].str_result = &tmail_subject;
2690 quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
2691 quick_widgets[6].str_result = &tmail_to;
2692 quick_widgets[6].text = mail_to_last ? mail_to_last : "";
2694 Quick_input.widgets = quick_widgets;
2696 if (quick_dialog (&Quick_input) != B_CANCEL) {
2697 g_free (mail_cc_last);
2698 g_free (mail_subject_last);
2699 g_free (mail_to_last);
2700 mail_cc_last = tmail_cc;
2701 mail_subject_last = tmail_subject;
2702 mail_to_last = tmail_to;
2703 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2708 /*******************/
2709 /* Word Completion */
2710 /*******************/
2713 /* find first character of current word */
2714 static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len)
2716 int i, c, last;
2718 /* return if at begin of file */
2719 if (edit->curs1 <= 0)
2720 return 0;
2722 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2723 /* return if not at end or in word */
2724 if (isspace (c) || !(isalnum (c) || c == '_'))
2725 return 0;
2727 /* search start of word to be completed */
2728 for (i = 2;; i++) {
2729 /* return if at begin of file */
2730 if (edit->curs1 - i < 0)
2731 return 0;
2733 last = c;
2734 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2736 if (!(isalnum (c) || c == '_')) {
2737 /* return if word starts with digit */
2738 if (isdigit (last))
2739 return 0;
2741 *word_start = edit->curs1 - (i - 1); /* start found */
2742 *word_len = i - 1;
2743 break;
2746 /* success */
2747 return 1;
2751 /* (re)set search parameters to the given values */
2752 static void edit_set_search_parameters (int rs, int rb, int rr, int rw, int rc)
2754 replace_scanf = rs;
2755 replace_backwards = rb;
2756 replace_regexp = rr;
2757 replace_whole = rw;
2758 replace_case = rc;
2762 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2764 /* collect the possible completions */
2765 static int
2766 edit_collect_completions (WEdit *edit, long start, int word_len,
2767 char *match_expr, struct selection *compl,
2768 int *num)
2770 int len, max_len = 0, i, skip;
2771 unsigned char *bufpos;
2773 /* collect max MAX_WORD_COMPLETIONS completions */
2774 while (*num < MAX_WORD_COMPLETIONS) {
2775 /* get next match */
2776 start =
2777 edit_find (start - 1, (unsigned char *) match_expr, &len,
2778 edit->last_byte, edit_get_byte, (void *) edit, 0);
2780 /* not matched */
2781 if (start < 0)
2782 break;
2784 /* add matched completion if not yet added */
2785 bufpos =
2786 &edit->
2787 buffers1[start >> S_EDIT_BUF_SIZE][start & M_EDIT_BUF_SIZE];
2788 skip = 0;
2789 for (i = 0; i < *num; i++) {
2790 if (strncmp
2791 ((char *) &compl[i].text[word_len],
2792 (char *) &bufpos[word_len], max (len,
2793 compl[i].len) -
2794 word_len) == 0) {
2795 skip = 1;
2796 break; /* skip it, already added */
2799 if (skip)
2800 continue;
2802 compl[*num].text = g_malloc (len + 1);
2803 compl[*num].len = len;
2804 for (i = 0; i < len; i++)
2805 compl[*num].text[i] = *(bufpos + i);
2806 compl[*num].text[i] = '\0';
2807 (*num)++;
2809 /* note the maximal length needed for the completion dialog */
2810 if (len > max_len)
2811 max_len = len;
2813 return max_len;
2817 /* let the user select its preferred completion */
2818 static void
2819 edit_completion_dialog (WEdit * edit, int max_len, int word_len,
2820 struct selection *compl, int num_compl)
2822 int start_x, start_y, offset, i;
2823 char *curr = NULL;
2824 Dlg_head *compl_dlg;
2825 WListbox *compl_list;
2826 int compl_dlg_h; /* completion dialog height */
2827 int compl_dlg_w; /* completion dialog width */
2829 /* calculate the dialog metrics */
2830 compl_dlg_h = num_compl + 2;
2831 compl_dlg_w = max_len + 4;
2832 start_x = edit->curs_col + edit->start_col - (compl_dlg_w / 2);
2833 start_y = edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + 1;
2835 if (start_x < 0)
2836 start_x = 0;
2837 if (compl_dlg_w > COLS)
2838 compl_dlg_w = COLS;
2839 if (compl_dlg_h > LINES - 2)
2840 compl_dlg_h = LINES - 2;
2842 offset = start_x + compl_dlg_w - COLS;
2843 if (offset > 0)
2844 start_x -= offset;
2845 offset = start_y + compl_dlg_h - LINES;
2846 if (offset > 0)
2847 start_y -= (offset + 1);
2849 /* create the dialog */
2850 compl_dlg =
2851 create_dlg (start_y, start_x, compl_dlg_h, compl_dlg_w,
2852 dialog_colors, NULL, "[Completion]", NULL,
2853 DLG_COMPACT);
2855 /* create the listbox */
2856 compl_list =
2857 listbox_new (1, 1, compl_dlg_w - 2, compl_dlg_h - 2, NULL);
2859 /* add the dialog */
2860 add_widget (compl_dlg, compl_list);
2862 /* fill the listbox with the completions */
2863 for (i = 0; i < num_compl; i++)
2864 listbox_add_item (compl_list, LISTBOX_APPEND_AT_END, 0,
2865 (char *) compl[i].text, NULL);
2867 /* pop up the dialog */
2868 run_dlg (compl_dlg);
2870 /* apply the choosen completion */
2871 if (compl_dlg->ret_value == B_ENTER) {
2872 listbox_get_current (compl_list, &curr, NULL);
2873 if (curr)
2874 for (curr += word_len; *curr; curr++)
2875 edit_insert (edit, *curr);
2878 /* destroy dialog before return */
2879 destroy_dlg (compl_dlg);
2884 * Complete current word using regular expression search
2885 * backwards beginning at the current cursor position.
2887 void
2888 edit_complete_word_cmd (WEdit *edit)
2890 int word_len = 0, i, num_compl = 0, max_len;
2891 long word_start = 0;
2892 unsigned char *bufpos;
2893 char *match_expr;
2894 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2896 /* don't want to disturb another search */
2897 int old_rs = replace_scanf;
2898 int old_rb = replace_backwards;
2899 int old_rr = replace_regexp;
2900 int old_rw = replace_whole;
2901 int old_rc = replace_case;
2903 /* search start of word to be completed */
2904 if (!edit_find_word_start (edit, &word_start, &word_len))
2905 return;
2907 /* prepare match expression */
2908 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2909 [word_start & M_EDIT_BUF_SIZE];
2910 match_expr = g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len, bufpos);
2912 /* init search: backward, regexp, whole word, case sensitive */
2913 edit_set_search_parameters (0, 1, 1, 1, 1);
2915 /* collect the possible completions */
2916 /* start search from curs1 down to begin of file */
2917 max_len =
2918 edit_collect_completions (edit, word_start, word_len, match_expr,
2919 (struct selection *) &compl, &num_compl);
2921 if (num_compl > 0) {
2922 /* insert completed word if there is only one match */
2923 if (num_compl == 1) {
2924 for (i = word_len; i < compl[0].len; i++)
2925 edit_insert (edit, *(compl[0].text + i));
2927 /* more than one possible completion => ask the user */
2928 else {
2929 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2930 /* !!! pressed again the selection dialog pops up, but that !!! */
2931 /* !!! seems to require a further internal state !!! */
2932 /*beep (); */
2934 /* let the user select the preferred completion */
2935 edit_completion_dialog (edit, max_len, word_len,
2936 (struct selection *) &compl,
2937 num_compl);
2941 g_free (match_expr);
2942 /* release memory before return */
2943 for (i = 0; i < num_compl; i++)
2944 g_free (compl[i].text);
2946 /* restore search parameters */
2947 edit_set_search_parameters (old_rs, old_rb, old_rr, old_rw, old_rc);
2950 void
2951 edit_select_codepage_cmd (WEdit *edit)
2953 #ifdef HAVE_CHARSET
2954 do_select_codepage ();
2955 edit->force = REDRAW_COMPLETELY;
2956 edit_refresh_cmd (edit);
2957 #endif
2960 void
2961 edit_insert_literal_cmd (WEdit *edit)
2963 int char_for_insertion =
2964 edit_raw_key_query (_(" Insert Literal "),
2965 _(" Press any key: "), 0);
2966 edit_execute_key_command (edit, -1,
2967 ascii_alpha_to_cntrl (char_for_insertion));
2970 void
2971 edit_execute_macro_cmd (WEdit *edit)
2973 int command =
2974 CK_Macro (edit_raw_key_query
2975 (_(" Execute Macro "), _(" Press macro hotkey: "),
2976 1));
2977 if (command == CK_Macro (0))
2978 command = CK_Insert_Char;
2980 edit_execute_key_command (edit, command, -1);
2983 void
2984 edit_begin_end_macro_cmd(WEdit *edit)
2986 int command;
2988 /* edit is a pointer to the widget */
2989 if (edit) {
2990 command =
2991 edit->macro_i <
2992 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2993 edit_execute_key_command (edit, command, -1);