Ticket #2127: updated file extension for "sh"
[midnight-commander.git] / src / editor / editcmd.c
blob7a8eef0a342da1c3e9fa4ac3fb57646954e91ac9
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 int ret;
278 ret = mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
279 ret = mc_chmod (savename, edit->stat1.st_mode);
282 fd = mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, edit->stat1.st_mode);
283 if (fd == -1)
284 goto error_save;
286 /* pipe save */
287 p = edit_get_write_filter (savename, real_filename);
288 if (p != NULL)
290 FILE *file;
292 mc_close (fd);
293 file = (FILE *) popen (p, "w");
295 if (file)
297 filelen = edit_write_stream (edit, file);
298 #if 1
299 pclose (file);
300 #else
301 if (pclose (file) != 0)
303 tmp = g_strconcat (_(" Error writing to pipe: "), p, " ", (char *) NULL);
304 edit_error_dialog (_("Error"), tmp);
305 g_free (tmp);
306 g_free (p);
307 goto error_save;
309 #endif
311 else
313 tmp = g_strconcat (_(" Cannot open pipe for writing: "), p, " ", (char *) NULL);
315 edit_error_dialog (_("Error"), get_sys_error (tmp));
316 g_free (p);
317 g_free (tmp);
318 goto error_save;
320 g_free (p);
322 else if (edit->lb == LB_ASIS)
323 { /* do not change line breaks */
324 long buf;
325 buf = 0;
326 filelen = edit->last_byte;
327 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1)
329 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE)
331 mc_close (fd);
332 goto error_save;
334 buf++;
336 if (mc_write
337 (fd, (char *) edit->buffers1[buf],
338 edit->curs1 & M_EDIT_BUF_SIZE) != (edit->curs1 & M_EDIT_BUF_SIZE))
340 filelen = -1;
342 else if (edit->curs2)
344 edit->curs2--;
345 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
346 if (mc_write
347 (fd,
348 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
349 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
350 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) != 1 + (edit->curs2 & M_EDIT_BUF_SIZE))
352 filelen = -1;
354 else
356 while (--buf >= 0)
358 if (mc_write (fd, (char *) edit->buffers2[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE)
360 filelen = -1;
361 break;
365 edit->curs2++;
367 if (mc_close (fd))
368 goto error_save;
370 /* Update the file information, especially the mtime. */
371 if (mc_stat (savename, &edit->stat1) == -1)
372 goto error_save;
374 else
375 { /* change line breaks */
376 FILE *file;
378 mc_close (fd);
380 file = (FILE *) fopen (savename, "w");
382 if (file)
384 filelen = edit_write_stream (edit, file);
385 fclose (file);
387 else
389 char *msg;
391 msg = g_strdup_printf (_(" Cannot open file for writing: %s "), savename);
392 edit_error_dialog (_("Error"), msg);
393 g_free (msg);
394 goto error_save;
398 if (filelen != edit->last_byte)
399 goto error_save;
401 if (this_save_mode == EDIT_DO_BACKUP)
403 assert (option_backup_ext != NULL);
404 tmp = g_strconcat (real_filename, option_backup_ext, (char *) NULL);
405 if (mc_rename (real_filename, tmp) == -1)
407 g_free (tmp);
408 goto error_save;
412 if (this_save_mode != EDIT_QUICK_SAVE)
413 if (mc_rename (savename, real_filename) == -1)
414 goto error_save;
415 g_free (savename);
416 g_free (real_filename);
417 return 1;
418 error_save:
419 /* FIXME: Is this safe ?
420 * if (this_save_mode != EDIT_QUICK_SAVE)
421 * mc_unlink (savename);
423 g_free (real_filename);
424 g_free (savename);
425 return 0;
428 void
429 menu_save_mode_cmd (void)
431 /* diaog sizes */
432 const int DLG_X = 38;
433 const int DLG_Y = 13;
435 char *str_result;
437 const char *str[] = {
438 N_("&Quick save"),
439 N_("&Safe save"),
440 N_("&Do backups with following extension:")
443 QuickWidget widgets[] = {
444 /* 0 */
445 QUICK_BUTTON (18, DLG_X, DLG_Y - 3, DLG_Y, N_("&Cancel"), B_CANCEL, NULL),
446 /* 1 */
447 QUICK_BUTTON (6, DLG_X, DLG_Y - 3, DLG_Y, N_("&OK"), B_ENTER, NULL),
448 /* 2 */
449 QUICK_CHECKBOX (4, DLG_X, 8, DLG_Y, N_("Check &POSIX new line"), &option_check_nl_at_eof),
450 /* 3 */
451 QUICK_INPUT (8, DLG_X, 6, DLG_Y, option_backup_ext, 9, 0, "edit-backup-ext", &str_result),
452 /* 4 */
453 QUICK_RADIO (4, DLG_X, 3, DLG_Y, 3, str, &option_save_mode),
454 QUICK_END
457 QuickDialog dialog = {
458 DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "),
459 "[Edit Save Mode]", widgets, FALSE
462 size_t i;
463 size_t maxlen = 0;
464 size_t w0, w1, b_len, w3;
466 assert (option_backup_ext != NULL);
468 /* OK/Cancel buttons */
469 w0 = str_term_width1 (_(widgets[0].u.button.text)) + 3;
470 w1 = str_term_width1 (_(widgets[1].u.button.text)) + 5; /* default button */
471 b_len = w0 + w1 + 3;
473 maxlen = max (b_len, (size_t) str_term_width1 (_(dialog.title)) + 2);
475 w3 = 0;
476 for (i = 0; i < 3; i++)
478 #ifdef ENABLE_NLS
479 str[i] = _(str[i]);
480 #endif
481 w3 = max (w3, (size_t) str_term_width1 (str[i]));
484 maxlen = max (maxlen, w3 + 4);
486 dialog.xlen = min ((size_t) COLS, maxlen + 8);
488 widgets[3].u.input.len = w3;
489 widgets[1].relative_x = (dialog.xlen - b_len) / 2;
490 widgets[0].relative_x = widgets[1].relative_x + w0 + 2;
492 for (i = 0; i < sizeof (widgets) / sizeof (widgets[0]); i++)
493 widgets[i].x_divisions = dialog.xlen;
495 if (quick_dialog (&dialog) != B_CANCEL)
497 g_free (option_backup_ext);
498 option_backup_ext = str_result;
502 void
503 edit_set_filename (WEdit * edit, const char *f)
505 g_free (edit->filename);
506 if (!f)
507 f = "";
508 edit->filename = g_strdup (f);
509 if (edit->dir == NULL && *f != PATH_SEP)
510 #ifdef ENABLE_VFS
511 edit->dir = g_strdup (vfs_get_current_dir ());
512 #else /* ENABLE_VFS */
513 edit->dir = g_get_current_dir ();
514 #endif /* ENABLE_VFS */
517 static gboolean
518 edit_check_newline (WEdit * edit)
520 return !(option_check_nl_at_eof && edit->last_byte > 0
521 && edit_get_byte (edit, edit->last_byte - 1) != '\n'
522 && edit_query_dialog2 (_("Warning"),
523 _("The file you are saving is not finished with a newline"),
524 _("C&ontinue"), _("&Cancel")));
527 static char *
528 edit_get_save_file_as (WEdit * edit)
530 #define DLG_WIDTH 64
531 #define DLG_HEIGHT 14
533 static LineBreaks cur_lb = LB_ASIS;
535 char *filename = edit->filename;
537 const char *lb_names[LB_NAMES] = {
538 N_("&Do not change"),
539 N_("&Unix format (LF)"),
540 N_("&Windows/DOS format (CR LF)"),
541 N_("&Macintosh format (CR)")
544 QuickWidget quick_widgets[] = {
545 QUICK_BUTTON (6, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
546 QUICK_BUTTON (2, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
547 QUICK_RADIO (5, DLG_WIDTH, DLG_HEIGHT - 8, DLG_HEIGHT, LB_NAMES, lb_names, (int *) &cur_lb),
548 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 9, DLG_HEIGHT, N_("Change line breaks to:")),
549 QUICK_INPUT (3, DLG_WIDTH, DLG_HEIGHT - 11, DLG_HEIGHT, filename, DLG_WIDTH - 6, 0,
550 "save-as", &filename),
551 QUICK_LABEL (2, DLG_WIDTH, DLG_HEIGHT - 12, DLG_HEIGHT, N_(" Enter file name: ")),
552 QUICK_END
555 QuickDialog Quick_options = {
556 DLG_WIDTH, DLG_HEIGHT, -1, -1,
557 N_(" Save As "), "[Save File As]",
558 quick_widgets, FALSE
561 if (quick_dialog (&Quick_options) != B_CANCEL)
563 edit->lb = cur_lb;
564 return filename;
567 return NULL;
569 #undef DLG_WIDTH
570 #undef DLG_HEIGHT
573 /* Here we want to warn the users of overwriting an existing file,
574 but only if they have made a change to the filename */
575 /* returns 1 on success */
577 edit_save_as_cmd (WEdit * edit)
579 /* This heads the 'Save As' dialog box */
580 char *exp;
581 int save_lock = 0;
582 int different_filename = 0;
584 if (!edit_check_newline (edit))
585 return 0;
587 exp = edit_get_save_file_as (edit);
588 edit_push_action (edit, KEY_PRESS + edit->start_display);
590 if (exp)
592 if (!*exp)
594 g_free (exp);
595 edit->force |= REDRAW_COMPLETELY;
596 return 0;
598 else
600 int rv;
601 if (strcmp (edit->filename, exp))
603 int file;
604 different_filename = 1;
605 file = mc_open (exp, O_RDONLY | O_BINARY);
606 if (file != -1)
608 /* the file exists */
609 mc_close (file);
610 /* Overwrite the current file or cancel the operation */
611 if (edit_query_dialog2
612 (_("Warning"),
613 _(" A file already exists with this name. "),
614 _("&Overwrite"), _("&Cancel")))
616 edit->force |= REDRAW_COMPLETELY;
617 g_free (exp);
618 return 0;
621 else
623 edit->stat1.st_mode |= S_IWUSR;
625 save_lock = edit_lock_file (exp);
627 else
629 /* filenames equal, check if already locked */
630 if (!edit->locked && !edit->delete_file)
631 save_lock = edit_lock_file (exp);
634 if (different_filename)
637 * Allow user to write into saved (under another name) file
638 * even if original file had r/o user permissions.
640 edit->stat1.st_mode |= S_IWRITE;
643 rv = edit_save_file (edit, exp);
644 switch (rv)
646 case 1:
647 /* Succesful, so unlock both files */
648 if (different_filename)
650 if (save_lock)
651 edit_unlock_file (exp);
652 if (edit->locked)
653 edit->locked = edit_unlock_file (edit->filename);
655 else
657 if (edit->locked || save_lock)
658 edit->locked = edit_unlock_file (edit->filename);
661 edit_set_filename (edit, exp);
662 if (edit->lb != LB_ASIS)
663 edit_reload (edit, exp);
664 g_free (exp);
665 edit->modified = 0;
666 edit->delete_file = 0;
667 if (different_filename)
668 edit_load_syntax (edit, NULL, edit->syntax_type);
669 edit->force |= REDRAW_COMPLETELY;
670 return 1;
671 default:
672 edit_error_dialog (_(" Save As "), get_sys_error (_(" Cannot save file. ")));
673 /* fallthrough */
674 case -1:
675 /* Failed, so maintain modify (not save) lock */
676 if (save_lock)
677 edit_unlock_file (exp);
678 g_free (exp);
679 edit->force |= REDRAW_COMPLETELY;
680 return 0;
684 edit->force |= REDRAW_COMPLETELY;
685 return 0;
688 /* {{{ Macro stuff starts here */
690 /* creates a macro file if it doesn't exist */
691 static FILE *
692 edit_open_macro_file (const char *r)
694 gchar *filename;
695 FILE *fd;
696 int file;
697 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
698 file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
699 if (file == -1)
701 g_free (filename);
702 return 0;
704 close (file);
705 fd = fopen (filename, r);
706 g_free (filename);
707 return fd;
710 #define MAX_MACROS 1024
711 static int saved_macro[MAX_MACROS + 1];
712 static int saved_macros_loaded = 0;
715 This is just to stop the macro file be loaded over and over for keys
716 that aren't defined to anything. On slow systems this could be annoying.
718 static int
719 macro_exists (int k)
721 int i;
722 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
723 if (saved_macro[i] == k)
724 return i;
725 return -1;
728 /* returns 1 on error */
729 static int
730 edit_delete_macro (WEdit * edit, int k)
732 gchar *tmp, *tmp2;
733 struct macro macro[MAX_MACRO_LENGTH];
734 FILE *f, *g;
735 int s, i, n, j = 0;
737 (void) edit;
739 if (saved_macros_loaded)
741 j = macro_exists (k);
742 if (j < 0)
743 return 0;
745 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
746 g = fopen (tmp, "w");
747 g_free (tmp);
748 if (!g)
750 edit_error_dialog (_(" Delete macro "), get_sys_error (_(" Cannot open temp file ")));
751 return 1;
753 f = edit_open_macro_file ("r");
754 if (!f)
756 edit_error_dialog (_(" Delete macro "), get_sys_error (_(" Cannot open macro file ")));
757 fclose (g);
758 return 1;
760 for (;;)
762 n = fscanf (f, ("key '%d 0': "), &s);
763 if (!n || n == EOF)
764 break;
765 n = 0;
766 while (fscanf (f, "%lu %d, ", &macro[n].command, &macro[n].ch))
767 n++;
769 int ret;
770 ret = fscanf (f, ";\n");
772 if (s != k)
774 fprintf (g, ("key '%d 0': "), s);
775 for (i = 0; i < n; i++)
776 fprintf (g, "%lu %d, ", macro[i].command, macro[i].ch);
777 fprintf (g, ";\n");
780 fclose (f);
781 fclose (g);
782 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
783 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
784 if (rename (tmp, tmp2) == -1)
786 edit_error_dialog (_(" Delete macro "), get_sys_error (_(" Cannot overwrite macro file ")));
787 g_free (tmp);
788 g_free (tmp2);
789 return 1;
791 g_free (tmp);
792 g_free (tmp2);
794 if (saved_macros_loaded)
795 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
796 return 0;
799 /* returns 0 on error */
801 edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
803 FILE *f;
804 int s, i;
806 edit_push_action (edit, KEY_PRESS + edit->start_display);
807 s = editcmd_dialog_raw_key_query (_(" Save macro "), _(" Press the macro's new hotkey: "), 1);
808 edit->force |= REDRAW_COMPLETELY;
809 if (s)
811 if (edit_delete_macro (edit, s))
812 return 0;
813 f = edit_open_macro_file ("a+");
814 if (f)
816 fprintf (f, ("key '%d 0': "), s);
817 for (i = 0; i < n; i++)
818 fprintf (f, "%lu %d, ", macro[i].command, macro[i].ch);
819 fprintf (f, ";\n");
820 fclose (f);
821 if (saved_macros_loaded)
823 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
824 saved_macro[i] = s;
826 return 1;
828 else
829 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
831 return 0;
834 void
835 edit_delete_macro_cmd (WEdit * edit)
837 int command;
839 command = editcmd_dialog_raw_key_query (_(" Delete macro "), _(" Press macro hotkey: "), 1);
841 if (command != 0)
842 edit_delete_macro (edit, command);
845 /* return 0 on error */
847 edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
849 FILE *f;
850 int s, i = 0, found = 0;
852 (void) edit;
854 if (saved_macros_loaded)
855 if (macro_exists (k) < 0)
856 return 0;
858 f = edit_open_macro_file ("r");
859 if (f != NULL)
861 struct macro dummy;
864 int u;
865 u = fscanf (f, ("key '%d 0': "), &s);
866 if (!u || u == EOF)
867 break;
868 if (!saved_macros_loaded)
869 saved_macro[i++] = s;
870 if (!found)
872 *n = 0;
873 while (*n < MAX_MACRO_LENGTH
874 && 2 == fscanf (f, "%lu %d, ", &macro[*n].command, &macro[*n].ch))
875 (*n)++;
877 else
879 while (2 == fscanf (f, "%lu %d, ", &dummy.command, &dummy.ch));
882 int ret;
883 ret = fscanf (f, ";\n");
885 if (s == k)
886 found = 1;
888 while (!found || !saved_macros_loaded);
889 if (!saved_macros_loaded)
891 saved_macro[i] = 0;
892 saved_macros_loaded = 1;
894 fclose (f);
895 return found;
897 else
898 edit_error_dialog (_(" Load macro "), get_sys_error (_(" Cannot open macro file ")));
899 return 0;
902 /* }}} Macro stuff starts here */
904 /* returns 1 on success */
906 edit_save_confirm_cmd (WEdit * edit)
908 gchar *f = NULL;
910 if (!edit_check_newline (edit))
911 return 0;
913 if (edit_confirm_save)
915 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", (char *) NULL);
916 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel")))
918 g_free (f);
919 return 0;
921 g_free (f);
923 return edit_save_cmd (edit);
927 /* returns 1 on success */
928 static int
929 edit_save_cmd (WEdit * edit)
931 int res, save_lock = 0;
933 if (!edit->locked && !edit->delete_file)
934 save_lock = edit_lock_file (edit->filename);
935 res = edit_save_file (edit, edit->filename);
937 /* Maintain modify (not save) lock on failure */
938 if ((res > 0 && edit->locked) || save_lock)
939 edit->locked = edit_unlock_file (edit->filename);
941 /* On failure try 'save as', it does locking on its own */
942 if (!res)
943 return edit_save_as_cmd (edit);
944 edit->force |= REDRAW_COMPLETELY;
945 if (res > 0)
947 edit->delete_file = 0;
948 edit->modified = 0;
951 return 1;
955 /* returns 1 on success */
957 edit_new_cmd (WEdit * edit)
959 if (edit->modified)
961 if (edit_query_dialog2
962 (_("Warning"),
964 (" Current text was modified without a file save. \n Continue discards these changes. "),
965 _("C&ontinue"), _("&Cancel")))
967 edit->force |= REDRAW_COMPLETELY;
968 return 0;
971 edit->force |= REDRAW_COMPLETELY;
973 return edit_renew (edit); /* if this gives an error, something has really screwed up */
976 /* returns 1 on error */
977 static int
978 edit_load_file_from_filename (WEdit * edit, char *exp)
980 int prev_locked = edit->locked;
981 char *prev_filename = g_strdup (edit->filename);
983 if (!edit_reload (edit, exp))
985 g_free (prev_filename);
986 return 1;
989 if (prev_locked)
990 edit_unlock_file (prev_filename);
991 g_free (prev_filename);
992 return 0;
995 static void
996 edit_load_syntax_file (WEdit * edit)
998 char *extdir;
999 int dir = 0;
1001 if (geteuid () == 0)
1003 dir = query_dialog (_("Syntax file edit"),
1004 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
1005 _("&User"), _("&System Wide"));
1008 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
1009 if (!exist_file (extdir))
1011 g_free (extdir);
1012 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
1015 if (dir == 0)
1017 char *buffer;
1019 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
1020 check_for_default (extdir, buffer);
1021 edit_load_file_from_filename (edit, buffer);
1022 g_free (buffer);
1024 else if (dir == 1)
1025 edit_load_file_from_filename (edit, extdir);
1027 g_free (extdir);
1030 static void
1031 edit_load_menu_file (WEdit * edit)
1033 char *buffer;
1034 char *menufile;
1035 int dir = 0;
1037 dir = query_dialog (_(" Menu edit "),
1038 _(" Which menu file do you want to edit? "), D_NORMAL,
1039 geteuid ()? 2 : 3, _("&Local"), _("&User"), _("&System Wide"));
1041 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
1043 if (!exist_file (menufile))
1045 g_free (menufile);
1046 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
1049 switch (dir)
1051 case 0:
1052 buffer = g_strdup (EDIT_LOCAL_MENU);
1053 check_for_default (menufile, buffer);
1054 chmod (buffer, 0600);
1055 break;
1057 case 1:
1058 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
1059 check_for_default (menufile, buffer);
1060 break;
1062 case 2:
1063 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
1064 if (!exist_file (buffer))
1066 g_free (buffer);
1067 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
1069 break;
1071 default:
1072 g_free (menufile);
1073 return;
1076 edit_load_file_from_filename (edit, buffer);
1078 g_free (buffer);
1079 g_free (menufile);
1083 edit_load_cmd (WEdit * edit, edit_current_file_t what)
1085 char *exp;
1087 if (edit->modified
1088 && (edit_query_dialog2
1089 (_("Warning"),
1090 _(" Current text was modified without a file save. \n"
1091 " Continue discards these changes. "), _("C&ontinue"), _("&Cancel")) == 1))
1093 edit->force |= REDRAW_COMPLETELY;
1094 return 0;
1097 switch (what)
1099 case EDIT_FILE_COMMON:
1100 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
1101 MC_HISTORY_EDIT_LOAD, edit->filename);
1103 if (exp)
1105 if (*exp)
1106 edit_load_file_from_filename (edit, exp);
1107 g_free (exp);
1109 break;
1111 case EDIT_FILE_SYNTAX:
1112 edit_load_syntax_file (edit);
1113 break;
1115 case EDIT_FILE_MENU:
1116 edit_load_menu_file (edit);
1117 break;
1119 default:
1120 break;
1123 edit->force |= REDRAW_COMPLETELY;
1124 return 0;
1128 if mark2 is -1 then marking is from mark1 to the cursor.
1129 Otherwise its between the markers. This handles this.
1130 Returns 1 if no text is marked.
1133 eval_marks (WEdit * edit, long *start_mark, long *end_mark)
1135 if (edit->mark1 != edit->mark2)
1137 long start_bol, start_eol;
1138 long end_bol, end_eol;
1139 long col1, col2;
1140 long diff1, diff2;
1141 if (edit->mark2 >= 0)
1143 *start_mark = min (edit->mark1, edit->mark2);
1144 *end_mark = max (edit->mark1, edit->mark2);
1146 else
1148 *start_mark = min (edit->mark1, edit->curs1);
1149 *end_mark = max (edit->mark1, edit->curs1);
1150 edit->column2 = edit->curs_col + edit->over_col;
1152 if (column_highlighting
1153 && (((edit->mark1 > edit->curs1) && (edit->column1 < edit->column2))
1154 || ((edit->mark1 < edit->curs1) && (edit->column1 > edit->column2))))
1157 start_bol = edit_bol (edit, *start_mark);
1158 start_eol = edit_eol (edit, start_bol - 1) + 1;
1159 end_bol = edit_bol (edit, *end_mark);
1160 end_eol = edit_eol (edit, *end_mark);
1161 col1 = min (edit->column1, edit->column2);
1162 col2 = max (edit->column1, edit->column2);
1164 diff1 =
1165 edit_move_forward3 (edit, start_bol, col2, 0) - edit_move_forward3 (edit, start_bol,
1166 col1, 0);
1167 diff2 =
1168 edit_move_forward3 (edit, end_bol, col2, 0) - edit_move_forward3 (edit, end_bol,
1169 col1, 0);
1171 *start_mark -= diff1;
1172 *end_mark += diff2;
1173 *start_mark = max (*start_mark, start_eol);
1174 *end_mark = min (*end_mark, end_eol);
1176 return 0;
1178 else
1180 *start_mark = *end_mark = 0;
1181 edit->column2 = edit->column1 = 0;
1182 return 1;
1186 #define space_width 1
1188 void
1189 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
1191 long cursor;
1192 int i, col;
1193 cursor = edit->curs1;
1194 col = edit_get_col (edit);
1195 for (i = 0; i < size; i++)
1197 if (data[i] == '\n')
1198 { /* fill in and move to next line */
1199 int l;
1200 long p;
1201 if (edit_get_byte (edit, edit->curs1) != '\n')
1203 l = width - (edit_get_col (edit) - col);
1204 while (l > 0)
1206 edit_insert (edit, ' ');
1207 l -= space_width;
1210 for (p = edit->curs1;; p++)
1212 if (p == edit->last_byte)
1214 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1215 edit_insert_ahead (edit, '\n');
1216 p++;
1217 break;
1219 if (edit_get_byte (edit, p) == '\n')
1221 p++;
1222 break;
1225 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1226 l = col - edit_get_col (edit);
1227 while (l >= space_width)
1229 edit_insert (edit, ' ');
1230 l -= space_width;
1232 continue;
1234 edit_insert (edit, data[i]);
1236 edit_cursor_move (edit, cursor - edit->curs1);
1239 #define TEMP_BUF_LEN 1024
1242 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1244 long cursor;
1245 int i, col;
1246 int blocklen = -1, width;
1247 unsigned char *data;
1248 cursor = edit->curs1;
1249 col = edit_get_col (edit);
1250 data = g_malloc0 (TEMP_BUF_LEN);
1251 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0)
1253 for (width = 0; width < blocklen; width++)
1255 if (data[width] == '\n')
1256 break;
1258 for (i = 0; i < blocklen; i++)
1260 if (data[i] == '\n')
1261 { /* fill in and move to next line */
1262 int l;
1263 long p;
1264 if (edit_get_byte (edit, edit->curs1) != '\n')
1266 l = width - (edit_get_col (edit) - col);
1267 while (l > 0)
1269 edit_insert (edit, ' ');
1270 l -= space_width;
1273 for (p = edit->curs1;; p++)
1275 if (p == edit->last_byte)
1277 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1278 edit_insert_ahead (edit, '\n');
1279 p++;
1280 break;
1282 if (edit_get_byte (edit, p) == '\n')
1284 p++;
1285 break;
1288 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1289 l = col - edit_get_col (edit);
1290 while (l >= space_width)
1292 edit_insert (edit, ' ');
1293 l -= space_width;
1295 continue;
1297 edit_insert (edit, data[i]);
1300 edit_cursor_move (edit, cursor - edit->curs1);
1301 g_free (data);
1302 edit->force |= REDRAW_PAGE;
1303 return blocklen;
1306 void
1307 edit_block_copy_cmd (WEdit * edit)
1309 long start_mark, end_mark, current = edit->curs1;
1310 int size;
1311 unsigned char *copy_buf;
1313 edit_update_curs_col (edit);
1314 if (eval_marks (edit, &start_mark, &end_mark))
1315 return;
1317 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1319 /* all that gets pushed are deletes hence little space is used on the stack */
1321 edit_push_markers (edit);
1323 if (column_highlighting)
1325 edit_insert_column_of_text (edit, copy_buf, size, abs (edit->column2 - edit->column1));
1327 else
1329 while (size--)
1330 edit_insert_ahead (edit, copy_buf[size]);
1333 g_free (copy_buf);
1334 edit_scroll_screen_over_cursor (edit);
1336 if (column_highlighting)
1338 edit_set_markers (edit, 0, 0, 0, 0);
1339 edit_push_action (edit, COLUMN_ON);
1340 column_highlighting = 0;
1342 else if (start_mark < current && end_mark > current)
1343 edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
1345 edit->force |= REDRAW_PAGE;
1349 void
1350 edit_block_move_cmd (WEdit * edit)
1352 long count;
1353 long current;
1354 unsigned char *copy_buf;
1355 long start_mark, end_mark;
1356 int deleted = 0;
1357 int x = 0;
1359 if (eval_marks (edit, &start_mark, &end_mark))
1360 return;
1361 if (column_highlighting)
1363 edit_update_curs_col (edit);
1364 x = edit->curs_col;
1365 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1366 if ((x > edit->column1 && x < edit->column2)
1367 || (x > edit->column2 && x < edit->column1))
1368 return;
1370 else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1371 return;
1373 if ((end_mark - start_mark) > option_max_undo / 2)
1374 if (edit_query_dialog2
1375 (_("Warning"),
1377 (" Block is large, you may not be able to undo this action. "),
1378 _("C&ontinue"), _("&Cancel")))
1379 return;
1381 edit_push_markers (edit);
1382 current = edit->curs1;
1383 if (column_highlighting)
1385 long line;
1386 int size, c1, c2;
1387 line = edit->curs_line;
1388 if (edit->mark2 < 0)
1389 edit_mark_cmd (edit, 0);
1390 c1 = min (edit->column1, edit->column2);
1391 c2 = max (edit->column1, edit->column2);
1392 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1393 if (x < c2)
1395 edit_block_delete_cmd (edit);
1396 deleted = 1;
1398 edit_move_to_line (edit, line);
1399 edit_cursor_move (edit,
1400 edit_move_forward3 (edit,
1401 edit_bol (edit, edit->curs1), x, 0) - edit->curs1);
1402 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1403 if (!deleted)
1405 line = edit->curs_line;
1406 edit_update_curs_col (edit);
1407 x = edit->curs_col;
1408 edit_block_delete_cmd (edit);
1409 edit_move_to_line (edit, line);
1410 edit_cursor_move (edit,
1411 edit_move_forward3 (edit,
1412 edit_bol (edit,
1413 edit->curs1), x, 0) - edit->curs1);
1415 edit_set_markers (edit, 0, 0, 0, 0);
1416 edit_push_action (edit, COLUMN_ON);
1417 column_highlighting = 0;
1419 else
1421 copy_buf = g_malloc0 (end_mark - start_mark);
1422 edit_cursor_move (edit, start_mark - edit->curs1);
1423 edit_scroll_screen_over_cursor (edit);
1424 count = start_mark;
1425 while (count < end_mark)
1427 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1428 count++;
1430 edit_scroll_screen_over_cursor (edit);
1431 edit_cursor_move (edit,
1432 current - edit->curs1 -
1433 (((current - edit->curs1) > 0) ? end_mark - start_mark : 0));
1434 edit_scroll_screen_over_cursor (edit);
1435 while (count-- > start_mark)
1436 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1437 edit_set_markers (edit, edit->curs1, edit->curs1 + end_mark - start_mark, 0, 0);
1439 edit_scroll_screen_over_cursor (edit);
1440 g_free (copy_buf);
1441 edit->force |= REDRAW_PAGE;
1444 static void
1445 edit_delete_column_of_text (WEdit * edit)
1447 long p, q, r, m1, m2;
1448 long b, c, d, n;
1450 eval_marks (edit, &m1, &m2);
1451 n = edit_move_forward (edit, m1, 0, m2) + 1;
1452 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1453 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1454 b = max (min (c, d), min (edit->column1, edit->column2));
1455 c = max (c, max (edit->column1, edit->column2));
1457 while (n--)
1459 r = edit_bol (edit, edit->curs1);
1460 p = edit_move_forward3 (edit, r, b, 0);
1461 q = edit_move_forward3 (edit, r, c, 0);
1462 if (p < m1)
1463 p = m1;
1464 if (q > m2)
1465 q = m2;
1466 edit_cursor_move (edit, p - edit->curs1);
1467 while (q > p)
1469 /* delete line between margins */
1470 if (edit_get_byte (edit, edit->curs1) != '\n')
1471 edit_delete (edit, 1);
1472 q--;
1474 if (n)
1475 /* move to next line except on the last delete */
1476 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1480 /* if success return 0 */
1481 static int
1482 edit_block_delete (WEdit * edit)
1484 long count;
1485 long start_mark, end_mark;
1486 int curs_pos, line_width;
1487 long curs_line, c1, c2;
1489 if (eval_marks (edit, &start_mark, &end_mark))
1490 return 0;
1491 if (column_highlighting && edit->mark2 < 0)
1492 edit_mark_cmd (edit, 0);
1493 if ((end_mark - start_mark) > option_max_undo / 2)
1495 /* Warning message with a query to continue or cancel the operation */
1496 if (edit_query_dialog2
1497 (_("Warning"),
1499 (" Block is large, you may not be able to undo this action. "),
1500 _("C&ontinue"), _("&Cancel")))
1502 return 1;
1505 c1 = min (edit->column1, edit->column2);
1506 c2 = max (edit->column1, edit->column2);
1507 edit->column1 = c1;
1508 edit->column2 = c2;
1510 edit_push_markers (edit);
1512 curs_line = edit->curs_line;
1514 /* calculate line width and cursor position before cut */
1515 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1516 edit_eol (edit, edit->curs1));
1517 curs_pos = edit->curs_col + edit->over_col;
1519 /* move cursor to start of selection */
1520 edit_cursor_move (edit, start_mark - edit->curs1);
1521 edit_scroll_screen_over_cursor (edit);
1522 count = start_mark;
1523 if (start_mark < end_mark)
1525 if (column_highlighting)
1527 if (edit->mark2 < 0)
1528 edit_mark_cmd (edit, 0);
1529 edit_delete_column_of_text (edit);
1530 /* move cursor to the saved position */
1531 edit_move_to_line (edit, curs_line);
1532 /* calculate line width after cut */
1533 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1534 edit_eol (edit, edit->curs1));
1535 if (option_cursor_beyond_eol && curs_pos > line_width)
1536 edit->over_col = curs_pos - line_width;
1538 else
1540 while (count < end_mark)
1542 edit_delete (edit, 1);
1543 count++;
1547 edit_set_markers (edit, 0, 0, 0, 0);
1548 edit->force |= REDRAW_PAGE;
1549 return 0;
1552 /* returns 1 if canceelled by user */
1554 edit_block_delete_cmd (WEdit * edit)
1556 long start_mark, end_mark;
1557 if (eval_marks (edit, &start_mark, &end_mark))
1559 edit_delete_line (edit);
1560 return 0;
1562 return edit_block_delete (edit);
1565 #define INPUT_INDEX 9
1567 static gboolean
1568 editcmd_find (WEdit * edit, gsize * len)
1570 off_t search_start = edit->search_start;
1571 off_t search_end;
1572 long start_mark = 0;
1573 long end_mark = edit->last_byte;
1574 int mark_res = 0;
1576 if (edit_search_options.only_in_selection)
1578 mark_res = eval_marks (edit, &start_mark, &end_mark);
1579 if (mark_res != 0)
1581 edit->search->error = MC_SEARCH_E_NOTFOUND;
1582 edit->search->error_str = g_strdup (_(" Search string not found "));
1583 return FALSE;
1585 if (edit_search_options.backwards)
1587 if (search_start > end_mark || search_start <= start_mark)
1589 search_start = end_mark;
1592 else
1594 if (search_start < start_mark || search_start >= end_mark)
1596 search_start = start_mark;
1600 else
1602 if (edit_search_options.backwards)
1603 end_mark = max (1, edit->curs1) - 1;
1605 if (edit_search_options.backwards)
1607 search_end = end_mark;
1608 while ((int) search_start >= start_mark)
1610 if (search_end > (off_t) (search_start + edit->search->original_len) &&
1611 mc_search_is_fixed_search_str (edit->search))
1613 search_end = search_start + edit->search->original_len;
1615 if (mc_search_run (edit->search, (void *) edit, search_start, search_end, len)
1616 && edit->search->normal_offset == search_start)
1618 return TRUE;
1620 search_start--;
1622 edit->search->error_str = g_strdup (_(" Search string not found "));
1624 else
1626 return mc_search_run (edit->search, (void *) edit, search_start, end_mark, len);
1628 return FALSE;
1632 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1633 (and the above) routines to work properly - paul */
1635 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1637 static char *
1638 edit_replace_cmd__conv_to_display (char *str)
1640 #ifdef HAVE_CHARSET
1641 GString *tmp;
1642 tmp = str_convert_to_display (str);
1644 if (tmp && tmp->len)
1646 return g_string_free (tmp, FALSE);
1648 g_string_free (tmp, TRUE);
1649 #endif
1650 return g_strdup (str);
1653 static char *
1654 edit_replace_cmd__conv_to_input (char *str)
1656 #ifdef HAVE_CHARSET
1657 GString *tmp;
1658 tmp = str_convert_to_input (str);
1660 if (tmp && tmp->len)
1662 return g_string_free (tmp, FALSE);
1664 g_string_free (tmp, TRUE);
1665 return g_strdup (str);
1666 #endif
1667 return g_strdup (str);
1670 /* call with edit = 0 before shutdown to close memory leaks */
1671 void
1672 edit_replace_cmd (WEdit * edit, int again)
1674 /* 1 = search string, 2 = replace with */
1675 static char *saved1 = NULL; /* saved default[123] */
1676 static char *saved2 = NULL;
1677 char *input1 = NULL; /* user input from the dialog */
1678 char *input2 = NULL;
1679 char *disp1 = NULL;
1680 char *disp2 = NULL;
1681 int replace_yes;
1682 long times_replaced = 0, last_search;
1683 gboolean once_found = FALSE;
1685 if (!edit)
1687 g_free (saved1), saved1 = NULL;
1688 g_free (saved2), saved2 = NULL;
1689 return;
1692 last_search = edit->last_byte;
1694 edit->force |= REDRAW_COMPLETELY;
1696 if (again && !saved1 && !saved2)
1697 again = 0;
1699 if (again)
1701 input1 = g_strdup (saved1 ? saved1 : "");
1702 input2 = g_strdup (saved2 ? saved2 : "");
1704 else
1706 char *tmp_inp1, *tmp_inp2;
1707 disp1 = edit_replace_cmd__conv_to_display (saved1 ? saved1 : (char *) "");
1708 disp2 = edit_replace_cmd__conv_to_display (saved2 ? saved2 : (char *) "");
1710 edit_push_action (edit, KEY_PRESS + edit->start_display);
1712 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2);
1714 g_free (disp1);
1715 g_free (disp2);
1717 if (input1 == NULL || *input1 == '\0')
1719 edit->force = REDRAW_COMPLETELY;
1720 goto cleanup;
1723 tmp_inp1 = input1;
1724 tmp_inp2 = input2;
1725 input1 = edit_replace_cmd__conv_to_input (input1);
1726 input2 = edit_replace_cmd__conv_to_input (input2);
1727 g_free (tmp_inp1);
1728 g_free (tmp_inp2);
1730 g_free (saved1), saved1 = g_strdup (input1);
1731 g_free (saved2), saved2 = g_strdup (input2);
1733 if (edit->search)
1735 mc_search_free (edit->search);
1736 edit->search = NULL;
1740 if (!edit->search)
1742 edit->search = mc_search_new (input1, -1);
1743 if (edit->search == NULL)
1745 edit->search_start = edit->curs1;
1746 return;
1748 edit->search->search_type = edit_search_options.type;
1749 edit->search->is_all_charsets = edit_search_options.all_codepages;
1750 edit->search->is_case_sensitive = edit_search_options.case_sens;
1751 edit->search->whole_words = edit_search_options.whole_words;
1752 edit->search->search_fn = edit_search_cmd_callback;
1755 if (edit->found_len && edit->search_start == edit->found_start + 1
1756 && edit_search_options.backwards)
1757 edit->search_start--;
1759 if (edit->found_len && edit->search_start == edit->found_start - 1
1760 && !edit_search_options.backwards)
1761 edit->search_start++;
1765 gsize len = 0;
1766 long new_start;
1768 if (!editcmd_find (edit, &len))
1770 if (!(edit->search->error == MC_SEARCH_E_OK ||
1771 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND)))
1773 edit_error_dialog (_("Search"), edit->search->error_str);
1775 break;
1777 once_found = TRUE;
1778 new_start = edit->search->normal_offset;
1780 edit->search_start = new_start = edit->search->normal_offset;
1781 /*returns negative on not found or error in pattern */
1783 if (edit->search_start >= 0)
1785 guint i;
1787 edit->found_start = edit->search_start;
1788 i = edit->found_len = len;
1790 edit_cursor_move (edit, edit->search_start - edit->curs1);
1791 edit_scroll_screen_over_cursor (edit);
1793 replace_yes = 1;
1795 if (edit->replace_mode == 0)
1797 int l;
1798 l = edit->curs_row - edit->num_widget_lines / 3;
1799 if (l > 0)
1800 edit_scroll_downward (edit, l);
1801 if (l < 0)
1802 edit_scroll_upward (edit, -l);
1804 edit_scroll_screen_over_cursor (edit);
1805 edit->force |= REDRAW_PAGE;
1806 edit_render_keypress (edit);
1808 /*so that undo stops at each query */
1809 edit_push_key_press (edit);
1810 /* and prompt 2/3 down */
1811 disp1 = edit_replace_cmd__conv_to_display (saved1);
1812 disp2 = edit_replace_cmd__conv_to_display (saved2);
1813 switch (editcmd_dialog_replace_prompt_show (edit, disp1, disp2, -1, -1))
1815 case B_ENTER:
1816 replace_yes = 1;
1817 break;
1818 case B_SKIP_REPLACE:
1819 replace_yes = 0;
1820 break;
1821 case B_REPLACE_ALL:
1822 edit->replace_mode = 1;
1823 break;
1824 case B_CANCEL:
1825 replace_yes = 0;
1826 edit->replace_mode = -1;
1827 break;
1829 g_free (disp1);
1830 g_free (disp2);
1832 if (replace_yes)
1833 { /* delete then insert new */
1834 GString *repl_str, *tmp_str;
1835 tmp_str = g_string_new (input2);
1837 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1838 g_string_free (tmp_str, TRUE);
1839 if (edit->search->error != MC_SEARCH_E_OK)
1841 edit_error_dialog (_("Replace"), edit->search->error_str);
1842 break;
1845 while (i--)
1846 edit_delete (edit, 1);
1848 while (++i < repl_str->len)
1849 edit_insert (edit, repl_str->str[i]);
1851 g_string_free (repl_str, TRUE);
1852 edit->found_len = i;
1854 /* so that we don't find the same string again */
1855 if (edit_search_options.backwards)
1857 last_search = edit->search_start;
1858 edit->search_start--;
1860 else
1862 edit->search_start += i;
1863 last_search = edit->last_byte;
1865 edit_scroll_screen_over_cursor (edit);
1867 else
1869 const char *msg = _(" Replace ");
1870 /* try and find from right here for next search */
1871 edit->search_start = edit->curs1;
1872 edit_update_curs_col (edit);
1874 edit->force |= REDRAW_PAGE;
1875 edit_render_keypress (edit);
1876 if (times_replaced)
1878 message (D_NORMAL, msg, _(" %ld replacements made. "), times_replaced);
1880 else
1881 query_dialog (msg, _(" Search string not found "), D_NORMAL, 1, _("&OK"));
1882 edit->replace_mode = -1;
1885 while (edit->replace_mode >= 0);
1887 edit->force = REDRAW_COMPLETELY;
1888 edit_scroll_screen_over_cursor (edit);
1889 cleanup:
1890 g_free (input1);
1891 g_free (input2);
1895 void
1896 edit_search_cmd (WEdit * edit, int again)
1898 char *search_string = NULL, *search_string_dup = NULL;
1899 gsize len = 0;
1901 if (!edit)
1902 return;
1904 if (edit->search != NULL)
1906 search_string = g_strndup (edit->search->original, edit->search->original_len);
1907 search_string_dup = search_string;
1909 else
1911 GList *history;
1912 history = history_get (MC_HISTORY_SHARED_SEARCH);
1913 if (history != NULL && history->data != NULL)
1915 search_string_dup = search_string = (char *) g_strdup (history->data);
1916 history = g_list_first (history);
1917 g_list_foreach (history, (GFunc) g_free, NULL);
1918 g_list_free (history);
1920 edit->search_start = edit->curs1;
1923 if (!again)
1925 #ifdef HAVE_CHARSET
1926 GString *tmp;
1928 if (search_string && *search_string)
1930 tmp = str_convert_to_display (search_string);
1931 if (tmp != NULL)
1933 if (tmp->len == 0)
1934 g_string_free (tmp, TRUE);
1935 else
1937 g_free (search_string);
1938 search_string = search_string_dup = g_string_free (tmp, FALSE);
1942 #endif /* HAVE_CHARSET */
1943 editcmd_dialog_search_show (edit, &search_string);
1944 g_free (search_string_dup);
1945 search_string_dup = NULL;
1946 #ifdef HAVE_CHARSET
1947 if (search_string && *search_string)
1949 tmp = str_convert_to_input (search_string);
1950 if (tmp != NULL)
1952 if (tmp->len == 0)
1953 g_string_free (tmp, TRUE);
1954 else
1956 g_free (search_string);
1957 search_string = g_string_free (tmp, FALSE);
1961 #endif /* HAVE_CHARSET */
1963 edit_push_action (edit, KEY_PRESS + edit->start_display);
1965 if (search_string == NULL)
1967 edit->force |= REDRAW_COMPLETELY;
1968 edit_scroll_screen_over_cursor (edit);
1969 return;
1972 if (edit->search)
1974 mc_search_free (edit->search);
1975 edit->search = NULL;
1979 if (!edit->search)
1981 edit->search = mc_search_new (search_string, -1);
1982 if (edit->search == NULL)
1984 edit->search_start = edit->curs1;
1985 g_free (search_string);
1986 return;
1989 edit->search->search_type = edit_search_options.type;
1990 edit->search->is_all_charsets = edit_search_options.all_codepages;
1991 edit->search->is_case_sensitive = edit_search_options.case_sens;
1992 edit->search->whole_words = edit_search_options.whole_words;
1993 edit->search->search_fn = edit_search_cmd_callback;
1996 g_free (search_string);
1998 if (search_create_bookmark)
2000 edit_search_cmd_search_create_bookmark (edit);
2002 else
2004 if (edit->found_len && edit->search_start == edit->found_start + 1
2005 && edit_search_options.backwards)
2006 edit->search_start--;
2008 if (edit->found_len && edit->search_start == edit->found_start - 1
2009 && !edit_search_options.backwards)
2010 edit->search_start++;
2012 if (editcmd_find (edit, &len))
2014 edit->found_start = edit->search_start = edit->search->normal_offset;
2015 edit->found_len = len;
2016 edit->over_col = 0;
2017 edit_cursor_move (edit, edit->search_start - edit->curs1);
2018 edit_scroll_screen_over_cursor (edit);
2019 if (edit_search_options.backwards)
2020 edit->search_start--;
2021 else
2022 edit->search_start++;
2024 else
2026 edit->search_start = edit->curs1;
2027 if (edit->search->error_str)
2028 edit_error_dialog (_("Search"), edit->search->error_str);
2032 edit->force |= REDRAW_COMPLETELY;
2033 edit_scroll_screen_over_cursor (edit);
2038 * Check if it's OK to close the editor. If there are unsaved changes,
2039 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2042 edit_ok_to_exit (WEdit * edit)
2044 if (!edit->modified)
2045 return 1;
2047 if (!edit_check_newline (edit))
2048 return 0;
2050 switch (edit_query_dialog3
2051 (_("Quit"), _(" File was modified, Save with exit? "),
2052 _("&Cancel quit"), _("&Yes"), _("&No")))
2054 case 1:
2055 edit_push_markers (edit);
2056 edit_set_markers (edit, 0, 0, 0, 0);
2057 if (!edit_save_cmd (edit))
2058 return 0;
2059 break;
2060 case 2:
2061 break;
2062 case 0:
2063 case -1:
2064 return 0;
2067 return 1;
2070 /* Return a null terminated length of text. Result must be g_free'd */
2071 static unsigned char *
2072 edit_get_block (WEdit * edit, long start, long finish, int *l)
2074 unsigned char *s, *r;
2075 r = s = g_malloc0 (finish - start + 1);
2076 if (column_highlighting)
2078 *l = 0;
2079 /* copy from buffer, excluding chars that are out of the column 'margins' */
2080 while (start < finish)
2082 int c;
2083 long x;
2084 x = edit_move_forward3 (edit, edit_bol (edit, start), 0, start);
2085 c = edit_get_byte (edit, start);
2086 if ((x >= edit->column1 && x < edit->column2)
2087 || (x >= edit->column2 && x < edit->column1) || c == '\n')
2089 *s++ = c;
2090 (*l)++;
2092 start++;
2095 else
2097 *l = finish - start;
2098 while (start < finish)
2099 *s++ = edit_get_byte (edit, start++);
2101 *s = 0;
2102 return r;
2105 /* save block, returns 1 on success */
2107 edit_save_block (WEdit * edit, const char *filename, long start, long finish)
2109 int len, file;
2111 file = mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
2112 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY);
2113 if (file == -1)
2114 return 0;
2116 if (column_highlighting)
2118 int r;
2119 r = mc_write (file, VERTICAL_MAGIC, sizeof (VERTICAL_MAGIC));
2120 if (r > 0)
2122 unsigned char *block, *p;
2123 p = block = edit_get_block (edit, start, finish, &len);
2124 while (len)
2126 r = mc_write (file, p, len);
2127 if (r < 0)
2128 break;
2129 p += r;
2130 len -= r;
2132 g_free (block);
2135 else
2137 unsigned char *buf;
2138 int i = start, end;
2139 len = finish - start;
2140 buf = g_malloc0 (TEMP_BUF_LEN);
2141 while (start != finish)
2143 end = min (finish, start + TEMP_BUF_LEN);
2144 for (; i < end; i++)
2145 buf[i - start] = edit_get_byte (edit, i);
2146 len -= mc_write (file, (char *) buf, end - start);
2147 start = end;
2149 g_free (buf);
2151 mc_close (file);
2152 if (len)
2153 return 0;
2154 return 1;
2157 /* copies a block to clipboard file */
2158 static int
2159 edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
2161 int ret;
2162 gchar *tmp;
2163 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2164 ret = edit_save_block (edit, tmp, start, finish);
2165 g_free (tmp);
2166 return ret;
2170 void
2171 edit_paste_from_history (WEdit * edit)
2173 (void) edit;
2174 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
2178 edit_copy_to_X_buf_cmd (WEdit * edit)
2180 long start_mark, end_mark;
2181 if (eval_marks (edit, &start_mark, &end_mark))
2182 return 0;
2183 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
2185 edit_error_dialog (_(" Copy to clipboard "),
2186 get_sys_error (_(" Unable to save to file. ")));
2187 return 1;
2189 edit_mark_cmd (edit, 1);
2190 return 0;
2194 edit_cut_to_X_buf_cmd (WEdit * edit)
2196 long start_mark, end_mark;
2197 if (eval_marks (edit, &start_mark, &end_mark))
2198 return 0;
2199 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
2201 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2202 return 1;
2204 edit_block_delete_cmd (edit);
2205 edit_mark_cmd (edit, 1);
2206 return 0;
2209 void
2210 edit_paste_from_X_buf_cmd (WEdit * edit)
2212 gchar *tmp;
2213 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2214 edit_insert_file (edit, tmp);
2215 g_free (tmp);
2220 * Ask user for the line and go to that line.
2221 * Negative numbers mean line from the end (i.e. -1 is the last line).
2223 void
2224 edit_goto_cmd (WEdit * edit)
2226 char *f;
2227 static long line = 0; /* line as typed, saved as default */
2228 long l;
2229 char *error;
2230 char s[32];
2232 g_snprintf (s, sizeof (s), "%ld", line);
2233 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
2234 line ? s : "");
2235 if (!f)
2236 return;
2238 if (!*f)
2240 g_free (f);
2241 return;
2244 l = strtol (f, &error, 0);
2245 if (*error)
2247 g_free (f);
2248 return;
2251 line = l;
2252 if (l < 0)
2253 l = edit->total_lines + l + 2;
2254 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2255 edit_move_to_line (edit, l - 1);
2256 edit->force |= REDRAW_COMPLETELY;
2257 g_free (f);
2261 /* Return 1 on success */
2263 edit_save_block_cmd (WEdit * edit)
2265 long start_mark, end_mark;
2266 char *exp, *tmp;
2268 if (eval_marks (edit, &start_mark, &end_mark))
2269 return 1;
2271 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2272 exp =
2273 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2274 MC_HISTORY_EDIT_SAVE_BLOCK, tmp);
2275 g_free (tmp);
2276 edit_push_action (edit, KEY_PRESS + edit->start_display);
2277 if (exp)
2279 if (!*exp)
2281 g_free (exp);
2282 return 0;
2284 else
2286 if (edit_save_block (edit, exp, start_mark, end_mark))
2288 g_free (exp);
2289 edit->force |= REDRAW_COMPLETELY;
2290 return 1;
2292 else
2294 g_free (exp);
2295 edit_error_dialog (_(" Save Block "), get_sys_error (_(" Cannot save file. ")));
2299 edit->force |= REDRAW_COMPLETELY;
2300 return 0;
2304 /* returns 1 on success */
2306 edit_insert_file_cmd (WEdit * edit)
2308 gchar *tmp;
2309 char *exp;
2311 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2312 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2313 MC_HISTORY_EDIT_INSERT_FILE, tmp);
2314 g_free (tmp);
2315 edit_push_action (edit, KEY_PRESS + edit->start_display);
2316 if (exp)
2318 if (!*exp)
2320 g_free (exp);
2321 return 0;
2323 else
2325 if (edit_insert_file (edit, exp))
2327 g_free (exp);
2328 edit->force |= REDRAW_COMPLETELY;
2329 return 1;
2331 else
2333 g_free (exp);
2334 edit_error_dialog (_(" Insert File "), get_sys_error (_(" Cannot insert file. ")));
2338 edit->force |= REDRAW_COMPLETELY;
2339 return 0;
2342 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2344 edit_sort_cmd (WEdit * edit)
2346 static char *old = 0;
2347 char *exp, *tmp;
2348 long start_mark, end_mark;
2349 int e;
2351 if (eval_marks (edit, &start_mark, &end_mark))
2353 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2354 return 0;
2357 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2358 edit_save_block (edit, tmp, start_mark, end_mark);
2359 g_free (tmp);
2361 exp = input_dialog (_(" Run Sort "),
2362 _(" Enter sort options (see manpage) separated by whitespace: "),
2363 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2365 if (!exp)
2366 return 1;
2367 g_free (old);
2368 old = exp;
2369 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2370 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2371 e = system (tmp);
2372 g_free (tmp);
2373 if (e)
2375 if (e == -1 || e == 127)
2377 edit_error_dialog (_(" Sort "), get_sys_error (_(" Cannot execute sort command ")));
2379 else
2381 char q[8];
2382 sprintf (q, "%d ", e);
2383 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
2384 edit_error_dialog (_(" Sort "), tmp);
2385 g_free (tmp);
2387 return -1;
2390 edit->force |= REDRAW_COMPLETELY;
2392 if (edit_block_delete_cmd (edit))
2393 return 1;
2394 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2395 edit_insert_file (edit, tmp);
2396 g_free (tmp);
2397 return 0;
2401 * Ask user for a command, execute it and paste its output back to the
2402 * editor.
2405 edit_ext_cmd (WEdit * edit)
2407 char *exp, *tmp;
2408 int e;
2410 exp =
2411 input_dialog (_("Paste output of external command"),
2412 _("Enter shell command(s):"), MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2414 if (!exp)
2415 return 1;
2417 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2418 e = system (tmp);
2419 g_free (tmp);
2420 g_free (exp);
2422 if (e)
2424 edit_error_dialog (_("External command"), get_sys_error (_("Cannot execute command")));
2425 return -1;
2428 edit->force |= REDRAW_COMPLETELY;
2429 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2430 edit_insert_file (edit, tmp);
2431 g_free (tmp);
2432 return 0;
2435 /* if block is 1, a block must be highlighted and the shell command
2436 processes it. If block is 0 the shell command is a straight system
2437 command, that just produces some output which is to be inserted */
2438 void
2439 edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block)
2441 long start_mark, end_mark;
2442 char buf[BUFSIZ];
2443 FILE *script_home = NULL;
2444 FILE *block_file = NULL;
2445 gchar *o, *h, *b, *tmp;
2446 char *quoted_name = NULL;
2448 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2449 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2450 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2452 script_home = fopen (h, "r");
2453 if (script_home == NULL)
2455 FILE *script_src = NULL;
2457 script_home = fopen (h, "w");
2458 if (script_home == NULL)
2460 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2461 edit_error_dialog ("", get_sys_error (tmp));
2462 g_free (tmp);
2463 goto edit_block_process_cmd__EXIT;
2466 script_src = fopen (o, "r");
2467 if (script_src == NULL)
2469 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2470 script_src = fopen (o, "r");
2471 if (script_src == NULL)
2473 fclose (script_home);
2474 unlink (h);
2475 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2476 edit_error_dialog ("", get_sys_error (tmp));
2477 g_free (tmp);
2478 goto edit_block_process_cmd__EXIT;
2481 while (fgets (buf, sizeof (buf), script_src))
2482 fputs (buf, script_home);
2483 fclose (script_src);
2485 if (fclose (script_home))
2487 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2488 edit_error_dialog ("", get_sys_error (tmp));
2489 g_free (tmp);
2490 goto edit_block_process_cmd__EXIT;
2492 chmod (h, 0700);
2493 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2494 edit_error_dialog ("", get_sys_error (tmp));
2495 g_free (tmp);
2498 open_error_pipe ();
2500 if (block)
2501 { /* for marked block run indent formatter */
2502 if (eval_marks (edit, &start_mark, &end_mark))
2504 edit_error_dialog (_("Process block"),
2505 _(" You must first highlight a block of text. "));
2506 goto edit_block_process_cmd__EXIT;
2508 edit_save_block (edit, b, start_mark, end_mark);
2509 quoted_name = name_quote (edit->filename, 0);
2511 * Run script.
2512 * Initial space is to avoid polluting bash history.
2513 * Arguments:
2514 * $1 - name of the edited file (to check its extension etc).
2515 * $2 - file containing the current block.
2516 * $3 - file where error messages should be put
2517 * (for compatibility with old scripts).
2519 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2520 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2522 else
2525 * No block selected, just execute the command for the file.
2526 * Arguments:
2527 * $1 - name of the edited file.
2529 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2530 quoted_name, (char *) NULL);
2533 if (system (tmp) == -1)
2535 edit_error_dialog (_("Process block"), _("Error calling program"));
2537 else
2540 g_free (quoted_name);
2541 close_error_pipe (D_NORMAL, NULL);
2543 edit_refresh_cmd (edit);
2544 edit->force |= REDRAW_COMPLETELY;
2546 /* insert result block */
2547 if (block && !edit_block_delete_cmd (edit))
2549 edit_insert_file (edit, b);
2550 block_file = fopen (b, "w");
2551 if (block_file != NULL)
2552 fclose (block_file);
2555 g_free (tmp);
2557 edit_block_process_cmd__EXIT:
2558 g_free (b);
2559 g_free (h);
2560 g_free (o);
2563 /* prints at the cursor */
2564 /* returns the number of chars printed */
2566 edit_print_string (WEdit * e, const char *s)
2568 size_t i = 0;
2569 while (s[i] != '\0')
2570 edit_execute_cmd (e, CK_Insert_Char, (unsigned char) s[i++]);
2571 e->force |= REDRAW_COMPLETELY;
2572 edit_update_screen (e);
2573 return i;
2577 static void
2578 pipe_mail (WEdit * edit, char *to, char *subject, char *cc)
2580 FILE *p = 0;
2581 char *s;
2583 to = name_quote (to, 0);
2584 subject = name_quote (subject, 0);
2585 cc = name_quote (cc, 0);
2586 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "", cc, " ", to, (char *) NULL);
2587 g_free (to);
2588 g_free (subject);
2589 g_free (cc);
2591 if (s)
2593 p = popen (s, "w");
2594 g_free (s);
2597 if (p)
2599 long i;
2600 for (i = 0; i < edit->last_byte; i++)
2601 fputc (edit_get_byte (edit, i), p);
2602 pclose (p);
2606 #define MAIL_DLG_HEIGHT 12
2608 void
2609 edit_mail_dialog (WEdit * edit)
2611 char *tmail_to;
2612 char *tmail_subject;
2613 char *tmail_cc;
2615 static char *mail_cc_last = 0;
2616 static char *mail_subject_last = 0;
2617 static char *mail_to_last = 0;
2619 QuickWidget quick_widgets[] = {
2620 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2621 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2622 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2623 /* 3 */ QUICK_LABEL (2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to")),
2624 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2",
2625 &tmail_subject),
2626 /* 5 */ QUICK_LABEL (2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject")),
2627 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2628 /* 7 */ QUICK_LABEL (2, 50, 3, MAIL_DLG_HEIGHT, N_(" To")),
2629 /* 8 */ QUICK_LABEL (2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>")),
2630 QUICK_END
2633 QuickDialog Quick_input = {
2634 50, MAIL_DLG_HEIGHT, -1, -1, N_(" Mail "),
2635 "[Input Line Keys]", quick_widgets, FALSE
2638 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2639 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2640 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2642 if (quick_dialog (&Quick_input) != B_CANCEL)
2644 g_free (mail_cc_last);
2645 g_free (mail_subject_last);
2646 g_free (mail_to_last);
2647 mail_cc_last = tmail_cc;
2648 mail_subject_last = tmail_subject;
2649 mail_to_last = tmail_to;
2650 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2655 /*******************/
2656 /* Word Completion */
2657 /*******************/
2659 static gboolean
2660 is_break_char (char c)
2662 return (isspace (c) || strchr ("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2665 /* find first character of current word */
2666 static int
2667 edit_find_word_start (WEdit * edit, long *word_start, gsize * word_len)
2669 int c, last;
2670 gsize i;
2672 /* return if at begin of file */
2673 if (edit->curs1 <= 0)
2674 return 0;
2676 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2677 /* return if not at end or in word */
2678 if (is_break_char (c))
2679 return 0;
2681 /* search start of word to be completed */
2682 for (i = 2;; i++)
2684 /* return if at begin of file */
2685 if ((gsize) edit->curs1 < i)
2686 return 0;
2688 last = c;
2689 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2691 if (is_break_char (c))
2693 /* return if word starts with digit */
2694 if (isdigit (last))
2695 return 0;
2697 *word_start = edit->curs1 - (i - 1); /* start found */
2698 *word_len = i - 1;
2699 break;
2702 /* success */
2703 return 1;
2706 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2708 /* collect the possible completions */
2709 static gsize
2710 edit_collect_completions (WEdit * edit, long start, gsize word_len,
2711 char *match_expr, struct selection *compl, gsize * num)
2713 gsize len = 0;
2714 gsize max_len = 0;
2715 gsize i;
2716 int skip;
2717 GString *temp;
2718 mc_search_t *srch;
2720 long last_byte;
2722 srch = mc_search_new (match_expr, -1);
2723 if (srch == NULL)
2724 return 0;
2726 if (mc_config_get_bool
2727 (mc_main_config, CONFIG_APP_SECTION, "editor_wordcompletion_collect_entire_file", 0))
2729 last_byte = edit->last_byte;
2731 else
2733 last_byte = start;
2736 srch->search_type = MC_SEARCH_T_REGEX;
2737 srch->is_case_sensitive = TRUE;
2738 srch->search_fn = edit_search_cmd_callback;
2740 /* collect max MAX_WORD_COMPLETIONS completions */
2741 start = -1;
2742 while (1)
2744 /* get next match */
2745 if (mc_search_run (srch, (void *) edit, start + 1, last_byte, &len) == FALSE)
2746 break;
2747 start = srch->normal_offset;
2749 /* add matched completion if not yet added */
2750 temp = g_string_new ("");
2751 for (i = 0; i < len; i++)
2753 skip = edit_get_byte (edit, start + i);
2754 if (isspace (skip))
2755 continue;
2756 g_string_append_c (temp, skip);
2759 skip = 0;
2761 for (i = 0; i < (gsize) * num; i++)
2763 if (strncmp
2764 ((char *) &compl[i].text[word_len],
2765 (char *) &temp->str[word_len], max (len, compl[i].len) - (gsize) word_len) == 0)
2767 struct selection this = compl[i];
2768 for (++i; i < *num; i++)
2770 compl[i - 1] = compl[i];
2772 compl[*num - 1] = this;
2773 skip = 1;
2774 break; /* skip it, already added */
2777 if (skip)
2779 g_string_free (temp, TRUE);
2780 continue;
2782 if (*num == MAX_WORD_COMPLETIONS && MAX_WORD_COMPLETIONS)
2784 g_free (compl[0].text);
2785 for (i = 1; i < *num; i++)
2787 compl[i - 1] = compl[i];
2789 (*num)--;
2791 #ifdef HAVE_CHARSET
2793 GString *recoded;
2794 recoded = str_convert_to_display (temp->str);
2796 if (recoded && recoded->len)
2798 g_string_free (temp, TRUE);
2799 temp = recoded;
2801 else
2802 g_string_free (recoded, TRUE);
2804 #endif
2805 compl[*num].text = temp->str;
2806 compl[*num].len = temp->len;
2807 (*num)++;
2808 start += len;
2809 g_string_free (temp, FALSE);
2811 /* note the maximal length needed for the completion dialog */
2812 if (len > max_len)
2813 max_len = len;
2815 mc_search_free (srch);
2816 return max_len;
2820 * Complete current word using regular expression search
2821 * backwards beginning at the current cursor position.
2823 void
2824 edit_complete_word_cmd (WEdit * edit)
2826 gsize i, max_len, word_len = 0, num_compl = 0;
2827 long word_start = 0;
2828 unsigned char *bufpos;
2829 char *match_expr;
2830 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2832 /* search start of word to be completed */
2833 if (!edit_find_word_start (edit, &word_start, &word_len))
2834 return;
2836 /* prepare match expression */
2837 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE][word_start & M_EDIT_BUF_SIZE];
2839 /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
2840 match_expr =
2841 g_strdup_printf
2842 ("(^|\\s+|\\b)%.*s[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+",
2843 (int) word_len, bufpos);
2845 /* collect the possible completions */
2846 /* start search from begin to end of file */
2847 max_len =
2848 edit_collect_completions (edit, word_start, word_len, match_expr,
2849 (struct selection *) &compl, &num_compl);
2851 if (num_compl > 0)
2853 /* insert completed word if there is only one match */
2854 if (num_compl == 1)
2856 for (i = word_len; i < compl[0].len; i++)
2857 edit_insert (edit, *(compl[0].text + i));
2859 /* more than one possible completion => ask the user */
2860 else
2862 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2863 /* !!! pressed again the selection dialog pops up, but that !!! */
2864 /* !!! seems to require a further internal state !!! */
2865 /*tty_beep (); */
2867 /* let the user select the preferred completion */
2868 editcmd_dialog_completion_show (edit, max_len, word_len,
2869 (struct selection *) &compl, num_compl);
2873 g_free (match_expr);
2874 /* release memory before return */
2875 for (i = 0; i < num_compl; i++)
2876 g_free (compl[i].text);
2879 void
2880 edit_select_codepage_cmd (WEdit * edit)
2882 #ifdef HAVE_CHARSET
2883 const char *cp_id = NULL;
2884 if (do_select_codepage ())
2886 cp_id = get_codepage_id (source_codepage >= 0 ? source_codepage : display_codepage);
2888 if (cp_id != NULL)
2890 GIConv conv;
2891 conv = str_crt_conv_from (cp_id);
2892 if (conv != INVALID_CONV)
2894 if (edit->converter != str_cnv_from_term)
2895 str_close_conv (edit->converter);
2896 edit->converter = conv;
2900 if (cp_id != NULL)
2901 edit->utf8 = str_isutf8 (cp_id);
2904 edit->force = REDRAW_COMPLETELY;
2905 edit_refresh_cmd (edit);
2906 #else
2907 (void) edit;
2908 #endif
2911 void
2912 edit_insert_literal_cmd (WEdit * edit)
2914 int char_for_insertion = editcmd_dialog_raw_key_query (_(" Insert Literal "),
2915 _(" Press any key: "), 0);
2916 edit_execute_key_command (edit, -1, ascii_alpha_to_cntrl (char_for_insertion));
2919 void
2920 edit_execute_macro_cmd (WEdit * edit)
2922 int command =
2923 CK_Macro (editcmd_dialog_raw_key_query (_(" Execute Macro "), _(" Press macro hotkey: "),
2924 1));
2925 if (command == CK_Macro (0))
2926 command = CK_Insert_Char;
2928 edit_execute_key_command (edit, command, -1);
2931 void
2932 edit_begin_end_macro_cmd (WEdit * edit)
2934 /* edit is a pointer to the widget */
2935 if (edit)
2937 unsigned long command = edit->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2938 edit_execute_key_command (edit, command, -1);
2943 edit_load_forward_cmd (WEdit * edit)
2945 if (edit->modified)
2947 if (edit_query_dialog2
2948 (_("Warning"),
2949 _(" Current text was modified without a file save. \n"
2950 " Continue discards these changes. "), _("C&ontinue"), _("&Cancel")))
2952 edit->force |= REDRAW_COMPLETELY;
2953 return 0;
2956 if (edit_stack_iterator + 1 < MAX_HISTORY_MOVETO)
2958 if (edit_history_moveto[edit_stack_iterator + 1].line < 1)
2960 return 1;
2962 edit_stack_iterator++;
2963 if (edit_history_moveto[edit_stack_iterator].filename)
2965 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2966 edit_history_moveto[edit_stack_iterator].line);
2967 return 0;
2969 else
2971 return 1;
2974 else
2976 return 1;
2981 edit_load_back_cmd (WEdit * edit)
2983 if (edit->modified)
2985 if (edit_query_dialog2
2986 (_("Warning"),
2987 _(" Current text was modified without a file save. \n"
2988 " Continue discards these changes. "), _("C&ontinue"), _("&Cancel")))
2990 edit->force |= REDRAW_COMPLETELY;
2991 return 0;
2994 if (edit_stack_iterator > 0)
2996 edit_stack_iterator--;
2997 if (edit_history_moveto[edit_stack_iterator].filename)
2999 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
3000 edit_history_moveto[edit_stack_iterator].line);
3001 return 0;
3003 else
3005 return 1;
3008 else
3010 return 1;
3014 void
3015 edit_get_match_keyword_cmd (WEdit * edit)
3017 gsize word_len = 0, max_len = 0;
3018 int num_def = 0;
3019 int i;
3020 long word_start = 0;
3021 unsigned char *bufpos;
3022 char *match_expr;
3023 char *path = NULL;
3024 char *ptr = NULL;
3025 char *tagfile = NULL;
3027 etags_hash_t def_hash[MAX_DEFINITIONS];
3029 for (i = 0; i < MAX_DEFINITIONS; i++)
3031 def_hash[i].filename = NULL;
3034 /* search start of word to be completed */
3035 if (!edit_find_word_start (edit, &word_start, &word_len))
3036 return;
3038 /* prepare match expression */
3039 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE][word_start & M_EDIT_BUF_SIZE];
3040 match_expr = g_strdup_printf ("%.*s", (int) word_len, bufpos);
3042 ptr = g_get_current_dir ();
3043 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
3044 g_free (ptr);
3046 /* Recursive search file 'TAGS' in parent dirs */
3049 ptr = g_path_get_dirname (path);
3050 g_free (path);
3051 path = ptr;
3052 g_free (tagfile);
3053 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
3054 if (exist_file (tagfile))
3055 break;
3057 while (strcmp (path, G_DIR_SEPARATOR_S) != 0);
3059 if (tagfile)
3061 num_def =
3062 etags_set_definition_hash (tagfile, path, match_expr, (etags_hash_t *) & def_hash);
3063 g_free (tagfile);
3065 g_free (path);
3067 max_len = MAX_WIDTH_DEF_DIALOG;
3068 word_len = 0;
3069 if (num_def > 0)
3071 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
3072 (etags_hash_t *) & def_hash, num_def);
3074 g_free (match_expr);
3077 void
3078 edit_move_block_to_right (WEdit * edit)
3080 long start_mark, end_mark;
3081 long cur_bol, start_bol;
3083 if (eval_marks (edit, &start_mark, &end_mark))
3084 return;
3086 start_bol = edit_bol (edit, start_mark);
3087 cur_bol = edit_bol (edit, end_mark - 1);
3090 edit_cursor_move (edit, cur_bol - edit->curs1);
3091 if (option_fill_tabs_with_spaces)
3093 if (option_fake_half_tabs)
3095 insert_spaces_tab (edit, 1);
3097 else
3099 insert_spaces_tab (edit, 0);
3102 else
3104 edit_insert (edit, '\t');
3106 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
3107 if (cur_bol == 0)
3109 break;
3111 cur_bol = edit_bol (edit, cur_bol - 1);
3113 while (cur_bol >= start_bol);
3114 edit->force |= REDRAW_PAGE;
3117 void
3118 edit_move_block_to_left (WEdit * edit)
3120 long start_mark, end_mark;
3121 long cur_bol, start_bol;
3122 int i, del_tab_width;
3123 int next_char;
3125 if (eval_marks (edit, &start_mark, &end_mark))
3126 return;
3128 start_bol = edit_bol (edit, start_mark);
3129 cur_bol = edit_bol (edit, end_mark - 1);
3132 edit_cursor_move (edit, cur_bol - edit->curs1);
3133 if (option_fake_half_tabs)
3135 del_tab_width = HALF_TAB_SIZE;
3137 else
3139 del_tab_width = option_tab_spacing;
3141 next_char = edit_get_byte (edit, edit->curs1);
3142 if (next_char == '\t')
3144 edit_delete (edit, 1);
3146 else if (next_char == ' ')
3148 for (i = 1; i <= del_tab_width; i++)
3150 if (next_char == ' ')
3152 edit_delete (edit, 1);
3154 next_char = edit_get_byte (edit, edit->curs1);
3157 if (cur_bol == 0)
3159 break;
3161 cur_bol = edit_bol (edit, cur_bol - 1);
3163 while (cur_bol >= start_bol);
3164 edit->force |= REDRAW_PAGE;