Merge commit 'origin/50_history_section_names' into 50_history_sections.metux
[midnight-commander.git] / edit / editcmd.c
blob92f8b30fce05105e47bedb21d0195ceb2a27b831
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"
44 #include "edit.h"
45 #include "editlock.h"
46 #include "editcmddef.h"
47 #include "edit-widget.h"
49 #include "../src/color.h" /* dialog_colors */
50 #include "../src/tty.h" /* LINES */
51 #include "../src/widget.h" /* listbox_new() */
52 #include "../src/layout.h" /* clr_scr() */
53 #include "../src/main.h" /* mc_home */
54 #include "../src/help.h" /* interactive_display() */
55 #include "../src/key.h" /* XCTRL */
56 #include "../src/dialog.h" /* do_refresh() */
57 #include "../src/wtools.h" /* message() */
58 #include "../src/charsets.h"
59 #include "../src/selcodepage.h"
61 struct selection {
62 unsigned char * text;
63 int len;
66 /* globals: */
68 /* search and replace: */
69 static int replace_scanf = 0;
70 static int replace_regexp = 0;
71 static int replace_all = 0;
72 static int replace_prompt = 1;
73 static int replace_whole = 0;
74 static int replace_case = 0;
75 static int replace_backwards = 0;
76 static int search_create_bookmark = 0;
78 /* queries on a save */
79 int edit_confirm_save = 1;
81 #define NUM_REPL_ARGS 64
82 #define MAX_REPL_LEN 1024
84 static int edit_save_cmd (WEdit *edit);
85 static unsigned char *edit_get_block (WEdit *edit, long start,
86 long finish, int *l);
88 static inline int my_lower_case (int c)
90 return tolower(c & 0xFF);
93 static const char *
94 strcasechr (const char *s, int c)
96 for (c = my_lower_case (c); my_lower_case ((int) *s) != c; ++s)
97 if (*s == '\0')
98 return 0;
99 return s;
102 #ifndef HAVE_MEMMOVE
103 /* for Christophe */
104 static void *memmove (void *dest, const void *src, size_t n)
106 char *t;
107 const char *s;
109 if (dest <= src) {
110 t = (char *) dest;
111 s = (const char *) src;
112 while (n--)
113 *t++ = *s++;
114 } else {
115 t = (char *) dest + n;
116 s = (const char *) src + n;
117 while (n--)
118 *--t = *--s;
120 return dest;
122 #endif /* !HAVE_MEMMOVE */
124 /* #define itoa MY_itoa <---- this line is now in edit.h */
125 static char *
126 MY_itoa (int i)
128 static char t[14];
129 char *s = t + 13;
130 int j = i;
131 *s-- = 0;
132 do {
133 *s-- = i % 10 + '0';
134 } while ((i = i / 10));
135 if (j < 0)
136 *s-- = '-';
137 return ++s;
140 /* Temporary strings */
141 static char *stacked[16];
144 This joins strings end on end and allocates memory for the result.
145 The result is later automatically free'd and must not be free'd
146 by the caller.
148 static const char *
149 catstrs (const char *first,...)
151 static int i = 0;
152 va_list ap;
153 int len;
154 char *data;
156 if (!first)
157 return 0;
159 len = strlen (first);
160 va_start (ap, first);
162 while ((data = va_arg (ap, char *)) != 0)
163 len += strlen (data);
165 len++;
167 i = (i + 1) % 16;
168 g_free (stacked[i]);
170 stacked[i] = g_malloc (len);
171 va_end (ap);
172 va_start (ap, first);
173 strcpy (stacked[i], first);
174 while ((data = va_arg (ap, char *)) != 0)
175 strcat (stacked[i], data);
176 va_end (ap);
178 return stacked[i];
181 /* Free temporary strings */
182 void freestrs(void)
184 size_t i;
186 for (i = 0; i < sizeof(stacked) / sizeof(stacked[0]); i++) {
187 g_free (stacked[i]);
188 stacked[i] = NULL;
192 void edit_help_cmd (WEdit * edit)
194 interactive_display (NULL, "[Internal File Editor]");
195 edit->force |= REDRAW_COMPLETELY;
198 void edit_refresh_cmd (WEdit * edit)
200 #ifndef HAVE_SLANG
201 clr_scr();
202 do_refresh();
203 #else
205 int color;
206 edit_get_syntax_color (edit, -1, &color);
208 touchwin(stdscr);
209 #endif /* !HAVE_SLANG */
210 mc_refresh();
211 doupdate();
214 /* If 0 (quick save) then a) create/truncate <filename> file,
215 b) save to <filename>;
216 if 1 (safe save) then a) save to <tempnam>,
217 b) rename <tempnam> to <filename>;
218 if 2 (do backups) then a) save to <tempnam>,
219 b) rename <filename> to <filename.backup_ext>,
220 c) rename <tempnam> to <filename>. */
222 /* returns 0 on error, -1 on abort */
223 static int
224 edit_save_file (WEdit *edit, const char *filename)
226 char *p;
227 long filelen = 0;
228 char *savename = 0;
229 int this_save_mode, fd = -1;
231 if (!filename)
232 return 0;
233 if (!*filename)
234 return 0;
236 if (*filename != PATH_SEP && edit->dir) {
237 savename = concat_dir_and_file (edit->dir, filename);
238 filename = catstrs (savename, (char *) NULL);
239 g_free (savename);
242 this_save_mode = option_save_mode;
243 if (this_save_mode != EDIT_QUICK_SAVE) {
244 if (!vfs_file_is_local (filename) ||
245 (fd = mc_open (filename, O_RDONLY | O_BINARY)) == -1) {
247 * The file does not exists yet, so no safe save or
248 * backup are necessary.
250 this_save_mode = EDIT_QUICK_SAVE;
252 if (fd != -1)
253 mc_close (fd);
256 if (this_save_mode == EDIT_QUICK_SAVE &&
257 !edit->skip_detach_prompt) {
258 int rv;
259 struct stat sb;
261 rv = mc_stat (filename, &sb);
262 if (rv == 0 && sb.st_nlink > 1) {
263 rv = edit_query_dialog3 (_("Warning"),
264 _(" File has hard-links. Detach before saving? "),
265 _("&Yes"), _("&No"), _("&Cancel"));
266 switch (rv) {
267 case 0:
268 this_save_mode = EDIT_SAFE_SAVE;
269 /* fallthrough */
270 case 1:
271 edit->skip_detach_prompt = 1;
272 break;
273 default:
274 return -1;
278 /* Prevent overwriting changes from other editor sessions. */
279 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
281 /* The default action is "Cancel". */
282 query_set_sel(1);
284 rv = edit_query_dialog2 (
285 _("Warning"),
286 _("The file has been modified in the meantime. Save anyway?"),
287 _("&Yes"),
288 _("&Cancel"));
289 if (rv != 0)
290 return -1;
294 if (this_save_mode != EDIT_QUICK_SAVE) {
295 char *savedir, *saveprefix;
296 const char *slashpos;
297 slashpos = strrchr (filename, PATH_SEP);
298 if (slashpos) {
299 savedir = g_strdup (filename);
300 savedir[slashpos - filename + 1] = '\0';
301 } else
302 savedir = g_strdup (".");
303 saveprefix = concat_dir_and_file (savedir, "cooledit");
304 g_free (savedir);
305 fd = mc_mkstemps (&savename, saveprefix, NULL);
306 g_free (saveprefix);
307 if (!savename)
308 return 0;
309 /* FIXME:
310 * Close for now because mc_mkstemps use pure open system call
311 * to create temporary file and it needs to be reopened by
312 * VFS-aware mc_open().
314 close (fd);
315 } else
316 savename = g_strdup (filename);
318 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
319 mc_chmod (savename, edit->stat1.st_mode);
321 if ((fd =
322 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
323 edit->stat1.st_mode)) == -1)
324 goto error_save;
326 /* pipe save */
327 if ((p = edit_get_write_filter (savename, filename))) {
328 FILE *file;
330 mc_close (fd);
331 file = (FILE *) popen (p, "w");
333 if (file) {
334 filelen = edit_write_stream (edit, file);
335 #if 1
336 pclose (file);
337 #else
338 if (pclose (file) != 0) {
339 edit_error_dialog (_("Error"),
340 catstrs (_(" Error writing to pipe: "),
341 p, " ", (char *) NULL));
342 g_free (p);
343 goto error_save;
345 #endif
346 } else {
347 edit_error_dialog (_("Error"),
348 get_sys_error (catstrs
350 (" Cannot open pipe for writing: "),
351 p, " ", (char *) NULL)));
352 g_free (p);
353 goto error_save;
355 g_free (p);
356 } else {
357 long buf;
358 buf = 0;
359 filelen = edit->last_byte;
360 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
361 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
362 != EDIT_BUF_SIZE) {
363 mc_close (fd);
364 goto error_save;
366 buf++;
368 if (mc_write
369 (fd, (char *) edit->buffers1[buf],
370 edit->curs1 & M_EDIT_BUF_SIZE) !=
371 (edit->curs1 & M_EDIT_BUF_SIZE)) {
372 filelen = -1;
373 } else if (edit->curs2) {
374 edit->curs2--;
375 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
376 if (mc_write
377 (fd,
378 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
379 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
380 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
381 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
382 filelen = -1;
383 } else {
384 while (--buf >= 0) {
385 if (mc_write
386 (fd, (char *) edit->buffers2[buf],
387 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
388 filelen = -1;
389 break;
393 edit->curs2++;
395 if (mc_close (fd))
396 goto error_save;
398 /* Update the file information, especially the mtime. */
399 if (mc_stat (savename, &edit->stat1) == -1)
400 goto error_save;
403 if (filelen != edit->last_byte)
404 goto error_save;
406 if (this_save_mode == EDIT_DO_BACKUP) {
407 assert (option_backup_ext != NULL);
408 if (mc_rename (filename, catstrs (filename, option_backup_ext,
409 (char *) NULL)) == -1)
410 goto error_save;
413 if (this_save_mode != EDIT_QUICK_SAVE)
414 if (mc_rename (savename, filename) == -1)
415 goto error_save;
416 g_free (savename);
417 return 1;
418 error_save:
419 /* FIXME: Is this safe ?
420 * if (this_save_mode != EDIT_QUICK_SAVE)
421 * mc_unlink (savename);
423 g_free (savename);
424 return 0;
427 void menu_save_mode_cmd (void)
429 #define DLG_X 38
430 #define DLG_Y 10
431 static char *str_result;
432 static int save_mode_new;
433 static const char *str[] =
435 N_("Quick save "),
436 N_("Safe save "),
437 N_("Do backups -->")};
438 static QuickWidget widgets[] =
440 {quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
441 B_CANCEL, 0, 0, NULL},
442 {quick_button, 6, DLG_X, 7, DLG_Y, N_("&OK"), 0,
443 B_ENTER, 0, 0, NULL},
444 {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
445 0, 0, &str_result, "edit-backup-ext"},
446 {quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
447 0, 0, 0, NULL},
448 {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
449 0, &save_mode_new, (char **) str, NULL},
450 NULL_QuickWidget};
451 static QuickDialog dialog =
452 {DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
453 widgets, 0};
454 static int i18n_flag = 0;
456 if (!i18n_flag) {
457 size_t i;
458 size_t maxlen = 0;
459 int dlg_x;
460 size_t l1;
462 /* OK/Cancel buttons */
463 l1 = strlen (_(widgets[0].text)) + strlen (_(widgets[1].text)) + 5;
464 maxlen = max (maxlen, l1);
466 for (i = 0; i < 3; i++ ) {
467 str[i] = _(str[i]);
468 maxlen = max (maxlen, strlen (str[i]) + 7);
470 i18n_flag = 1;
472 dlg_x = maxlen + strlen (_(widgets[3].text)) + 5 + 1;
473 widgets[2].hotkey_pos = strlen (_(widgets[3].text)); /* input field length */
474 dlg_x = min (COLS, dlg_x);
475 dialog.xlen = dlg_x;
477 i = (dlg_x - l1)/3;
478 widgets[1].relative_x = i;
479 widgets[0].relative_x = i + strlen (_(widgets[1].text)) + i + 4;
481 widgets[2].relative_x = widgets[3].relative_x = maxlen + 2;
483 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
484 widgets[i].x_divisions = dlg_x;
487 assert (option_backup_ext != NULL);
488 widgets[2].text = option_backup_ext;
489 widgets[4].value = option_save_mode;
490 if (quick_dialog (&dialog) != B_ENTER)
491 return;
492 option_save_mode = save_mode_new;
494 g_free (option_backup_ext);
495 option_backup_ext = str_result;
496 str_result = NULL;
499 void
500 edit_set_filename (WEdit *edit, const char *f)
502 g_free (edit->filename);
503 if (!f)
504 f = "";
505 edit->filename = g_strdup (f);
506 if (edit->dir == NULL && *f != PATH_SEP)
507 #ifdef USE_VFS
508 edit->dir = g_strdup (vfs_get_current_dir ());
509 #else
510 edit->dir = g_get_current_dir ();
511 #endif
514 /* Here we want to warn the users of overwriting an existing file,
515 but only if they have made a change to the filename */
516 /* returns 1 on success */
518 edit_save_as_cmd (WEdit *edit)
520 /* This heads the 'Save As' dialog box */
521 char *exp;
522 int save_lock = 0;
523 int different_filename = 0;
525 exp = input_expand_dialog (_(" Save As "), _(" Enter file name: "),
526 ":edit_save_as_cmd: Save As ", edit->filename);
527 edit_push_action (edit, KEY_PRESS + edit->start_display);
529 if (exp) {
530 if (!*exp) {
531 g_free (exp);
532 edit->force |= REDRAW_COMPLETELY;
533 return 0;
534 } else {
535 int rv;
536 if (strcmp (edit->filename, exp)) {
537 int file;
538 different_filename = 1;
539 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
540 /* the file exists */
541 mc_close (file);
542 /* Overwrite the current file or cancel the operation */
543 if (edit_query_dialog2
544 (_("Warning"),
545 _(" A file already exists with this name. "),
546 _("&Overwrite"), _("&Cancel"))) {
547 edit->force |= REDRAW_COMPLETELY;
548 g_free (exp);
549 return 0;
552 save_lock = edit_lock_file (exp);
553 } else {
554 /* filenames equal, check if already locked */
555 if (!edit->locked && !edit->delete_file)
556 save_lock = edit_lock_file (exp);
559 rv = edit_save_file (edit, exp);
560 switch (rv) {
561 case 1:
562 /* Succesful, so unlock both files */
563 if (different_filename) {
564 if (save_lock)
565 edit_unlock_file (exp);
566 if (edit->locked)
567 edit->locked = edit_unlock_file (edit->filename);
568 } else {
569 if (edit->locked || save_lock)
570 edit->locked = edit_unlock_file (edit->filename);
573 edit_set_filename (edit, exp);
574 g_free (exp);
575 edit->modified = 0;
576 edit->delete_file = 0;
577 if (different_filename)
578 edit_load_syntax (edit, NULL, option_syntax_type);
579 edit->force |= REDRAW_COMPLETELY;
580 return 1;
581 default:
582 edit_error_dialog (_(" Save As "),
583 get_sys_error (_
584 (" Cannot save file. ")));
585 /* fallthrough */
586 case -1:
587 /* Failed, so maintain modify (not save) lock */
588 if (save_lock)
589 edit_unlock_file (exp);
590 g_free (exp);
591 edit->force |= REDRAW_COMPLETELY;
592 return 0;
596 edit->force |= REDRAW_COMPLETELY;
597 return 0;
600 /* {{{ Macro stuff starts here */
602 static cb_ret_t
603 raw_callback (struct Dlg_head *h, dlg_msg_t msg, int parm)
605 switch (msg) {
606 case DLG_KEY:
607 h->running = 0;
608 h->ret_value = parm;
609 return MSG_HANDLED;
610 default:
611 return default_dlg_callback (h, msg, parm);
615 /* gets a raw key from the keyboard. Passing cancel = 1 draws
616 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
617 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
618 and Esc are cannot returned */
620 edit_raw_key_query (const char *heading, const char *query, int cancel)
622 int w = strlen (query) + 7;
623 struct Dlg_head *raw_dlg =
624 create_dlg (0, 0, 7, w, dialog_colors, raw_callback,
625 NULL, heading,
626 DLG_CENTER | DLG_TRYUP | DLG_WANT_TAB);
627 add_widget (raw_dlg,
628 input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0));
629 add_widget (raw_dlg, label_new (3 - cancel, 2, query));
630 if (cancel)
631 add_widget (raw_dlg,
632 button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON,
633 _("Cancel"), 0));
634 run_dlg (raw_dlg);
635 w = raw_dlg->ret_value;
636 destroy_dlg (raw_dlg);
637 if (cancel) {
638 if (w == XCTRL ('g') || w == XCTRL ('c') || w == ESC_CHAR
639 || w == B_CANCEL)
640 return 0;
643 return w;
646 /* creates a macro file if it doesn't exist */
647 static FILE *edit_open_macro_file (const char *r)
649 const char *filename;
650 int file;
651 filename = catstrs (home_dir, PATH_SEP_STR MACRO_FILE, (char *) NULL);
652 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
653 return 0;
654 close (file);
655 return fopen (filename, r);
658 #define MAX_MACROS 1024
659 static int saved_macro[MAX_MACROS + 1];
660 static int saved_macros_loaded = 0;
663 This is just to stop the macro file be loaded over and over for keys
664 that aren't defined to anything. On slow systems this could be annoying.
666 static int
667 macro_exists (int k)
669 int i;
670 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
671 if (saved_macro[i] == k)
672 return i;
673 return -1;
676 /* returns 1 on error */
677 static int
678 edit_delete_macro (WEdit * edit, int k)
680 struct macro macro[MAX_MACRO_LENGTH];
681 FILE *f, *g;
682 int s, i, n, j = 0;
684 (void) edit;
686 if (saved_macros_loaded)
687 if ((j = macro_exists (k)) < 0)
688 return 0;
689 g = fopen (catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL), "w");
690 if (!g) {
691 edit_error_dialog (_(" Delete macro "),
692 get_sys_error (_(" Cannot open temp file ")));
693 return 1;
695 f = edit_open_macro_file ("r");
696 if (!f) {
697 edit_error_dialog (_(" Delete macro "),
698 get_sys_error (_(" Cannot open macro file ")));
699 fclose (g);
700 return 1;
702 for (;;) {
703 n = fscanf (f, ("key '%d 0': "), &s);
704 if (!n || n == EOF)
705 break;
706 n = 0;
707 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
708 n++;
709 fscanf (f, ";\n");
710 if (s != k) {
711 fprintf (g, ("key '%d 0': "), s);
712 for (i = 0; i < n; i++)
713 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
714 fprintf (g, ";\n");
717 fclose (f);
718 fclose (g);
719 if (rename (catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL), catstrs (home_dir, PATH_SEP_STR MACRO_FILE, (char *) NULL)) == -1) {
720 edit_error_dialog (_(" Delete macro "),
721 get_sys_error (_(" Cannot overwrite macro file ")));
722 return 1;
724 if (saved_macros_loaded)
725 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
726 return 0;
729 /* returns 0 on error */
730 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
732 FILE *f;
733 int s, i;
735 edit_push_action (edit, KEY_PRESS + edit->start_display);
736 s = edit_raw_key_query (_(" Save macro "),
737 _(" Press the macro's new hotkey: "), 1);
738 edit->force |= REDRAW_COMPLETELY;
739 if (s) {
740 if (edit_delete_macro (edit, s))
741 return 0;
742 f = edit_open_macro_file ("a+");
743 if (f) {
744 fprintf (f, ("key '%d 0': "), s);
745 for (i = 0; i < n; i++)
746 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
747 fprintf (f, ";\n");
748 fclose (f);
749 if (saved_macros_loaded) {
750 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
751 saved_macro[i] = s;
753 return 1;
754 } else
755 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
757 return 0;
760 void edit_delete_macro_cmd (WEdit * edit)
762 int command;
764 command = edit_raw_key_query (_ (" Delete macro "),
765 _ (" Press macro hotkey: "), 1);
767 if (!command)
768 return;
770 edit_delete_macro (edit, command);
773 /* return 0 on error */
774 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
776 FILE *f;
777 int s, i = 0, found = 0;
779 (void) edit;
781 if (saved_macros_loaded)
782 if (macro_exists (k) < 0)
783 return 0;
785 if ((f = edit_open_macro_file ("r"))) {
786 struct macro dummy;
787 do {
788 int u;
789 u = fscanf (f, ("key '%d 0': "), &s);
790 if (!u || u == EOF)
791 break;
792 if (!saved_macros_loaded)
793 saved_macro[i++] = s;
794 if (!found) {
795 *n = 0;
796 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
797 (*n)++;
798 } else {
799 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
801 fscanf (f, ";\n");
802 if (s == k)
803 found = 1;
804 } while (!found || !saved_macros_loaded);
805 if (!saved_macros_loaded) {
806 saved_macro[i] = 0;
807 saved_macros_loaded = 1;
809 fclose (f);
810 return found;
811 } else
812 edit_error_dialog (_(" Load macro "),
813 get_sys_error (_(" Cannot open macro file ")));
814 return 0;
817 /* }}} Macro stuff starts here */
819 /* returns 1 on success */
820 int edit_save_confirm_cmd (WEdit * edit)
822 const char *f;
824 if (edit_confirm_save) {
825 f = catstrs (_(" Confirm save file? : "), edit->filename, " ", (char *) NULL);
826 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel")))
827 return 0;
829 return edit_save_cmd (edit);
833 /* returns 1 on success */
834 static int
835 edit_save_cmd (WEdit *edit)
837 int res, save_lock = 0;
839 if (!edit->locked && !edit->delete_file)
840 save_lock = edit_lock_file (edit->filename);
841 res = edit_save_file (edit, edit->filename);
843 /* Maintain modify (not save) lock on failure */
844 if ((res > 0 && edit->locked) || save_lock)
845 edit->locked = edit_unlock_file (edit->filename);
847 /* On failure try 'save as', it does locking on its own */
848 if (!res)
849 return edit_save_as_cmd (edit);
850 edit->force |= REDRAW_COMPLETELY;
851 if (res > 0) {
852 edit->delete_file = 0;
853 edit->modified = 0;
856 return 1;
860 /* returns 1 on success */
861 int edit_new_cmd (WEdit * edit)
863 if (edit->modified) {
864 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
865 edit->force |= REDRAW_COMPLETELY;
866 return 0;
869 edit->force |= REDRAW_COMPLETELY;
871 return edit_renew (edit); /* if this gives an error, something has really screwed up */
874 /* returns 1 on error */
875 static int
876 edit_load_file_from_filename (WEdit * edit, char *exp)
878 int prev_locked = edit->locked;
879 char *prev_filename = g_strdup (edit->filename);
881 if (!edit_reload (edit, exp)) {
882 g_free (prev_filename);
883 return 1;
886 if (prev_locked)
887 edit_unlock_file (prev_filename);
888 g_free (prev_filename);
889 return 0;
893 edit_load_cmd (WEdit *edit)
895 char *exp;
897 if (edit->modified) {
898 if (edit_query_dialog2
899 (_("Warning"),
900 _(" Current text was modified without a file save. \n"
901 " Continue discards these changes. "), _("C&ontinue"),
902 _("&Cancel"))) {
903 edit->force |= REDRAW_COMPLETELY;
904 return 0;
908 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
909 ":edit_load_cmd: Load ", edit->filename);
911 if (exp) {
912 if (*exp)
913 edit_load_file_from_filename (edit, exp);
914 g_free (exp);
916 edit->force |= REDRAW_COMPLETELY;
917 return 0;
921 if mark2 is -1 then marking is from mark1 to the cursor.
922 Otherwise its between the markers. This handles this.
923 Returns 1 if no text is marked.
925 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
927 if (edit->mark1 != edit->mark2) {
928 if (edit->mark2 >= 0) {
929 *start_mark = min (edit->mark1, edit->mark2);
930 *end_mark = max (edit->mark1, edit->mark2);
931 } else {
932 *start_mark = min (edit->mark1, edit->curs1);
933 *end_mark = max (edit->mark1, edit->curs1);
934 edit->column2 = edit->curs_col;
936 return 0;
937 } else {
938 *start_mark = *end_mark = 0;
939 edit->column2 = edit->column1 = 0;
940 return 1;
944 #define space_width 1
946 static void
947 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
949 long cursor;
950 int i, col;
951 cursor = edit->curs1;
952 col = edit_get_col (edit);
953 for (i = 0; i < size; i++) {
954 if (data[i] == '\n') { /* fill in and move to next line */
955 int l;
956 long p;
957 if (edit_get_byte (edit, edit->curs1) != '\n') {
958 l = width - (edit_get_col (edit) - col);
959 while (l > 0) {
960 edit_insert (edit, ' ');
961 l -= space_width;
964 for (p = edit->curs1;; p++) {
965 if (p == edit->last_byte) {
966 edit_cursor_move (edit, edit->last_byte - edit->curs1);
967 edit_insert_ahead (edit, '\n');
968 p++;
969 break;
971 if (edit_get_byte (edit, p) == '\n') {
972 p++;
973 break;
976 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
977 l = col - edit_get_col (edit);
978 while (l >= space_width) {
979 edit_insert (edit, ' ');
980 l -= space_width;
982 continue;
984 edit_insert (edit, data[i]);
986 edit_cursor_move (edit, cursor - edit->curs1);
990 void
991 edit_block_copy_cmd (WEdit *edit)
993 long start_mark, end_mark, current = edit->curs1;
994 int size;
995 unsigned char *copy_buf;
997 edit_update_curs_col (edit);
998 if (eval_marks (edit, &start_mark, &end_mark))
999 return;
1001 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1003 /* all that gets pushed are deletes hence little space is used on the stack */
1005 edit_push_markers (edit);
1007 if (column_highlighting) {
1008 edit_insert_column_of_text (edit, copy_buf, size,
1009 abs (edit->column2 - edit->column1));
1010 } else {
1011 while (size--)
1012 edit_insert_ahead (edit, copy_buf[size]);
1015 g_free (copy_buf);
1016 edit_scroll_screen_over_cursor (edit);
1018 if (column_highlighting) {
1019 edit_set_markers (edit, 0, 0, 0, 0);
1020 edit_push_action (edit, COLUMN_ON);
1021 column_highlighting = 0;
1022 } else if (start_mark < current && end_mark > current)
1023 edit_set_markers (edit, start_mark,
1024 end_mark + end_mark - start_mark, 0, 0);
1026 edit->force |= REDRAW_PAGE;
1030 void
1031 edit_block_move_cmd (WEdit *edit)
1033 long count;
1034 long current;
1035 unsigned char *copy_buf;
1036 long start_mark, end_mark;
1037 int deleted = 0;
1038 int x = 0;
1040 if (eval_marks (edit, &start_mark, &end_mark))
1041 return;
1042 if (column_highlighting) {
1043 edit_update_curs_col (edit);
1044 x = edit->curs_col;
1045 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1046 if ((x > edit->column1 && x < edit->column2)
1047 || (x > edit->column2 && x < edit->column1))
1048 return;
1049 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1050 return;
1052 if ((end_mark - start_mark) > option_max_undo / 2)
1053 if (edit_query_dialog2
1054 (_("Warning"),
1056 (" Block is large, you may not be able to undo this action. "),
1057 _("C&ontinue"), _("&Cancel")))
1058 return;
1060 edit_push_markers (edit);
1061 current = edit->curs1;
1062 if (column_highlighting) {
1063 int size, c1, c2, line;
1064 line = edit->curs_line;
1065 if (edit->mark2 < 0)
1066 edit_mark_cmd (edit, 0);
1067 c1 = min (edit->column1, edit->column2);
1068 c2 = max (edit->column1, edit->column2);
1069 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1070 if (x < c2) {
1071 edit_block_delete_cmd (edit);
1072 deleted = 1;
1074 edit_move_to_line (edit, line);
1075 edit_cursor_move (edit,
1076 edit_move_forward3 (edit,
1077 edit_bol (edit, edit->curs1),
1078 x, 0) - edit->curs1);
1079 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1080 if (!deleted) {
1081 line = edit->curs_line;
1082 edit_update_curs_col (edit);
1083 x = edit->curs_col;
1084 edit_block_delete_cmd (edit);
1085 edit_move_to_line (edit, line);
1086 edit_cursor_move (edit,
1087 edit_move_forward3 (edit,
1088 edit_bol (edit,
1089 edit->curs1),
1090 x, 0) - edit->curs1);
1092 edit_set_markers (edit, 0, 0, 0, 0);
1093 edit_push_action (edit, COLUMN_ON);
1094 column_highlighting = 0;
1095 } else {
1096 copy_buf = g_malloc (end_mark - start_mark);
1097 edit_cursor_move (edit, start_mark - edit->curs1);
1098 edit_scroll_screen_over_cursor (edit);
1099 count = start_mark;
1100 while (count < end_mark) {
1101 copy_buf[end_mark - count - 1] = edit_delete (edit);
1102 count++;
1104 edit_scroll_screen_over_cursor (edit);
1105 edit_cursor_move (edit,
1106 current - edit->curs1 -
1107 (((current - edit->curs1) >
1108 0) ? end_mark - start_mark : 0));
1109 edit_scroll_screen_over_cursor (edit);
1110 while (count-- > start_mark)
1111 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1112 edit_set_markers (edit, edit->curs1,
1113 edit->curs1 + end_mark - start_mark, 0, 0);
1115 edit_scroll_screen_over_cursor (edit);
1116 g_free (copy_buf);
1117 edit->force |= REDRAW_PAGE;
1120 static void
1121 edit_delete_column_of_text (WEdit * edit)
1123 long p, q, r, m1, m2;
1124 int b, c, d;
1125 int n;
1127 eval_marks (edit, &m1, &m2);
1128 n = edit_move_forward (edit, m1, 0, m2) + 1;
1129 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1130 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1132 b = min (c, d);
1133 c = max (c, d);
1135 while (n--) {
1136 r = edit_bol (edit, edit->curs1);
1137 p = edit_move_forward3 (edit, r, b, 0);
1138 q = edit_move_forward3 (edit, r, c, 0);
1139 if (p < m1)
1140 p = m1;
1141 if (q > m2)
1142 q = m2;
1143 edit_cursor_move (edit, p - edit->curs1);
1144 while (q > p) { /* delete line between margins */
1145 if (edit_get_byte (edit, edit->curs1) != '\n')
1146 edit_delete (edit);
1147 q--;
1149 if (n) /* move to next line except on the last delete */
1150 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1154 /* if success return 0 */
1155 static int
1156 edit_block_delete (WEdit *edit)
1158 long count;
1159 long start_mark, end_mark;
1160 if (eval_marks (edit, &start_mark, &end_mark))
1161 return 0;
1162 if (column_highlighting && edit->mark2 < 0)
1163 edit_mark_cmd (edit, 0);
1164 if ((end_mark - start_mark) > option_max_undo / 2) {
1165 /* Warning message with a query to continue or cancel the operation */
1166 if (edit_query_dialog2
1167 (_("Warning"),
1169 (" Block is large, you may not be able to undo this action. "),
1170 _("C&ontinue"), _("&Cancel"))) {
1171 return 1;
1174 edit_push_markers (edit);
1175 edit_cursor_move (edit, start_mark - edit->curs1);
1176 edit_scroll_screen_over_cursor (edit);
1177 count = start_mark;
1178 if (start_mark < end_mark) {
1179 if (column_highlighting) {
1180 if (edit->mark2 < 0)
1181 edit_mark_cmd (edit, 0);
1182 edit_delete_column_of_text (edit);
1183 } else {
1184 while (count < end_mark) {
1185 edit_delete (edit);
1186 count++;
1190 edit_set_markers (edit, 0, 0, 0, 0);
1191 edit->force |= REDRAW_PAGE;
1192 return 0;
1195 /* returns 1 if canceelled by user */
1196 int edit_block_delete_cmd (WEdit * edit)
1198 long start_mark, end_mark;
1199 if (eval_marks (edit, &start_mark, &end_mark)) {
1200 edit_delete_line (edit);
1201 return 0;
1203 return edit_block_delete (edit);
1207 #define INPUT_INDEX 9
1208 #define SEARCH_DLG_WIDTH 58
1209 #define SEARCH_DLG_HEIGHT 10
1210 #define REPLACE_DLG_WIDTH 58
1211 #define REPLACE_DLG_HEIGHT 15
1212 #define CONFIRM_DLG_WIDTH 79
1213 #define CONFIRM_DLG_HEIGTH 6
1214 #define B_REPLACE_ALL (B_USER+1)
1215 #define B_REPLACE_ONE (B_USER+2)
1216 #define B_SKIP_REPLACE (B_USER+3)
1218 static int
1219 edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
1221 QuickWidget quick_widgets[] =
1223 {quick_button, 63, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Cancel"),
1224 0, B_CANCEL, 0, 0, NULL},
1225 {quick_button, 50, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("O&ne"),
1226 0, B_REPLACE_ONE, 0, 0, NULL},
1227 {quick_button, 37, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("A&ll"),
1228 0, B_REPLACE_ALL, 0, 0, NULL},
1229 {quick_button, 21, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Skip"),
1230 0, B_SKIP_REPLACE, 0, 0, NULL},
1231 {quick_button, 4, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Replace"),
1232 0, B_ENTER, 0, 0, NULL},
1233 {quick_label, 2, CONFIRM_DLG_WIDTH, 2, CONFIRM_DLG_HEIGTH, 0,
1234 0, 0, 0, 0, 0},
1235 NULL_QuickWidget};
1237 GString *label_text = g_string_new (_(" Replace with: "));
1238 if (*replace_text) {
1239 size_t label_len;
1240 label_len = label_text->len;
1241 g_string_append (label_text, replace_text);
1242 convert_to_display (label_text->str + label_len);
1244 quick_widgets[5].text = label_text->str;
1247 int retval;
1248 QuickDialog Quick_input =
1249 {CONFIRM_DLG_WIDTH, CONFIRM_DLG_HEIGTH, 0, 0, N_ (" Confirm replace "),
1250 "[Input Line Keys]", 0 /*quick_widgets */, 0 };
1252 Quick_input.widgets = quick_widgets;
1254 Quick_input.xpos = xpos;
1256 /* Sometimes menu can hide replaced text. I don't like it */
1258 if ((edit->curs_row >= ypos - 1) && (edit->curs_row <= ypos + CONFIRM_DLG_HEIGTH - 1))
1259 ypos -= CONFIRM_DLG_HEIGTH;
1261 Quick_input.ypos = ypos;
1262 retval = quick_dialog (&Quick_input);
1263 g_string_free (label_text, TRUE);
1264 return retval;
1268 static void
1269 edit_replace_dialog (WEdit * edit, const char *search_default,
1270 const char *replace_default, const char *argorder_default,
1271 /*@out@*/ char **search_text, /*@out@*/ char **replace_text,
1272 /*@out@*/ char **arg_order)
1274 int treplace_scanf = replace_scanf;
1275 int treplace_regexp = replace_regexp;
1276 int treplace_all = replace_all;
1277 int treplace_prompt = replace_prompt;
1278 int treplace_backwards = replace_backwards;
1279 int treplace_whole = replace_whole;
1280 int treplace_case = replace_case;
1282 /* Alt-p is in use as hotkey for previous entry; don't use */
1283 QuickWidget quick_widgets[] =
1285 {quick_button, 6, 10, 12, REPLACE_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1286 0, NULL},
1287 {quick_button, 2, 10, 12, REPLACE_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
1288 0, NULL},
1289 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1290 0, 0, NULL},
1291 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("replace &All"), 0, 0,
1292 0, 0, NULL},
1293 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("pro&Mpt on replace"), 0, 0,
1294 0, 0, NULL},
1295 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1296 0, 0, NULL},
1297 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1298 0, 0, NULL},
1299 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1300 0, 0, NULL},
1301 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 8, REPLACE_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1302 0, 0, NULL},
1303 {quick_input, 3, REPLACE_DLG_WIDTH, 7, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1304 0, "edit-argord"},
1305 {quick_label, 2, REPLACE_DLG_WIDTH, 6, REPLACE_DLG_HEIGHT, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1306 0, 0, 0},
1307 {quick_input, 3, REPLACE_DLG_WIDTH, 5, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1308 0, "edit-replace"},
1309 {quick_label, 2, REPLACE_DLG_WIDTH, 4, REPLACE_DLG_HEIGHT, N_(" Enter replacement string:"), 0, 0, 0,
1310 0, 0},
1311 {quick_input, 3, REPLACE_DLG_WIDTH, 3, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1312 0, "edit-search"},
1313 {quick_label, 2, REPLACE_DLG_WIDTH, 2, REPLACE_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1314 0, 0},
1315 NULL_QuickWidget};
1317 (void) edit;
1319 quick_widgets[2].result = &treplace_scanf;
1320 quick_widgets[3].result = &treplace_all;
1321 quick_widgets[4].result = &treplace_prompt;
1322 quick_widgets[5].result = &treplace_backwards;
1323 quick_widgets[6].result = &treplace_regexp;
1324 quick_widgets[7].result = &treplace_whole;
1325 quick_widgets[8].result = &treplace_case;
1326 quick_widgets[9].str_result = arg_order;
1327 quick_widgets[9].text = argorder_default;
1328 quick_widgets[11].str_result = replace_text;
1329 quick_widgets[11].text = replace_default;
1330 quick_widgets[13].str_result = search_text;
1331 quick_widgets[13].text = search_default;
1333 QuickDialog Quick_input =
1334 {REPLACE_DLG_WIDTH, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "),
1335 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1337 Quick_input.widgets = quick_widgets;
1339 if (quick_dialog (&Quick_input) != B_CANCEL) {
1340 replace_scanf = treplace_scanf;
1341 replace_backwards = treplace_backwards;
1342 replace_regexp = treplace_regexp;
1343 replace_all = treplace_all;
1344 replace_prompt = treplace_prompt;
1345 replace_whole = treplace_whole;
1346 replace_case = treplace_case;
1347 return;
1348 } else {
1349 *arg_order = NULL;
1350 *replace_text = NULL;
1351 *search_text = NULL;
1352 return;
1358 static void
1359 edit_search_dialog (WEdit * edit, char **search_text)
1361 int treplace_scanf = replace_scanf;
1362 int treplace_regexp = replace_regexp;
1363 int treplace_whole = replace_whole;
1364 int treplace_case = replace_case;
1365 int treplace_backwards = replace_backwards;
1367 QuickWidget quick_widgets[] =
1369 {quick_button, 6, 10, 7, SEARCH_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1370 0, NULL},
1371 {quick_button, 2, 10, 7, SEARCH_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
1372 0, NULL},
1373 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1374 0, 0, NULL },
1375 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1376 0, 0, NULL},
1377 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1378 0, 0, NULL},
1379 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1380 0, 0, NULL},
1381 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 4, SEARCH_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1382 0, 0, NULL},
1383 {quick_input, 3, SEARCH_DLG_WIDTH, 3, SEARCH_DLG_HEIGHT, "", 52, 0, 0,
1384 0, "edit-search"},
1385 {quick_label, 2, SEARCH_DLG_WIDTH, 2, SEARCH_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1386 0, 0},
1387 NULL_QuickWidget};
1389 (void) edit;
1391 quick_widgets[2].result = &treplace_scanf;
1392 quick_widgets[3].result = &treplace_backwards;
1393 quick_widgets[4].result = &treplace_regexp;
1394 quick_widgets[5].result = &treplace_whole;
1395 quick_widgets[6].result = &treplace_case;
1396 quick_widgets[7].str_result = search_text;
1397 quick_widgets[7].text = *search_text;
1400 QuickDialog Quick_input =
1401 {SEARCH_DLG_WIDTH, SEARCH_DLG_HEIGHT, -1, 0, N_("Search"),
1402 "[Input Line Keys]", 0 /*quick_widgets */, 0};
1404 Quick_input.widgets = quick_widgets;
1406 if (quick_dialog (&Quick_input) != B_CANCEL) {
1407 replace_scanf = treplace_scanf;
1408 replace_backwards = treplace_backwards;
1409 replace_regexp = treplace_regexp;
1410 replace_whole = treplace_whole;
1411 replace_case = treplace_case;
1412 } else {
1413 *search_text = NULL;
1419 static long sargs[NUM_REPL_ARGS][256 / sizeof (long)];
1421 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1422 sargs[4], sargs[5], sargs[6], sargs[7], \
1423 sargs[8], sargs[9], sargs[10], sargs[11], \
1424 sargs[12], sargs[13], sargs[14], sargs[15]
1426 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1427 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1428 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1429 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1432 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1433 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1434 static int
1435 string_regexp_search (char *pattern, char *string, int match_type,
1436 int match_bol, int icase, int *found_len, void *d)
1438 static regex_t r;
1439 static char *old_pattern = NULL;
1440 static int old_type, old_icase;
1441 regmatch_t *pmatch;
1442 static regmatch_t s[1];
1444 pmatch = (regmatch_t *) d;
1445 if (!pmatch)
1446 pmatch = s;
1448 if (!old_pattern || strcmp (old_pattern, pattern)
1449 || old_type != match_type || old_icase != icase) {
1450 if (old_pattern) {
1451 regfree (&r);
1452 g_free (old_pattern);
1453 old_pattern = 0;
1455 if (regcomp (&r, pattern, REG_EXTENDED | (icase ? REG_ICASE : 0) |
1456 REG_NEWLINE)) {
1457 *found_len = 0;
1458 return -3;
1460 old_pattern = g_strdup (pattern);
1461 old_type = match_type;
1462 old_icase = icase;
1464 if (regexec
1465 (&r, string, d ? NUM_REPL_ARGS : 1, pmatch,
1466 ((match_bol
1467 || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) {
1468 *found_len = 0;
1469 return -1;
1471 *found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
1472 return (pmatch[0].rm_so);
1475 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1476 (and the above) routines to work properly - paul */
1478 typedef int (*edit_getbyte_fn) (WEdit *, long);
1480 static long
1481 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)
1483 long p, q = 0;
1484 long l = strlen ((char *) exp), f = 0;
1485 int n = 0;
1487 for (p = 0; p < l; p++) /* count conversions... */
1488 if (exp[p] == '%')
1489 if (exp[++p] != '%') /* ...except for "%%" */
1490 n++;
1492 if (replace_scanf || replace_regexp) {
1493 int c;
1494 unsigned char *buf;
1495 unsigned char mbuf[MAX_REPL_LEN * 2 + 3];
1497 replace_scanf = (!replace_regexp); /* can't have both */
1499 buf = mbuf;
1501 if (replace_scanf) {
1502 unsigned char e[MAX_REPL_LEN];
1503 if (n >= NUM_REPL_ARGS)
1504 return -3;
1506 if (replace_case) {
1507 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++)
1508 buf[p - start] = (*get_byte) (data, p);
1509 } else {
1510 for (p = 0; exp[p] != 0; p++)
1511 exp[p] = my_lower_case (exp[p]);
1512 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) {
1513 c = (*get_byte) (data, p);
1514 buf[p - start] = my_lower_case (c);
1518 buf[(q = p - start)] = 0;
1519 strcpy ((char *) e, (char *) exp);
1520 strcat ((char *) e, "%n");
1521 exp = e;
1523 while (q) {
1524 *((int *) sargs[n]) = 0; /* --> here was the problem - now fixed: good */
1525 if (n == sscanf ((char *) buf, (char *) exp, SCANF_ARGS)) {
1526 if (*((int *) sargs[n])) {
1527 *len = *((int *) sargs[n]);
1528 return start;
1531 if (once_only)
1532 return -2;
1533 if (q + start < last_byte) {
1534 if (replace_case) {
1535 buf[q] = (*get_byte) (data, q + start);
1536 } else {
1537 c = (*get_byte) (data, q + start);
1538 buf[q] = my_lower_case (c);
1540 q++;
1542 buf[q] = 0;
1543 start++;
1544 buf++; /* move the window along */
1545 if (buf == mbuf + MAX_REPL_LEN) { /* the window is about to go past the end of array, so... */
1546 memmove (mbuf, buf, strlen ((char *) buf) + 1); /* reset it */
1547 buf = mbuf;
1549 q--;
1551 } else { /* regexp matching */
1552 long offset = 0;
1553 int found_start, match_bol, move_win = 0;
1555 while (start + offset < last_byte) {
1556 match_bol = (start == 0 || (*get_byte) (data, start + offset - 1) == '\n');
1557 if (!move_win) {
1558 p = start + offset;
1559 q = 0;
1561 for (; p < last_byte && q < MAX_REPL_LEN; p++, q++) {
1562 mbuf[q] = (*get_byte) (data, p);
1563 if (mbuf[q] == '\n') {
1564 q++;
1565 break;
1568 offset += q;
1569 mbuf[q] = 0;
1571 buf = mbuf;
1572 while (q) {
1573 found_start = string_regexp_search ((char *) exp, (char *) buf, match_normal, match_bol, !replace_case, len, d);
1575 if (found_start <= -2) { /* regcomp/regexec error */
1576 *len = 0;
1577 return -3;
1579 else if (found_start == -1) /* not found: try next line */
1580 break;
1581 else if (*len == 0) { /* null pattern: try again at next character */
1582 q--;
1583 buf++;
1584 match_bol = 0;
1585 continue;
1587 else /* found */
1588 return (start + offset - q + found_start);
1590 if (once_only)
1591 return -2;
1593 if (buf[q - 1] != '\n') { /* incomplete line: try to recover */
1594 buf = mbuf + MAX_REPL_LEN / 2;
1595 q = strlen ((const char *) buf);
1596 memmove (mbuf, buf, q);
1597 p = start + q;
1598 move_win = 1;
1600 else
1601 move_win = 0;
1604 } else {
1605 *len = strlen ((const char *) exp);
1606 if (replace_case) {
1607 for (p = start; p <= last_byte - l; p++) {
1608 if ((*get_byte) (data, p) == (unsigned char)exp[0]) { /* check if first char matches */
1609 for (f = 0, q = 0; q < l && f < 1; q++)
1610 if ((*get_byte) (data, q + p) != (unsigned char)exp[q])
1611 f = 1;
1612 if (f == 0)
1613 return p;
1615 if (once_only)
1616 return -2;
1618 } else {
1619 for (p = 0; exp[p] != 0; p++)
1620 exp[p] = my_lower_case (exp[p]);
1622 for (p = start; p <= last_byte - l; p++) {
1623 if (my_lower_case ((*get_byte) (data, p)) == (unsigned char)exp[0]) {
1624 for (f = 0, q = 0; q < l && f < 1; q++)
1625 if (my_lower_case ((*get_byte) (data, q + p)) != (unsigned char)exp[q])
1626 f = 1;
1627 if (f == 0)
1628 return p;
1630 if (once_only)
1631 return -2;
1635 return -2;
1639 static long
1640 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)
1641 { /*front end to find_string to check for
1642 whole words */
1643 long p;
1644 p = search_start;
1646 while ((p = edit_find_string (p, exp, len, last_byte, get_byte, data, once_only, d)) >= 0) {
1647 if (replace_whole) {
1648 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1649 if (!strcasechr (option_whole_chars_search, (*get_byte) (data, p - 1))
1650 && !strcasechr (option_whole_chars_search, (*get_byte) (data, p + *len)))
1651 return p;
1652 if (once_only)
1653 return -2;
1654 } else
1655 return p;
1656 if (once_only)
1657 break;
1658 p++; /*not a whole word so continue search. */
1660 return p;
1663 static long
1664 edit_find (long search_start, unsigned char *exp, int *len, long last_byte, edit_getbyte_fn get_byte, void *data, void *d)
1666 long p;
1667 if (replace_backwards) {
1668 while (search_start >= 0) {
1669 p = edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 1, d);
1670 if (p == search_start)
1671 return p;
1672 search_start--;
1674 } else {
1675 return edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 0, d);
1677 return -2;
1680 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1682 #define snprint(v) { \
1683 *p1++ = *p++; \
1684 *p1 = '\0'; \
1685 n = snprintf(s,e-s,q1,v); \
1686 if (n >= (size_t) (e - s)) goto nospc; \
1687 s += n; \
1690 /* this function uses the sprintf command to do a vprintf */
1691 /* it takes pointers to arguments instead of the arguments themselves */
1692 /* The return value is the number of bytes written excluding '\0'
1693 if successfull, -1 if the resulting string would be too long and
1694 -2 if the format string is errorneous. */
1695 static int snprintf_p (char *str, size_t size, const char *fmt,...)
1696 __attribute__ ((format (printf, 3, 4)));
1698 static int snprintf_p (char *str, size_t size, const char *fmt,...)
1700 va_list ap;
1701 size_t n;
1702 const char *q, *p;
1703 char *s = str, *e = str + size;
1704 char q1[40];
1705 char *p1;
1706 int nargs = 0;
1708 va_start (ap, fmt);
1709 p = q = fmt;
1711 while ((p = strchr (p, '%'))) {
1712 n = p - q;
1713 if (n >= (size_t) (e - s))
1714 goto nospc;
1715 memcpy (s, q, n); /* copy stuff between format specifiers */
1716 s += n;
1717 q = p;
1718 p1 = q1;
1719 *p1++ = *p++;
1720 if (*p == '%') {
1721 p++;
1722 *s++ = '%';
1723 if (s == e)
1724 goto nospc;
1725 q = p;
1726 continue;
1728 if (*p == 'n')
1729 goto err;
1730 /* We were passed only 16 arguments. */
1731 if (++nargs == 16)
1732 goto err;
1733 if (*p == '#')
1734 *p1++ = *p++;
1735 if (*p == '0')
1736 *p1++ = *p++;
1737 if (*p == '-')
1738 *p1++ = *p++;
1739 if (*p == '+')
1740 *p1++ = *p++;
1741 if (*p == '*') {
1742 p++;
1743 strcpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace field width with a number */
1744 p1 += strlen (p1);
1745 } else {
1746 while (is_digit (*p) && p1 < q1 + 20)
1747 *p1++ = *p++;
1748 if (is_digit (*p))
1749 goto err;
1751 if (*p == '.')
1752 *p1++ = *p++;
1753 if (*p == '*') {
1754 p++;
1755 strcpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace precision with a number */
1756 p1 += strlen (p1);
1757 } else {
1758 while (is_digit (*p) && p1 < q1 + 32)
1759 *p1++ = *p++;
1760 if (is_digit (*p))
1761 goto err;
1763 /* flags done, now get argument */
1764 if (*p == 's') {
1765 snprint (va_arg (ap, char *));
1766 } else if (*p == 'h') {
1767 if (strchr ("diouxX", *p))
1768 snprint (*va_arg (ap, short *));
1769 } else if (*p == 'l') {
1770 *p1++ = *p++;
1771 if (strchr ("diouxX", *p))
1772 snprint (*va_arg (ap, long *));
1773 } else if (strchr ("cdiouxX", *p)) {
1774 snprint (*va_arg (ap, int *));
1775 } else if (*p == 'L') {
1776 *p1++ = *p++;
1777 if (strchr ("EefgG", *p))
1778 snprint (*va_arg (ap, double *)); /* should be long double */
1779 } else if (strchr ("EefgG", *p)) {
1780 snprint (*va_arg (ap, double *));
1781 } else if (strchr ("DOU", *p)) {
1782 snprint (*va_arg (ap, long *));
1783 } else if (*p == 'p') {
1784 snprint (*va_arg (ap, void **));
1785 } else
1786 goto err;
1787 q = p;
1789 va_end (ap);
1790 n = strlen (q);
1791 if (n >= (size_t) (e - s))
1792 return -1;
1793 memcpy (s, q, n + 1);
1794 return s + n - str;
1795 nospc:
1796 va_end (ap);
1797 return -1;
1798 err:
1799 va_end (ap);
1800 return -2;
1803 static void regexp_error (WEdit *edit)
1805 (void) edit;
1806 edit_error_dialog (_("Error"), _(" Invalid regular expression, or scanf expression with too many conversions "));
1809 /* call with edit = 0 before shutdown to close memory leaks */
1810 void
1811 edit_replace_cmd (WEdit *edit, int again)
1813 static regmatch_t pmatch[NUM_REPL_ARGS];
1814 /* 1 = search string, 2 = replace with, 3 = argument order */
1815 static char *saved1 = NULL; /* saved default[123] */
1816 static char *saved2 = NULL;
1817 static char *saved3 = NULL;
1818 char *input1 = NULL; /* user input from the dialog */
1819 char *input2 = NULL;
1820 char *input3 = NULL;
1821 int replace_yes;
1822 int replace_continue;
1823 int treplace_prompt = 0;
1824 long times_replaced = 0, last_search;
1825 int argord[NUM_REPL_ARGS];
1827 if (!edit) {
1828 g_free (saved1), saved1 = NULL;
1829 g_free (saved2), saved2 = NULL;
1830 g_free (saved3), saved3 = NULL;
1831 return;
1834 last_search = edit->last_byte;
1836 edit->force |= REDRAW_COMPLETELY;
1838 if (again && !saved1 && !saved2)
1839 again = 0;
1841 if (again) {
1842 input1 = g_strdup (saved1 ? saved1 : "");
1843 input2 = g_strdup (saved2 ? saved2 : "");
1844 input3 = g_strdup (saved3 ? saved3 : "");
1845 } else {
1846 char *disp1 = g_strdup (saved1 ? saved1 : "");
1847 char *disp2 = g_strdup (saved2 ? saved2 : "");
1848 char *disp3 = g_strdup (saved3 ? saved3 : "");
1850 convert_to_display (disp1);
1851 convert_to_display (disp2);
1852 convert_to_display (disp3);
1854 edit_push_action (edit, KEY_PRESS + edit->start_display);
1855 edit_replace_dialog (edit, disp1, disp2, disp3, &input1, &input2,
1856 &input3);
1858 g_free (disp1);
1859 g_free (disp2);
1860 g_free (disp3);
1862 convert_from_input (input1);
1863 convert_from_input (input2);
1864 convert_from_input (input3);
1866 treplace_prompt = replace_prompt;
1867 if (input1 == NULL || *input1 == '\0') {
1868 edit->force = REDRAW_COMPLETELY;
1869 goto cleanup;
1872 g_free (saved1), saved1 = g_strdup (input1);
1873 g_free (saved2), saved2 = g_strdup (input2);
1874 g_free (saved3), saved3 = g_strdup (input3);
1879 const char *s;
1880 int ord;
1881 size_t i;
1883 s = input3;
1884 for (i = 0; i < NUM_REPL_ARGS; i++) {
1885 if (s != NULL && *s != '\0') {
1886 ord = atoi (s);
1887 if ((ord > 0) && (ord <= NUM_REPL_ARGS))
1888 argord[i] = ord - 1;
1889 else
1890 argord[i] = i;
1891 s = strchr (s, ',');
1892 if (s != NULL)
1893 s++;
1894 } else
1895 argord[i] = i;
1899 replace_continue = replace_all;
1901 if (edit->found_len && edit->search_start == edit->found_start + 1
1902 && replace_backwards)
1903 edit->search_start--;
1905 if (edit->found_len && edit->search_start == edit->found_start - 1
1906 && !replace_backwards)
1907 edit->search_start++;
1909 do {
1910 int len = 0;
1911 long new_start;
1912 new_start =
1913 edit_find (edit->search_start, (unsigned char *) input1, &len,
1914 last_search, edit_get_byte, (void *) edit, pmatch);
1915 if (new_start == -3) {
1916 regexp_error (edit);
1917 break;
1919 edit->search_start = new_start;
1920 /*returns negative on not found or error in pattern */
1922 if (edit->search_start >= 0) {
1923 int i;
1925 edit->found_start = edit->search_start;
1926 i = edit->found_len = len;
1928 edit_cursor_move (edit, edit->search_start - edit->curs1);
1929 edit_scroll_screen_over_cursor (edit);
1931 replace_yes = 1;
1933 if (treplace_prompt) {
1934 int l;
1935 l = edit->curs_row - edit->num_widget_lines / 3;
1936 if (l > 0)
1937 edit_scroll_downward (edit, l);
1938 if (l < 0)
1939 edit_scroll_upward (edit, -l);
1941 edit_scroll_screen_over_cursor (edit);
1942 edit->force |= REDRAW_PAGE;
1943 edit_render_keypress (edit);
1945 /*so that undo stops at each query */
1946 edit_push_key_press (edit);
1948 switch (edit_replace_prompt (edit, input2, /* and prompt 2/3 down */
1949 (edit->num_widget_columns -
1950 CONFIRM_DLG_WIDTH) / 2,
1951 edit->num_widget_lines * 2 /
1952 3)) {
1953 case B_ENTER:
1954 break;
1955 case B_SKIP_REPLACE:
1956 replace_yes = 0;
1957 break;
1958 case B_REPLACE_ALL:
1959 treplace_prompt = 0;
1960 replace_continue = 1;
1961 break;
1962 case B_REPLACE_ONE:
1963 replace_continue = 0;
1964 break;
1965 case B_CANCEL:
1966 replace_yes = 0;
1967 replace_continue = 0;
1968 break;
1971 if (replace_yes) { /* delete then insert new */
1972 if (replace_scanf) {
1973 char repl_str[MAX_REPL_LEN + 2];
1974 int ret = 0;
1976 /* we need to fill in sargs just like with scanf */
1977 if (replace_regexp) {
1978 int k, j;
1979 for (k = 1;
1980 k < NUM_REPL_ARGS && pmatch[k].rm_eo >= 0;
1981 k++) {
1982 unsigned char *t;
1984 if (pmatch[k].rm_eo - pmatch[k].rm_so > 255) {
1985 ret = -1;
1986 break;
1988 t = (unsigned char *) &sargs[k - 1][0];
1989 for (j = 0;
1990 j < pmatch[k].rm_eo - pmatch[k].rm_so
1991 && j < 255; j++, t++)
1992 *t = (unsigned char) edit_get_byte (edit,
1993 edit->
1994 search_start
1996 pmatch
1997 [0].
1998 rm_so +
1999 pmatch
2000 [k].
2001 rm_so +
2003 *t = '\0';
2005 for (; k <= NUM_REPL_ARGS; k++)
2006 sargs[k - 1][0] = 0;
2008 if (!ret)
2009 ret =
2010 snprintf_p (repl_str, MAX_REPL_LEN + 2, input2,
2011 PRINTF_ARGS);
2012 if (ret >= 0) {
2013 times_replaced++;
2014 while (i--)
2015 edit_delete (edit);
2016 while (repl_str[++i])
2017 edit_insert (edit, repl_str[i]);
2018 } else {
2019 edit_error_dialog (_(" Replace "),
2020 ret ==
2021 -2 ?
2023 (" Error in replacement format string. ")
2024 : _(" Replacement too long. "));
2025 replace_continue = 0;
2027 } else {
2028 times_replaced++;
2029 while (i--)
2030 edit_delete (edit);
2031 while (input2[++i])
2032 edit_insert (edit, input2[i]);
2034 edit->found_len = i;
2036 /* so that we don't find the same string again */
2037 if (replace_backwards) {
2038 last_search = edit->search_start;
2039 edit->search_start--;
2040 } else {
2041 edit->search_start += i;
2042 last_search = edit->last_byte;
2044 edit_scroll_screen_over_cursor (edit);
2045 } else {
2046 const char *msg = _(" Replace ");
2047 /* try and find from right here for next search */
2048 edit->search_start = edit->curs1;
2049 edit_update_curs_col (edit);
2051 edit->force |= REDRAW_PAGE;
2052 edit_render_keypress (edit);
2053 if (times_replaced) {
2054 message (0, msg, _(" %ld replacements made. "),
2055 times_replaced);
2056 } else
2057 query_dialog (msg, _(" Search string not found "),
2058 D_NORMAL, 1, _("&OK"));
2059 replace_continue = 0;
2061 } while (replace_continue);
2063 edit->force = REDRAW_COMPLETELY;
2064 edit_scroll_screen_over_cursor (edit);
2065 cleanup:
2066 g_free (input1);
2067 g_free (input2);
2068 g_free (input3);
2074 void edit_search_cmd (WEdit * edit, int again)
2076 static char *old = NULL;
2077 char *exp = "";
2079 if (!edit) {
2080 g_free (old);
2081 old = NULL;
2082 return;
2085 exp = old ? old : exp;
2086 if (again) { /*ctrl-hotkey for search again. */
2087 if (!old)
2088 return;
2089 exp = g_strdup (old);
2090 } else {
2092 #ifdef HAVE_CHARSET
2093 if (exp && *exp)
2094 convert_to_display (exp);
2095 #endif /* HAVE_CHARSET */
2097 edit_search_dialog (edit, &exp);
2099 #ifdef HAVE_CHARSET
2100 if (exp && *exp)
2101 convert_from_input (exp);
2102 #endif /* HAVE_CHARSET */
2104 edit_push_action (edit, KEY_PRESS + edit->start_display);
2107 if (exp) {
2108 if (*exp) {
2109 int len = 0;
2110 g_free (old);
2111 old = g_strdup (exp);
2113 if (search_create_bookmark) {
2114 int found = 0, books = 0;
2115 int l = 0, l_last = -1;
2116 long p, q = 0;
2117 for (;;) {
2118 p = edit_find (q, (unsigned char *) exp, &len, edit->last_byte,
2119 edit_get_byte, (void *) edit, 0);
2120 if (p < 0)
2121 break;
2122 found++;
2123 l += edit_count_lines (edit, q, p);
2124 if (l != l_last) {
2125 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
2126 books++;
2128 l_last = l;
2129 q = p + 1;
2131 if (found) {
2132 /* in response to number of bookmarks added because of string being found %d times */
2133 message (0, _("Search"), _(" %d items found, %d bookmarks added "), found, books);
2134 } else {
2135 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2137 } else {
2139 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
2140 edit->search_start--;
2142 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
2143 edit->search_start++;
2145 edit->search_start = edit_find (edit->search_start, (unsigned char *) exp, &len, edit->last_byte,
2146 edit_get_byte, (void *) edit, 0);
2148 if (edit->search_start >= 0) {
2149 edit->found_start = edit->search_start;
2150 edit->found_len = len;
2152 edit_cursor_move (edit, edit->search_start - edit->curs1);
2153 edit_scroll_screen_over_cursor (edit);
2154 if (replace_backwards)
2155 edit->search_start--;
2156 else
2157 edit->search_start++;
2158 } else if (edit->search_start == -3) {
2159 edit->search_start = edit->curs1;
2160 regexp_error (edit);
2161 } else {
2162 edit->search_start = edit->curs1;
2163 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
2167 g_free (exp);
2169 edit->force |= REDRAW_COMPLETELY;
2170 edit_scroll_screen_over_cursor (edit);
2175 * Check if it's OK to close the editor. If there are unsaved changes,
2176 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2179 edit_ok_to_exit (WEdit *edit)
2181 if (!edit->modified)
2182 return 1;
2184 switch (edit_query_dialog3
2185 (_("Quit"), _(" File was modified, Save with exit? "),
2186 _("&Cancel quit"), _("&Yes"), _("&No"))) {
2187 case 1:
2188 edit_push_markers (edit);
2189 edit_set_markers (edit, 0, 0, 0, 0);
2190 if (!edit_save_cmd (edit))
2191 return 0;
2192 break;
2193 case 2:
2194 break;
2195 case 0:
2196 case -1:
2197 return 0;
2200 return 1;
2204 #define TEMP_BUF_LEN 1024
2206 /* Return a null terminated length of text. Result must be g_free'd */
2207 static unsigned char *
2208 edit_get_block (WEdit *edit, long start, long finish, int *l)
2210 unsigned char *s, *r;
2211 r = s = g_malloc (finish - start + 1);
2212 if (column_highlighting) {
2213 *l = 0;
2214 /* copy from buffer, excluding chars that are out of the column 'margins' */
2215 while (start < finish) {
2216 int c, x;
2217 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
2218 start);
2219 c = edit_get_byte (edit, start);
2220 if ((x >= edit->column1 && x < edit->column2)
2221 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
2222 *s++ = c;
2223 (*l)++;
2225 start++;
2227 } else {
2228 *l = finish - start;
2229 while (start < finish)
2230 *s++ = edit_get_byte (edit, start++);
2232 *s = 0;
2233 return r;
2236 /* save block, returns 1 on success */
2238 edit_save_block (WEdit * edit, const char *filename, long start,
2239 long finish)
2241 int len, file;
2243 if ((file =
2244 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
2245 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
2246 return 0;
2248 if (column_highlighting) {
2249 unsigned char *block, *p;
2250 int r;
2251 p = block = edit_get_block (edit, start, finish, &len);
2252 while (len) {
2253 r = mc_write (file, p, len);
2254 if (r < 0)
2255 break;
2256 p += r;
2257 len -= r;
2259 g_free (block);
2260 } else {
2261 unsigned char *buf;
2262 int i = start, end;
2263 len = finish - start;
2264 buf = g_malloc (TEMP_BUF_LEN);
2265 while (start != finish) {
2266 end = min (finish, start + TEMP_BUF_LEN);
2267 for (; i < end; i++)
2268 buf[i - start] = edit_get_byte (edit, i);
2269 len -= mc_write (file, (char *) buf, end - start);
2270 start = end;
2272 g_free (buf);
2274 mc_close (file);
2275 if (len)
2276 return 0;
2277 return 1;
2280 /* copies a block to clipboard file */
2281 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
2283 return edit_save_block (edit, catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL), start, finish);
2287 void edit_paste_from_history (WEdit *edit)
2289 (void) edit;
2290 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
2293 int edit_copy_to_X_buf_cmd (WEdit * edit)
2295 long start_mark, end_mark;
2296 if (eval_marks (edit, &start_mark, &end_mark))
2297 return 0;
2298 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2299 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2300 return 1;
2302 edit_mark_cmd (edit, 1);
2303 return 0;
2306 int edit_cut_to_X_buf_cmd (WEdit * edit)
2308 long start_mark, end_mark;
2309 if (eval_marks (edit, &start_mark, &end_mark))
2310 return 0;
2311 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2312 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2313 return 1;
2315 edit_block_delete_cmd (edit);
2316 edit_mark_cmd (edit, 1);
2317 return 0;
2320 void edit_paste_from_X_buf_cmd (WEdit * edit)
2322 edit_insert_file (edit, catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL));
2327 * Ask user for the line and go to that line.
2328 * Negative numbers mean line from the end (i.e. -1 is the last line).
2330 void
2331 edit_goto_cmd (WEdit *edit)
2333 char *f;
2334 static long line = 0; /* line as typed, saved as default */
2335 long l;
2336 char *error;
2337 char s[32];
2339 g_snprintf (s, sizeof (s), "%ld", line);
2340 f = input_dialog (_(" Goto line "), _(" Enter line: "), ":edit_goto_cmd: Goto line ",
2341 line ? s : "");
2342 if (!f)
2343 return;
2345 if (!*f) {
2346 g_free (f);
2347 return;
2350 l = strtol (f, &error, 0);
2351 if (*error) {
2352 g_free (f);
2353 return;
2356 line = l;
2357 if (l < 0)
2358 l = edit->total_lines + l + 2;
2359 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2360 edit_move_to_line (edit, l - 1);
2361 edit->force |= REDRAW_COMPLETELY;
2362 g_free (f);
2366 /* Return 1 on success */
2368 edit_save_block_cmd (WEdit *edit)
2370 long start_mark, end_mark;
2371 char *exp;
2372 if (eval_marks (edit, &start_mark, &end_mark))
2373 return 1;
2374 exp =
2375 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2376 ":edit_save_block_cmd: Save Block ",
2377 catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL));
2378 edit_push_action (edit, KEY_PRESS + edit->start_display);
2379 if (exp) {
2380 if (!*exp) {
2381 g_free (exp);
2382 return 0;
2383 } else {
2384 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2385 g_free (exp);
2386 edit->force |= REDRAW_COMPLETELY;
2387 return 1;
2388 } else {
2389 g_free (exp);
2390 edit_error_dialog (_(" Save Block "),
2391 get_sys_error (_
2392 (" Cannot save file. ")));
2396 edit->force |= REDRAW_COMPLETELY;
2397 return 0;
2401 /* returns 1 on success */
2403 edit_insert_file_cmd (WEdit *edit)
2405 char *exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2406 ":edit_insert_file_cmd: Insert File ",
2407 catstrs (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL));
2408 edit_push_action (edit, KEY_PRESS + edit->start_display);
2409 if (exp) {
2410 if (!*exp) {
2411 g_free (exp);
2412 return 0;
2413 } else {
2414 if (edit_insert_file (edit, exp)) {
2415 g_free (exp);
2416 edit->force |= REDRAW_COMPLETELY;
2417 return 1;
2418 } else {
2419 g_free (exp);
2420 edit_error_dialog (_(" Insert File "),
2421 get_sys_error (_
2422 (" Cannot insert file. ")));
2426 edit->force |= REDRAW_COMPLETELY;
2427 return 0;
2430 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2431 int edit_sort_cmd (WEdit * edit)
2433 static char *old = 0;
2434 char *exp;
2435 long start_mark, end_mark;
2436 int e;
2438 if (eval_marks (edit, &start_mark, &end_mark)) {
2439 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2440 return 0;
2442 edit_save_block (edit, catstrs (home_dir, PATH_SEP_STR BLOCK_FILE, (char *) NULL), start_mark, end_mark);
2444 exp = input_dialog (_(" Run Sort "),
2445 _(" Enter sort options (see manpage) separated by whitespace: "),
2446 ":edit_sort_cmd: Run Sort ", (old != NULL) ? old : "");
2448 if (!exp)
2449 return 1;
2450 g_free (old);
2451 old = exp;
2453 e = system (catstrs (" sort ", exp, " ", home_dir, PATH_SEP_STR BLOCK_FILE, " > ", home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2454 if (e) {
2455 if (e == -1 || e == 127) {
2456 edit_error_dialog (_(" Sort "),
2457 get_sys_error (_(" Cannot execute sort command ")));
2458 } else {
2459 char q[8];
2460 sprintf (q, "%d ", e);
2461 edit_error_dialog (_(" Sort "),
2462 catstrs (_(" Sort returned non-zero: "), q, (char *) NULL));
2464 return -1;
2467 edit->force |= REDRAW_COMPLETELY;
2469 if (edit_block_delete_cmd (edit))
2470 return 1;
2471 edit_insert_file (edit, catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2472 return 0;
2476 * Ask user for a command, execute it and paste its output back to the
2477 * editor.
2480 edit_ext_cmd (WEdit *edit)
2482 char *exp;
2483 int e;
2485 exp =
2486 input_dialog (_("Paste output of external command"),
2487 _("Enter shell command(s):"),
2488 ":edit_ext_cmd: Paste output of ext.cmd ", NULL);
2490 if (!exp)
2491 return 1;
2493 e = system (catstrs (exp, " > ", home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2494 g_free (exp);
2496 if (e) {
2497 edit_error_dialog (_("External command"),
2498 get_sys_error (_("Cannot execute command")));
2499 return -1;
2502 edit->force |= REDRAW_COMPLETELY;
2504 edit_insert_file (edit, catstrs (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL));
2505 return 0;
2508 /* if block is 1, a block must be highlighted and the shell command
2509 processes it. If block is 0 the shell command is a straight system
2510 command, that just produces some output which is to be inserted */
2511 void
2512 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2514 long start_mark, end_mark;
2515 char buf[BUFSIZ];
2516 FILE *script_home = NULL;
2517 FILE *script_src = NULL;
2518 FILE *block_file = NULL;
2519 const char *o = NULL;
2520 const char *h = NULL;
2521 const char *b = NULL;
2522 char *quoted_name = NULL;
2524 o = catstrs (mc_home, shell_cmd, (char *) NULL); /* original source script */
2525 h = catstrs (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2526 b = catstrs (home_dir, PATH_SEP_STR BLOCK_FILE, (char *) NULL); /* block file */
2528 if (!(script_home = fopen (h, "r"))) {
2529 if (!(script_home = fopen (h, "w"))) {
2530 edit_error_dialog ("", get_sys_error (catstrs
2532 ("Error creating script:"),
2533 h, (char *) NULL)));
2534 return;
2536 if (!(script_src = fopen (o, "r"))) {
2537 fclose (script_home);
2538 unlink (h);
2539 edit_error_dialog ("", get_sys_error (catstrs
2540 (_("Error reading script:"),
2541 o, (char *) NULL)));
2542 return;
2544 while (fgets (buf, sizeof (buf), script_src))
2545 fputs (buf, script_home);
2546 if (fclose (script_home)) {
2547 edit_error_dialog ("", get_sys_error (catstrs
2549 ("Error closing script:"),
2550 h, (char *) NULL)));
2551 return;
2553 chmod (h, 0700);
2554 edit_error_dialog ("", get_sys_error (catstrs
2555 (_("Script created:"), h, (char *) NULL)));
2558 open_error_pipe ();
2560 if (block) { /* for marked block run indent formatter */
2561 if (eval_marks (edit, &start_mark, &end_mark)) {
2562 edit_error_dialog (_("Process block"),
2564 (" You must first highlight a block of text. "));
2565 return;
2567 edit_save_block (edit, b, start_mark, end_mark);
2568 quoted_name = name_quote (edit->filename, 0);
2570 * Run script.
2571 * Initial space is to avoid polluting bash history.
2572 * Arguments:
2573 * $1 - name of the edited file (to check its extension etc).
2574 * $2 - file containing the current block.
2575 * $3 - file where error messages should be put
2576 * (for compatibility with old scripts).
2578 system (catstrs (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2579 " ", home_dir, PATH_SEP_STR BLOCK_FILE " /dev/null", (char *) NULL));
2581 } else {
2583 * No block selected, just execute the command for the file.
2584 * Arguments:
2585 * $1 - name of the edited file.
2587 system (catstrs (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2588 quoted_name, (char *) NULL));
2590 g_free (quoted_name);
2591 close_error_pipe (0, 0);
2593 edit_refresh_cmd (edit);
2594 edit->force |= REDRAW_COMPLETELY;
2596 /* insert result block */
2597 if (block) {
2598 if (edit_block_delete_cmd (edit))
2599 return;
2600 edit_insert_file (edit, b);
2601 if ((block_file = fopen (b, "w")))
2602 fclose (block_file);
2603 return;
2606 return;
2609 /* prints at the cursor */
2610 /* returns the number of chars printed */
2611 int edit_print_string (WEdit * e, const char *s)
2613 int i = 0;
2614 while (s[i])
2615 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2616 e->force |= REDRAW_COMPLETELY;
2617 edit_update_screen (e);
2618 return i;
2622 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2624 FILE *p = 0;
2625 char *s;
2627 to = name_quote (to, 0);
2628 subject = name_quote (subject, 0);
2629 cc = name_quote (cc, 0);
2630 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2631 g_free (to);
2632 g_free (subject);
2633 g_free (cc);
2635 if (s) {
2636 p = popen (s, "w");
2637 g_free (s);
2640 if (p) {
2641 long i;
2642 for (i = 0; i < edit->last_byte; i++)
2643 fputc (edit_get_byte (edit, i), p);
2644 pclose (p);
2648 #define MAIL_DLG_HEIGHT 12
2650 void edit_mail_dialog (WEdit * edit)
2652 char *tmail_to;
2653 char *tmail_subject;
2654 char *tmail_cc;
2656 static char *mail_cc_last = 0;
2657 static char *mail_subject_last = 0;
2658 static char *mail_to_last = 0;
2660 QuickDialog Quick_input =
2661 {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
2662 "[Input Line Keys]", 0, 0};
2664 QuickWidget quick_widgets[] =
2666 {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
2667 0, NULL},
2668 {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
2669 0, NULL},
2670 {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2671 0, "mail-dlg-input"},
2672 {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
2673 0, 0},
2674 {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2675 0, "mail-dlg-input-2"},
2676 {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
2677 0, 0},
2678 {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2679 0, "mail-dlg-input-3"},
2680 {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
2681 0, 0},
2682 {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2683 0, 0},
2684 NULL_QuickWidget};
2686 quick_widgets[2].str_result = &tmail_cc;
2687 quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
2688 quick_widgets[4].str_result = &tmail_subject;
2689 quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
2690 quick_widgets[6].str_result = &tmail_to;
2691 quick_widgets[6].text = mail_to_last ? mail_to_last : "";
2693 Quick_input.widgets = quick_widgets;
2695 if (quick_dialog (&Quick_input) != B_CANCEL) {
2696 g_free (mail_cc_last);
2697 g_free (mail_subject_last);
2698 g_free (mail_to_last);
2699 mail_cc_last = tmail_cc;
2700 mail_subject_last = tmail_subject;
2701 mail_to_last = tmail_to;
2702 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2707 /*******************/
2708 /* Word Completion */
2709 /*******************/
2712 /* find first character of current word */
2713 static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len)
2715 int i, c, last;
2717 /* return if at begin of file */
2718 if (edit->curs1 <= 0)
2719 return 0;
2721 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2722 /* return if not at end or in word */
2723 if (isspace (c) || !(isalnum (c) || c == '_'))
2724 return 0;
2726 /* search start of word to be completed */
2727 for (i = 2;; i++) {
2728 /* return if at begin of file */
2729 if (edit->curs1 - i < 0)
2730 return 0;
2732 last = c;
2733 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2735 if (!(isalnum (c) || c == '_')) {
2736 /* return if word starts with digit */
2737 if (isdigit (last))
2738 return 0;
2740 *word_start = edit->curs1 - (i - 1); /* start found */
2741 *word_len = i - 1;
2742 break;
2745 /* success */
2746 return 1;
2750 /* (re)set search parameters to the given values */
2751 static void edit_set_search_parameters (int rs, int rb, int rr, int rw, int rc)
2753 replace_scanf = rs;
2754 replace_backwards = rb;
2755 replace_regexp = rr;
2756 replace_whole = rw;
2757 replace_case = rc;
2761 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2763 /* collect the possible completions */
2764 static int
2765 edit_collect_completions (WEdit *edit, long start, int word_len,
2766 char *match_expr, struct selection *compl,
2767 int *num)
2769 int len, max_len = 0, i, skip;
2770 unsigned char *bufpos;
2772 /* collect max MAX_WORD_COMPLETIONS completions */
2773 while (*num < MAX_WORD_COMPLETIONS) {
2774 /* get next match */
2775 start =
2776 edit_find (start - 1, (unsigned char *) match_expr, &len,
2777 edit->last_byte, edit_get_byte, (void *) edit, 0);
2779 /* not matched */
2780 if (start < 0)
2781 break;
2783 /* add matched completion if not yet added */
2784 bufpos =
2785 &edit->
2786 buffers1[start >> S_EDIT_BUF_SIZE][start & M_EDIT_BUF_SIZE];
2787 skip = 0;
2788 for (i = 0; i < *num; i++) {
2789 if (strncmp
2790 ((char *) &compl[i].text[word_len],
2791 (char *) &bufpos[word_len], max (len,
2792 compl[i].len) -
2793 word_len) == 0) {
2794 skip = 1;
2795 break; /* skip it, already added */
2798 if (skip)
2799 continue;
2801 compl[*num].text = g_malloc (len + 1);
2802 compl[*num].len = len;
2803 for (i = 0; i < len; i++)
2804 compl[*num].text[i] = *(bufpos + i);
2805 compl[*num].text[i] = '\0';
2806 (*num)++;
2808 /* note the maximal length needed for the completion dialog */
2809 if (len > max_len)
2810 max_len = len;
2812 return max_len;
2816 /* let the user select its preferred completion */
2817 static void
2818 edit_completion_dialog (WEdit * edit, int max_len, int word_len,
2819 struct selection *compl, int num_compl)
2821 int start_x, start_y, offset, i;
2822 char *curr = NULL;
2823 Dlg_head *compl_dlg;
2824 WListbox *compl_list;
2825 int compl_dlg_h; /* completion dialog height */
2826 int compl_dlg_w; /* completion dialog width */
2828 /* calculate the dialog metrics */
2829 compl_dlg_h = num_compl + 2;
2830 compl_dlg_w = max_len + 4;
2831 start_x = edit->curs_col + edit->start_col - (compl_dlg_w / 2);
2832 start_y = edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + 1;
2834 if (start_x < 0)
2835 start_x = 0;
2836 if (compl_dlg_w > COLS)
2837 compl_dlg_w = COLS;
2838 if (compl_dlg_h > LINES - 2)
2839 compl_dlg_h = LINES - 2;
2841 offset = start_x + compl_dlg_w - COLS;
2842 if (offset > 0)
2843 start_x -= offset;
2844 offset = start_y + compl_dlg_h - LINES;
2845 if (offset > 0)
2846 start_y -= (offset + 1);
2848 /* create the dialog */
2849 compl_dlg =
2850 create_dlg (start_y, start_x, compl_dlg_h, compl_dlg_w,
2851 dialog_colors, NULL, "[Completion]", NULL,
2852 DLG_COMPACT);
2854 /* create the listbox */
2855 compl_list =
2856 listbox_new (1, 1, compl_dlg_w - 2, compl_dlg_h - 2, NULL);
2858 /* add the dialog */
2859 add_widget (compl_dlg, compl_list);
2861 /* fill the listbox with the completions */
2862 for (i = 0; i < num_compl; i++)
2863 listbox_add_item (compl_list, LISTBOX_APPEND_AT_END, 0,
2864 (char *) compl[i].text, NULL);
2866 /* pop up the dialog */
2867 run_dlg (compl_dlg);
2869 /* apply the choosen completion */
2870 if (compl_dlg->ret_value == B_ENTER) {
2871 listbox_get_current (compl_list, &curr, NULL);
2872 if (curr)
2873 for (curr += word_len; *curr; curr++)
2874 edit_insert (edit, *curr);
2877 /* destroy dialog before return */
2878 destroy_dlg (compl_dlg);
2883 * Complete current word using regular expression search
2884 * backwards beginning at the current cursor position.
2886 void
2887 edit_complete_word_cmd (WEdit *edit)
2889 int word_len = 0, i, num_compl = 0, max_len;
2890 long word_start = 0;
2891 unsigned char *bufpos;
2892 char *match_expr;
2893 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2895 /* don't want to disturb another search */
2896 int old_rs = replace_scanf;
2897 int old_rb = replace_backwards;
2898 int old_rr = replace_regexp;
2899 int old_rw = replace_whole;
2900 int old_rc = replace_case;
2902 /* search start of word to be completed */
2903 if (!edit_find_word_start (edit, &word_start, &word_len))
2904 return;
2906 /* prepare match expression */
2907 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2908 [word_start & M_EDIT_BUF_SIZE];
2909 match_expr = g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len, bufpos);
2911 /* init search: backward, regexp, whole word, case sensitive */
2912 edit_set_search_parameters (0, 1, 1, 1, 1);
2914 /* collect the possible completions */
2915 /* start search from curs1 down to begin of file */
2916 max_len =
2917 edit_collect_completions (edit, word_start, word_len, match_expr,
2918 (struct selection *) &compl, &num_compl);
2920 if (num_compl > 0) {
2921 /* insert completed word if there is only one match */
2922 if (num_compl == 1) {
2923 for (i = word_len; i < compl[0].len; i++)
2924 edit_insert (edit, *(compl[0].text + i));
2926 /* more than one possible completion => ask the user */
2927 else {
2928 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2929 /* !!! pressed again the selection dialog pops up, but that !!! */
2930 /* !!! seems to require a further internal state !!! */
2931 /*beep (); */
2933 /* let the user select the preferred completion */
2934 edit_completion_dialog (edit, max_len, word_len,
2935 (struct selection *) &compl,
2936 num_compl);
2940 g_free (match_expr);
2941 /* release memory before return */
2942 for (i = 0; i < num_compl; i++)
2943 g_free (compl[i].text);
2945 /* restore search parameters */
2946 edit_set_search_parameters (old_rs, old_rb, old_rr, old_rw, old_rc);
2949 void
2950 edit_select_codepage_cmd (WEdit *edit)
2952 #ifdef HAVE_CHARSET
2953 do_select_codepage ();
2954 edit->force = REDRAW_COMPLETELY;
2955 edit_refresh_cmd (edit);
2956 #endif
2959 void
2960 edit_insert_literal_cmd (WEdit *edit)
2962 int char_for_insertion =
2963 edit_raw_key_query (_(" Insert Literal "),
2964 _(" Press any key: "), 0);
2965 edit_execute_key_command (edit, -1,
2966 ascii_alpha_to_cntrl (char_for_insertion));
2969 void
2970 edit_execute_macro_cmd (WEdit *edit)
2972 int command =
2973 CK_Macro (edit_raw_key_query
2974 (_(" Execute Macro "), _(" Press macro hotkey: "),
2975 1));
2976 if (command == CK_Macro (0))
2977 command = CK_Insert_Char;
2979 edit_execute_key_command (edit, command, -1);
2982 void
2983 edit_begin_end_macro_cmd(WEdit *edit)
2985 int command;
2987 /* edit is a pointer to the widget */
2988 if (edit) {
2989 command =
2990 edit->macro_i <
2991 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2992 edit_execute_key_command (edit, command, -1);