Merge branch '2121_dir_symlink'
[kaloumi3.git] / src / editor / editcmd.c
blob437cc348628be4842fcfa10b4b966090173f7766
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 "lib/global.h"
49 #include "lib/tty/tty.h"
50 #include "lib/tty/key.h" /* XCTRL */
51 #include "lib/mcconfig.h"
52 #include "lib/skin.h"
53 #include "lib/strutil.h" /* utf string functions */
54 #include "lib/vfs/mc-vfs/vfs.h"
56 #include "src/history.h"
57 #include "src/widget.h" /* listbox_new() */
58 #include "src/layout.h" /* clr_scr() */
59 #include "src/main.h" /* mc_home source_codepage */
60 #include "src/help.h" /* interactive_display() */
61 #include "src/wtools.h" /* message() */
62 #include "src/charsets.h"
63 #include "src/selcodepage.h"
64 #include "src/cmddef.h"
66 #include "src/editor/edit-impl.h"
67 #include "src/editor/editlock.h"
68 #include "src/editor/edit-widget.h"
69 #include "src/editor/editcmd_dialogs.h"
70 #include "src/editor/etags.h"
72 /* globals: */
74 /* search and replace: */
75 int search_create_bookmark = 0;
76 /* static int search_in_all_charsets = 0; */
78 /* queries on a save */
79 int edit_confirm_save = 1;
81 static int edit_save_cmd (WEdit * edit);
82 static unsigned char *edit_get_block (WEdit * edit, long start, long finish, int *l);
84 static void
85 edit_search_cmd_search_create_bookmark (WEdit * edit)
87 int found = 0, books = 0;
88 long 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 (;;)
97 if (!mc_search_run (edit->search, (void *) edit, q, edit->last_byte, &len))
98 break;
99 if (found == 0)
100 edit->search_start = edit->search->normal_offset;
101 found++;
102 l += edit_count_lines (edit, q, edit->search->normal_offset);
103 if (l != l_last)
105 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
106 books++;
108 l_last = l;
109 q = edit->search->normal_offset + 1;
112 if (found == 0)
114 edit_error_dialog (_("Search"), _(" Search string not found "));
116 else
118 edit_cursor_move (edit, edit->search_start - edit->curs1);
119 edit_scroll_screen_over_cursor (edit);
123 static int
124 edit_search_cmd_callback (const void *user_data, gsize char_offset)
126 return edit_get_byte ((WEdit *) user_data, (long) char_offset);
129 void
130 edit_help_cmd (WEdit * edit)
132 interactive_display (NULL, "[Internal File Editor]");
133 edit->force |= REDRAW_COMPLETELY;
136 void
137 edit_refresh_cmd (WEdit * edit)
139 #ifdef HAVE_SLANG
140 int color;
142 edit_get_syntax_color (edit, -1, &color);
143 tty_touch_screen ();
144 mc_refresh ();
145 #else
146 (void) edit;
148 clr_scr ();
149 repaint_screen ();
150 #endif /* !HAVE_SLANG */
151 tty_keypad (TRUE);
154 /* If 0 (quick save) then a) create/truncate <filename> file,
155 b) save to <filename>;
156 if 1 (safe save) then a) save to <tempnam>,
157 b) rename <tempnam> to <filename>;
158 if 2 (do backups) then a) save to <tempnam>,
159 b) rename <filename> to <filename.backup_ext>,
160 c) rename <tempnam> to <filename>. */
162 /* returns 0 on error, -1 on abort */
163 static int
164 edit_save_file (WEdit * edit, const char *filename)
166 char *p;
167 gchar *tmp;
168 long filelen = 0;
169 char *savename = 0;
170 gchar *real_filename;
171 int this_save_mode, fd = -1;
173 if (!filename)
174 return 0;
175 if (!*filename)
176 return 0;
178 if (*filename != PATH_SEP && edit->dir)
180 real_filename = concat_dir_and_file (edit->dir, filename);
182 else
184 real_filename = g_strdup (filename);
187 this_save_mode = option_save_mode;
188 if (this_save_mode != EDIT_QUICK_SAVE)
190 if (!vfs_file_is_local (real_filename) ||
191 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1)
194 * The file does not exists yet, so no safe save or
195 * backup are necessary.
197 this_save_mode = EDIT_QUICK_SAVE;
199 if (fd != -1)
200 mc_close (fd);
203 if (this_save_mode == EDIT_QUICK_SAVE && !edit->skip_detach_prompt)
205 int rv;
206 struct stat sb;
208 rv = mc_stat (real_filename, &sb);
209 if (rv == 0 && sb.st_nlink > 1)
211 rv = edit_query_dialog3 (_("Warning"),
212 _(" File has hard-links. Detach before saving? "),
213 _("&Yes"), _("&No"), _("&Cancel"));
214 switch (rv)
216 case 0:
217 this_save_mode = EDIT_SAFE_SAVE;
218 /* fallthrough */
219 case 1:
220 edit->skip_detach_prompt = 1;
221 break;
222 default:
223 g_free (real_filename);
224 return -1;
228 /* Prevent overwriting changes from other editor sessions. */
229 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime)
232 /* The default action is "Cancel". */
233 query_set_sel (1);
235 rv = edit_query_dialog2 (_("Warning"),
236 _("The file has been modified in the meantime. Save anyway?"),
237 _("&Yes"), _("&Cancel"));
238 if (rv != 0)
240 g_free (real_filename);
241 return -1;
246 if (this_save_mode != EDIT_QUICK_SAVE)
248 char *savedir, *saveprefix;
249 const char *slashpos;
250 slashpos = strrchr (real_filename, PATH_SEP);
251 if (slashpos)
253 savedir = g_strdup (real_filename);
254 savedir[slashpos - real_filename + 1] = '\0';
256 else
257 savedir = g_strdup (".");
258 saveprefix = concat_dir_and_file (savedir, "cooledit");
259 g_free (savedir);
260 fd = mc_mkstemps (&savename, saveprefix, NULL);
261 g_free (saveprefix);
262 if (!savename)
264 g_free (real_filename);
265 return 0;
267 /* FIXME:
268 * Close for now because mc_mkstemps use pure open system call
269 * to create temporary file and it needs to be reopened by
270 * VFS-aware mc_open().
272 close (fd);
274 else
275 savename = g_strdup (real_filename);
277 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
278 mc_chmod (savename, edit->stat1.st_mode);
280 if ((fd =
281 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, edit->stat1.st_mode)) == -1)
282 goto error_save;
284 /* pipe save */
285 if ((p = edit_get_write_filter (savename, real_filename)))
287 FILE *file;
289 mc_close (fd);
290 file = (FILE *) popen (p, "w");
292 if (file)
294 filelen = edit_write_stream (edit, file);
295 #if 1
296 pclose (file);
297 #else
298 if (pclose (file) != 0)
300 tmp = g_strconcat (_(" Error writing to pipe: "), p, " ", (char *) NULL);
301 edit_error_dialog (_("Error"), tmp);
302 g_free (tmp);
303 g_free (p);
304 goto error_save;
306 #endif
308 else
310 tmp = g_strconcat (_(" Cannot open pipe for writing: "), p, " ", (char *) NULL);
312 edit_error_dialog (_("Error"), get_sys_error (tmp));
313 g_free (p);
314 g_free (tmp);
315 goto error_save;
317 g_free (p);
319 else if (edit->lb == LB_ASIS)
320 { /* do not change line breaks */
321 long buf;
322 buf = 0;
323 filelen = edit->last_byte;
324 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1)
326 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE)
328 mc_close (fd);
329 goto error_save;
331 buf++;
333 if (mc_write
334 (fd, (char *) edit->buffers1[buf],
335 edit->curs1 & M_EDIT_BUF_SIZE) != (edit->curs1 & M_EDIT_BUF_SIZE))
337 filelen = -1;
339 else if (edit->curs2)
341 edit->curs2--;
342 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
343 if (mc_write
344 (fd,
345 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
346 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
347 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) != 1 + (edit->curs2 & M_EDIT_BUF_SIZE))
349 filelen = -1;
351 else
353 while (--buf >= 0)
355 if (mc_write (fd, (char *) edit->buffers2[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE)
357 filelen = -1;
358 break;
362 edit->curs2++;
364 if (mc_close (fd))
365 goto error_save;
367 /* Update the file information, especially the mtime. */
368 if (mc_stat (savename, &edit->stat1) == -1)
369 goto error_save;
371 else
372 { /* change line breaks */
373 FILE *file;
375 mc_close (fd);
377 file = (FILE *) fopen (savename, "w");
379 if (file)
381 filelen = edit_write_stream (edit, file);
382 fclose (file);
384 else
386 char *msg;
388 msg = g_strdup_printf (_(" Cannot open file for writing: %s "), savename);
389 edit_error_dialog (_("Error"), msg);
390 g_free (msg);
391 goto error_save;
395 if (filelen != edit->last_byte)
396 goto error_save;
398 if (this_save_mode == EDIT_DO_BACKUP)
400 assert (option_backup_ext != NULL);
401 tmp = g_strconcat (real_filename, option_backup_ext, (char *) NULL);
402 if (mc_rename (real_filename, tmp) == -1)
404 g_free (tmp);
405 goto error_save;
409 if (this_save_mode != EDIT_QUICK_SAVE)
410 if (mc_rename (savename, real_filename) == -1)
411 goto error_save;
412 g_free (savename);
413 g_free (real_filename);
414 return 1;
415 error_save:
416 /* FIXME: Is this safe ?
417 * if (this_save_mode != EDIT_QUICK_SAVE)
418 * mc_unlink (savename);
420 g_free (real_filename);
421 g_free (savename);
422 return 0;
425 void
426 menu_save_mode_cmd (void)
428 /* diaog sizes */
429 const int DLG_X = 38;
430 const int DLG_Y = 13;
432 char *str_result;
434 const char *str[] = {
435 N_("&Quick save"),
436 N_("&Safe save"),
437 N_("&Do backups with following extension:")
440 QuickWidget widgets[] = {
441 /* 0 */
442 QUICK_BUTTON (18, DLG_X, DLG_Y - 3, DLG_Y, N_("&Cancel"), B_CANCEL, NULL),
443 /* 1 */
444 QUICK_BUTTON (6, DLG_X, DLG_Y - 3, DLG_Y, N_("&OK"), B_ENTER, NULL),
445 /* 2 */
446 QUICK_CHECKBOX (4, DLG_X, 8, DLG_Y, N_("Check &POSIX new line"), &option_check_nl_at_eof),
447 /* 3 */
448 QUICK_INPUT (8, DLG_X, 6, DLG_Y, option_backup_ext, 9, 0, "edit-backup-ext", &str_result),
449 /* 4 */
450 QUICK_RADIO (4, DLG_X, 3, DLG_Y, 3, str, &option_save_mode),
451 QUICK_END
454 QuickDialog dialog = {
455 DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "),
456 "[Edit Save Mode]", widgets, FALSE
459 size_t i;
460 size_t maxlen = 0;
461 size_t w0, w1, b_len, w3;
463 assert (option_backup_ext != NULL);
465 /* OK/Cancel buttons */
466 w0 = str_term_width1 (_(widgets[0].u.button.text)) + 3;
467 w1 = str_term_width1 (_(widgets[1].u.button.text)) + 5; /* default button */
468 b_len = w0 + w1 + 3;
470 maxlen = max (b_len, (size_t) str_term_width1 (_(dialog.title)) + 2);
472 w3 = 0;
473 for (i = 0; i < 3; i++)
475 #ifdef ENABLE_NLS
476 str[i] = _(str[i]);
477 #endif
478 w3 = max (w3, (size_t) str_term_width1 (str[i]));
481 maxlen = max (maxlen, w3 + 4);
483 dialog.xlen = min ((size_t) COLS, maxlen + 8);
485 widgets[3].u.input.len = w3;
486 widgets[1].relative_x = (dialog.xlen - b_len) / 2;
487 widgets[0].relative_x = widgets[1].relative_x + w0 + 2;
489 for (i = 0; i < sizeof (widgets) / sizeof (widgets[0]); i++)
490 widgets[i].x_divisions = dialog.xlen;
492 if (quick_dialog (&dialog) != B_CANCEL)
494 g_free (option_backup_ext);
495 option_backup_ext = str_result;
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 ENABLE_VFS
508 edit->dir = g_strdup (vfs_get_current_dir ());
509 #else /* ENABLE_VFS */
510 edit->dir = g_get_current_dir ();
511 #endif /* ENABLE_VFS */
514 static gboolean
515 edit_check_newline (WEdit * edit)
517 return !(option_check_nl_at_eof && edit->last_byte > 0
518 && edit_get_byte (edit, edit->last_byte - 1) != '\n'
519 && edit_query_dialog2 (_("Warning"),
520 _("The file you are saving is not finished with a newline"),
521 _("C&ontinue"), _("&Cancel")));
524 static char *
525 edit_get_save_file_as (WEdit * edit)
527 #define DLG_WIDTH 64
528 #define DLG_HEIGHT 14
530 static LineBreaks cur_lb = LB_ASIS;
532 char *filename = edit->filename;
534 const char *lb_names[LB_NAMES] = {
535 N_("&Do not change"),
536 N_("&Unix format (LF)"),
537 N_("&Windows/DOS format (CR LF)"),
538 N_("&Macintosh format (CR)")
541 QuickWidget quick_widgets[] = {
542 QUICK_BUTTON (6, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
543 QUICK_BUTTON (2, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
544 QUICK_RADIO (5, DLG_WIDTH, DLG_HEIGHT - 8, DLG_HEIGHT, LB_NAMES, lb_names, (int *) &cur_lb),
545 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 9, DLG_HEIGHT, N_("Change line breaks to:")),
546 QUICK_INPUT (3, DLG_WIDTH, DLG_HEIGHT - 11, DLG_HEIGHT, filename, DLG_WIDTH - 6, 0,
547 "save-as", &filename),
548 QUICK_LABEL (2, DLG_WIDTH, DLG_HEIGHT - 12, DLG_HEIGHT, N_(" Enter file name: ")),
549 QUICK_END
552 QuickDialog Quick_options = {
553 DLG_WIDTH, DLG_HEIGHT, -1, -1,
554 N_(" Save As "), "[Save File As]",
555 quick_widgets, FALSE
558 if (quick_dialog (&Quick_options) != B_CANCEL)
560 edit->lb = cur_lb;
561 return filename;
564 return NULL;
566 #undef DLG_WIDTH
567 #undef DLG_HEIGHT
570 /* Here we want to warn the users of overwriting an existing file,
571 but only if they have made a change to the filename */
572 /* returns 1 on success */
574 edit_save_as_cmd (WEdit * edit)
576 /* This heads the 'Save As' dialog box */
577 char *exp;
578 int save_lock = 0;
579 int different_filename = 0;
581 if (!edit_check_newline (edit))
582 return 0;
584 exp = edit_get_save_file_as (edit);
585 edit_push_action (edit, KEY_PRESS + edit->start_display);
587 if (exp)
589 if (!*exp)
591 g_free (exp);
592 edit->force |= REDRAW_COMPLETELY;
593 return 0;
595 else
597 int rv;
598 if (strcmp (edit->filename, exp))
600 int file;
601 different_filename = 1;
602 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1)
604 /* the file exists */
605 mc_close (file);
606 /* Overwrite the current file or cancel the operation */
607 if (edit_query_dialog2
608 (_("Warning"),
609 _(" A file already exists with this name. "),
610 _("&Overwrite"), _("&Cancel")))
612 edit->force |= REDRAW_COMPLETELY;
613 g_free (exp);
614 return 0;
617 else
619 edit->stat1.st_mode |= S_IWUSR;
621 save_lock = edit_lock_file (exp);
623 else
625 /* filenames equal, check if already locked */
626 if (!edit->locked && !edit->delete_file)
627 save_lock = edit_lock_file (exp);
630 if (different_filename)
633 * Allow user to write into saved (under another name) file
634 * even if original file had r/o user permissions.
636 edit->stat1.st_mode |= S_IWRITE;
639 rv = edit_save_file (edit, exp);
640 switch (rv)
642 case 1:
643 /* Succesful, so unlock both files */
644 if (different_filename)
646 if (save_lock)
647 edit_unlock_file (exp);
648 if (edit->locked)
649 edit->locked = edit_unlock_file (edit->filename);
651 else
653 if (edit->locked || save_lock)
654 edit->locked = edit_unlock_file (edit->filename);
657 edit_set_filename (edit, exp);
658 if (edit->lb != LB_ASIS)
659 edit_reload (edit, exp);
660 g_free (exp);
661 edit->modified = 0;
662 edit->delete_file = 0;
663 if (different_filename)
664 edit_load_syntax (edit, NULL, option_syntax_type);
665 edit->force |= REDRAW_COMPLETELY;
666 return 1;
667 default:
668 edit_error_dialog (_(" Save As "), get_sys_error (_(" Cannot save file. ")));
669 /* fallthrough */
670 case -1:
671 /* Failed, so maintain modify (not save) lock */
672 if (save_lock)
673 edit_unlock_file (exp);
674 g_free (exp);
675 edit->force |= REDRAW_COMPLETELY;
676 return 0;
680 edit->force |= REDRAW_COMPLETELY;
681 return 0;
684 /* {{{ Macro stuff starts here */
686 /* creates a macro file if it doesn't exist */
687 static FILE *
688 edit_open_macro_file (const char *r)
690 gchar *filename;
691 FILE *fd;
692 int file;
693 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
694 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
696 g_free (filename);
697 return 0;
699 close (file);
700 fd = fopen (filename, r);
701 g_free (filename);
702 return fd;
705 #define MAX_MACROS 1024
706 static int saved_macro[MAX_MACROS + 1];
707 static int saved_macros_loaded = 0;
710 This is just to stop the macro file be loaded over and over for keys
711 that aren't defined to anything. On slow systems this could be annoying.
713 static int
714 macro_exists (int k)
716 int i;
717 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
718 if (saved_macro[i] == k)
719 return i;
720 return -1;
723 /* returns 1 on error */
724 static int
725 edit_delete_macro (WEdit * edit, int k)
727 gchar *tmp, *tmp2;
728 struct macro macro[MAX_MACRO_LENGTH];
729 FILE *f, *g;
730 int s, i, n, j = 0;
732 (void) edit;
734 if (saved_macros_loaded)
735 if ((j = macro_exists (k)) < 0)
736 return 0;
737 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
738 g = fopen (tmp, "w");
739 g_free (tmp);
740 if (!g)
742 edit_error_dialog (_(" Delete macro "), get_sys_error (_(" Cannot open temp file ")));
743 return 1;
745 f = edit_open_macro_file ("r");
746 if (!f)
748 edit_error_dialog (_(" Delete macro "), get_sys_error (_(" Cannot open macro file ")));
749 fclose (g);
750 return 1;
752 for (;;)
754 n = fscanf (f, ("key '%d 0': "), &s);
755 if (!n || n == EOF)
756 break;
757 n = 0;
758 while (fscanf (f, "%lu %d, ", &macro[n].command, &macro[n].ch))
759 n++;
760 fscanf (f, ";\n");
761 if (s != k)
763 fprintf (g, ("key '%d 0': "), s);
764 for (i = 0; i < n; i++)
765 fprintf (g, "%lu %d, ", macro[i].command, macro[i].ch);
766 fprintf (g, ";\n");
769 fclose (f);
770 fclose (g);
771 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
772 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
773 if (rename (tmp, tmp2) == -1)
775 edit_error_dialog (_(" Delete macro "), get_sys_error (_(" Cannot overwrite macro file ")));
776 g_free (tmp);
777 g_free (tmp2);
778 return 1;
780 g_free (tmp);
781 g_free (tmp2);
783 if (saved_macros_loaded)
784 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
785 return 0;
788 /* returns 0 on error */
790 edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
792 FILE *f;
793 int s, i;
795 edit_push_action (edit, KEY_PRESS + edit->start_display);
796 s = editcmd_dialog_raw_key_query (_(" Save macro "), _(" Press the macro's new hotkey: "), 1);
797 edit->force |= REDRAW_COMPLETELY;
798 if (s)
800 if (edit_delete_macro (edit, s))
801 return 0;
802 f = edit_open_macro_file ("a+");
803 if (f)
805 fprintf (f, ("key '%d 0': "), s);
806 for (i = 0; i < n; i++)
807 fprintf (f, "%lu %d, ", macro[i].command, macro[i].ch);
808 fprintf (f, ";\n");
809 fclose (f);
810 if (saved_macros_loaded)
812 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
813 saved_macro[i] = s;
815 return 1;
817 else
818 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
820 return 0;
823 void
824 edit_delete_macro_cmd (WEdit * edit)
826 int command;
828 command = editcmd_dialog_raw_key_query (_(" Delete macro "), _(" Press macro hotkey: "), 1);
830 if (command != 0)
831 edit_delete_macro (edit, command);
834 /* return 0 on error */
836 edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
838 FILE *f;
839 int s, i = 0, found = 0;
841 (void) edit;
843 if (saved_macros_loaded)
844 if (macro_exists (k) < 0)
845 return 0;
847 if ((f = edit_open_macro_file ("r")))
849 struct macro dummy;
852 int u;
853 u = fscanf (f, ("key '%d 0': "), &s);
854 if (!u || u == EOF)
855 break;
856 if (!saved_macros_loaded)
857 saved_macro[i++] = s;
858 if (!found)
860 *n = 0;
861 while (*n < MAX_MACRO_LENGTH
862 && 2 == fscanf (f, "%lu %d, ", &macro[*n].command, &macro[*n].ch))
863 (*n)++;
865 else
867 while (2 == fscanf (f, "%lu %d, ", &dummy.command, &dummy.ch));
869 fscanf (f, ";\n");
870 if (s == k)
871 found = 1;
873 while (!found || !saved_macros_loaded);
874 if (!saved_macros_loaded)
876 saved_macro[i] = 0;
877 saved_macros_loaded = 1;
879 fclose (f);
880 return found;
882 else
883 edit_error_dialog (_(" Load macro "), get_sys_error (_(" Cannot open macro file ")));
884 return 0;
887 /* }}} Macro stuff starts here */
889 /* returns 1 on success */
891 edit_save_confirm_cmd (WEdit * edit)
893 gchar *f = NULL;
895 if (!edit_check_newline (edit))
896 return 0;
898 if (edit_confirm_save)
900 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", (char *) NULL);
901 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel")))
903 g_free (f);
904 return 0;
906 g_free (f);
908 return edit_save_cmd (edit);
912 /* returns 1 on success */
913 static int
914 edit_save_cmd (WEdit * edit)
916 int res, save_lock = 0;
918 if (!edit->locked && !edit->delete_file)
919 save_lock = edit_lock_file (edit->filename);
920 res = edit_save_file (edit, edit->filename);
922 /* Maintain modify (not save) lock on failure */
923 if ((res > 0 && edit->locked) || save_lock)
924 edit->locked = edit_unlock_file (edit->filename);
926 /* On failure try 'save as', it does locking on its own */
927 if (!res)
928 return edit_save_as_cmd (edit);
929 edit->force |= REDRAW_COMPLETELY;
930 if (res > 0)
932 edit->delete_file = 0;
933 edit->modified = 0;
936 return 1;
940 /* returns 1 on success */
942 edit_new_cmd (WEdit * edit)
944 if (edit->modified)
946 if (edit_query_dialog2
947 (_("Warning"),
949 (" Current text was modified without a file save. \n Continue discards these changes. "),
950 _("C&ontinue"), _("&Cancel")))
952 edit->force |= REDRAW_COMPLETELY;
953 return 0;
956 edit->force |= REDRAW_COMPLETELY;
958 return edit_renew (edit); /* if this gives an error, something has really screwed up */
961 /* returns 1 on error */
962 static int
963 edit_load_file_from_filename (WEdit * edit, char *exp)
965 int prev_locked = edit->locked;
966 char *prev_filename = g_strdup (edit->filename);
968 if (!edit_reload (edit, exp))
970 g_free (prev_filename);
971 return 1;
974 if (prev_locked)
975 edit_unlock_file (prev_filename);
976 g_free (prev_filename);
977 return 0;
980 static void
981 edit_load_syntax_file (WEdit * edit)
983 char *extdir;
984 int dir = 0;
986 if (geteuid () == 0)
988 dir = query_dialog (_("Syntax file edit"),
989 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
990 _("&User"), _("&System Wide"));
993 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
994 if (!exist_file (extdir))
996 g_free (extdir);
997 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
1000 if (dir == 0)
1002 char *buffer;
1004 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
1005 check_for_default (extdir, buffer);
1006 edit_load_file_from_filename (edit, buffer);
1007 g_free (buffer);
1009 else if (dir == 1)
1010 edit_load_file_from_filename (edit, extdir);
1012 g_free (extdir);
1015 static void
1016 edit_load_menu_file (WEdit * edit)
1018 char *buffer;
1019 char *menufile;
1020 int dir = 0;
1022 dir = query_dialog (_(" Menu edit "),
1023 _(" Which menu file do you want to edit? "), D_NORMAL,
1024 geteuid ()? 2 : 3, _("&Local"), _("&User"), _("&System Wide"));
1026 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
1028 if (!exist_file (menufile))
1030 g_free (menufile);
1031 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
1034 switch (dir)
1036 case 0:
1037 buffer = g_strdup (EDIT_LOCAL_MENU);
1038 check_for_default (menufile, buffer);
1039 chmod (buffer, 0600);
1040 break;
1042 case 1:
1043 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
1044 check_for_default (menufile, buffer);
1045 break;
1047 case 2:
1048 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
1049 if (!exist_file (buffer))
1051 g_free (buffer);
1052 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
1054 break;
1056 default:
1057 g_free (menufile);
1058 return;
1061 edit_load_file_from_filename (edit, buffer);
1063 g_free (buffer);
1064 g_free (menufile);
1068 edit_load_cmd (WEdit * edit, edit_current_file_t what)
1070 char *exp;
1072 if (edit->modified
1073 && (edit_query_dialog2
1074 (_("Warning"),
1075 _(" Current text was modified without a file save. \n"
1076 " Continue discards these changes. "), _("C&ontinue"), _("&Cancel")) == 1))
1078 edit->force |= REDRAW_COMPLETELY;
1079 return 0;
1082 switch (what)
1084 case EDIT_FILE_COMMON:
1085 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
1086 MC_HISTORY_EDIT_LOAD, edit->filename);
1088 if (exp)
1090 if (*exp)
1091 edit_load_file_from_filename (edit, exp);
1092 g_free (exp);
1094 break;
1096 case EDIT_FILE_SYNTAX:
1097 edit_load_syntax_file (edit);
1098 break;
1100 case EDIT_FILE_MENU:
1101 edit_load_menu_file (edit);
1102 break;
1104 default:
1105 break;
1108 edit->force |= REDRAW_COMPLETELY;
1109 return 0;
1113 if mark2 is -1 then marking is from mark1 to the cursor.
1114 Otherwise its between the markers. This handles this.
1115 Returns 1 if no text is marked.
1118 eval_marks (WEdit * edit, long *start_mark, long *end_mark)
1120 if (edit->mark1 != edit->mark2)
1122 long start_bol, start_eol;
1123 long end_bol, end_eol;
1124 long col1, col2;
1125 long diff1, diff2;
1126 if (edit->mark2 >= 0)
1128 *start_mark = min (edit->mark1, edit->mark2);
1129 *end_mark = max (edit->mark1, edit->mark2);
1131 else
1133 *start_mark = min (edit->mark1, edit->curs1);
1134 *end_mark = max (edit->mark1, edit->curs1);
1135 edit->column2 = edit->curs_col + edit->over_col;
1137 if (column_highlighting
1138 && (((edit->mark1 > edit->curs1) && (edit->column1 < edit->column2))
1139 || ((edit->mark1 < edit->curs1) && (edit->column1 > edit->column2))))
1142 start_bol = edit_bol (edit, *start_mark);
1143 start_eol = edit_eol (edit, start_bol - 1) + 1;
1144 end_bol = edit_bol (edit, *end_mark);
1145 end_eol = edit_eol (edit, *end_mark);
1146 col1 = min (edit->column1, edit->column2);
1147 col2 = max (edit->column1, edit->column2);
1149 diff1 =
1150 edit_move_forward3 (edit, start_bol, col2, 0) - edit_move_forward3 (edit, start_bol,
1151 col1, 0);
1152 diff2 =
1153 edit_move_forward3 (edit, end_bol, col2, 0) - edit_move_forward3 (edit, end_bol,
1154 col1, 0);
1156 *start_mark -= diff1;
1157 *end_mark += diff2;
1158 *start_mark = max (*start_mark, start_eol);
1159 *end_mark = min (*end_mark, end_eol);
1161 return 0;
1163 else
1165 *start_mark = *end_mark = 0;
1166 edit->column2 = edit->column1 = 0;
1167 return 1;
1171 #define space_width 1
1173 void
1174 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
1176 long cursor;
1177 int i, col;
1178 cursor = edit->curs1;
1179 col = edit_get_col (edit);
1180 for (i = 0; i < size; i++)
1182 if (data[i] == '\n')
1183 { /* fill in and move to next line */
1184 int l;
1185 long p;
1186 if (edit_get_byte (edit, edit->curs1) != '\n')
1188 l = width - (edit_get_col (edit) - col);
1189 while (l > 0)
1191 edit_insert (edit, ' ');
1192 l -= space_width;
1195 for (p = edit->curs1;; p++)
1197 if (p == edit->last_byte)
1199 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1200 edit_insert_ahead (edit, '\n');
1201 p++;
1202 break;
1204 if (edit_get_byte (edit, p) == '\n')
1206 p++;
1207 break;
1210 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1211 l = col - edit_get_col (edit);
1212 while (l >= space_width)
1214 edit_insert (edit, ' ');
1215 l -= space_width;
1217 continue;
1219 edit_insert (edit, data[i]);
1221 edit_cursor_move (edit, cursor - edit->curs1);
1224 #define TEMP_BUF_LEN 1024
1227 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1229 long cursor;
1230 int i, col;
1231 int blocklen = -1, width;
1232 unsigned char *data;
1233 cursor = edit->curs1;
1234 col = edit_get_col (edit);
1235 data = g_malloc0 (TEMP_BUF_LEN);
1236 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0)
1238 for (width = 0; width < blocklen; width++)
1240 if (data[width] == '\n')
1241 break;
1243 for (i = 0; i < blocklen; i++)
1245 if (data[i] == '\n')
1246 { /* fill in and move to next line */
1247 int l;
1248 long p;
1249 if (edit_get_byte (edit, edit->curs1) != '\n')
1251 l = width - (edit_get_col (edit) - col);
1252 while (l > 0)
1254 edit_insert (edit, ' ');
1255 l -= space_width;
1258 for (p = edit->curs1;; p++)
1260 if (p == edit->last_byte)
1262 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1263 edit_insert_ahead (edit, '\n');
1264 p++;
1265 break;
1267 if (edit_get_byte (edit, p) == '\n')
1269 p++;
1270 break;
1273 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1274 l = col - edit_get_col (edit);
1275 while (l >= space_width)
1277 edit_insert (edit, ' ');
1278 l -= space_width;
1280 continue;
1282 edit_insert (edit, data[i]);
1285 edit_cursor_move (edit, cursor - edit->curs1);
1286 g_free (data);
1287 edit->force |= REDRAW_PAGE;
1288 return blocklen;
1291 void
1292 edit_block_copy_cmd (WEdit * edit)
1294 long start_mark, end_mark, current = edit->curs1;
1295 int size;
1296 unsigned char *copy_buf;
1298 edit_update_curs_col (edit);
1299 if (eval_marks (edit, &start_mark, &end_mark))
1300 return;
1302 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1304 /* all that gets pushed are deletes hence little space is used on the stack */
1306 edit_push_markers (edit);
1308 if (column_highlighting)
1310 edit_insert_column_of_text (edit, copy_buf, size, abs (edit->column2 - edit->column1));
1312 else
1314 while (size--)
1315 edit_insert_ahead (edit, copy_buf[size]);
1318 g_free (copy_buf);
1319 edit_scroll_screen_over_cursor (edit);
1321 if (column_highlighting)
1323 edit_set_markers (edit, 0, 0, 0, 0);
1324 edit_push_action (edit, COLUMN_ON);
1325 column_highlighting = 0;
1327 else if (start_mark < current && end_mark > current)
1328 edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
1330 edit->force |= REDRAW_PAGE;
1334 void
1335 edit_block_move_cmd (WEdit * edit)
1337 long count;
1338 long current;
1339 unsigned char *copy_buf;
1340 long start_mark, end_mark;
1341 int deleted = 0;
1342 int x = 0;
1344 if (eval_marks (edit, &start_mark, &end_mark))
1345 return;
1346 if (column_highlighting)
1348 edit_update_curs_col (edit);
1349 x = edit->curs_col;
1350 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1351 if ((x > edit->column1 && x < edit->column2)
1352 || (x > edit->column2 && x < edit->column1))
1353 return;
1355 else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1356 return;
1358 if ((end_mark - start_mark) > option_max_undo / 2)
1359 if (edit_query_dialog2
1360 (_("Warning"),
1362 (" Block is large, you may not be able to undo this action. "),
1363 _("C&ontinue"), _("&Cancel")))
1364 return;
1366 edit_push_markers (edit);
1367 current = edit->curs1;
1368 if (column_highlighting)
1370 long line;
1371 int size, c1, c2;
1372 line = edit->curs_line;
1373 if (edit->mark2 < 0)
1374 edit_mark_cmd (edit, 0);
1375 c1 = min (edit->column1, edit->column2);
1376 c2 = max (edit->column1, edit->column2);
1377 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1378 if (x < c2)
1380 edit_block_delete_cmd (edit);
1381 deleted = 1;
1383 edit_move_to_line (edit, line);
1384 edit_cursor_move (edit,
1385 edit_move_forward3 (edit,
1386 edit_bol (edit, edit->curs1), x, 0) - edit->curs1);
1387 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1388 if (!deleted)
1390 line = edit->curs_line;
1391 edit_update_curs_col (edit);
1392 x = edit->curs_col;
1393 edit_block_delete_cmd (edit);
1394 edit_move_to_line (edit, line);
1395 edit_cursor_move (edit,
1396 edit_move_forward3 (edit,
1397 edit_bol (edit,
1398 edit->curs1), x, 0) - edit->curs1);
1400 edit_set_markers (edit, 0, 0, 0, 0);
1401 edit_push_action (edit, COLUMN_ON);
1402 column_highlighting = 0;
1404 else
1406 copy_buf = g_malloc0 (end_mark - start_mark);
1407 edit_cursor_move (edit, start_mark - edit->curs1);
1408 edit_scroll_screen_over_cursor (edit);
1409 count = start_mark;
1410 while (count < end_mark)
1412 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1413 count++;
1415 edit_scroll_screen_over_cursor (edit);
1416 edit_cursor_move (edit,
1417 current - edit->curs1 -
1418 (((current - edit->curs1) > 0) ? end_mark - start_mark : 0));
1419 edit_scroll_screen_over_cursor (edit);
1420 while (count-- > start_mark)
1421 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1422 edit_set_markers (edit, edit->curs1, edit->curs1 + end_mark - start_mark, 0, 0);
1424 edit_scroll_screen_over_cursor (edit);
1425 g_free (copy_buf);
1426 edit->force |= REDRAW_PAGE;
1429 static void
1430 edit_delete_column_of_text (WEdit * edit)
1432 long p, q, r, m1, m2;
1433 long b, c, d, n;
1435 eval_marks (edit, &m1, &m2);
1436 n = edit_move_forward (edit, m1, 0, m2) + 1;
1437 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1438 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1439 b = max (min (c, d), min (edit->column1, edit->column2));
1440 c = max (c, max (edit->column1, edit->column2));
1442 while (n--)
1444 r = edit_bol (edit, edit->curs1);
1445 p = edit_move_forward3 (edit, r, b, 0);
1446 q = edit_move_forward3 (edit, r, c, 0);
1447 if (p < m1)
1448 p = m1;
1449 if (q > m2)
1450 q = m2;
1451 edit_cursor_move (edit, p - edit->curs1);
1452 while (q > p)
1454 /* delete line between margins */
1455 if (edit_get_byte (edit, edit->curs1) != '\n')
1456 edit_delete (edit, 1);
1457 q--;
1459 if (n)
1460 /* move to next line except on the last delete */
1461 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1465 /* if success return 0 */
1466 static int
1467 edit_block_delete (WEdit * edit)
1469 long count;
1470 long start_mark, end_mark;
1471 int curs_pos, line_width;
1472 long curs_line, c1, c2;
1474 if (eval_marks (edit, &start_mark, &end_mark))
1475 return 0;
1476 if (column_highlighting && edit->mark2 < 0)
1477 edit_mark_cmd (edit, 0);
1478 if ((end_mark - start_mark) > option_max_undo / 2)
1480 /* Warning message with a query to continue or cancel the operation */
1481 if (edit_query_dialog2
1482 (_("Warning"),
1484 (" Block is large, you may not be able to undo this action. "),
1485 _("C&ontinue"), _("&Cancel")))
1487 return 1;
1490 c1 = min (edit->column1, edit->column2);
1491 c2 = max (edit->column1, edit->column2);
1492 edit->column1 = c1;
1493 edit->column2 = c2;
1495 edit_push_markers (edit);
1497 curs_line = edit->curs_line;
1499 /* calculate line width and cursor position before cut */
1500 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1501 edit_eol (edit, edit->curs1));
1502 curs_pos = edit->curs_col + edit->over_col;
1504 /* move cursor to start of selection */
1505 edit_cursor_move (edit, start_mark - edit->curs1);
1506 edit_scroll_screen_over_cursor (edit);
1507 count = start_mark;
1508 if (start_mark < end_mark)
1510 if (column_highlighting)
1512 if (edit->mark2 < 0)
1513 edit_mark_cmd (edit, 0);
1514 edit_delete_column_of_text (edit);
1515 /* move cursor to the saved position */
1516 edit_move_to_line (edit, curs_line);
1517 /* calculate line width after cut */
1518 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1519 edit_eol (edit, edit->curs1));
1520 if (option_cursor_beyond_eol && curs_pos > line_width)
1521 edit->over_col = curs_pos - line_width;
1523 else
1525 while (count < end_mark)
1527 edit_delete (edit, 1);
1528 count++;
1532 edit_set_markers (edit, 0, 0, 0, 0);
1533 edit->force |= REDRAW_PAGE;
1534 return 0;
1537 /* returns 1 if canceelled by user */
1539 edit_block_delete_cmd (WEdit * edit)
1541 long start_mark, end_mark;
1542 if (eval_marks (edit, &start_mark, &end_mark))
1544 edit_delete_line (edit);
1545 return 0;
1547 return edit_block_delete (edit);
1550 #define INPUT_INDEX 9
1552 static gboolean
1553 editcmd_find (WEdit * edit, gsize * len)
1555 off_t search_start = edit->search_start;
1556 off_t search_end;
1557 long start_mark = 0;
1558 long end_mark = edit->last_byte;
1559 int mark_res = 0;
1561 if (edit_search_options.only_in_selection)
1563 mark_res = eval_marks (edit, &start_mark, &end_mark);
1564 if (mark_res != 0)
1566 edit->search->error = MC_SEARCH_E_NOTFOUND;
1567 edit->search->error_str = g_strdup (_(" Search string not found "));
1568 return FALSE;
1570 if (edit_search_options.backwards)
1572 if (search_start > end_mark || search_start <= start_mark)
1574 search_start = end_mark;
1577 else
1579 if (search_start < start_mark || search_start >= end_mark)
1581 search_start = start_mark;
1585 else
1587 if (edit_search_options.backwards)
1588 end_mark = max (1, edit->curs1) - 1;
1590 if (edit_search_options.backwards)
1592 search_end = end_mark;
1593 while ((int) search_start >= start_mark)
1595 if (search_end > (off_t) (search_start + edit->search->original_len) &&
1596 mc_search_is_fixed_search_str (edit->search))
1598 search_end = search_start + edit->search->original_len;
1600 if (mc_search_run (edit->search, (void *) edit, search_start, search_end, len)
1601 && edit->search->normal_offset == search_start)
1603 return TRUE;
1605 search_start--;
1607 edit->search->error_str = g_strdup (_(" Search string not found "));
1609 else
1611 return mc_search_run (edit->search, (void *) edit, search_start, end_mark, len);
1613 return FALSE;
1617 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1618 (and the above) routines to work properly - paul */
1620 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1622 static char *
1623 edit_replace_cmd__conv_to_display (char *str)
1625 #ifdef HAVE_CHARSET
1626 GString *tmp;
1627 tmp = str_convert_to_display (str);
1629 if (tmp && tmp->len)
1631 return g_string_free (tmp, FALSE);
1633 g_string_free (tmp, TRUE);
1634 #endif
1635 return g_strdup (str);
1638 static char *
1639 edit_replace_cmd__conv_to_input (char *str)
1641 #ifdef HAVE_CHARSET
1642 GString *tmp;
1643 tmp = str_convert_to_input (str);
1645 if (tmp && tmp->len)
1647 return g_string_free (tmp, FALSE);
1649 g_string_free (tmp, TRUE);
1650 return g_strdup (str);
1651 #endif
1652 return g_strdup (str);
1655 /* call with edit = 0 before shutdown to close memory leaks */
1656 void
1657 edit_replace_cmd (WEdit * edit, int again)
1659 /* 1 = search string, 2 = replace with */
1660 static char *saved1 = NULL; /* saved default[123] */
1661 static char *saved2 = NULL;
1662 char *input1 = NULL; /* user input from the dialog */
1663 char *input2 = NULL;
1664 char *disp1 = NULL;
1665 char *disp2 = NULL;
1666 int replace_yes;
1667 long times_replaced = 0, last_search;
1668 gboolean once_found = FALSE;
1670 if (!edit)
1672 g_free (saved1), saved1 = NULL;
1673 g_free (saved2), saved2 = NULL;
1674 return;
1677 last_search = edit->last_byte;
1679 edit->force |= REDRAW_COMPLETELY;
1681 if (again && !saved1 && !saved2)
1682 again = 0;
1684 if (again)
1686 input1 = g_strdup (saved1 ? saved1 : "");
1687 input2 = g_strdup (saved2 ? saved2 : "");
1689 else
1691 char *tmp_inp1, *tmp_inp2;
1692 disp1 = edit_replace_cmd__conv_to_display (saved1 ? saved1 : (char *) "");
1693 disp2 = edit_replace_cmd__conv_to_display (saved2 ? saved2 : (char *) "");
1695 edit_push_action (edit, KEY_PRESS + edit->start_display);
1697 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2);
1699 g_free (disp1);
1700 g_free (disp2);
1702 if (input1 == NULL || *input1 == '\0')
1704 edit->force = REDRAW_COMPLETELY;
1705 goto cleanup;
1708 tmp_inp1 = input1;
1709 tmp_inp2 = input2;
1710 input1 = edit_replace_cmd__conv_to_input (input1);
1711 input2 = edit_replace_cmd__conv_to_input (input2);
1712 g_free (tmp_inp1);
1713 g_free (tmp_inp2);
1715 g_free (saved1), saved1 = g_strdup (input1);
1716 g_free (saved2), saved2 = g_strdup (input2);
1718 if (edit->search)
1720 mc_search_free (edit->search);
1721 edit->search = NULL;
1725 if (!edit->search)
1727 edit->search = mc_search_new (input1, -1);
1728 if (edit->search == NULL)
1730 edit->search_start = edit->curs1;
1731 return;
1733 edit->search->search_type = edit_search_options.type;
1734 edit->search->is_all_charsets = edit_search_options.all_codepages;
1735 edit->search->is_case_sentitive = edit_search_options.case_sens;
1736 edit->search->whole_words = edit_search_options.whole_words;
1737 edit->search->search_fn = edit_search_cmd_callback;
1740 if (edit->found_len && edit->search_start == edit->found_start + 1
1741 && edit_search_options.backwards)
1742 edit->search_start--;
1744 if (edit->found_len && edit->search_start == edit->found_start - 1
1745 && !edit_search_options.backwards)
1746 edit->search_start++;
1750 gsize len = 0;
1751 long new_start;
1753 if (!editcmd_find (edit, &len))
1755 if (!(edit->search->error == MC_SEARCH_E_OK ||
1756 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND)))
1758 edit_error_dialog (_("Search"), edit->search->error_str);
1760 break;
1762 once_found = TRUE;
1763 new_start = edit->search->normal_offset;
1765 edit->search_start = new_start = edit->search->normal_offset;
1766 /*returns negative on not found or error in pattern */
1768 if (edit->search_start >= 0)
1770 guint i;
1772 edit->found_start = edit->search_start;
1773 i = edit->found_len = len;
1775 edit_cursor_move (edit, edit->search_start - edit->curs1);
1776 edit_scroll_screen_over_cursor (edit);
1778 replace_yes = 1;
1780 if (edit->replace_mode == 0)
1782 int l;
1783 l = edit->curs_row - edit->num_widget_lines / 3;
1784 if (l > 0)
1785 edit_scroll_downward (edit, l);
1786 if (l < 0)
1787 edit_scroll_upward (edit, -l);
1789 edit_scroll_screen_over_cursor (edit);
1790 edit->force |= REDRAW_PAGE;
1791 edit_render_keypress (edit);
1793 /*so that undo stops at each query */
1794 edit_push_key_press (edit);
1795 /* and prompt 2/3 down */
1796 disp1 = edit_replace_cmd__conv_to_display (saved1);
1797 disp2 = edit_replace_cmd__conv_to_display (saved2);
1798 switch (editcmd_dialog_replace_prompt_show (edit, disp1, disp2, -1, -1))
1800 case B_ENTER:
1801 replace_yes = 1;
1802 break;
1803 case B_SKIP_REPLACE:
1804 replace_yes = 0;
1805 break;
1806 case B_REPLACE_ALL:
1807 edit->replace_mode = 1;
1808 break;
1809 case B_CANCEL:
1810 replace_yes = 0;
1811 edit->replace_mode = -1;
1812 break;
1814 g_free (disp1);
1815 g_free (disp2);
1817 if (replace_yes)
1818 { /* delete then insert new */
1819 GString *repl_str, *tmp_str;
1820 tmp_str = g_string_new (input2);
1822 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1823 g_string_free (tmp_str, TRUE);
1824 if (edit->search->error != MC_SEARCH_E_OK)
1826 edit_error_dialog (_("Replace"), edit->search->error_str);
1827 break;
1830 while (i--)
1831 edit_delete (edit, 1);
1833 while (++i < repl_str->len)
1834 edit_insert (edit, repl_str->str[i]);
1836 g_string_free (repl_str, TRUE);
1837 edit->found_len = i;
1839 /* so that we don't find the same string again */
1840 if (edit_search_options.backwards)
1842 last_search = edit->search_start;
1843 edit->search_start--;
1845 else
1847 edit->search_start += i;
1848 last_search = edit->last_byte;
1850 edit_scroll_screen_over_cursor (edit);
1852 else
1854 const char *msg = _(" Replace ");
1855 /* try and find from right here for next search */
1856 edit->search_start = edit->curs1;
1857 edit_update_curs_col (edit);
1859 edit->force |= REDRAW_PAGE;
1860 edit_render_keypress (edit);
1861 if (times_replaced)
1863 message (D_NORMAL, msg, _(" %ld replacements made. "), times_replaced);
1865 else
1866 query_dialog (msg, _(" Search string not found "), D_NORMAL, 1, _("&OK"));
1867 edit->replace_mode = -1;
1870 while (edit->replace_mode >= 0);
1872 edit->force = REDRAW_COMPLETELY;
1873 edit_scroll_screen_over_cursor (edit);
1874 cleanup:
1875 g_free (input1);
1876 g_free (input2);
1880 void
1881 edit_search_cmd (WEdit * edit, int again)
1883 char *search_string = NULL, *search_string_dup = NULL;
1884 gsize len = 0;
1886 if (!edit)
1887 return;
1889 if (edit->search != NULL)
1891 search_string = g_strndup (edit->search->original, edit->search->original_len);
1892 search_string_dup = search_string;
1894 else
1896 GList *history;
1897 history = history_get (MC_HISTORY_SHARED_SEARCH);
1898 if (history != NULL && history->data != NULL)
1900 search_string_dup = search_string = (char *) g_strdup (history->data);
1901 history = g_list_first (history);
1902 g_list_foreach (history, (GFunc) g_free, NULL);
1903 g_list_free (history);
1905 edit->search_start = edit->curs1;
1908 if (!again)
1910 #ifdef HAVE_CHARSET
1911 GString *tmp;
1913 if (search_string && *search_string)
1915 tmp = str_convert_to_display (search_string);
1916 if (tmp != NULL)
1918 if (tmp->len == 0)
1919 g_string_free (tmp, TRUE);
1920 else
1922 g_free (search_string);
1923 search_string = search_string_dup = g_string_free (tmp, FALSE);
1927 #endif /* HAVE_CHARSET */
1928 editcmd_dialog_search_show (edit, &search_string);
1929 g_free (search_string_dup);
1930 search_string_dup = NULL;
1931 #ifdef HAVE_CHARSET
1932 if (search_string && *search_string)
1934 tmp = str_convert_to_input (search_string);
1935 if (tmp != NULL)
1937 if (tmp->len == 0)
1938 g_string_free (tmp, TRUE);
1939 else
1941 g_free (search_string);
1942 search_string = g_string_free (tmp, FALSE);
1946 #endif /* HAVE_CHARSET */
1948 edit_push_action (edit, KEY_PRESS + edit->start_display);
1950 if (search_string == NULL)
1952 edit->force |= REDRAW_COMPLETELY;
1953 edit_scroll_screen_over_cursor (edit);
1954 return;
1957 if (edit->search)
1959 mc_search_free (edit->search);
1960 edit->search = NULL;
1964 if (!edit->search)
1966 edit->search = mc_search_new (search_string, -1);
1967 if (edit->search == NULL)
1969 edit->search_start = edit->curs1;
1970 g_free (search_string);
1971 return;
1974 edit->search->search_type = edit_search_options.type;
1975 edit->search->is_all_charsets = edit_search_options.all_codepages;
1976 edit->search->is_case_sentitive = edit_search_options.case_sens;
1977 edit->search->whole_words = edit_search_options.whole_words;
1978 edit->search->search_fn = edit_search_cmd_callback;
1981 g_free (search_string);
1983 if (search_create_bookmark)
1985 edit_search_cmd_search_create_bookmark (edit);
1987 else
1989 if (edit->found_len && edit->search_start == edit->found_start + 1
1990 && edit_search_options.backwards)
1991 edit->search_start--;
1993 if (edit->found_len && edit->search_start == edit->found_start - 1
1994 && !edit_search_options.backwards)
1995 edit->search_start++;
1997 if (editcmd_find (edit, &len))
1999 edit->found_start = edit->search_start = edit->search->normal_offset;
2000 edit->found_len = len;
2001 edit->over_col = 0;
2002 edit_cursor_move (edit, edit->search_start - edit->curs1);
2003 edit_scroll_screen_over_cursor (edit);
2004 if (edit_search_options.backwards)
2005 edit->search_start--;
2006 else
2007 edit->search_start++;
2009 else
2011 edit->search_start = edit->curs1;
2012 if (edit->search->error_str)
2013 edit_error_dialog (_("Search"), edit->search->error_str);
2017 edit->force |= REDRAW_COMPLETELY;
2018 edit_scroll_screen_over_cursor (edit);
2023 * Check if it's OK to close the editor. If there are unsaved changes,
2024 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2027 edit_ok_to_exit (WEdit * edit)
2029 if (!edit->modified)
2030 return 1;
2032 if (!edit_check_newline (edit))
2033 return 0;
2035 switch (edit_query_dialog3
2036 (_("Quit"), _(" File was modified, Save with exit? "),
2037 _("&Cancel quit"), _("&Yes"), _("&No")))
2039 case 1:
2040 edit_push_markers (edit);
2041 edit_set_markers (edit, 0, 0, 0, 0);
2042 if (!edit_save_cmd (edit))
2043 return 0;
2044 break;
2045 case 2:
2046 break;
2047 case 0:
2048 case -1:
2049 return 0;
2052 return 1;
2055 /* Return a null terminated length of text. Result must be g_free'd */
2056 static unsigned char *
2057 edit_get_block (WEdit * edit, long start, long finish, int *l)
2059 unsigned char *s, *r;
2060 r = s = g_malloc0 (finish - start + 1);
2061 if (column_highlighting)
2063 *l = 0;
2064 /* copy from buffer, excluding chars that are out of the column 'margins' */
2065 while (start < finish)
2067 int c;
2068 long x;
2069 x = edit_move_forward3 (edit, edit_bol (edit, start), 0, start);
2070 c = edit_get_byte (edit, start);
2071 if ((x >= edit->column1 && x < edit->column2)
2072 || (x >= edit->column2 && x < edit->column1) || c == '\n')
2074 *s++ = c;
2075 (*l)++;
2077 start++;
2080 else
2082 *l = finish - start;
2083 while (start < finish)
2084 *s++ = edit_get_byte (edit, start++);
2086 *s = 0;
2087 return r;
2090 /* save block, returns 1 on success */
2092 edit_save_block (WEdit * edit, const char *filename, long start, long finish)
2094 int len, file;
2096 if ((file =
2097 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
2098 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
2099 return 0;
2101 if (column_highlighting)
2103 int r;
2104 r = mc_write (file, VERTICAL_MAGIC, sizeof (VERTICAL_MAGIC));
2105 if (r > 0)
2107 unsigned char *block, *p;
2108 p = block = edit_get_block (edit, start, finish, &len);
2109 while (len)
2111 r = mc_write (file, p, len);
2112 if (r < 0)
2113 break;
2114 p += r;
2115 len -= r;
2117 g_free (block);
2120 else
2122 unsigned char *buf;
2123 int i = start, end;
2124 len = finish - start;
2125 buf = g_malloc0 (TEMP_BUF_LEN);
2126 while (start != finish)
2128 end = min (finish, start + TEMP_BUF_LEN);
2129 for (; i < end; i++)
2130 buf[i - start] = edit_get_byte (edit, i);
2131 len -= mc_write (file, (char *) buf, end - start);
2132 start = end;
2134 g_free (buf);
2136 mc_close (file);
2137 if (len)
2138 return 0;
2139 return 1;
2142 /* copies a block to clipboard file */
2143 static int
2144 edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
2146 int ret;
2147 gchar *tmp;
2148 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2149 ret = edit_save_block (edit, tmp, start, finish);
2150 g_free (tmp);
2151 return ret;
2155 void
2156 edit_paste_from_history (WEdit * edit)
2158 (void) edit;
2159 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
2163 edit_copy_to_X_buf_cmd (WEdit * edit)
2165 long start_mark, end_mark;
2166 if (eval_marks (edit, &start_mark, &end_mark))
2167 return 0;
2168 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
2170 edit_error_dialog (_(" Copy to clipboard "),
2171 get_sys_error (_(" Unable to save to file. ")));
2172 return 1;
2174 edit_mark_cmd (edit, 1);
2175 return 0;
2179 edit_cut_to_X_buf_cmd (WEdit * edit)
2181 long start_mark, end_mark;
2182 if (eval_marks (edit, &start_mark, &end_mark))
2183 return 0;
2184 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
2186 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2187 return 1;
2189 edit_block_delete_cmd (edit);
2190 edit_mark_cmd (edit, 1);
2191 return 0;
2194 void
2195 edit_paste_from_X_buf_cmd (WEdit * edit)
2197 gchar *tmp;
2198 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2199 edit_insert_file (edit, tmp);
2200 g_free (tmp);
2205 * Ask user for the line and go to that line.
2206 * Negative numbers mean line from the end (i.e. -1 is the last line).
2208 void
2209 edit_goto_cmd (WEdit * edit)
2211 char *f;
2212 static long line = 0; /* line as typed, saved as default */
2213 long l;
2214 char *error;
2215 char s[32];
2217 g_snprintf (s, sizeof (s), "%ld", line);
2218 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
2219 line ? s : "");
2220 if (!f)
2221 return;
2223 if (!*f)
2225 g_free (f);
2226 return;
2229 l = strtol (f, &error, 0);
2230 if (*error)
2232 g_free (f);
2233 return;
2236 line = l;
2237 if (l < 0)
2238 l = edit->total_lines + l + 2;
2239 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2240 edit_move_to_line (edit, l - 1);
2241 edit->force |= REDRAW_COMPLETELY;
2242 g_free (f);
2246 /* Return 1 on success */
2248 edit_save_block_cmd (WEdit * edit)
2250 long start_mark, end_mark;
2251 char *exp, *tmp;
2253 if (eval_marks (edit, &start_mark, &end_mark))
2254 return 1;
2256 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2257 exp =
2258 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2259 MC_HISTORY_EDIT_SAVE_BLOCK, tmp);
2260 g_free (tmp);
2261 edit_push_action (edit, KEY_PRESS + edit->start_display);
2262 if (exp)
2264 if (!*exp)
2266 g_free (exp);
2267 return 0;
2269 else
2271 if (edit_save_block (edit, exp, start_mark, end_mark))
2273 g_free (exp);
2274 edit->force |= REDRAW_COMPLETELY;
2275 return 1;
2277 else
2279 g_free (exp);
2280 edit_error_dialog (_(" Save Block "), get_sys_error (_(" Cannot save file. ")));
2284 edit->force |= REDRAW_COMPLETELY;
2285 return 0;
2289 /* returns 1 on success */
2291 edit_insert_file_cmd (WEdit * edit)
2293 gchar *tmp;
2294 char *exp;
2296 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2297 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2298 MC_HISTORY_EDIT_INSERT_FILE, tmp);
2299 g_free (tmp);
2300 edit_push_action (edit, KEY_PRESS + edit->start_display);
2301 if (exp)
2303 if (!*exp)
2305 g_free (exp);
2306 return 0;
2308 else
2310 if (edit_insert_file (edit, exp))
2312 g_free (exp);
2313 edit->force |= REDRAW_COMPLETELY;
2314 return 1;
2316 else
2318 g_free (exp);
2319 edit_error_dialog (_(" Insert File "), get_sys_error (_(" Cannot insert file. ")));
2323 edit->force |= REDRAW_COMPLETELY;
2324 return 0;
2327 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2329 edit_sort_cmd (WEdit * edit)
2331 static char *old = 0;
2332 char *exp, *tmp;
2333 long start_mark, end_mark;
2334 int e;
2336 if (eval_marks (edit, &start_mark, &end_mark))
2338 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2339 return 0;
2342 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2343 edit_save_block (edit, tmp, start_mark, end_mark);
2344 g_free (tmp);
2346 exp = input_dialog (_(" Run Sort "),
2347 _(" Enter sort options (see manpage) separated by whitespace: "),
2348 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2350 if (!exp)
2351 return 1;
2352 g_free (old);
2353 old = exp;
2354 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2355 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2356 e = system (tmp);
2357 g_free (tmp);
2358 if (e)
2360 if (e == -1 || e == 127)
2362 edit_error_dialog (_(" Sort "), get_sys_error (_(" Cannot execute sort command ")));
2364 else
2366 char q[8];
2367 sprintf (q, "%d ", e);
2368 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
2369 edit_error_dialog (_(" Sort "), tmp);
2370 g_free (tmp);
2372 return -1;
2375 edit->force |= REDRAW_COMPLETELY;
2377 if (edit_block_delete_cmd (edit))
2378 return 1;
2379 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2380 edit_insert_file (edit, tmp);
2381 g_free (tmp);
2382 return 0;
2386 * Ask user for a command, execute it and paste its output back to the
2387 * editor.
2390 edit_ext_cmd (WEdit * edit)
2392 char *exp, *tmp;
2393 int e;
2395 exp =
2396 input_dialog (_("Paste output of external command"),
2397 _("Enter shell command(s):"), MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2399 if (!exp)
2400 return 1;
2402 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2403 e = system (tmp);
2404 g_free (tmp);
2405 g_free (exp);
2407 if (e)
2409 edit_error_dialog (_("External command"), get_sys_error (_("Cannot execute command")));
2410 return -1;
2413 edit->force |= REDRAW_COMPLETELY;
2414 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2415 edit_insert_file (edit, tmp);
2416 g_free (tmp);
2417 return 0;
2420 /* if block is 1, a block must be highlighted and the shell command
2421 processes it. If block is 0 the shell command is a straight system
2422 command, that just produces some output which is to be inserted */
2423 void
2424 edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block)
2426 long start_mark, end_mark;
2427 char buf[BUFSIZ];
2428 FILE *script_home = NULL;
2429 FILE *block_file = NULL;
2430 gchar *o, *h, *b, *tmp;
2431 char *quoted_name = NULL;
2433 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2434 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2435 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2437 script_home = fopen (h, "r");
2438 if (script_home == NULL)
2440 FILE *script_src = NULL;
2442 script_home = fopen (h, "w");
2443 if (script_home == NULL)
2445 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2446 edit_error_dialog ("", get_sys_error (tmp));
2447 g_free (tmp);
2448 goto edit_block_process_cmd__EXIT;
2451 script_src = fopen (o, "r");
2452 if (script_src == NULL)
2454 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2455 script_src = fopen (o, "r");
2456 if (script_src == NULL)
2458 fclose (script_home);
2459 unlink (h);
2460 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2461 edit_error_dialog ("", get_sys_error (tmp));
2462 g_free (tmp);
2463 goto edit_block_process_cmd__EXIT;
2466 while (fgets (buf, sizeof (buf), script_src))
2467 fputs (buf, script_home);
2468 fclose (script_src);
2470 if (fclose (script_home))
2472 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2473 edit_error_dialog ("", get_sys_error (tmp));
2474 g_free (tmp);
2475 goto edit_block_process_cmd__EXIT;
2477 chmod (h, 0700);
2478 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2479 edit_error_dialog ("", get_sys_error (tmp));
2480 g_free (tmp);
2483 open_error_pipe ();
2485 if (block)
2486 { /* for marked block run indent formatter */
2487 if (eval_marks (edit, &start_mark, &end_mark))
2489 edit_error_dialog (_("Process block"),
2490 _(" You must first highlight a block of text. "));
2491 goto edit_block_process_cmd__EXIT;
2493 edit_save_block (edit, b, start_mark, end_mark);
2494 quoted_name = name_quote (edit->filename, 0);
2496 * Run script.
2497 * Initial space is to avoid polluting bash history.
2498 * Arguments:
2499 * $1 - name of the edited file (to check its extension etc).
2500 * $2 - file containing the current block.
2501 * $3 - file where error messages should be put
2502 * (for compatibility with old scripts).
2504 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2505 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2506 system (tmp);
2507 g_free (tmp);
2509 else
2512 * No block selected, just execute the command for the file.
2513 * Arguments:
2514 * $1 - name of the edited file.
2516 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2517 quoted_name, (char *) NULL);
2518 system (tmp);
2519 g_free (tmp);
2521 g_free (quoted_name);
2522 close_error_pipe (D_NORMAL, NULL);
2524 edit_refresh_cmd (edit);
2525 edit->force |= REDRAW_COMPLETELY;
2527 /* insert result block */
2528 if (block && !edit_block_delete_cmd (edit))
2530 edit_insert_file (edit, b);
2531 block_file = fopen (b, "w");
2532 if (block_file != NULL)
2533 fclose (block_file);
2536 edit_block_process_cmd__EXIT:
2537 g_free (b);
2538 g_free (h);
2539 g_free (o);
2542 /* prints at the cursor */
2543 /* returns the number of chars printed */
2545 edit_print_string (WEdit * e, const char *s)
2547 size_t i = 0;
2548 while (s[i] != '\0')
2549 edit_execute_cmd (e, CK_Insert_Char, (unsigned char) s[i++]);
2550 e->force |= REDRAW_COMPLETELY;
2551 edit_update_screen (e);
2552 return i;
2556 static void
2557 pipe_mail (WEdit * edit, char *to, char *subject, char *cc)
2559 FILE *p = 0;
2560 char *s;
2562 to = name_quote (to, 0);
2563 subject = name_quote (subject, 0);
2564 cc = name_quote (cc, 0);
2565 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "", cc, " ", to, (char *) NULL);
2566 g_free (to);
2567 g_free (subject);
2568 g_free (cc);
2570 if (s)
2572 p = popen (s, "w");
2573 g_free (s);
2576 if (p)
2578 long i;
2579 for (i = 0; i < edit->last_byte; i++)
2580 fputc (edit_get_byte (edit, i), p);
2581 pclose (p);
2585 #define MAIL_DLG_HEIGHT 12
2587 void
2588 edit_mail_dialog (WEdit * edit)
2590 char *tmail_to;
2591 char *tmail_subject;
2592 char *tmail_cc;
2594 static char *mail_cc_last = 0;
2595 static char *mail_subject_last = 0;
2596 static char *mail_to_last = 0;
2598 QuickWidget quick_widgets[] = {
2599 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2600 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2601 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2602 /* 3 */ QUICK_LABEL (2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to")),
2603 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2",
2604 &tmail_subject),
2605 /* 5 */ QUICK_LABEL (2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject")),
2606 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2607 /* 7 */ QUICK_LABEL (2, 50, 3, MAIL_DLG_HEIGHT, N_(" To")),
2608 /* 8 */ QUICK_LABEL (2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>")),
2609 QUICK_END
2612 QuickDialog Quick_input = {
2613 50, MAIL_DLG_HEIGHT, -1, -1, N_(" Mail "),
2614 "[Input Line Keys]", quick_widgets, FALSE
2617 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2618 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2619 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2621 if (quick_dialog (&Quick_input) != B_CANCEL)
2623 g_free (mail_cc_last);
2624 g_free (mail_subject_last);
2625 g_free (mail_to_last);
2626 mail_cc_last = tmail_cc;
2627 mail_subject_last = tmail_subject;
2628 mail_to_last = tmail_to;
2629 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2634 /*******************/
2635 /* Word Completion */
2636 /*******************/
2638 static gboolean
2639 is_break_char (char c)
2641 return (isspace (c) || strchr ("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2644 /* find first character of current word */
2645 static int
2646 edit_find_word_start (WEdit * edit, long *word_start, gsize * word_len)
2648 int c, last;
2649 gsize i;
2651 /* return if at begin of file */
2652 if (edit->curs1 <= 0)
2653 return 0;
2655 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2656 /* return if not at end or in word */
2657 if (is_break_char (c))
2658 return 0;
2660 /* search start of word to be completed */
2661 for (i = 2;; i++)
2663 /* return if at begin of file */
2664 if ((gsize) edit->curs1 < i)
2665 return 0;
2667 last = c;
2668 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2670 if (is_break_char (c))
2672 /* return if word starts with digit */
2673 if (isdigit (last))
2674 return 0;
2676 *word_start = edit->curs1 - (i - 1); /* start found */
2677 *word_len = i - 1;
2678 break;
2681 /* success */
2682 return 1;
2685 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2687 /* collect the possible completions */
2688 static gsize
2689 edit_collect_completions (WEdit * edit, long start, gsize word_len,
2690 char *match_expr, struct selection *compl, gsize * num)
2692 gsize len = 0;
2693 gsize max_len = 0;
2694 gsize i;
2695 int skip;
2696 GString *temp;
2697 mc_search_t *srch;
2699 long last_byte;
2701 srch = mc_search_new (match_expr, -1);
2702 if (srch == NULL)
2703 return 0;
2705 if (mc_config_get_bool
2706 (mc_main_config, CONFIG_APP_SECTION, "editor_wordcompletion_collect_entire_file", 0))
2708 last_byte = edit->last_byte;
2710 else
2712 last_byte = start;
2715 srch->search_type = MC_SEARCH_T_REGEX;
2716 srch->is_case_sentitive = TRUE;
2717 srch->search_fn = edit_search_cmd_callback;
2719 /* collect max MAX_WORD_COMPLETIONS completions */
2720 start = -1;
2721 while (1)
2723 /* get next match */
2724 if (mc_search_run (srch, (void *) edit, start + 1, last_byte, &len) == FALSE)
2725 break;
2726 start = srch->normal_offset;
2728 /* add matched completion if not yet added */
2729 temp = g_string_new ("");
2730 for (i = 0; i < len; i++)
2732 skip = edit_get_byte (edit, start + i);
2733 if (isspace (skip))
2734 continue;
2735 g_string_append_c (temp, skip);
2738 skip = 0;
2740 for (i = 0; i < (gsize) * num; i++)
2742 if (strncmp
2743 ((char *) &compl[i].text[word_len],
2744 (char *) &temp->str[word_len], max (len, compl[i].len) - (gsize) word_len) == 0)
2746 struct selection this = compl[i];
2747 for (++i; i < *num; i++)
2749 compl[i - 1] = compl[i];
2751 compl[*num - 1] = this;
2752 skip = 1;
2753 break; /* skip it, already added */
2756 if (skip)
2758 g_string_free (temp, TRUE);
2759 continue;
2761 if (*num == MAX_WORD_COMPLETIONS && MAX_WORD_COMPLETIONS)
2763 g_free (compl[0].text);
2764 for (i = 1; i < *num; i++)
2766 compl[i - 1] = compl[i];
2768 (*num)--;
2770 #ifdef HAVE_CHARSET
2772 GString *recoded;
2773 recoded = str_convert_to_display (temp->str);
2775 if (recoded && recoded->len)
2777 g_string_free (temp, TRUE);
2778 temp = recoded;
2780 else
2781 g_string_free (recoded, TRUE);
2783 #endif
2784 compl[*num].text = temp->str;
2785 compl[*num].len = temp->len;
2786 (*num)++;
2787 start += len;
2788 g_string_free (temp, FALSE);
2790 /* note the maximal length needed for the completion dialog */
2791 if (len > max_len)
2792 max_len = len;
2794 mc_search_free (srch);
2795 return max_len;
2799 * Complete current word using regular expression search
2800 * backwards beginning at the current cursor position.
2802 void
2803 edit_complete_word_cmd (WEdit * edit)
2805 gsize i, max_len, word_len = 0, num_compl = 0;
2806 long word_start = 0;
2807 unsigned char *bufpos;
2808 char *match_expr;
2809 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2811 /* search start of word to be completed */
2812 if (!edit_find_word_start (edit, &word_start, &word_len))
2813 return;
2815 /* prepare match expression */
2816 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE][word_start & M_EDIT_BUF_SIZE];
2818 /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
2819 match_expr =
2820 g_strdup_printf
2821 ("(^|\\s+|\\b)%.*s[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+",
2822 (int) word_len, bufpos);
2824 /* collect the possible completions */
2825 /* start search from begin to end of file */
2826 max_len =
2827 edit_collect_completions (edit, word_start, word_len, match_expr,
2828 (struct selection *) &compl, &num_compl);
2830 if (num_compl > 0)
2832 /* insert completed word if there is only one match */
2833 if (num_compl == 1)
2835 for (i = word_len; i < compl[0].len; i++)
2836 edit_insert (edit, *(compl[0].text + i));
2838 /* more than one possible completion => ask the user */
2839 else
2841 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2842 /* !!! pressed again the selection dialog pops up, but that !!! */
2843 /* !!! seems to require a further internal state !!! */
2844 /*tty_beep (); */
2846 /* let the user select the preferred completion */
2847 editcmd_dialog_completion_show (edit, max_len, word_len,
2848 (struct selection *) &compl, num_compl);
2852 g_free (match_expr);
2853 /* release memory before return */
2854 for (i = 0; i < num_compl; i++)
2855 g_free (compl[i].text);
2858 void
2859 edit_select_codepage_cmd (WEdit * edit)
2861 #ifdef HAVE_CHARSET
2862 const char *cp_id = NULL;
2863 if (do_select_codepage ())
2865 cp_id = get_codepage_id (source_codepage >= 0 ? source_codepage : display_codepage);
2867 if (cp_id != NULL)
2869 GIConv conv;
2870 conv = str_crt_conv_from (cp_id);
2871 if (conv != INVALID_CONV)
2873 if (edit->converter != str_cnv_from_term)
2874 str_close_conv (edit->converter);
2875 edit->converter = conv;
2879 if (cp_id != NULL)
2880 edit->utf8 = str_isutf8 (cp_id);
2883 edit->force = REDRAW_COMPLETELY;
2884 edit_refresh_cmd (edit);
2885 #else
2886 (void) edit;
2887 #endif
2890 void
2891 edit_insert_literal_cmd (WEdit * edit)
2893 int char_for_insertion = editcmd_dialog_raw_key_query (_(" Insert Literal "),
2894 _(" Press any key: "), 0);
2895 edit_execute_key_command (edit, -1, ascii_alpha_to_cntrl (char_for_insertion));
2898 void
2899 edit_execute_macro_cmd (WEdit * edit)
2901 int command =
2902 CK_Macro (editcmd_dialog_raw_key_query (_(" Execute Macro "), _(" Press macro hotkey: "),
2903 1));
2904 if (command == CK_Macro (0))
2905 command = CK_Insert_Char;
2907 edit_execute_key_command (edit, command, -1);
2910 void
2911 edit_begin_end_macro_cmd (WEdit * edit)
2913 /* edit is a pointer to the widget */
2914 if (edit)
2916 unsigned long command = edit->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2917 edit_execute_key_command (edit, command, -1);
2922 edit_load_forward_cmd (WEdit * edit)
2924 if (edit->modified)
2926 if (edit_query_dialog2
2927 (_("Warning"),
2928 _(" Current text was modified without a file save. \n"
2929 " Continue discards these changes. "), _("C&ontinue"), _("&Cancel")))
2931 edit->force |= REDRAW_COMPLETELY;
2932 return 0;
2935 if (edit_stack_iterator + 1 < MAX_HISTORY_MOVETO)
2937 if (edit_history_moveto[edit_stack_iterator + 1].line < 1)
2939 return 1;
2941 edit_stack_iterator++;
2942 if (edit_history_moveto[edit_stack_iterator].filename)
2944 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2945 edit_history_moveto[edit_stack_iterator].line);
2946 return 0;
2948 else
2950 return 1;
2953 else
2955 return 1;
2960 edit_load_back_cmd (WEdit * edit)
2962 if (edit->modified)
2964 if (edit_query_dialog2
2965 (_("Warning"),
2966 _(" Current text was modified without a file save. \n"
2967 " Continue discards these changes. "), _("C&ontinue"), _("&Cancel")))
2969 edit->force |= REDRAW_COMPLETELY;
2970 return 0;
2973 if (edit_stack_iterator > 0)
2975 edit_stack_iterator--;
2976 if (edit_history_moveto[edit_stack_iterator].filename)
2978 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2979 edit_history_moveto[edit_stack_iterator].line);
2980 return 0;
2982 else
2984 return 1;
2987 else
2989 return 1;
2993 void
2994 edit_get_match_keyword_cmd (WEdit * edit)
2996 gsize word_len = 0, max_len = 0;
2997 int num_def = 0;
2998 int i;
2999 long word_start = 0;
3000 unsigned char *bufpos;
3001 char *match_expr;
3002 char *path = NULL;
3003 char *ptr = NULL;
3004 char *tagfile = NULL;
3006 etags_hash_t def_hash[MAX_DEFINITIONS];
3008 for (i = 0; i < MAX_DEFINITIONS; i++)
3010 def_hash[i].filename = NULL;
3013 /* search start of word to be completed */
3014 if (!edit_find_word_start (edit, &word_start, &word_len))
3015 return;
3017 /* prepare match expression */
3018 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE][word_start & M_EDIT_BUF_SIZE];
3019 match_expr = g_strdup_printf ("%.*s", (int) word_len, bufpos);
3021 ptr = g_get_current_dir ();
3022 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
3023 g_free (ptr);
3025 /* Recursive search file 'TAGS' in parent dirs */
3028 ptr = g_path_get_dirname (path);
3029 g_free (path);
3030 path = ptr;
3031 g_free (tagfile);
3032 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
3033 if (exist_file (tagfile))
3034 break;
3036 while (strcmp (path, G_DIR_SEPARATOR_S) != 0);
3038 if (tagfile)
3040 num_def =
3041 etags_set_definition_hash (tagfile, path, match_expr, (etags_hash_t *) & def_hash);
3042 g_free (tagfile);
3044 g_free (path);
3046 max_len = MAX_WIDTH_DEF_DIALOG;
3047 word_len = 0;
3048 if (num_def > 0)
3050 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
3051 (etags_hash_t *) & def_hash, num_def);
3053 g_free (match_expr);
3056 void
3057 edit_move_block_to_right (WEdit * edit)
3059 long start_mark, end_mark;
3060 long cur_bol, start_bol;
3062 if (eval_marks (edit, &start_mark, &end_mark))
3063 return;
3065 start_bol = edit_bol (edit, start_mark);
3066 cur_bol = edit_bol (edit, end_mark - 1);
3069 edit_cursor_move (edit, cur_bol - edit->curs1);
3070 if (option_fill_tabs_with_spaces)
3072 if (option_fake_half_tabs)
3074 insert_spaces_tab (edit, 1);
3076 else
3078 insert_spaces_tab (edit, 0);
3081 else
3083 edit_insert (edit, '\t');
3085 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
3086 if (cur_bol == 0)
3088 break;
3090 cur_bol = edit_bol (edit, cur_bol - 1);
3092 while (cur_bol >= start_bol);
3093 edit->force |= REDRAW_PAGE;
3096 void
3097 edit_move_block_to_left (WEdit * edit)
3099 long start_mark, end_mark;
3100 long cur_bol, start_bol;
3101 int i, del_tab_width;
3102 int next_char;
3104 if (eval_marks (edit, &start_mark, &end_mark))
3105 return;
3107 start_bol = edit_bol (edit, start_mark);
3108 cur_bol = edit_bol (edit, end_mark - 1);
3111 edit_cursor_move (edit, cur_bol - edit->curs1);
3112 if (option_fake_half_tabs)
3114 del_tab_width = HALF_TAB_SIZE;
3116 else
3118 del_tab_width = option_tab_spacing;
3120 next_char = edit_get_byte (edit, edit->curs1);
3121 if (next_char == '\t')
3123 edit_delete (edit, 1);
3125 else if (next_char == ' ')
3127 for (i = 1; i <= del_tab_width; i++)
3129 if (next_char == ' ')
3131 edit_delete (edit, 1);
3133 next_char = edit_get_byte (edit, edit->curs1);
3136 if (cur_bol == 0)
3138 break;
3140 cur_bol = edit_bol (edit, cur_bol - 1);
3142 while (cur_bol >= start_bol);
3143 edit->force |= REDRAW_PAGE;