Merge branch '380_bw_colors_and_frames'
[midnight-commander.git] / edit / editcmd.c
blob0b751d2d2d0b7066f518b56d7681e3431a7f6ae7
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 /** \file
26 * \brief Source: editor high level editing commands
27 * \author Paul Sheer
28 * \date 1996, 1997
31 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
33 #include <config.h>
35 #include <assert.h>
36 #include <ctype.h>
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <sys/stat.h>
45 #include <stdlib.h>
46 #include <fcntl.h>
48 #include "../src/global.h"
50 #include "../src/tty/tty.h"
51 #include "../src/tty/key.h" /* XCTRL */
53 #include "../src/history.h"
54 #include "../src/widget.h" /* listbox_new() */
55 #include "../src/layout.h" /* clr_scr() */
56 #include "../src/main.h" /* mc_home source_codepage */
57 #include "../src/help.h" /* interactive_display() */
58 #include "../src/wtools.h" /* message() */
59 #include "../src/charsets.h"
60 #include "../src/selcodepage.h"
61 #include "../src/strutil.h" /* utf string functions */
63 #include "../edit/edit-impl.h"
64 #include "../edit/edit.h"
65 #include "../edit/editlock.h"
66 #include "../edit/editcmddef.h"
67 #include "../edit/edit-widget.h"
68 #include "../edit/editcmd_dialogs.h"
69 #include "../edit/etags.h"
71 /* globals: */
73 /* search and replace: */
74 int search_create_bookmark = 0;
75 /* static int search_in_all_charsets = 0; */
77 /* queries on a save */
78 int edit_confirm_save = 1;
80 static int edit_save_cmd (WEdit *edit);
81 static unsigned char *edit_get_block (WEdit *edit, long start,
82 long finish, int *l);
84 static void
85 edit_search_cmd_search_create_bookmark(WEdit * edit)
87 int found = 0, books = 0;
88 int l = 0, l_last = -1;
89 long q = 0;
90 gsize len = 0;
92 search_create_bookmark = 0;
93 book_mark_flush (edit, -1);
95 for (;;) {
96 if (!mc_search_run(edit->search, (void *) edit, q, edit->last_byte, &len))
97 break;
98 if (found == 0)
99 edit->search_start = edit->search->normal_offset;
100 found++;
101 l += edit_count_lines (edit, q, edit->search->normal_offset);
102 if (l != l_last) {
103 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
104 books++;
106 l_last = l;
107 q = edit->search->normal_offset + 1;
110 if (found == 0) {
111 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
112 } else {
113 edit_cursor_move (edit, edit->search_start - edit->curs1);
114 edit_scroll_screen_over_cursor (edit);
118 static int
119 edit_search_cmd_callback(const void *user_data, gsize char_offset)
121 return edit_get_byte ((WEdit * )user_data, (long) char_offset);
124 void edit_help_cmd (WEdit * edit)
126 interactive_display (NULL, "[Internal File Editor]");
127 edit->force |= REDRAW_COMPLETELY;
130 void
131 edit_refresh_cmd (WEdit * edit)
133 #ifdef HAVE_SLANG
134 int color;
136 edit_get_syntax_color (edit, -1, &color);
137 tty_touch_screen ();
138 mc_refresh ();
139 #else
140 clr_scr ();
141 repaint_screen ();
142 #endif /* !HAVE_SLANG */
143 tty_keypad (TRUE);
146 /* If 0 (quick save) then a) create/truncate <filename> file,
147 b) save to <filename>;
148 if 1 (safe save) then a) save to <tempnam>,
149 b) rename <tempnam> to <filename>;
150 if 2 (do backups) then a) save to <tempnam>,
151 b) rename <filename> to <filename.backup_ext>,
152 c) rename <tempnam> to <filename>. */
154 /* returns 0 on error, -1 on abort */
155 static int
156 edit_save_file (WEdit *edit, const char *filename)
158 char *p;
159 gchar *tmp;
160 long filelen = 0;
161 char *savename = 0;
162 gchar *real_filename;
163 int this_save_mode, fd = -1;
165 if (!filename)
166 return 0;
167 if (!*filename)
168 return 0;
170 if (*filename != PATH_SEP && edit->dir) {
171 real_filename = concat_dir_and_file (edit->dir, filename);
172 } else {
173 real_filename = g_strdup(filename);
176 this_save_mode = option_save_mode;
177 if (this_save_mode != EDIT_QUICK_SAVE) {
178 if (!vfs_file_is_local (real_filename) ||
179 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1) {
181 * The file does not exists yet, so no safe save or
182 * backup are necessary.
184 this_save_mode = EDIT_QUICK_SAVE;
186 if (fd != -1)
187 mc_close (fd);
190 if (this_save_mode == EDIT_QUICK_SAVE &&
191 !edit->skip_detach_prompt) {
192 int rv;
193 struct stat sb;
195 rv = mc_stat (real_filename, &sb);
196 if (rv == 0 && sb.st_nlink > 1) {
197 rv = edit_query_dialog3 (_("Warning"),
198 _(" File has hard-links. Detach before saving? "),
199 _("&Yes"), _("&No"), _("&Cancel"));
200 switch (rv) {
201 case 0:
202 this_save_mode = EDIT_SAFE_SAVE;
203 /* fallthrough */
204 case 1:
205 edit->skip_detach_prompt = 1;
206 break;
207 default:
208 g_free(real_filename);
209 return -1;
213 /* Prevent overwriting changes from other editor sessions. */
214 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
216 /* The default action is "Cancel". */
217 query_set_sel(1);
219 rv = edit_query_dialog2 (
220 _("Warning"),
221 _("The file has been modified in the meantime. Save anyway?"),
222 _("&Yes"),
223 _("&Cancel"));
224 if (rv != 0){
225 g_free(real_filename);
226 return -1;
231 if (this_save_mode != EDIT_QUICK_SAVE) {
232 char *savedir, *saveprefix;
233 const char *slashpos;
234 slashpos = strrchr (real_filename, PATH_SEP);
235 if (slashpos) {
236 savedir = g_strdup (real_filename);
237 savedir[slashpos - real_filename + 1] = '\0';
238 } else
239 savedir = g_strdup (".");
240 saveprefix = concat_dir_and_file (savedir, "cooledit");
241 g_free (savedir);
242 fd = mc_mkstemps (&savename, saveprefix, NULL);
243 g_free (saveprefix);
244 if (!savename){
245 g_free(real_filename);
246 return 0;
248 /* FIXME:
249 * Close for now because mc_mkstemps use pure open system call
250 * to create temporary file and it needs to be reopened by
251 * VFS-aware mc_open().
253 close (fd);
254 } else
255 savename = g_strdup (real_filename);
257 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
258 mc_chmod (savename, edit->stat1.st_mode);
260 if ((fd =
261 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
262 edit->stat1.st_mode)) == -1)
263 goto error_save;
265 /* pipe save */
266 if ((p = edit_get_write_filter (savename, real_filename))) {
267 FILE *file;
269 mc_close (fd);
270 file = (FILE *) popen (p, "w");
272 if (file) {
273 filelen = edit_write_stream (edit, file);
274 #if 1
275 pclose (file);
276 #else
277 if (pclose (file) != 0) {
278 tmp = g_strconcat (_(" Error writing to pipe: "),
279 p, " ", (char *) NULL);
280 edit_error_dialog (_("Error"), tmp);
281 g_free(tmp);
282 g_free (p);
283 goto error_save;
285 #endif
286 } else {
287 tmp = g_strconcat (_(" Cannot open pipe for writing: "),
288 p, " ", (char *) NULL);
290 edit_error_dialog (_("Error"),
291 get_sys_error (tmp));
292 g_free (p);
293 g_free(tmp);
294 goto error_save;
296 g_free (p);
297 } else if (edit->lb == LB_ASIS) { /* do not change line breaks */
298 long buf;
299 buf = 0;
300 filelen = edit->last_byte;
301 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
302 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
303 != EDIT_BUF_SIZE) {
304 mc_close (fd);
305 goto error_save;
307 buf++;
309 if (mc_write
310 (fd, (char *) edit->buffers1[buf],
311 edit->curs1 & M_EDIT_BUF_SIZE) !=
312 (edit->curs1 & M_EDIT_BUF_SIZE)) {
313 filelen = -1;
314 } else if (edit->curs2) {
315 edit->curs2--;
316 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
317 if (mc_write
318 (fd,
319 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
320 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
321 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
322 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
323 filelen = -1;
324 } else {
325 while (--buf >= 0) {
326 if (mc_write
327 (fd, (char *) edit->buffers2[buf],
328 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
329 filelen = -1;
330 break;
334 edit->curs2++;
336 if (mc_close (fd))
337 goto error_save;
339 /* Update the file information, especially the mtime. */
340 if (mc_stat (savename, &edit->stat1) == -1)
341 goto error_save;
342 } else { /* change line breaks */
343 FILE *file;
345 mc_close (fd);
347 file = (FILE *) fopen (savename, "w");
349 if (file) {
350 filelen = edit_write_stream (edit, file);
351 fclose (file);
352 } else {
353 char *msg;
355 msg = g_strdup_printf (_(" Cannot open file for writing: %s "), savename);
356 edit_error_dialog (_("Error"), msg);
357 g_free (msg);
358 goto error_save;
362 if (filelen != edit->last_byte)
363 goto error_save;
365 if (this_save_mode == EDIT_DO_BACKUP) {
366 assert (option_backup_ext != NULL);
367 tmp = g_strconcat (real_filename, option_backup_ext,(char *) NULL);
368 if (mc_rename (real_filename, tmp) == -1){
369 g_free(tmp);
370 goto error_save;
374 if (this_save_mode != EDIT_QUICK_SAVE)
375 if (mc_rename (savename, real_filename) == -1)
376 goto error_save;
377 g_free (savename);
378 g_free(real_filename);
379 return 1;
380 error_save:
381 /* FIXME: Is this safe ?
382 * if (this_save_mode != EDIT_QUICK_SAVE)
383 * mc_unlink (savename);
385 g_free(real_filename);
386 g_free (savename);
387 return 0;
390 void
391 menu_save_mode_cmd (void)
393 /* diaog sizes */
394 const int DLG_X = 38;
395 const int DLG_Y = 10;
397 char *str_result;
399 const char *str[] =
401 N_("Quick save "),
402 N_("Safe save "),
403 N_("Do backups -->")
406 QuickWidget widgets[] =
408 /* 0 */ QUICK_BUTTON (18, DLG_X, 7, DLG_Y, N_("&Cancel"), B_CANCEL, NULL),
409 /* 1 */ QUICK_BUTTON ( 6, DLG_X, 7, DLG_Y, N_("&OK"), B_ENTER, NULL),
410 /* 2 */ QUICK_INPUT (23, DLG_X, 5, DLG_Y, option_backup_ext, 9, 0, "edit-backup-ext", &str_result),
411 /* 3 */ QUICK_LABEL (22, DLG_X, 4, DLG_Y, N_("Extension:")),
412 /* 4 */ QUICK_RADIO ( 4, DLG_X, 3, DLG_Y, 3, str, &option_save_mode),
413 QUICK_END
416 QuickDialog dialog =
418 DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "),
419 "[Edit Save Mode]", widgets, FALSE
422 size_t i;
423 size_t maxlen = 0;
424 int dlg_x;
425 size_t l1, w0, w1, w3;
427 assert (option_backup_ext != NULL);
429 /* OK/Cancel buttons */
430 w0 = str_term_width1 (_(widgets[0].u.button.text)) + 2;
431 w1 = str_term_width1 (_(widgets[1].u.button.text)) + 4; /* default batton */
433 w3 = str_term_width1 (_(widgets[3].u.label.text));
435 maxlen = l1 = w0 + w1 + 6;
437 for (i = 0; i < 3; i++) {
438 #ifdef ENABLE_NLS
439 str[i] = _(str[i]);
440 #endif
441 maxlen = max (maxlen, (size_t) str_term_width1 (str[i]) + 7);
444 dlg_x = maxlen + w3 + 5 + 2;
445 widgets[2].u.input.len = w3; /* input field length */
446 dlg_x = min (COLS, dlg_x);
447 dialog.xlen = dlg_x;
449 widgets[0].relative_x = dlg_x * 2/3 - w0/2;
450 widgets[1].relative_x = dlg_x/3 - w1/2;
451 widgets[2].relative_x = widgets[3].relative_x = maxlen + 3;
453 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
454 widgets[i].x_divisions = dlg_x;
456 if (quick_dialog (&dialog) != B_CANCEL) {
457 g_free (option_backup_ext);
458 option_backup_ext = str_result;
462 void
463 edit_set_filename (WEdit *edit, const char *f)
465 g_free (edit->filename);
466 if (!f)
467 f = "";
468 edit->filename = g_strdup (f);
469 if (edit->dir == NULL && *f != PATH_SEP)
470 #ifdef USE_VFS
471 edit->dir = g_strdup (vfs_get_current_dir ());
472 #else
473 edit->dir = g_get_current_dir ();
474 #endif
477 static char *
478 edit_get_save_file_as (WEdit *edit)
480 #define DLG_WIDTH 64
481 #define DLG_HEIGHT 14
483 static LineBreaks cur_lb = LB_ASIS;
485 char *filename = edit->filename;
487 char *lb_names[LB_NAMES] =
489 N_("&Do not change"),
490 N_("&Unix format (LF)"),
491 N_("&Windows/DOS format (CR LF)"),
492 N_("&Macintosh format (CR)")
495 QuickWidget quick_widgets[] =
497 QUICK_BUTTON (6, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
498 QUICK_BUTTON (2, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
499 QUICK_RADIO (5, DLG_WIDTH, DLG_HEIGHT - 8, DLG_HEIGHT, LB_NAMES, (const char **) lb_names, &cur_lb),
500 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 9, DLG_HEIGHT, N_("Change line breaks to:")),
501 QUICK_INPUT (3, DLG_WIDTH, DLG_HEIGHT - 11, DLG_HEIGHT, filename, DLG_WIDTH - 6, 0, "save-as", &filename),
502 QUICK_LABEL (2, DLG_WIDTH, DLG_HEIGHT - 12, DLG_HEIGHT, N_(" Enter file name: ")),
503 QUICK_END
506 QuickDialog Quick_options =
508 DLG_WIDTH, DLG_HEIGHT, -1, -1,
509 N_(" Save As "), "[Save File As]",
510 quick_widgets, FALSE
513 if (quick_dialog (&Quick_options) != B_CANCEL) {
514 edit->lb = cur_lb;
515 return filename;
518 return NULL;
520 #undef DLG_WIDTH
521 #undef DLG_HEIGHT
524 /* Here we want to warn the users of overwriting an existing file,
525 but only if they have made a change to the filename */
526 /* returns 1 on success */
528 edit_save_as_cmd (WEdit *edit)
530 /* This heads the 'Save As' dialog box */
531 char *exp;
532 int save_lock = 0;
533 int different_filename = 0;
535 exp = edit_get_save_file_as (edit);
536 edit_push_action (edit, KEY_PRESS + edit->start_display);
538 if (exp) {
539 if (!*exp) {
540 g_free (exp);
541 edit->force |= REDRAW_COMPLETELY;
542 return 0;
543 } else {
544 int rv;
545 if (strcmp (edit->filename, exp)) {
546 int file;
547 different_filename = 1;
548 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
549 /* the file exists */
550 mc_close (file);
551 /* Overwrite the current file or cancel the operation */
552 if (edit_query_dialog2
553 (_("Warning"),
554 _(" A file already exists with this name. "),
555 _("&Overwrite"), _("&Cancel"))) {
556 edit->force |= REDRAW_COMPLETELY;
557 g_free (exp);
558 return 0;
560 } else {
561 edit->stat1.st_mode |= S_IWUSR;
563 save_lock = edit_lock_file (exp);
564 } else {
565 /* filenames equal, check if already locked */
566 if (!edit->locked && !edit->delete_file)
567 save_lock = edit_lock_file (exp);
570 if (different_filename)
573 * Allow user to write into saved (under another name) file
574 * even if original file had r/o user permissions.
576 edit->stat1.st_mode |= S_IWRITE;
579 rv = edit_save_file (edit, exp);
580 switch (rv) {
581 case 1:
582 /* Succesful, so unlock both files */
583 if (different_filename) {
584 if (save_lock)
585 edit_unlock_file (exp);
586 if (edit->locked)
587 edit->locked = edit_unlock_file (edit->filename);
588 } else {
589 if (edit->locked || save_lock)
590 edit->locked = edit_unlock_file (edit->filename);
593 edit_set_filename (edit, exp);
594 if (edit->lb != LB_ASIS)
595 edit_reload(edit, exp);
596 g_free (exp);
597 edit->modified = 0;
598 edit->delete_file = 0;
599 if (different_filename)
600 edit_load_syntax (edit, NULL, option_syntax_type);
601 edit->force |= REDRAW_COMPLETELY;
602 return 1;
603 default:
604 edit_error_dialog (_(" Save As "),
605 get_sys_error (_
606 (" Cannot save file. ")));
607 /* fallthrough */
608 case -1:
609 /* Failed, so maintain modify (not save) lock */
610 if (save_lock)
611 edit_unlock_file (exp);
612 g_free (exp);
613 edit->force |= REDRAW_COMPLETELY;
614 return 0;
618 edit->force |= REDRAW_COMPLETELY;
619 return 0;
622 /* {{{ Macro stuff starts here */
624 /* creates a macro file if it doesn't exist */
625 static FILE *edit_open_macro_file (const char *r)
627 gchar *filename;
628 FILE *fd;
629 int file;
630 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
631 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
632 g_free(filename);
633 return 0;
635 close (file);
636 fd = fopen (filename, r);
637 g_free(filename);
638 return fd;
641 #define MAX_MACROS 1024
642 static int saved_macro[MAX_MACROS + 1];
643 static int saved_macros_loaded = 0;
646 This is just to stop the macro file be loaded over and over for keys
647 that aren't defined to anything. On slow systems this could be annoying.
649 static int
650 macro_exists (int k)
652 int i;
653 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
654 if (saved_macro[i] == k)
655 return i;
656 return -1;
659 /* returns 1 on error */
660 static int
661 edit_delete_macro (WEdit * edit, int k)
663 gchar *tmp, *tmp2;
664 struct macro macro[MAX_MACRO_LENGTH];
665 FILE *f, *g;
666 int s, i, n, j = 0;
668 (void) edit;
670 if (saved_macros_loaded)
671 if ((j = macro_exists (k)) < 0)
672 return 0;
673 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
674 g = fopen (tmp , "w");
675 g_free(tmp);
676 if (!g) {
677 edit_error_dialog (_(" Delete macro "),
678 get_sys_error (_(" Cannot open temp file ")));
679 return 1;
681 f = edit_open_macro_file ("r");
682 if (!f) {
683 edit_error_dialog (_(" Delete macro "),
684 get_sys_error (_(" Cannot open macro file ")));
685 fclose (g);
686 return 1;
688 for (;;) {
689 n = fscanf (f, ("key '%d 0': "), &s);
690 if (!n || n == EOF)
691 break;
692 n = 0;
693 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
694 n++;
695 fscanf (f, ";\n");
696 if (s != k) {
697 fprintf (g, ("key '%d 0': "), s);
698 for (i = 0; i < n; i++)
699 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
700 fprintf (g, ";\n");
703 fclose (f);
704 fclose (g);
705 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
706 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
707 if (rename ( tmp, tmp2) == -1) {
708 edit_error_dialog (_(" Delete macro "),
709 get_sys_error (_(" Cannot overwrite macro file ")));
710 g_free(tmp);
711 g_free(tmp2);
712 return 1;
714 g_free(tmp);
715 g_free(tmp2);
717 if (saved_macros_loaded)
718 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
719 return 0;
722 /* returns 0 on error */
723 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
725 FILE *f;
726 int s, i;
728 edit_push_action (edit, KEY_PRESS + edit->start_display);
729 s = editcmd_dialog_raw_key_query (_(" Save macro "),
730 _(" Press the macro's new hotkey: "), 1);
731 edit->force |= REDRAW_COMPLETELY;
732 if (s) {
733 if (edit_delete_macro (edit, s))
734 return 0;
735 f = edit_open_macro_file ("a+");
736 if (f) {
737 fprintf (f, ("key '%d 0': "), s);
738 for (i = 0; i < n; i++)
739 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
740 fprintf (f, ";\n");
741 fclose (f);
742 if (saved_macros_loaded) {
743 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
744 saved_macro[i] = s;
746 return 1;
747 } else
748 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
750 return 0;
753 void edit_delete_macro_cmd (WEdit * edit)
755 int command;
757 command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
758 _ (" Press macro hotkey: "), 1);
760 if (!command)
761 return;
763 edit_delete_macro (edit, command);
766 /* return 0 on error */
767 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
769 FILE *f;
770 int s, i = 0, found = 0;
772 (void) edit;
774 if (saved_macros_loaded)
775 if (macro_exists (k) < 0)
776 return 0;
778 if ((f = edit_open_macro_file ("r"))) {
779 struct macro dummy;
780 do {
781 int u;
782 u = fscanf (f, ("key '%d 0': "), &s);
783 if (!u || u == EOF)
784 break;
785 if (!saved_macros_loaded)
786 saved_macro[i++] = s;
787 if (!found) {
788 *n = 0;
789 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
790 (*n)++;
791 } else {
792 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
794 fscanf (f, ";\n");
795 if (s == k)
796 found = 1;
797 } while (!found || !saved_macros_loaded);
798 if (!saved_macros_loaded) {
799 saved_macro[i] = 0;
800 saved_macros_loaded = 1;
802 fclose (f);
803 return found;
804 } else
805 edit_error_dialog (_(" Load macro "),
806 get_sys_error (_(" Cannot open macro file ")));
807 return 0;
810 /* }}} Macro stuff starts here */
812 /* returns 1 on success */
813 int edit_save_confirm_cmd (WEdit * edit)
815 gchar *f = NULL;
817 if (edit_confirm_save) {
818 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", NULL);
819 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel"))){
820 g_free(f);
821 return 0;
823 g_free(f);
825 return edit_save_cmd (edit);
829 /* returns 1 on success */
830 static int
831 edit_save_cmd (WEdit *edit)
833 int res, save_lock = 0;
835 if (!edit->locked && !edit->delete_file)
836 save_lock = edit_lock_file (edit->filename);
837 res = edit_save_file (edit, edit->filename);
839 /* Maintain modify (not save) lock on failure */
840 if ((res > 0 && edit->locked) || save_lock)
841 edit->locked = edit_unlock_file (edit->filename);
843 /* On failure try 'save as', it does locking on its own */
844 if (!res)
845 return edit_save_as_cmd (edit);
846 edit->force |= REDRAW_COMPLETELY;
847 if (res > 0) {
848 edit->delete_file = 0;
849 edit->modified = 0;
852 return 1;
856 /* returns 1 on success */
857 int edit_new_cmd (WEdit * edit)
859 if (edit->modified) {
860 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
861 edit->force |= REDRAW_COMPLETELY;
862 return 0;
865 edit->force |= REDRAW_COMPLETELY;
867 return edit_renew (edit); /* if this gives an error, something has really screwed up */
870 /* returns 1 on error */
871 static int
872 edit_load_file_from_filename (WEdit * edit, char *exp)
874 int prev_locked = edit->locked;
875 char *prev_filename = g_strdup (edit->filename);
877 if (!edit_reload (edit, exp)) {
878 g_free (prev_filename);
879 return 1;
882 if (prev_locked)
883 edit_unlock_file (prev_filename);
884 g_free (prev_filename);
885 return 0;
888 static void
889 edit_load_syntax_file (WEdit * edit)
891 char *extdir;
892 int dir = 0;
894 if (geteuid () == 0) {
895 dir = query_dialog (_("Syntax file edit"),
896 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
897 _("&User"), _("&System Wide"));
900 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
901 if (!exist_file(extdir)) {
902 g_free (extdir);
903 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
906 if (dir == 0) {
907 char *buffer;
909 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
910 check_for_default (extdir, buffer);
911 edit_load_file_from_filename (edit, buffer);
912 g_free (buffer);
913 } else if (dir == 1)
914 edit_load_file_from_filename (edit, extdir);
916 g_free (extdir);
919 static void
920 edit_load_menu_file (WEdit * edit)
922 char *buffer;
923 char *menufile;
924 int dir = 0;
926 dir = query_dialog (
927 _(" Menu edit "),
928 _(" Which menu file do you want to edit? "), D_NORMAL,
929 geteuid() ? 2 : 3, _("&Local"), _("&User"), _("&System Wide")
932 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
934 if (!exist_file (menufile)) {
935 g_free (menufile);
936 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
939 switch (dir) {
940 case 0:
941 buffer = g_strdup (EDIT_LOCAL_MENU);
942 check_for_default (menufile, buffer);
943 chmod (buffer, 0600);
944 break;
946 case 1:
947 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
948 check_for_default (menufile, buffer);
949 break;
951 case 2:
952 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
953 if (!exist_file (buffer)) {
954 g_free (buffer);
955 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
957 break;
959 default:
960 g_free (menufile);
961 return;
964 edit_load_file_from_filename (edit, buffer);
966 g_free (buffer);
967 g_free (menufile);
971 edit_load_cmd (WEdit *edit, edit_current_file_t what)
973 char *exp;
975 if (edit->modified
976 && (edit_query_dialog2
977 (_("Warning"),
978 _(" Current text was modified without a file save. \n"
979 " Continue discards these changes. "),
980 _("C&ontinue"), _("&Cancel")) == 1)) {
981 edit->force |= REDRAW_COMPLETELY;
982 return 0;
985 switch (what) {
986 case EDIT_FILE_COMMON:
987 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
988 MC_HISTORY_EDIT_LOAD, edit->filename);
990 if (exp) {
991 if (*exp)
992 edit_load_file_from_filename (edit, exp);
993 g_free (exp);
995 break;
997 case EDIT_FILE_SYNTAX:
998 edit_load_syntax_file (edit);
999 break;
1001 case EDIT_FILE_MENU:
1002 edit_load_menu_file (edit);
1003 break;
1005 default:
1006 break;
1009 edit->force |= REDRAW_COMPLETELY;
1010 return 0;
1014 if mark2 is -1 then marking is from mark1 to the cursor.
1015 Otherwise its between the markers. This handles this.
1016 Returns 1 if no text is marked.
1018 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
1020 if (edit->mark1 != edit->mark2) {
1021 if (edit->mark2 >= 0) {
1022 *start_mark = min (edit->mark1, edit->mark2);
1023 *end_mark = max (edit->mark1, edit->mark2);
1024 } else {
1025 *start_mark = min (edit->mark1, edit->curs1);
1026 *end_mark = max (edit->mark1, edit->curs1);
1027 edit->column2 = edit->curs_col + edit->over_col;
1029 return 0;
1030 } else {
1031 *start_mark = *end_mark = 0;
1032 edit->column2 = edit->column1 = 0;
1033 return 1;
1037 #define space_width 1
1039 void
1040 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
1042 long cursor;
1043 int i, col;
1044 cursor = edit->curs1;
1045 col = edit_get_col (edit);
1046 for (i = 0; i < size; i++) {
1047 if (data[i] == '\n') { /* fill in and move to next line */
1048 int l;
1049 long p;
1050 if (edit_get_byte (edit, edit->curs1) != '\n') {
1051 l = width - (edit_get_col (edit) - col);
1052 while (l > 0) {
1053 edit_insert (edit, ' ');
1054 l -= space_width;
1057 for (p = edit->curs1;; p++) {
1058 if (p == edit->last_byte) {
1059 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1060 edit_insert_ahead (edit, '\n');
1061 p++;
1062 break;
1064 if (edit_get_byte (edit, p) == '\n') {
1065 p++;
1066 break;
1069 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1070 l = col - edit_get_col (edit);
1071 while (l >= space_width) {
1072 edit_insert (edit, ' ');
1073 l -= space_width;
1075 continue;
1077 edit_insert (edit, data[i]);
1079 edit_cursor_move (edit, cursor - edit->curs1);
1082 #define TEMP_BUF_LEN 1024
1085 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1087 long cursor;
1088 int i, col;
1089 int blocklen = -1, width;
1090 unsigned char *data;
1091 cursor = edit->curs1;
1092 col = edit_get_col (edit);
1093 data = g_malloc (TEMP_BUF_LEN);
1094 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0) {
1095 for (width = 0; width < blocklen; width++) {
1096 if (data[width] == '\n')
1097 break;
1099 for (i = 0; i < blocklen; i++) {
1100 if (data[i] == '\n') { /* fill in and move to next line */
1101 int l;
1102 long p;
1103 if (edit_get_byte (edit, edit->curs1) != '\n') {
1104 l = width - (edit_get_col (edit) - col);
1105 while (l > 0) {
1106 edit_insert (edit, ' ');
1107 l -= space_width;
1110 for (p = edit->curs1;; p++) {
1111 if (p == edit->last_byte) {
1112 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1113 edit_insert_ahead (edit, '\n');
1114 p++;
1115 break;
1117 if (edit_get_byte (edit, p) == '\n') {
1118 p++;
1119 break;
1122 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1123 l = col - edit_get_col (edit);
1124 while (l >= space_width) {
1125 edit_insert (edit, ' ');
1126 l -= space_width;
1128 continue;
1130 edit_insert (edit, data[i]);
1133 edit_cursor_move (edit, cursor - edit->curs1);
1134 g_free(data);
1135 edit->force |= REDRAW_PAGE;
1136 return blocklen;
1139 void
1140 edit_block_copy_cmd (WEdit *edit)
1142 long start_mark, end_mark, current = edit->curs1;
1143 int size;
1144 unsigned char *copy_buf;
1146 edit_update_curs_col (edit);
1147 if (eval_marks (edit, &start_mark, &end_mark))
1148 return;
1150 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1152 /* all that gets pushed are deletes hence little space is used on the stack */
1154 edit_push_markers (edit);
1156 if (column_highlighting) {
1157 edit_insert_column_of_text (edit, copy_buf, size,
1158 abs (edit->column2 - edit->column1));
1159 } else {
1160 while (size--)
1161 edit_insert_ahead (edit, copy_buf[size]);
1164 g_free (copy_buf);
1165 edit_scroll_screen_over_cursor (edit);
1167 if (column_highlighting) {
1168 edit_set_markers (edit, 0, 0, 0, 0);
1169 edit_push_action (edit, COLUMN_ON);
1170 column_highlighting = 0;
1171 } else if (start_mark < current && end_mark > current)
1172 edit_set_markers (edit, start_mark,
1173 end_mark + end_mark - start_mark, 0, 0);
1175 edit->force |= REDRAW_PAGE;
1179 void
1180 edit_block_move_cmd (WEdit *edit)
1182 long count;
1183 long current;
1184 unsigned char *copy_buf;
1185 long start_mark, end_mark;
1186 int deleted = 0;
1187 int x = 0;
1189 if (eval_marks (edit, &start_mark, &end_mark))
1190 return;
1191 if (column_highlighting) {
1192 edit_update_curs_col (edit);
1193 x = edit->curs_col;
1194 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1195 if ((x > edit->column1 && x < edit->column2)
1196 || (x > edit->column2 && x < edit->column1))
1197 return;
1198 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1199 return;
1201 if ((end_mark - start_mark) > option_max_undo / 2)
1202 if (edit_query_dialog2
1203 (_("Warning"),
1205 (" Block is large, you may not be able to undo this action. "),
1206 _("C&ontinue"), _("&Cancel")))
1207 return;
1209 edit_push_markers (edit);
1210 current = edit->curs1;
1211 if (column_highlighting) {
1212 int size, c1, c2, line;
1213 line = edit->curs_line;
1214 if (edit->mark2 < 0)
1215 edit_mark_cmd (edit, 0);
1216 c1 = min (edit->column1, edit->column2);
1217 c2 = max (edit->column1, edit->column2);
1218 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1219 if (x < c2) {
1220 edit_block_delete_cmd (edit);
1221 deleted = 1;
1223 edit_move_to_line (edit, line);
1224 edit_cursor_move (edit,
1225 edit_move_forward3 (edit,
1226 edit_bol (edit, edit->curs1),
1227 x, 0) - edit->curs1);
1228 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1229 if (!deleted) {
1230 line = edit->curs_line;
1231 edit_update_curs_col (edit);
1232 x = edit->curs_col;
1233 edit_block_delete_cmd (edit);
1234 edit_move_to_line (edit, line);
1235 edit_cursor_move (edit,
1236 edit_move_forward3 (edit,
1237 edit_bol (edit,
1238 edit->curs1),
1239 x, 0) - edit->curs1);
1241 edit_set_markers (edit, 0, 0, 0, 0);
1242 edit_push_action (edit, COLUMN_ON);
1243 column_highlighting = 0;
1244 } else {
1245 copy_buf = g_malloc (end_mark - start_mark);
1246 edit_cursor_move (edit, start_mark - edit->curs1);
1247 edit_scroll_screen_over_cursor (edit);
1248 count = start_mark;
1249 while (count < end_mark) {
1250 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1251 count++;
1253 edit_scroll_screen_over_cursor (edit);
1254 edit_cursor_move (edit,
1255 current - edit->curs1 -
1256 (((current - edit->curs1) >
1257 0) ? end_mark - start_mark : 0));
1258 edit_scroll_screen_over_cursor (edit);
1259 while (count-- > start_mark)
1260 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1261 edit_set_markers (edit, edit->curs1,
1262 edit->curs1 + end_mark - start_mark, 0, 0);
1264 edit_scroll_screen_over_cursor (edit);
1265 g_free (copy_buf);
1266 edit->force |= REDRAW_PAGE;
1269 static void
1270 edit_delete_column_of_text (WEdit * edit)
1272 long p, q, r, m1, m2;
1273 int b, c, d;
1274 int n;
1276 eval_marks (edit, &m1, &m2);
1277 n = edit_move_forward (edit, m1, 0, m2) + 1;
1278 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1279 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1281 b = max(min (c, d), min (edit->column1, edit->column2));
1282 c = max (c, d + edit->over_col);
1284 while (n--) {
1285 r = edit_bol (edit, edit->curs1);
1286 p = edit_move_forward3 (edit, r, b, 0);
1287 q = edit_move_forward3 (edit, r, c, 0);
1288 if (p < m1)
1289 p = m1;
1290 if (q > m2)
1291 q = m2;
1292 edit_cursor_move (edit, p - edit->curs1);
1293 while (q > p) { /* delete line between margins */
1294 if (edit_get_byte (edit, edit->curs1) != '\n')
1295 edit_delete (edit, 1);
1296 q--;
1298 if (n) /* move to next line except on the last delete */
1299 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1303 /* if success return 0 */
1304 static int
1305 edit_block_delete (WEdit *edit)
1307 long count;
1308 long start_mark, end_mark;
1309 if (eval_marks (edit, &start_mark, &end_mark))
1310 return 0;
1311 if (column_highlighting && edit->mark2 < 0)
1312 edit_mark_cmd (edit, 0);
1313 if ((end_mark - start_mark) > option_max_undo / 2) {
1314 /* Warning message with a query to continue or cancel the operation */
1315 if (edit_query_dialog2
1316 (_("Warning"),
1318 (" Block is large, you may not be able to undo this action. "),
1319 _("C&ontinue"), _("&Cancel"))) {
1320 return 1;
1323 edit_push_markers (edit);
1324 edit_cursor_move (edit, start_mark - edit->curs1);
1325 edit_scroll_screen_over_cursor (edit);
1326 count = start_mark;
1327 if (start_mark < end_mark) {
1328 if (column_highlighting) {
1329 if (edit->mark2 < 0)
1330 edit_mark_cmd (edit, 0);
1331 edit_delete_column_of_text (edit);
1332 } else {
1333 while (count < end_mark) {
1334 edit_delete (edit, 1);
1335 count++;
1339 edit_set_markers (edit, 0, 0, 0, 0);
1340 edit->force |= REDRAW_PAGE;
1341 return 0;
1344 /* returns 1 if canceelled by user */
1345 int edit_block_delete_cmd (WEdit * edit)
1347 long start_mark, end_mark;
1348 if (eval_marks (edit, &start_mark, &end_mark)) {
1349 edit_delete_line (edit);
1350 return 0;
1352 return edit_block_delete (edit);
1355 #define INPUT_INDEX 9
1357 static gboolean
1358 editcmd_find (WEdit *edit, gsize *len)
1360 off_t search_start = edit->search_start;
1361 off_t search_end;
1362 long start_mark = 0;
1363 long end_mark = edit->last_byte;
1364 int mark_res = 0;
1366 if (edit->only_in_selection) {
1367 mark_res = eval_marks(edit, &start_mark, &end_mark);
1368 if (mark_res != 0) {
1369 edit->search->error = MC_SEARCH_E_NOTFOUND;
1370 edit->search->error_str = g_strdup(_(" Search string not found "));
1371 return FALSE;
1373 if (edit->replace_backwards) {
1374 if (search_start > end_mark || search_start <= start_mark) {
1375 search_start = end_mark;
1377 } else {
1378 if (search_start < start_mark || search_start >= end_mark) {
1379 search_start = start_mark;
1382 } else {
1383 if (edit->replace_backwards)
1384 end_mark = max(1, edit->curs1) - 1;
1386 if (edit->replace_backwards) {
1387 search_end = end_mark;
1388 while ((int) search_start >= start_mark) {
1389 if (search_end > search_start + edit->search->original_len
1390 && mc_search_is_fixed_search_str(edit->search)) {
1391 search_end = search_start + edit->search->original_len;
1393 if (mc_search_run(edit->search, (void *) edit, search_start, search_end, len)
1394 && edit->search->normal_offset == search_start ) {
1395 return TRUE;
1397 search_start--;
1399 edit->search->error_str = g_strdup(_(" Search string not found "));
1400 } else {
1401 return mc_search_run(edit->search, (void *) edit, search_start, end_mark, len);
1403 return FALSE;
1407 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1408 (and the above) routines to work properly - paul */
1410 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1412 static char *
1413 edit_replace_cmd__conv_to_display(char *str)
1415 #ifdef HAVE_CHARSET
1416 GString *tmp;
1417 tmp = str_convert_to_display (str);
1419 if (tmp && tmp->len){
1420 g_free(str);
1421 str = tmp->str;
1423 g_string_free (tmp, FALSE);
1424 return str;
1425 #else
1426 return g_strdup(str);
1427 #endif
1430 static char *
1431 edit_replace_cmd__conv_to_input(char *str)
1433 #ifdef HAVE_CHARSET
1434 GString *tmp;
1435 tmp = str_convert_to_input (str);
1437 if (tmp && tmp->len){
1438 g_free(str);
1439 str = tmp->str;
1441 g_string_free (tmp, FALSE);
1442 return str;
1443 #else
1444 return g_strdup(str);
1445 #endif
1447 /* call with edit = 0 before shutdown to close memory leaks */
1448 void
1449 edit_replace_cmd (WEdit *edit, int again)
1451 /* 1 = search string, 2 = replace with */
1452 static char *saved1 = NULL; /* saved default[123] */
1453 static char *saved2 = NULL;
1454 char *input1 = NULL; /* user input from the dialog */
1455 char *input2 = NULL;
1456 int replace_yes;
1457 long times_replaced = 0, last_search;
1458 gboolean once_found = FALSE;
1460 if (!edit) {
1461 g_free (saved1), saved1 = NULL;
1462 g_free (saved2), saved2 = NULL;
1463 return;
1466 last_search = edit->last_byte;
1468 edit->force |= REDRAW_COMPLETELY;
1470 if (again && !saved1 && !saved2)
1471 again = 0;
1473 if (again) {
1474 input1 = g_strdup (saved1 ? saved1 : "");
1475 input2 = g_strdup (saved2 ? saved2 : "");
1476 } else {
1477 char *disp1 = edit_replace_cmd__conv_to_display(g_strdup (saved1 ? saved1 : ""));
1478 char *disp2 = edit_replace_cmd__conv_to_display(g_strdup (saved2 ? saved2 : ""));
1480 edit_push_action (edit, KEY_PRESS + edit->start_display);
1482 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1484 g_free (disp1);
1485 g_free (disp2);
1487 if (input1 == NULL || *input1 == '\0') {
1488 edit->force = REDRAW_COMPLETELY;
1489 goto cleanup;
1492 input1 = edit_replace_cmd__conv_to_input(input1);
1493 input2 = edit_replace_cmd__conv_to_input(input2);
1495 g_free (saved1), saved1 = g_strdup (input1);
1496 g_free (saved2), saved2 = g_strdup (input2);
1498 if (edit->search) {
1499 mc_search_free(edit->search);
1500 edit->search = NULL;
1504 if (!edit->search) {
1505 edit->search = mc_search_new(input1, -1);
1506 if (edit->search == NULL) {
1507 edit->search_start = edit->curs1;
1508 return;
1510 edit->search->search_type = edit->search_type;
1511 edit->search->is_all_charsets = edit->all_codepages;
1512 edit->search->is_case_sentitive = edit->replace_case;
1513 edit->search->whole_words = edit->whole_words;
1514 edit->search->search_fn = edit_search_cmd_callback;
1517 if (edit->found_len && edit->search_start == edit->found_start + 1
1518 && edit->replace_backwards)
1519 edit->search_start--;
1521 if (edit->found_len && edit->search_start == edit->found_start - 1
1522 && !edit->replace_backwards)
1523 edit->search_start++;
1525 do {
1526 gsize len = 0;
1527 long new_start;
1529 if (! editcmd_find(edit, &len)) {
1530 if (!(edit->search->error == MC_SEARCH_E_OK ||
1531 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND))) {
1532 edit_error_dialog (_ ("Search"), edit->search->error_str);
1534 break;
1536 once_found = TRUE;
1537 new_start = edit->search->normal_offset;
1539 edit->search_start = new_start = edit->search->normal_offset;
1540 /*returns negative on not found or error in pattern */
1542 if (edit->search_start >= 0) {
1543 guint i;
1545 edit->found_start = edit->search_start;
1546 i = edit->found_len = len;
1548 edit_cursor_move (edit, edit->search_start - edit->curs1);
1549 edit_scroll_screen_over_cursor (edit);
1551 replace_yes = 1;
1553 if (edit->replace_mode == 0) {
1554 int l;
1555 l = edit->curs_row - edit->num_widget_lines / 3;
1556 if (l > 0)
1557 edit_scroll_downward (edit, l);
1558 if (l < 0)
1559 edit_scroll_upward (edit, -l);
1561 edit_scroll_screen_over_cursor (edit);
1562 edit->force |= REDRAW_PAGE;
1563 edit_render_keypress (edit);
1565 /*so that undo stops at each query */
1566 edit_push_key_press (edit);
1567 /* and prompt 2/3 down */
1568 switch (editcmd_dialog_replace_prompt_show (edit, input1, input2, -1, -1)) {
1569 case B_ENTER:
1570 replace_yes = 1;
1571 break;
1572 case B_SKIP_REPLACE:
1573 replace_yes = 0;
1574 break;
1575 case B_REPLACE_ALL:
1576 edit->replace_mode=1;
1577 break;
1578 case B_CANCEL:
1579 replace_yes = 0;
1580 edit->replace_mode = -1;
1581 break;
1584 if (replace_yes) { /* delete then insert new */
1585 GString *repl_str, *tmp_str;
1586 tmp_str = g_string_new(input2);
1588 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1589 g_string_free(tmp_str, TRUE);
1590 if (edit->search->error != MC_SEARCH_E_OK)
1592 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1593 break;
1596 while (i--)
1597 edit_delete (edit, 1);
1599 while (++i < repl_str->len)
1600 edit_insert (edit, repl_str->str[i]);
1602 g_string_free(repl_str, TRUE);
1603 edit->found_len = i;
1605 /* so that we don't find the same string again */
1606 if (edit->replace_backwards) {
1607 last_search = edit->search_start;
1608 edit->search_start--;
1609 } else {
1610 edit->search_start += i;
1611 last_search = edit->last_byte;
1613 edit_scroll_screen_over_cursor (edit);
1614 } else {
1615 const char *msg = _(" Replace ");
1616 /* try and find from right here for next search */
1617 edit->search_start = edit->curs1;
1618 edit_update_curs_col (edit);
1620 edit->force |= REDRAW_PAGE;
1621 edit_render_keypress (edit);
1622 if (times_replaced) {
1623 message (D_NORMAL, msg, _(" %ld replacements made. "),
1624 times_replaced);
1625 } else
1626 query_dialog (msg, _(" Search string not found "),
1627 D_NORMAL, 1, _("&OK"));
1628 edit->replace_mode = -1;
1630 } while (edit->replace_mode >= 0);
1632 edit->force = REDRAW_COMPLETELY;
1633 edit_scroll_screen_over_cursor (edit);
1634 cleanup:
1635 g_free (input1);
1636 g_free (input2);
1640 void edit_search_cmd (WEdit * edit, int again)
1642 char *search_string = NULL, *search_string_dup = NULL;
1644 gsize len = 0;
1646 if (!edit)
1647 return;
1649 if (edit->search != NULL) {
1650 search_string = g_strndup(edit->search->original, edit->search->original_len);
1651 search_string_dup = search_string;
1652 } else {
1653 GList *history;
1654 history = history_get (MC_HISTORY_SHARED_SEARCH);
1655 if (history != NULL && history->data != NULL) {
1656 search_string_dup = search_string = (char *) g_strdup(history->data);
1657 history = g_list_first (history);
1658 g_list_foreach (history, (GFunc) g_free, NULL);
1659 g_list_free (history);
1661 edit->search_start = edit->curs1;
1664 if (!again) {
1665 #ifdef HAVE_CHARSET
1666 GString *tmp;
1667 if (search_string && *search_string) {
1668 tmp = str_convert_to_display (search_string);
1670 g_free(search_string_dup);
1671 search_string_dup = NULL;
1673 if (tmp && tmp->len)
1674 search_string = search_string_dup = tmp->str;
1675 g_string_free (tmp, FALSE);
1677 #endif /* HAVE_CHARSET */
1678 editcmd_dialog_search_show (edit, &search_string);
1679 #ifdef HAVE_CHARSET
1680 if (search_string && *search_string) {
1681 tmp = str_convert_to_input (search_string);
1682 if (tmp && tmp->len)
1683 search_string = tmp->str;
1685 g_string_free (tmp, FALSE);
1687 if (search_string_dup)
1688 g_free(search_string_dup);
1690 #endif /* HAVE_CHARSET */
1692 edit_push_action (edit, KEY_PRESS + edit->start_display);
1694 if (!search_string) {
1695 edit->force |= REDRAW_COMPLETELY;
1696 edit_scroll_screen_over_cursor (edit);
1697 return;
1700 if (edit->search) {
1701 mc_search_free(edit->search);
1702 edit->search = NULL;
1706 if (!edit->search) {
1707 edit->search = mc_search_new(search_string, -1);
1708 if (edit->search == NULL) {
1709 edit->search_start = edit->curs1;
1710 return;
1712 edit->search->search_type = edit->search_type;
1713 edit->search->is_all_charsets = edit->all_codepages;
1714 edit->search->is_case_sentitive = edit->replace_case;
1715 edit->search->whole_words = edit->whole_words;
1716 edit->search->search_fn = edit_search_cmd_callback;
1719 if (search_create_bookmark) {
1720 edit_search_cmd_search_create_bookmark(edit);
1721 } else {
1722 if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
1723 edit->search_start--;
1725 if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
1726 edit->search_start++;
1729 if (editcmd_find(edit, &len)) {
1730 edit->found_start = edit->search_start = edit->search->normal_offset;
1731 edit->found_len = len;
1732 edit->over_col = 0;
1733 edit_cursor_move (edit, edit->search_start - edit->curs1);
1734 edit_scroll_screen_over_cursor (edit);
1735 if (edit->replace_backwards)
1736 edit->search_start--;
1737 else
1738 edit->search_start++;
1739 } else {
1740 edit->search_start = edit->curs1;
1741 if (edit->search->error_str)
1742 edit_error_dialog (_ ("Search"), edit->search->error_str);
1746 edit->force |= REDRAW_COMPLETELY;
1747 edit_scroll_screen_over_cursor (edit);
1752 * Check if it's OK to close the editor. If there are unsaved changes,
1753 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
1756 edit_ok_to_exit (WEdit *edit)
1758 if (!edit->modified)
1759 return 1;
1761 switch (edit_query_dialog3
1762 (_("Quit"), _(" File was modified, Save with exit? "),
1763 _("&Cancel quit"), _("&Yes"), _("&No"))) {
1764 case 1:
1765 edit_push_markers (edit);
1766 edit_set_markers (edit, 0, 0, 0, 0);
1767 if (!edit_save_cmd (edit))
1768 return 0;
1769 break;
1770 case 2:
1771 break;
1772 case 0:
1773 case -1:
1774 return 0;
1777 return 1;
1780 /* Return a null terminated length of text. Result must be g_free'd */
1781 static unsigned char *
1782 edit_get_block (WEdit *edit, long start, long finish, int *l)
1784 unsigned char *s, *r;
1785 r = s = g_malloc (finish - start + 1);
1786 if (column_highlighting) {
1787 *l = 0;
1788 /* copy from buffer, excluding chars that are out of the column 'margins' */
1789 while (start < finish) {
1790 int c, x;
1791 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
1792 start);
1793 c = edit_get_byte (edit, start);
1794 if ((x >= edit->column1 && x < edit->column2)
1795 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1796 *s++ = c;
1797 (*l)++;
1799 start++;
1801 } else {
1802 *l = finish - start;
1803 while (start < finish)
1804 *s++ = edit_get_byte (edit, start++);
1806 *s = 0;
1807 return r;
1810 /* save block, returns 1 on success */
1812 edit_save_block (WEdit * edit, const char *filename, long start,
1813 long finish)
1815 int len, file;
1817 if ((file =
1818 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
1819 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
1820 return 0;
1822 if (column_highlighting) {
1823 int r;
1824 r = mc_write (file, VERTICAL_MAGIC, sizeof(VERTICAL_MAGIC));
1825 if (r > 0) {
1826 unsigned char *block, *p;
1827 p = block = edit_get_block (edit, start, finish, &len);
1828 while (len) {
1829 r = mc_write (file, p, len);
1830 if (r < 0)
1831 break;
1832 p += r;
1833 len -= r;
1835 g_free (block);
1837 } else {
1838 unsigned char *buf;
1839 int i = start, end;
1840 len = finish - start;
1841 buf = g_malloc (TEMP_BUF_LEN);
1842 while (start != finish) {
1843 end = min (finish, start + TEMP_BUF_LEN);
1844 for (; i < end; i++)
1845 buf[i - start] = edit_get_byte (edit, i);
1846 len -= mc_write (file, (char *) buf, end - start);
1847 start = end;
1849 g_free (buf);
1851 mc_close (file);
1852 if (len)
1853 return 0;
1854 return 1;
1857 /* copies a block to clipboard file */
1858 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1860 int ret;
1861 gchar *tmp;
1862 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1863 ret = edit_save_block (edit, tmp, start, finish);
1864 g_free(tmp);
1865 return ret;
1869 void edit_paste_from_history (WEdit *edit)
1871 (void) edit;
1872 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
1875 int edit_copy_to_X_buf_cmd (WEdit * edit)
1877 long start_mark, end_mark;
1878 if (eval_marks (edit, &start_mark, &end_mark))
1879 return 0;
1880 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1881 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
1882 return 1;
1884 edit_mark_cmd (edit, 1);
1885 return 0;
1888 int edit_cut_to_X_buf_cmd (WEdit * edit)
1890 long start_mark, end_mark;
1891 if (eval_marks (edit, &start_mark, &end_mark))
1892 return 0;
1893 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1894 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
1895 return 1;
1897 edit_block_delete_cmd (edit);
1898 edit_mark_cmd (edit, 1);
1899 return 0;
1902 void edit_paste_from_X_buf_cmd (WEdit * edit)
1904 gchar *tmp;
1905 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1906 edit_insert_file (edit, tmp);
1907 g_free(tmp);
1912 * Ask user for the line and go to that line.
1913 * Negative numbers mean line from the end (i.e. -1 is the last line).
1915 void
1916 edit_goto_cmd (WEdit *edit)
1918 char *f;
1919 static long line = 0; /* line as typed, saved as default */
1920 long l;
1921 char *error;
1922 char s[32];
1924 g_snprintf (s, sizeof (s), "%ld", line);
1925 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
1926 line ? s : "");
1927 if (!f)
1928 return;
1930 if (!*f) {
1931 g_free (f);
1932 return;
1935 l = strtol (f, &error, 0);
1936 if (*error) {
1937 g_free (f);
1938 return;
1941 line = l;
1942 if (l < 0)
1943 l = edit->total_lines + l + 2;
1944 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
1945 edit_move_to_line (edit, l - 1);
1946 edit->force |= REDRAW_COMPLETELY;
1947 g_free (f);
1951 /* Return 1 on success */
1953 edit_save_block_cmd (WEdit *edit)
1955 long start_mark, end_mark;
1956 char *exp, *tmp;
1958 if (eval_marks (edit, &start_mark, &end_mark))
1959 return 1;
1961 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1962 exp =
1963 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
1964 MC_HISTORY_EDIT_SAVE_BLOCK,
1965 tmp);
1966 g_free(tmp);
1967 edit_push_action (edit, KEY_PRESS + edit->start_display);
1968 if (exp) {
1969 if (!*exp) {
1970 g_free (exp);
1971 return 0;
1972 } else {
1973 if (edit_save_block (edit, exp, start_mark, end_mark)) {
1974 g_free (exp);
1975 edit->force |= REDRAW_COMPLETELY;
1976 return 1;
1977 } else {
1978 g_free (exp);
1979 edit_error_dialog (_(" Save Block "),
1980 get_sys_error (_
1981 (" Cannot save file. ")));
1985 edit->force |= REDRAW_COMPLETELY;
1986 return 0;
1990 /* returns 1 on success */
1992 edit_insert_file_cmd (WEdit *edit)
1994 gchar *tmp;
1995 char *exp;
1997 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1998 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
1999 MC_HISTORY_EDIT_INSERT_FILE,
2000 tmp);
2001 g_free(tmp);
2002 edit_push_action (edit, KEY_PRESS + edit->start_display);
2003 if (exp) {
2004 if (!*exp) {
2005 g_free (exp);
2006 return 0;
2007 } else {
2008 if (edit_insert_file (edit, exp)) {
2009 g_free (exp);
2010 edit->force |= REDRAW_COMPLETELY;
2011 return 1;
2012 } else {
2013 g_free (exp);
2014 edit_error_dialog (_(" Insert File "),
2015 get_sys_error (_
2016 (" Cannot insert file. ")));
2020 edit->force |= REDRAW_COMPLETELY;
2021 return 0;
2024 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2025 int edit_sort_cmd (WEdit * edit)
2027 static char *old = 0;
2028 char *exp, *tmp;
2029 long start_mark, end_mark;
2030 int e;
2032 if (eval_marks (edit, &start_mark, &end_mark)) {
2033 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2034 return 0;
2037 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2038 edit_save_block (edit, tmp, start_mark, end_mark);
2039 g_free(tmp);
2041 exp = input_dialog (_(" Run Sort "),
2042 _(" Enter sort options (see manpage) separated by whitespace: "),
2043 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2045 if (!exp)
2046 return 1;
2047 g_free (old);
2048 old = exp;
2049 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2050 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2051 e = system (tmp);
2052 g_free(tmp);
2053 if (e) {
2054 if (e == -1 || e == 127) {
2055 edit_error_dialog (_(" Sort "),
2056 get_sys_error (_(" Cannot execute sort command ")));
2057 } else {
2058 char q[8];
2059 sprintf (q, "%d ", e);
2060 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
2061 edit_error_dialog (_(" Sort "), tmp);
2062 g_free(tmp);
2064 return -1;
2067 edit->force |= REDRAW_COMPLETELY;
2069 if (edit_block_delete_cmd (edit))
2070 return 1;
2071 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2072 edit_insert_file (edit, tmp);
2073 g_free(tmp);
2074 return 0;
2078 * Ask user for a command, execute it and paste its output back to the
2079 * editor.
2082 edit_ext_cmd (WEdit *edit)
2084 char *exp, *tmp;
2085 int e;
2087 exp =
2088 input_dialog (_("Paste output of external command"),
2089 _("Enter shell command(s):"),
2090 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2092 if (!exp)
2093 return 1;
2095 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2096 e = system (tmp);
2097 g_free(tmp);
2098 g_free (exp);
2100 if (e) {
2101 edit_error_dialog (_("External command"),
2102 get_sys_error (_("Cannot execute command")));
2103 return -1;
2106 edit->force |= REDRAW_COMPLETELY;
2107 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2108 edit_insert_file (edit, tmp);
2109 g_free(tmp);
2110 return 0;
2113 /* if block is 1, a block must be highlighted and the shell command
2114 processes it. If block is 0 the shell command is a straight system
2115 command, that just produces some output which is to be inserted */
2116 void
2117 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2119 long start_mark, end_mark;
2120 char buf[BUFSIZ];
2121 FILE *script_home = NULL;
2122 FILE *script_src = NULL;
2123 FILE *block_file = NULL;
2124 gchar *o, *h, *b, *tmp;
2125 char *quoted_name = NULL;
2127 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2128 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2129 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2131 if (!(script_home = fopen (h, "r"))) {
2132 if (!(script_home = fopen (h, "w"))) {
2133 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2134 edit_error_dialog ("", get_sys_error (tmp));
2135 g_free(tmp);
2136 goto edit_block_process_cmd__EXIT;
2138 if (!(script_src = fopen (o, "r"))) {
2139 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2140 if (!(script_src = fopen (o, "r"))) {
2141 fclose (script_home);
2142 unlink (h);
2143 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2144 edit_error_dialog ("", get_sys_error (tmp));
2145 g_free(tmp);
2146 goto edit_block_process_cmd__EXIT;
2149 while (fgets (buf, sizeof (buf), script_src))
2150 fputs (buf, script_home);
2151 if (fclose (script_home)) {
2152 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2153 edit_error_dialog ("", get_sys_error (tmp));
2154 g_free(tmp);
2155 goto edit_block_process_cmd__EXIT;
2157 chmod (h, 0700);
2158 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2159 edit_error_dialog ("", get_sys_error (tmp));
2160 g_free(tmp);
2163 open_error_pipe ();
2165 if (block) { /* for marked block run indent formatter */
2166 if (eval_marks (edit, &start_mark, &end_mark)) {
2167 edit_error_dialog (_("Process block"),
2169 (" You must first highlight a block of text. "));
2170 goto edit_block_process_cmd__EXIT;
2172 edit_save_block (edit, b, start_mark, end_mark);
2173 quoted_name = name_quote (edit->filename, 0);
2175 * Run script.
2176 * Initial space is to avoid polluting bash history.
2177 * Arguments:
2178 * $1 - name of the edited file (to check its extension etc).
2179 * $2 - file containing the current block.
2180 * $3 - file where error messages should be put
2181 * (for compatibility with old scripts).
2183 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2184 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2185 system (tmp);
2186 g_free(tmp);
2187 } else {
2189 * No block selected, just execute the command for the file.
2190 * Arguments:
2191 * $1 - name of the edited file.
2193 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2194 quoted_name, (char *) NULL);
2195 system (tmp);
2196 g_free(tmp);
2198 g_free (quoted_name);
2199 close_error_pipe (D_NORMAL, NULL);
2201 edit_refresh_cmd (edit);
2202 edit->force |= REDRAW_COMPLETELY;
2204 /* insert result block */
2205 if (block) {
2206 if (edit_block_delete_cmd (edit))
2207 goto edit_block_process_cmd__EXIT;
2208 edit_insert_file (edit, b);
2209 if ((block_file = fopen (b, "w")))
2210 fclose (block_file);
2211 goto edit_block_process_cmd__EXIT;
2213 edit_block_process_cmd__EXIT:
2214 g_free(b);
2215 g_free(h);
2216 g_free(o);
2217 return;
2220 /* prints at the cursor */
2221 /* returns the number of chars printed */
2222 int edit_print_string (WEdit * e, const char *s)
2224 int i = 0;
2225 while (s[i])
2226 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2227 e->force |= REDRAW_COMPLETELY;
2228 edit_update_screen (e);
2229 return i;
2233 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2235 FILE *p = 0;
2236 char *s;
2238 to = name_quote (to, 0);
2239 subject = name_quote (subject, 0);
2240 cc = name_quote (cc, 0);
2241 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2242 g_free (to);
2243 g_free (subject);
2244 g_free (cc);
2246 if (s) {
2247 p = popen (s, "w");
2248 g_free (s);
2251 if (p) {
2252 long i;
2253 for (i = 0; i < edit->last_byte; i++)
2254 fputc (edit_get_byte (edit, i), p);
2255 pclose (p);
2259 #define MAIL_DLG_HEIGHT 12
2261 void edit_mail_dialog (WEdit * edit)
2263 char *tmail_to;
2264 char *tmail_subject;
2265 char *tmail_cc;
2267 static char *mail_cc_last = 0;
2268 static char *mail_subject_last = 0;
2269 static char *mail_to_last = 0;
2271 QuickWidget quick_widgets[] =
2273 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2274 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2275 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2276 /* 3 */ QUICK_LABEL (2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to")),
2277 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2", &tmail_subject),
2278 /* 5 */ QUICK_LABEL (2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject")),
2279 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2280 /* 7 */ QUICK_LABEL (2, 50, 3, MAIL_DLG_HEIGHT, N_(" To")),
2281 /* 8 */ QUICK_LABEL (2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>")),
2282 QUICK_END
2285 QuickDialog Quick_input =
2287 50, MAIL_DLG_HEIGHT, -1, -1, N_(" Mail "),
2288 "[Input Line Keys]", quick_widgets, FALSE
2291 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2292 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2293 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2295 if (quick_dialog (&Quick_input) != B_CANCEL) {
2296 g_free (mail_cc_last);
2297 g_free (mail_subject_last);
2298 g_free (mail_to_last);
2299 mail_cc_last = tmail_cc;
2300 mail_subject_last = tmail_subject;
2301 mail_to_last = tmail_to;
2302 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2307 /*******************/
2308 /* Word Completion */
2309 /*******************/
2311 static gboolean is_break_char(char c)
2313 return (isspace(c) || strchr("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2316 /* find first character of current word */
2317 static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len)
2319 int i, c, last;
2321 /* return if at begin of file */
2322 if (edit->curs1 <= 0)
2323 return 0;
2325 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2326 /* return if not at end or in word */
2327 if (is_break_char(c))
2328 return 0;
2330 /* search start of word to be completed */
2331 for (i = 2;; i++) {
2332 /* return if at begin of file */
2333 if (edit->curs1 - i < 0)
2334 return 0;
2336 last = c;
2337 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2339 if (is_break_char(c)) {
2340 /* return if word starts with digit */
2341 if (isdigit (last))
2342 return 0;
2344 *word_start = edit->curs1 - (i - 1); /* start found */
2345 *word_len = i - 1;
2346 break;
2349 /* success */
2350 return 1;
2353 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2355 /* collect the possible completions */
2356 static int
2357 edit_collect_completions (WEdit *edit, long start, int word_len,
2358 char *match_expr, struct selection *compl,
2359 int *num)
2361 gsize len = 0;
2362 gsize max_len = 0;
2363 gsize i;
2364 int skip;
2365 GString *temp;
2366 mc_search_t *srch;
2368 srch = mc_search_new(match_expr, -1);
2369 if (srch == NULL)
2370 return 0;
2372 srch->search_type = MC_SEARCH_T_REGEX;
2373 srch->is_case_sentitive = TRUE;
2374 srch->search_fn = edit_search_cmd_callback;
2376 /* collect max MAX_WORD_COMPLETIONS completions */
2377 start--;
2378 while (*num < MAX_WORD_COMPLETIONS) {
2379 /* get next match */
2380 if (mc_search_run (srch, (void *) edit, start+1, edit->last_byte, &len) == FALSE)
2381 break;
2382 start = srch->normal_offset;
2384 /* add matched completion if not yet added */
2385 temp = g_string_new("");
2386 for (i = 0; i < len; i++){
2387 skip = edit_get_byte(edit, start+i);
2388 if (isspace(skip))
2389 continue;
2390 g_string_append_c (temp, skip);
2393 skip = 0;
2395 for (i = 0; i < (gsize) *num; i++) {
2396 if (strncmp
2398 (char *) &compl[i].text[word_len],
2399 (char *) &temp->str[word_len],
2400 max (len, compl[i].len) - (gsize)word_len
2401 ) == 0) {
2402 skip = 1;
2403 break; /* skip it, already added */
2406 if (skip) {
2407 g_string_free(temp, TRUE);
2408 continue;
2411 compl[*num].text = temp->str;
2412 compl[*num].len = temp->len;
2413 (*num)++;
2414 g_string_free(temp, FALSE);
2416 /* note the maximal length needed for the completion dialog */
2417 if (len > max_len)
2418 max_len = len;
2420 mc_search_free(srch);
2421 return max_len;
2425 * Complete current word using regular expression search
2426 * backwards beginning at the current cursor position.
2428 void
2429 edit_complete_word_cmd (WEdit *edit)
2431 int word_len = 0, num_compl = 0;
2432 gsize i, max_len;
2433 long word_start = 0;
2434 unsigned char *bufpos;
2435 char *match_expr;
2436 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2438 /* search start of word to be completed */
2439 if (!edit_find_word_start (edit, &word_start, &word_len))
2440 return;
2442 /* prepare match expression */
2443 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2444 [word_start & M_EDIT_BUF_SIZE];
2446 match_expr = g_strdup_printf ("(^|\\s)%.*s[^\\s\\.=\\+\\{\\}\\[\\]\\(\\)\\\\\\!\\,<>\\?\\/@#\\$%%\\^&\\*\\~\\|\\\"'\\:\\;]+", word_len, bufpos);
2448 /* collect the possible completions */
2449 /* start search from begin to end of file */
2450 max_len =
2451 edit_collect_completions (edit, 0, word_len, match_expr,
2452 (struct selection *) &compl, &num_compl);
2454 if (num_compl > 0) {
2455 /* insert completed word if there is only one match */
2456 if (num_compl == 1) {
2457 for (i = word_len; i < compl[0].len; i++)
2458 edit_insert (edit, *(compl[0].text + i));
2460 /* more than one possible completion => ask the user */
2461 else {
2462 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2463 /* !!! pressed again the selection dialog pops up, but that !!! */
2464 /* !!! seems to require a further internal state !!! */
2465 /*tty_beep (); */
2467 /* let the user select the preferred completion */
2468 editcmd_dialog_completion_show (edit, max_len, word_len,
2469 (struct selection *) &compl,
2470 num_compl);
2474 g_free (match_expr);
2475 /* release memory before return */
2476 for (i = 0; i < (gsize) num_compl; i++)
2477 g_free (compl[i].text);
2481 void
2482 edit_select_codepage_cmd (WEdit *edit)
2484 #ifdef HAVE_CHARSET
2485 const char *cp_id = NULL;
2486 if (do_select_codepage ()) {
2487 cp_id = get_codepage_id (source_codepage >= 0 ?
2488 source_codepage : display_codepage);
2490 if (cp_id != NULL) {
2491 GIConv conv;
2492 conv = str_crt_conv_from (cp_id);
2493 if (conv != INVALID_CONV) {
2494 if (edit->converter != str_cnv_from_term)
2495 str_close_conv (edit->converter);
2496 edit->converter = conv;
2501 if (cp_id != NULL)
2502 edit->utf8 = str_isutf8 (cp_id);
2505 edit->force = REDRAW_COMPLETELY;
2506 edit_refresh_cmd (edit);
2507 #endif
2510 void
2511 edit_insert_literal_cmd (WEdit *edit)
2513 int char_for_insertion =
2514 editcmd_dialog_raw_key_query (_(" Insert Literal "),
2515 _(" Press any key: "), 0);
2516 edit_execute_key_command (edit, -1,
2517 ascii_alpha_to_cntrl (char_for_insertion));
2520 void
2521 edit_execute_macro_cmd (WEdit *edit)
2523 int command =
2524 CK_Macro (editcmd_dialog_raw_key_query
2525 (_(" Execute Macro "), _(" Press macro hotkey: "),
2526 1));
2527 if (command == CK_Macro (0))
2528 command = CK_Insert_Char;
2530 edit_execute_key_command (edit, command, -1);
2533 void
2534 edit_begin_end_macro_cmd(WEdit *edit)
2536 int command;
2538 /* edit is a pointer to the widget */
2539 if (edit) {
2540 command =
2541 edit->macro_i <
2542 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2543 edit_execute_key_command (edit, command, -1);
2548 edit_load_forward_cmd (WEdit *edit)
2550 if (edit->modified) {
2551 if (edit_query_dialog2
2552 (_("Warning"),
2553 _(" Current text was modified without a file save. \n"
2554 " Continue discards these changes. "), _("C&ontinue"),
2555 _("&Cancel"))) {
2556 edit->force |= REDRAW_COMPLETELY;
2557 return 0;
2560 if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
2561 if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
2562 return 1;
2564 edit_stack_iterator++;
2565 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2566 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2567 edit_history_moveto[edit_stack_iterator].line);
2568 return 0;
2569 } else {
2570 return 1;
2572 } else {
2573 return 1;
2578 edit_load_back_cmd (WEdit *edit)
2580 if (edit->modified) {
2581 if (edit_query_dialog2
2582 (_("Warning"),
2583 _(" Current text was modified without a file save. \n"
2584 " Continue discards these changes. "), _("C&ontinue"),
2585 _("&Cancel"))) {
2586 edit->force |= REDRAW_COMPLETELY;
2587 return 0;
2590 if ( edit_stack_iterator > 0 ) {
2591 edit_stack_iterator--;
2592 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2593 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2594 edit_history_moveto[edit_stack_iterator].line);
2595 return 0;
2596 } else {
2597 return 1;
2599 } else {
2600 return 1;
2604 void
2605 edit_get_match_keyword_cmd (WEdit *edit)
2607 int word_len = 0;
2608 int num_def = 0;
2609 int max_len = 0;
2610 int i;
2611 long word_start = 0;
2612 unsigned char *bufpos;
2613 char *match_expr;
2614 char *path = NULL;
2615 char *ptr = NULL;
2616 char *tagfile = NULL;
2618 etags_hash_t def_hash[MAX_DEFINITIONS];
2620 for ( i = 0; i < MAX_DEFINITIONS; i++) {
2621 def_hash[i].filename = NULL;
2624 /* search start of word to be completed */
2625 if (!edit_find_word_start (edit, &word_start, &word_len))
2626 return;
2628 /* prepare match expression */
2629 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2630 [word_start & M_EDIT_BUF_SIZE];
2631 match_expr = g_strdup_printf ("%.*s", word_len, bufpos);
2633 ptr = g_get_current_dir ();
2634 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
2635 g_free (ptr);
2637 /* Recursive search file 'TAGS' in parent dirs */
2638 do {
2639 ptr = g_path_get_dirname (path);
2640 g_free(path); path = ptr;
2641 g_free (tagfile);
2642 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
2643 if ( exist_file (tagfile) )
2644 break;
2645 } while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
2647 if (tagfile){
2648 num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
2649 g_free (tagfile);
2651 g_free (path);
2653 max_len = MAX_WIDTH_DEF_DIALOG;
2654 word_len = 0;
2655 if ( num_def > 0 ) {
2656 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
2657 (etags_hash_t *) &def_hash,
2658 num_def);
2660 g_free (match_expr);
2663 void
2664 edit_move_block_to_right (WEdit * edit)
2666 long start_mark, end_mark;
2667 long cur_bol, start_bol;
2669 if ( eval_marks (edit, &start_mark, &end_mark) )
2670 return;
2672 start_bol = edit_bol (edit, start_mark);
2673 cur_bol = edit_bol (edit, end_mark - 1);
2674 do {
2675 edit_cursor_move (edit, cur_bol - edit->curs1);
2676 if ( option_fill_tabs_with_spaces ) {
2677 if ( option_fake_half_tabs ) {
2678 insert_spaces_tab (edit, 1);
2679 } else {
2680 insert_spaces_tab (edit, 0);
2682 } else {
2683 edit_insert (edit, '\t');
2685 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
2686 if ( cur_bol == 0 ) {
2687 break;
2689 cur_bol = edit_bol (edit, cur_bol - 1);
2690 } while (cur_bol >= start_bol) ;
2691 edit->force |= REDRAW_PAGE;
2694 void
2695 edit_move_block_to_left (WEdit * edit)
2697 long start_mark, end_mark;
2698 long cur_bol, start_bol;
2699 int i, del_tab_width;
2700 int next_char;
2702 if ( eval_marks (edit, &start_mark, &end_mark) )
2703 return;
2705 start_bol = edit_bol (edit, start_mark);
2706 cur_bol = edit_bol (edit, end_mark - 1);
2707 do {
2708 edit_cursor_move (edit, cur_bol - edit->curs1);
2709 if (option_fake_half_tabs) {
2710 del_tab_width = HALF_TAB_SIZE;
2711 } else {
2712 del_tab_width = option_tab_spacing;
2714 next_char = edit_get_byte (edit, edit->curs1);
2715 if ( next_char == '\t' ) {
2716 edit_delete (edit, 1);
2717 } else if ( next_char == ' ' ) {
2718 for (i = 1; i <= del_tab_width; i++) {
2719 if ( next_char == ' ' ) {
2720 edit_delete (edit, 1);
2722 next_char = edit_get_byte (edit, edit->curs1);
2725 if ( cur_bol == 0 ) {
2726 break;
2728 cur_bol = edit_bol (edit, cur_bol - 1);
2729 } while (cur_bol >= start_bol) ;
2730 edit->force |= REDRAW_PAGE;