Ticket #1990: code cleanup before 4.7.0.2 release.
[midnight-commander/osp/fridri1.git] / src / editor / editcmd.c
blobf78d9d4dace53c1912e7b720bd634713bdc96cb6
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 */
55 #include "src/history.h"
56 #include "src/widget.h" /* listbox_new() */
57 #include "src/layout.h" /* clr_scr() */
58 #include "src/main.h" /* mc_home source_codepage */
59 #include "src/help.h" /* interactive_display() */
60 #include "src/wtools.h" /* message() */
61 #include "src/charsets.h"
62 #include "src/selcodepage.h"
63 #include "src/cmddef.h"
65 #include "lib/vfs/mc-vfs/vfs.h"
67 #include "src/editor/edit-impl.h"
68 #include "src/editor/edit.h"
69 #include "src/editor/editlock.h"
70 #include "src/editor/edit-widget.h"
71 #include "src/editor/editcmd_dialogs.h"
72 #include "src/editor/etags.h"
74 /* globals: */
76 /* search and replace: */
77 int search_create_bookmark = 0;
78 /* static int search_in_all_charsets = 0; */
80 /* queries on a save */
81 int edit_confirm_save = 1;
83 static int edit_save_cmd (WEdit *edit);
84 static unsigned char *edit_get_block (WEdit *edit, long start,
85 long finish, int *l);
87 static void
88 edit_search_cmd_search_create_bookmark(WEdit * edit)
90 int found = 0, books = 0;
91 long l = 0, l_last = -1;
92 long q = 0;
93 gsize len = 0;
95 search_create_bookmark = 0;
96 book_mark_flush (edit, -1);
98 for (;;) {
99 if (!mc_search_run(edit->search, (void *) edit, q, edit->last_byte, &len))
100 break;
101 if (found == 0)
102 edit->search_start = edit->search->normal_offset;
103 found++;
104 l += edit_count_lines (edit, q, edit->search->normal_offset);
105 if (l != l_last) {
106 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
107 books++;
109 l_last = l;
110 q = edit->search->normal_offset + 1;
113 if (found == 0) {
114 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
115 } else {
116 edit_cursor_move (edit, edit->search_start - edit->curs1);
117 edit_scroll_screen_over_cursor (edit);
121 static int
122 edit_search_cmd_callback(const void *user_data, gsize char_offset)
124 return edit_get_byte ((WEdit * )user_data, (long) char_offset);
127 void edit_help_cmd (WEdit * edit)
129 interactive_display (NULL, "[Internal File Editor]");
130 edit->force |= REDRAW_COMPLETELY;
133 void
134 edit_refresh_cmd (WEdit * edit)
136 #ifdef HAVE_SLANG
137 int color;
139 edit_get_syntax_color (edit, -1, &color);
140 tty_touch_screen ();
141 mc_refresh ();
142 #else
143 (void) edit;
145 clr_scr ();
146 repaint_screen ();
147 #endif /* !HAVE_SLANG */
148 tty_keypad (TRUE);
151 /* If 0 (quick save) then a) create/truncate <filename> file,
152 b) save to <filename>;
153 if 1 (safe save) then a) save to <tempnam>,
154 b) rename <tempnam> to <filename>;
155 if 2 (do backups) then a) save to <tempnam>,
156 b) rename <filename> to <filename.backup_ext>,
157 c) rename <tempnam> to <filename>. */
159 /* returns 0 on error, -1 on abort */
160 static int
161 edit_save_file (WEdit *edit, const char *filename)
163 char *p;
164 gchar *tmp;
165 long filelen = 0;
166 char *savename = 0;
167 gchar *real_filename;
168 int this_save_mode, fd = -1;
170 if (!filename)
171 return 0;
172 if (!*filename)
173 return 0;
175 if (*filename != PATH_SEP && edit->dir) {
176 real_filename = concat_dir_and_file (edit->dir, filename);
177 } else {
178 real_filename = g_strdup(filename);
181 this_save_mode = option_save_mode;
182 if (this_save_mode != EDIT_QUICK_SAVE) {
183 if (!vfs_file_is_local (real_filename) ||
184 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1) {
186 * The file does not exists yet, so no safe save or
187 * backup are necessary.
189 this_save_mode = EDIT_QUICK_SAVE;
191 if (fd != -1)
192 mc_close (fd);
195 if (this_save_mode == EDIT_QUICK_SAVE &&
196 !edit->skip_detach_prompt) {
197 int rv;
198 struct stat sb;
200 rv = mc_stat (real_filename, &sb);
201 if (rv == 0 && sb.st_nlink > 1) {
202 rv = edit_query_dialog3 (_("Warning"),
203 _(" File has hard-links. Detach before saving? "),
204 _("&Yes"), _("&No"), _("&Cancel"));
205 switch (rv) {
206 case 0:
207 this_save_mode = EDIT_SAFE_SAVE;
208 /* fallthrough */
209 case 1:
210 edit->skip_detach_prompt = 1;
211 break;
212 default:
213 g_free(real_filename);
214 return -1;
218 /* Prevent overwriting changes from other editor sessions. */
219 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
221 /* The default action is "Cancel". */
222 query_set_sel(1);
224 rv = edit_query_dialog2 (
225 _("Warning"),
226 _("The file has been modified in the meantime. Save anyway?"),
227 _("&Yes"),
228 _("&Cancel"));
229 if (rv != 0){
230 g_free(real_filename);
231 return -1;
236 if (this_save_mode != EDIT_QUICK_SAVE) {
237 char *savedir, *saveprefix;
238 const char *slashpos;
239 slashpos = strrchr (real_filename, PATH_SEP);
240 if (slashpos) {
241 savedir = g_strdup (real_filename);
242 savedir[slashpos - real_filename + 1] = '\0';
243 } else
244 savedir = g_strdup (".");
245 saveprefix = concat_dir_and_file (savedir, "cooledit");
246 g_free (savedir);
247 fd = mc_mkstemps (&savename, saveprefix, NULL);
248 g_free (saveprefix);
249 if (!savename){
250 g_free(real_filename);
251 return 0;
253 /* FIXME:
254 * Close for now because mc_mkstemps use pure open system call
255 * to create temporary file and it needs to be reopened by
256 * VFS-aware mc_open().
258 close (fd);
259 } else
260 savename = g_strdup (real_filename);
262 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
263 mc_chmod (savename, edit->stat1.st_mode);
265 if ((fd =
266 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
267 edit->stat1.st_mode)) == -1)
268 goto error_save;
270 /* pipe save */
271 if ((p = edit_get_write_filter (savename, real_filename))) {
272 FILE *file;
274 mc_close (fd);
275 file = (FILE *) popen (p, "w");
277 if (file) {
278 filelen = edit_write_stream (edit, file);
279 #if 1
280 pclose (file);
281 #else
282 if (pclose (file) != 0) {
283 tmp = g_strconcat (_(" Error writing to pipe: "),
284 p, " ", (char *) NULL);
285 edit_error_dialog (_("Error"), tmp);
286 g_free(tmp);
287 g_free (p);
288 goto error_save;
290 #endif
291 } else {
292 tmp = g_strconcat (_(" Cannot open pipe for writing: "),
293 p, " ", (char *) NULL);
295 edit_error_dialog (_("Error"),
296 get_sys_error (tmp));
297 g_free (p);
298 g_free(tmp);
299 goto error_save;
301 g_free (p);
302 } else if (edit->lb == LB_ASIS) { /* do not change line breaks */
303 long buf;
304 buf = 0;
305 filelen = edit->last_byte;
306 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
307 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
308 != EDIT_BUF_SIZE) {
309 mc_close (fd);
310 goto error_save;
312 buf++;
314 if (mc_write
315 (fd, (char *) edit->buffers1[buf],
316 edit->curs1 & M_EDIT_BUF_SIZE) !=
317 (edit->curs1 & M_EDIT_BUF_SIZE)) {
318 filelen = -1;
319 } else if (edit->curs2) {
320 edit->curs2--;
321 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
322 if (mc_write
323 (fd,
324 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
325 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
326 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
327 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
328 filelen = -1;
329 } else {
330 while (--buf >= 0) {
331 if (mc_write
332 (fd, (char *) edit->buffers2[buf],
333 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
334 filelen = -1;
335 break;
339 edit->curs2++;
341 if (mc_close (fd))
342 goto error_save;
344 /* Update the file information, especially the mtime. */
345 if (mc_stat (savename, &edit->stat1) == -1)
346 goto error_save;
347 } else { /* change line breaks */
348 FILE *file;
350 mc_close (fd);
352 file = (FILE *) fopen (savename, "w");
354 if (file) {
355 filelen = edit_write_stream (edit, file);
356 fclose (file);
357 } else {
358 char *msg;
360 msg = g_strdup_printf (_(" Cannot open file for writing: %s "), savename);
361 edit_error_dialog (_("Error"), msg);
362 g_free (msg);
363 goto error_save;
367 if (filelen != edit->last_byte)
368 goto error_save;
370 if (this_save_mode == EDIT_DO_BACKUP) {
371 assert (option_backup_ext != NULL);
372 tmp = g_strconcat (real_filename, option_backup_ext, (char *) NULL);
373 if (mc_rename (real_filename, tmp) == -1){
374 g_free(tmp);
375 goto error_save;
379 if (this_save_mode != EDIT_QUICK_SAVE)
380 if (mc_rename (savename, real_filename) == -1)
381 goto error_save;
382 g_free (savename);
383 g_free(real_filename);
384 return 1;
385 error_save:
386 /* FIXME: Is this safe ?
387 * if (this_save_mode != EDIT_QUICK_SAVE)
388 * mc_unlink (savename);
390 g_free(real_filename);
391 g_free (savename);
392 return 0;
395 void
396 menu_save_mode_cmd (void)
398 /* diaog sizes */
399 const int DLG_X = 38;
400 const int DLG_Y = 13;
402 char *str_result;
404 const char *str[] =
406 N_("&Quick save"),
407 N_("&Safe save"),
408 N_("&Do backups with following extension:")
411 QuickWidget widgets[] =
413 /* 0 */
414 QUICK_BUTTON (18, DLG_X, DLG_Y - 3, DLG_Y, N_("&Cancel"), B_CANCEL, NULL),
415 /* 1 */
416 QUICK_BUTTON ( 6, DLG_X, DLG_Y - 3, DLG_Y, N_("&OK"), B_ENTER, NULL),
417 /* 2 */
418 QUICK_CHECKBOX ( 4, DLG_X, 8, DLG_Y, N_("Check &POSIX new line"), &option_check_nl_at_eof),
419 /* 3 */
420 QUICK_INPUT ( 8, DLG_X, 6, DLG_Y, option_backup_ext, 9, 0, "edit-backup-ext", &str_result),
421 /* 4 */
422 QUICK_RADIO ( 4, DLG_X, 3, DLG_Y, 3, str, &option_save_mode),
423 QUICK_END
426 QuickDialog dialog =
428 DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "),
429 "[Edit Save Mode]", widgets, FALSE
432 size_t i;
433 size_t maxlen = 0;
434 size_t w0, w1, b_len, w3;
436 assert (option_backup_ext != NULL);
438 /* OK/Cancel buttons */
439 w0 = str_term_width1 (_(widgets[0].u.button.text)) + 3;
440 w1 = str_term_width1 (_(widgets[1].u.button.text)) + 5; /* default button */
441 b_len = w0 + w1 + 3;
443 maxlen = max (b_len, (size_t) str_term_width1 (_(dialog.title)) + 2);
445 w3 = 0;
446 for (i = 0; i < 3; i++) {
447 #ifdef ENABLE_NLS
448 str[i] = _(str[i]);
449 #endif
450 w3 = max (w3, (size_t) str_term_width1 (str[i]));
453 maxlen = max (maxlen, w3 + 4);
455 dialog.xlen = min ((size_t) COLS, maxlen + 8);
457 widgets[3].u.input.len = w3;
458 widgets[1].relative_x = (dialog.xlen - b_len)/2;
459 widgets[0].relative_x = widgets[1].relative_x + w0 + 2;
461 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
462 widgets[i].x_divisions = dialog.xlen;
464 if (quick_dialog (&dialog) != B_CANCEL) {
465 g_free (option_backup_ext);
466 option_backup_ext = str_result;
470 void
471 edit_set_filename (WEdit *edit, const char *f)
473 g_free (edit->filename);
474 if (!f)
475 f = "";
476 edit->filename = g_strdup (f);
477 if (edit->dir == NULL && *f != PATH_SEP)
478 #ifdef ENABLE_VFS
479 edit->dir = g_strdup (vfs_get_current_dir ());
480 #else /* ENABLE_VFS */
481 edit->dir = g_get_current_dir ();
482 #endif /* ENABLE_VFS */
485 static gboolean
486 edit_check_newline (WEdit *edit)
488 return !(option_check_nl_at_eof && edit->last_byte > 0
489 && edit_get_byte (edit, edit->last_byte - 1) != '\n'
490 && edit_query_dialog2 (_("Warning"),
491 _("The file you are saving is not finished with a newline"),
492 _("C&ontinue"), _("&Cancel")));
495 static char *
496 edit_get_save_file_as (WEdit *edit)
498 #define DLG_WIDTH 64
499 #define DLG_HEIGHT 14
501 static LineBreaks cur_lb = LB_ASIS;
503 char *filename = edit->filename;
505 const char *lb_names[LB_NAMES] =
507 N_("&Do not change"),
508 N_("&Unix format (LF)"),
509 N_("&Windows/DOS format (CR LF)"),
510 N_("&Macintosh format (CR)")
513 QuickWidget quick_widgets[] =
515 QUICK_BUTTON (6, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
516 QUICK_BUTTON (2, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
517 QUICK_RADIO (5, DLG_WIDTH, DLG_HEIGHT - 8, DLG_HEIGHT, LB_NAMES, lb_names, (int *) &cur_lb),
518 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 9, DLG_HEIGHT, N_("Change line breaks to:")),
519 QUICK_INPUT (3, DLG_WIDTH, DLG_HEIGHT - 11, DLG_HEIGHT, filename, DLG_WIDTH - 6, 0, "save-as", &filename),
520 QUICK_LABEL (2, DLG_WIDTH, DLG_HEIGHT - 12, DLG_HEIGHT, N_(" Enter file name: ")),
521 QUICK_END
524 QuickDialog Quick_options =
526 DLG_WIDTH, DLG_HEIGHT, -1, -1,
527 N_(" Save As "), "[Save File As]",
528 quick_widgets, FALSE
531 if (quick_dialog (&Quick_options) != B_CANCEL) {
532 edit->lb = cur_lb;
533 return filename;
536 return NULL;
538 #undef DLG_WIDTH
539 #undef DLG_HEIGHT
542 /* Here we want to warn the users of overwriting an existing file,
543 but only if they have made a change to the filename */
544 /* returns 1 on success */
546 edit_save_as_cmd (WEdit *edit)
548 /* This heads the 'Save As' dialog box */
549 char *exp;
550 int save_lock = 0;
551 int different_filename = 0;
553 if (!edit_check_newline (edit))
554 return 0;
556 exp = edit_get_save_file_as (edit);
557 edit_push_action (edit, KEY_PRESS + edit->start_display);
559 if (exp) {
560 if (!*exp) {
561 g_free (exp);
562 edit->force |= REDRAW_COMPLETELY;
563 return 0;
564 } else {
565 int rv;
566 if (strcmp (edit->filename, exp)) {
567 int file;
568 different_filename = 1;
569 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
570 /* the file exists */
571 mc_close (file);
572 /* Overwrite the current file or cancel the operation */
573 if (edit_query_dialog2
574 (_("Warning"),
575 _(" A file already exists with this name. "),
576 _("&Overwrite"), _("&Cancel"))) {
577 edit->force |= REDRAW_COMPLETELY;
578 g_free (exp);
579 return 0;
581 } else {
582 edit->stat1.st_mode |= S_IWUSR;
584 save_lock = edit_lock_file (exp);
585 } else {
586 /* filenames equal, check if already locked */
587 if (!edit->locked && !edit->delete_file)
588 save_lock = edit_lock_file (exp);
591 if (different_filename)
594 * Allow user to write into saved (under another name) file
595 * even if original file had r/o user permissions.
597 edit->stat1.st_mode |= S_IWRITE;
600 rv = edit_save_file (edit, exp);
601 switch (rv) {
602 case 1:
603 /* Succesful, so unlock both files */
604 if (different_filename) {
605 if (save_lock)
606 edit_unlock_file (exp);
607 if (edit->locked)
608 edit->locked = edit_unlock_file (edit->filename);
609 } else {
610 if (edit->locked || save_lock)
611 edit->locked = edit_unlock_file (edit->filename);
614 edit_set_filename (edit, exp);
615 if (edit->lb != LB_ASIS)
616 edit_reload(edit, exp);
617 g_free (exp);
618 edit->modified = 0;
619 edit->delete_file = 0;
620 if (different_filename)
621 edit_load_syntax (edit, NULL, option_syntax_type);
622 edit->force |= REDRAW_COMPLETELY;
623 return 1;
624 default:
625 edit_error_dialog (_(" Save As "),
626 get_sys_error (_
627 (" Cannot save file. ")));
628 /* fallthrough */
629 case -1:
630 /* Failed, so maintain modify (not save) lock */
631 if (save_lock)
632 edit_unlock_file (exp);
633 g_free (exp);
634 edit->force |= REDRAW_COMPLETELY;
635 return 0;
639 edit->force |= REDRAW_COMPLETELY;
640 return 0;
643 /* {{{ Macro stuff starts here */
645 /* creates a macro file if it doesn't exist */
646 static FILE *edit_open_macro_file (const char *r)
648 gchar *filename;
649 FILE *fd;
650 int file;
651 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
652 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
653 g_free(filename);
654 return 0;
656 close (file);
657 fd = fopen (filename, r);
658 g_free(filename);
659 return fd;
662 #define MAX_MACROS 1024
663 static int saved_macro[MAX_MACROS + 1];
664 static int saved_macros_loaded = 0;
667 This is just to stop the macro file be loaded over and over for keys
668 that aren't defined to anything. On slow systems this could be annoying.
670 static int
671 macro_exists (int k)
673 int i;
674 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
675 if (saved_macro[i] == k)
676 return i;
677 return -1;
680 /* returns 1 on error */
681 static int
682 edit_delete_macro (WEdit * edit, int k)
684 gchar *tmp, *tmp2;
685 struct macro macro[MAX_MACRO_LENGTH];
686 FILE *f, *g;
687 int s, i, n, j = 0;
689 (void) edit;
691 if (saved_macros_loaded)
692 if ((j = macro_exists (k)) < 0)
693 return 0;
694 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
695 g = fopen (tmp , "w");
696 g_free(tmp);
697 if (!g) {
698 edit_error_dialog (_(" Delete macro "),
699 get_sys_error (_(" Cannot open temp file ")));
700 return 1;
702 f = edit_open_macro_file ("r");
703 if (!f) {
704 edit_error_dialog (_(" Delete macro "),
705 get_sys_error (_(" Cannot open macro file ")));
706 fclose (g);
707 return 1;
709 for (;;) {
710 n = fscanf (f, ("key '%d 0': "), &s);
711 if (!n || n == EOF)
712 break;
713 n = 0;
714 while (fscanf (f, "%lu %d, ", &macro[n].command, &macro[n].ch))
715 n++;
716 fscanf (f, ";\n");
717 if (s != k) {
718 fprintf (g, ("key '%d 0': "), s);
719 for (i = 0; i < n; i++)
720 fprintf (g, "%lu %d, ", macro[i].command, macro[i].ch);
721 fprintf (g, ";\n");
724 fclose (f);
725 fclose (g);
726 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
727 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
728 if (rename ( tmp, tmp2) == -1) {
729 edit_error_dialog (_(" Delete macro "),
730 get_sys_error (_(" Cannot overwrite macro file ")));
731 g_free(tmp);
732 g_free(tmp2);
733 return 1;
735 g_free(tmp);
736 g_free(tmp2);
738 if (saved_macros_loaded)
739 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
740 return 0;
743 /* returns 0 on error */
744 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
746 FILE *f;
747 int s, i;
749 edit_push_action (edit, KEY_PRESS + edit->start_display);
750 s = editcmd_dialog_raw_key_query (_(" Save macro "),
751 _(" Press the macro's new hotkey: "), 1);
752 edit->force |= REDRAW_COMPLETELY;
753 if (s) {
754 if (edit_delete_macro (edit, s))
755 return 0;
756 f = edit_open_macro_file ("a+");
757 if (f) {
758 fprintf (f, ("key '%d 0': "), s);
759 for (i = 0; i < n; i++)
760 fprintf (f, "%lu %d, ", macro[i].command, macro[i].ch);
761 fprintf (f, ";\n");
762 fclose (f);
763 if (saved_macros_loaded) {
764 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
765 saved_macro[i] = s;
767 return 1;
768 } else
769 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
771 return 0;
774 void
775 edit_delete_macro_cmd (WEdit * edit)
777 int command;
779 command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
780 _ (" Press macro hotkey: "), 1);
782 if (command != 0)
783 edit_delete_macro (edit, command);
786 /* return 0 on error */
787 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
789 FILE *f;
790 int s, i = 0, found = 0;
792 (void) edit;
794 if (saved_macros_loaded)
795 if (macro_exists (k) < 0)
796 return 0;
798 if ((f = edit_open_macro_file ("r"))) {
799 struct macro dummy;
800 do {
801 int u;
802 u = fscanf (f, ("key '%d 0': "), &s);
803 if (!u || u == EOF)
804 break;
805 if (!saved_macros_loaded)
806 saved_macro[i++] = s;
807 if (!found) {
808 *n = 0;
809 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%lu %d, ", &macro[*n].command, &macro[*n].ch))
810 (*n)++;
811 } else {
812 while (2 == fscanf (f, "%lu %d, ", &dummy.command, &dummy.ch));
814 fscanf (f, ";\n");
815 if (s == k)
816 found = 1;
817 } while (!found || !saved_macros_loaded);
818 if (!saved_macros_loaded) {
819 saved_macro[i] = 0;
820 saved_macros_loaded = 1;
822 fclose (f);
823 return found;
824 } else
825 edit_error_dialog (_(" Load macro "),
826 get_sys_error (_(" Cannot open macro file ")));
827 return 0;
830 /* }}} Macro stuff starts here */
832 /* returns 1 on success */
833 int edit_save_confirm_cmd (WEdit * edit)
835 gchar *f = NULL;
837 if (!edit_check_newline (edit))
838 return 0;
840 if (edit_confirm_save) {
841 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", (char *) NULL);
842 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel"))){
843 g_free(f);
844 return 0;
846 g_free(f);
848 return edit_save_cmd (edit);
852 /* returns 1 on success */
853 static int
854 edit_save_cmd (WEdit *edit)
856 int res, save_lock = 0;
858 if (!edit->locked && !edit->delete_file)
859 save_lock = edit_lock_file (edit->filename);
860 res = edit_save_file (edit, edit->filename);
862 /* Maintain modify (not save) lock on failure */
863 if ((res > 0 && edit->locked) || save_lock)
864 edit->locked = edit_unlock_file (edit->filename);
866 /* On failure try 'save as', it does locking on its own */
867 if (!res)
868 return edit_save_as_cmd (edit);
869 edit->force |= REDRAW_COMPLETELY;
870 if (res > 0) {
871 edit->delete_file = 0;
872 edit->modified = 0;
875 return 1;
879 /* returns 1 on success */
880 int edit_new_cmd (WEdit * edit)
882 if (edit->modified) {
883 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
884 edit->force |= REDRAW_COMPLETELY;
885 return 0;
888 edit->force |= REDRAW_COMPLETELY;
890 return edit_renew (edit); /* if this gives an error, something has really screwed up */
893 /* returns 1 on error */
894 static int
895 edit_load_file_from_filename (WEdit * edit, char *exp)
897 int prev_locked = edit->locked;
898 char *prev_filename = g_strdup (edit->filename);
900 if (!edit_reload (edit, exp)) {
901 g_free (prev_filename);
902 return 1;
905 if (prev_locked)
906 edit_unlock_file (prev_filename);
907 g_free (prev_filename);
908 return 0;
911 static void
912 edit_load_syntax_file (WEdit * edit)
914 char *extdir;
915 int dir = 0;
917 if (geteuid () == 0) {
918 dir = query_dialog (_("Syntax file edit"),
919 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
920 _("&User"), _("&System Wide"));
923 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
924 if (!exist_file(extdir)) {
925 g_free (extdir);
926 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
929 if (dir == 0) {
930 char *buffer;
932 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
933 check_for_default (extdir, buffer);
934 edit_load_file_from_filename (edit, buffer);
935 g_free (buffer);
936 } else if (dir == 1)
937 edit_load_file_from_filename (edit, extdir);
939 g_free (extdir);
942 static void
943 edit_load_menu_file (WEdit * edit)
945 char *buffer;
946 char *menufile;
947 int dir = 0;
949 dir = query_dialog (
950 _(" Menu edit "),
951 _(" Which menu file do you want to edit? "), D_NORMAL,
952 geteuid() ? 2 : 3, _("&Local"), _("&User"), _("&System Wide")
955 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
957 if (!exist_file (menufile)) {
958 g_free (menufile);
959 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
962 switch (dir) {
963 case 0:
964 buffer = g_strdup (EDIT_LOCAL_MENU);
965 check_for_default (menufile, buffer);
966 chmod (buffer, 0600);
967 break;
969 case 1:
970 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
971 check_for_default (menufile, buffer);
972 break;
974 case 2:
975 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
976 if (!exist_file (buffer)) {
977 g_free (buffer);
978 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
980 break;
982 default:
983 g_free (menufile);
984 return;
987 edit_load_file_from_filename (edit, buffer);
989 g_free (buffer);
990 g_free (menufile);
994 edit_load_cmd (WEdit *edit, edit_current_file_t what)
996 char *exp;
998 if (edit->modified
999 && (edit_query_dialog2
1000 (_("Warning"),
1001 _(" Current text was modified without a file save. \n"
1002 " Continue discards these changes. "),
1003 _("C&ontinue"), _("&Cancel")) == 1)) {
1004 edit->force |= REDRAW_COMPLETELY;
1005 return 0;
1008 switch (what) {
1009 case EDIT_FILE_COMMON:
1010 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
1011 MC_HISTORY_EDIT_LOAD, edit->filename);
1013 if (exp) {
1014 if (*exp)
1015 edit_load_file_from_filename (edit, exp);
1016 g_free (exp);
1018 break;
1020 case EDIT_FILE_SYNTAX:
1021 edit_load_syntax_file (edit);
1022 break;
1024 case EDIT_FILE_MENU:
1025 edit_load_menu_file (edit);
1026 break;
1028 default:
1029 break;
1032 edit->force |= REDRAW_COMPLETELY;
1033 return 0;
1037 if mark2 is -1 then marking is from mark1 to the cursor.
1038 Otherwise its between the markers. This handles this.
1039 Returns 1 if no text is marked.
1041 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
1043 if (edit->mark1 != edit->mark2) {
1044 long start_bol, start_eol;
1045 long end_bol, end_eol;
1046 long col1, col2;
1047 long diff1, diff2;
1048 if (edit->mark2 >= 0) {
1049 *start_mark = min (edit->mark1, edit->mark2);
1050 *end_mark = max (edit->mark1, edit->mark2);
1051 } else {
1052 *start_mark = min (edit->mark1, edit->curs1);
1053 *end_mark = max (edit->mark1, edit->curs1);
1054 edit->column2 = edit->curs_col + edit->over_col;
1056 if (column_highlighting
1057 && (((edit->mark1 > edit->curs1) && (edit->column1 < edit->column2))
1058 || ((edit->mark1 < edit->curs1) && (edit->column1 > edit->column2)))) {
1060 start_bol = edit_bol (edit, *start_mark);
1061 start_eol = edit_eol (edit, start_bol - 1) + 1;
1062 end_bol = edit_bol (edit, *end_mark);
1063 end_eol = edit_eol (edit, *end_mark);
1064 col1 = min (edit->column1, edit->column2);
1065 col2 = max (edit->column1, edit->column2);
1067 diff1 = edit_move_forward3 (edit, start_bol, col2, 0) - edit_move_forward3 (edit, start_bol, col1, 0);
1068 diff2 = edit_move_forward3 (edit, end_bol, col2, 0) - edit_move_forward3 (edit, end_bol, col1, 0);
1070 *start_mark -= diff1;
1071 *end_mark += diff2;
1072 *start_mark = max (*start_mark, start_eol);
1073 *end_mark = min (*end_mark, end_eol);
1075 return 0;
1076 } else {
1077 *start_mark = *end_mark = 0;
1078 edit->column2 = edit->column1 = 0;
1079 return 1;
1083 #define space_width 1
1085 void
1086 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
1088 long cursor;
1089 int i, col;
1090 cursor = edit->curs1;
1091 col = edit_get_col (edit);
1092 for (i = 0; i < size; i++) {
1093 if (data[i] == '\n') { /* fill in and move to next line */
1094 int l;
1095 long p;
1096 if (edit_get_byte (edit, edit->curs1) != '\n') {
1097 l = width - (edit_get_col (edit) - col);
1098 while (l > 0) {
1099 edit_insert (edit, ' ');
1100 l -= space_width;
1103 for (p = edit->curs1;; p++) {
1104 if (p == edit->last_byte) {
1105 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1106 edit_insert_ahead (edit, '\n');
1107 p++;
1108 break;
1110 if (edit_get_byte (edit, p) == '\n') {
1111 p++;
1112 break;
1115 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1116 l = col - edit_get_col (edit);
1117 while (l >= space_width) {
1118 edit_insert (edit, ' ');
1119 l -= space_width;
1121 continue;
1123 edit_insert (edit, data[i]);
1125 edit_cursor_move (edit, cursor - edit->curs1);
1128 #define TEMP_BUF_LEN 1024
1131 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1133 long cursor;
1134 int i, col;
1135 int blocklen = -1, width;
1136 unsigned char *data;
1137 cursor = edit->curs1;
1138 col = edit_get_col (edit);
1139 data = g_malloc0 (TEMP_BUF_LEN);
1140 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0) {
1141 for (width = 0; width < blocklen; width++) {
1142 if (data[width] == '\n')
1143 break;
1145 for (i = 0; i < blocklen; i++) {
1146 if (data[i] == '\n') { /* fill in and move to next line */
1147 int l;
1148 long p;
1149 if (edit_get_byte (edit, edit->curs1) != '\n') {
1150 l = width - (edit_get_col (edit) - col);
1151 while (l > 0) {
1152 edit_insert (edit, ' ');
1153 l -= space_width;
1156 for (p = edit->curs1;; p++) {
1157 if (p == edit->last_byte) {
1158 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1159 edit_insert_ahead (edit, '\n');
1160 p++;
1161 break;
1163 if (edit_get_byte (edit, p) == '\n') {
1164 p++;
1165 break;
1168 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1169 l = col - edit_get_col (edit);
1170 while (l >= space_width) {
1171 edit_insert (edit, ' ');
1172 l -= space_width;
1174 continue;
1176 edit_insert (edit, data[i]);
1179 edit_cursor_move (edit, cursor - edit->curs1);
1180 g_free(data);
1181 edit->force |= REDRAW_PAGE;
1182 return blocklen;
1185 void
1186 edit_block_copy_cmd (WEdit *edit)
1188 long start_mark, end_mark, current = edit->curs1;
1189 int size;
1190 unsigned char *copy_buf;
1192 edit_update_curs_col (edit);
1193 if (eval_marks (edit, &start_mark, &end_mark))
1194 return;
1196 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1198 /* all that gets pushed are deletes hence little space is used on the stack */
1200 edit_push_markers (edit);
1202 if (column_highlighting) {
1203 edit_insert_column_of_text (edit, copy_buf, size,
1204 abs (edit->column2 - edit->column1));
1205 } else {
1206 while (size--)
1207 edit_insert_ahead (edit, copy_buf[size]);
1210 g_free (copy_buf);
1211 edit_scroll_screen_over_cursor (edit);
1213 if (column_highlighting) {
1214 edit_set_markers (edit, 0, 0, 0, 0);
1215 edit_push_action (edit, COLUMN_ON);
1216 column_highlighting = 0;
1217 } else if (start_mark < current && end_mark > current)
1218 edit_set_markers (edit, start_mark,
1219 end_mark + end_mark - start_mark, 0, 0);
1221 edit->force |= REDRAW_PAGE;
1225 void
1226 edit_block_move_cmd (WEdit *edit)
1228 long count;
1229 long current;
1230 unsigned char *copy_buf;
1231 long start_mark, end_mark;
1232 int deleted = 0;
1233 int x = 0;
1235 if (eval_marks (edit, &start_mark, &end_mark))
1236 return;
1237 if (column_highlighting) {
1238 edit_update_curs_col (edit);
1239 x = edit->curs_col;
1240 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1241 if ((x > edit->column1 && x < edit->column2)
1242 || (x > edit->column2 && x < edit->column1))
1243 return;
1244 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1245 return;
1247 if ((end_mark - start_mark) > option_max_undo / 2)
1248 if (edit_query_dialog2
1249 (_("Warning"),
1251 (" Block is large, you may not be able to undo this action. "),
1252 _("C&ontinue"), _("&Cancel")))
1253 return;
1255 edit_push_markers (edit);
1256 current = edit->curs1;
1257 if (column_highlighting) {
1258 long line;
1259 int size, c1, c2;
1260 line = edit->curs_line;
1261 if (edit->mark2 < 0)
1262 edit_mark_cmd (edit, 0);
1263 c1 = min (edit->column1, edit->column2);
1264 c2 = max (edit->column1, edit->column2);
1265 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1266 if (x < c2) {
1267 edit_block_delete_cmd (edit);
1268 deleted = 1;
1270 edit_move_to_line (edit, line);
1271 edit_cursor_move (edit,
1272 edit_move_forward3 (edit,
1273 edit_bol (edit, edit->curs1),
1274 x, 0) - edit->curs1);
1275 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1276 if (!deleted) {
1277 line = edit->curs_line;
1278 edit_update_curs_col (edit);
1279 x = edit->curs_col;
1280 edit_block_delete_cmd (edit);
1281 edit_move_to_line (edit, line);
1282 edit_cursor_move (edit,
1283 edit_move_forward3 (edit,
1284 edit_bol (edit,
1285 edit->curs1),
1286 x, 0) - edit->curs1);
1288 edit_set_markers (edit, 0, 0, 0, 0);
1289 edit_push_action (edit, COLUMN_ON);
1290 column_highlighting = 0;
1291 } else {
1292 copy_buf = g_malloc0 (end_mark - start_mark);
1293 edit_cursor_move (edit, start_mark - edit->curs1);
1294 edit_scroll_screen_over_cursor (edit);
1295 count = start_mark;
1296 while (count < end_mark) {
1297 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1298 count++;
1300 edit_scroll_screen_over_cursor (edit);
1301 edit_cursor_move (edit,
1302 current - edit->curs1 -
1303 (((current - edit->curs1) >
1304 0) ? end_mark - start_mark : 0));
1305 edit_scroll_screen_over_cursor (edit);
1306 while (count-- > start_mark)
1307 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1308 edit_set_markers (edit, edit->curs1,
1309 edit->curs1 + end_mark - start_mark, 0, 0);
1311 edit_scroll_screen_over_cursor (edit);
1312 g_free (copy_buf);
1313 edit->force |= REDRAW_PAGE;
1316 static void
1317 edit_delete_column_of_text (WEdit * edit)
1319 long p, q, r, m1, m2;
1320 long b, c, d, n;
1322 eval_marks (edit, &m1, &m2);
1323 n = edit_move_forward (edit, m1, 0, m2) + 1;
1324 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1325 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1326 b = max (min (c, d), min (edit->column1, edit->column2));
1327 c = max (c, max (edit->column1, edit->column2));
1329 while (n--) {
1330 r = edit_bol (edit, edit->curs1);
1331 p = edit_move_forward3 (edit, r, b, 0);
1332 q = edit_move_forward3 (edit, r, c, 0);
1333 if (p < m1)
1334 p = m1;
1335 if (q > m2)
1336 q = m2;
1337 edit_cursor_move (edit, p - edit->curs1);
1338 while (q > p) {
1339 /* delete line between margins */
1340 if (edit_get_byte (edit, edit->curs1) != '\n')
1341 edit_delete (edit, 1);
1342 q--;
1344 if (n)
1345 /* move to next line except on the last delete */
1346 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1350 /* if success return 0 */
1351 static int
1352 edit_block_delete (WEdit *edit)
1354 long count;
1355 long start_mark, end_mark;
1356 int curs_pos, line_width;
1357 long curs_line, c1, c2;
1359 if (eval_marks (edit, &start_mark, &end_mark))
1360 return 0;
1361 if (column_highlighting && edit->mark2 < 0)
1362 edit_mark_cmd (edit, 0);
1363 if ((end_mark - start_mark) > option_max_undo / 2) {
1364 /* Warning message with a query to continue or cancel the operation */
1365 if (edit_query_dialog2
1366 (_("Warning"),
1368 (" Block is large, you may not be able to undo this action. "),
1369 _("C&ontinue"), _("&Cancel"))) {
1370 return 1;
1373 c1 = min (edit->column1, edit->column2);
1374 c2 = max (edit->column1, edit->column2);
1375 edit->column1 = c1;
1376 edit->column2 = c2;
1378 edit_push_markers (edit);
1380 curs_line = edit->curs_line;
1382 /* calculate line width and cursor position before cut */
1383 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1384 edit_eol (edit, edit->curs1));
1385 curs_pos = edit->curs_col + edit->over_col;
1387 /* move cursor to start of selection */
1388 edit_cursor_move (edit, start_mark - edit->curs1);
1389 edit_scroll_screen_over_cursor (edit);
1390 count = start_mark;
1391 if (start_mark < end_mark) {
1392 if (column_highlighting) {
1393 if (edit->mark2 < 0)
1394 edit_mark_cmd (edit, 0);
1395 edit_delete_column_of_text (edit);
1396 /* move cursor to the saved position */
1397 edit_move_to_line (edit, curs_line);
1398 /* calculate line width after cut */
1399 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1400 edit_eol (edit, edit->curs1));
1401 if (option_cursor_beyond_eol && curs_pos > line_width)
1402 edit->over_col = curs_pos - line_width;
1403 } else {
1404 while (count < end_mark) {
1405 edit_delete (edit, 1);
1406 count++;
1410 edit_set_markers (edit, 0, 0, 0, 0);
1411 edit->force |= REDRAW_PAGE;
1412 return 0;
1415 /* returns 1 if canceelled by user */
1416 int edit_block_delete_cmd (WEdit * edit)
1418 long start_mark, end_mark;
1419 if (eval_marks (edit, &start_mark, &end_mark)) {
1420 edit_delete_line (edit);
1421 return 0;
1423 return edit_block_delete (edit);
1426 #define INPUT_INDEX 9
1428 static gboolean
1429 editcmd_find (WEdit *edit, gsize *len)
1431 off_t search_start = edit->search_start;
1432 off_t search_end;
1433 long start_mark = 0;
1434 long end_mark = edit->last_byte;
1435 int mark_res = 0;
1437 if (edit->only_in_selection) {
1438 mark_res = eval_marks(edit, &start_mark, &end_mark);
1439 if (mark_res != 0) {
1440 edit->search->error = MC_SEARCH_E_NOTFOUND;
1441 edit->search->error_str = g_strdup(_(" Search string not found "));
1442 return FALSE;
1444 if (edit->replace_backwards) {
1445 if (search_start > end_mark || search_start <= start_mark) {
1446 search_start = end_mark;
1448 } else {
1449 if (search_start < start_mark || search_start >= end_mark) {
1450 search_start = start_mark;
1453 } else {
1454 if (edit->replace_backwards)
1455 end_mark = max(1, edit->curs1) - 1;
1457 if (edit->replace_backwards) {
1458 search_end = end_mark;
1459 while ((int) search_start >= start_mark) {
1460 if (search_end > search_start + edit->search->original_len
1461 && mc_search_is_fixed_search_str(edit->search)) {
1462 search_end = search_start + edit->search->original_len;
1464 if (mc_search_run(edit->search, (void *) edit, search_start, search_end, len)
1465 && edit->search->normal_offset == search_start ) {
1466 return TRUE;
1468 search_start--;
1470 edit->search->error_str = g_strdup(_(" Search string not found "));
1471 } else {
1472 return mc_search_run(edit->search, (void *) edit, search_start, end_mark, len);
1474 return FALSE;
1478 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1479 (and the above) routines to work properly - paul */
1481 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1483 static char *
1484 edit_replace_cmd__conv_to_display (char *str)
1486 #ifdef HAVE_CHARSET
1487 GString *tmp;
1488 tmp = str_convert_to_display (str);
1490 if (tmp && tmp->len){
1491 return g_string_free (tmp, FALSE);
1493 g_string_free (tmp, TRUE);
1494 #endif
1495 return g_strdup(str);
1498 static char *
1499 edit_replace_cmd__conv_to_input(char *str)
1501 #ifdef HAVE_CHARSET
1502 GString *tmp;
1503 tmp = str_convert_to_input (str);
1505 if (tmp && tmp->len){
1506 return g_string_free (tmp, FALSE);
1508 g_string_free (tmp, TRUE);
1509 return g_strdup(str);
1510 #endif
1511 return g_strdup(str);
1513 /* call with edit = 0 before shutdown to close memory leaks */
1514 void
1515 edit_replace_cmd (WEdit *edit, int again)
1517 /* 1 = search string, 2 = replace with */
1518 static char *saved1 = NULL; /* saved default[123] */
1519 static char *saved2 = NULL;
1520 char *input1 = NULL; /* user input from the dialog */
1521 char *input2 = NULL;
1522 int replace_yes;
1523 long times_replaced = 0, last_search;
1524 gboolean once_found = FALSE;
1526 if (!edit) {
1527 g_free (saved1), saved1 = NULL;
1528 g_free (saved2), saved2 = NULL;
1529 return;
1532 last_search = edit->last_byte;
1534 edit->force |= REDRAW_COMPLETELY;
1536 if (again && !saved1 && !saved2)
1537 again = 0;
1539 if (again) {
1540 input1 = g_strdup (saved1 ? saved1 : "");
1541 input2 = g_strdup (saved2 ? saved2 : "");
1542 } else {
1543 char *disp1 = edit_replace_cmd__conv_to_display (saved1 ? saved1 : (char *) "");
1544 char *disp2 = edit_replace_cmd__conv_to_display (saved2 ? saved2 : (char *) "");
1545 char *tmp_inp1, *tmp_inp2;
1547 edit_push_action (edit, KEY_PRESS + edit->start_display);
1549 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1551 g_free (disp1);
1552 g_free (disp2);
1554 if (input1 == NULL || *input1 == '\0') {
1555 edit->force = REDRAW_COMPLETELY;
1556 goto cleanup;
1559 tmp_inp1 = input1; tmp_inp2 = input2;
1560 input1 = edit_replace_cmd__conv_to_input(input1);
1561 input2 = edit_replace_cmd__conv_to_input(input2);
1562 g_free(tmp_inp1); g_free(tmp_inp2);
1564 g_free (saved1), saved1 = g_strdup (input1);
1565 g_free (saved2), saved2 = g_strdup (input2);
1567 if (edit->search) {
1568 mc_search_free(edit->search);
1569 edit->search = NULL;
1573 if (!edit->search) {
1574 edit->search = mc_search_new(input1, -1);
1575 if (edit->search == NULL) {
1576 edit->search_start = edit->curs1;
1577 return;
1579 edit->search->search_type = edit->search_type;
1580 edit->search->is_all_charsets = edit->all_codepages;
1581 edit->search->is_case_sentitive = edit->replace_case;
1582 edit->search->whole_words = edit->whole_words;
1583 edit->search->search_fn = edit_search_cmd_callback;
1586 if (edit->found_len && edit->search_start == edit->found_start + 1
1587 && edit->replace_backwards)
1588 edit->search_start--;
1590 if (edit->found_len && edit->search_start == edit->found_start - 1
1591 && !edit->replace_backwards)
1592 edit->search_start++;
1594 do {
1595 gsize len = 0;
1596 long new_start;
1598 if (! editcmd_find(edit, &len)) {
1599 if (!(edit->search->error == MC_SEARCH_E_OK ||
1600 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND))) {
1601 edit_error_dialog (_ ("Search"), edit->search->error_str);
1603 break;
1605 once_found = TRUE;
1606 new_start = edit->search->normal_offset;
1608 edit->search_start = new_start = edit->search->normal_offset;
1609 /*returns negative on not found or error in pattern */
1611 if (edit->search_start >= 0) {
1612 guint i;
1614 edit->found_start = edit->search_start;
1615 i = edit->found_len = len;
1617 edit_cursor_move (edit, edit->search_start - edit->curs1);
1618 edit_scroll_screen_over_cursor (edit);
1620 replace_yes = 1;
1622 if (edit->replace_mode == 0) {
1623 int l;
1624 l = edit->curs_row - edit->num_widget_lines / 3;
1625 if (l > 0)
1626 edit_scroll_downward (edit, l);
1627 if (l < 0)
1628 edit_scroll_upward (edit, -l);
1630 edit_scroll_screen_over_cursor (edit);
1631 edit->force |= REDRAW_PAGE;
1632 edit_render_keypress (edit);
1634 /*so that undo stops at each query */
1635 edit_push_key_press (edit);
1636 /* and prompt 2/3 down */
1637 switch (editcmd_dialog_replace_prompt_show (edit, input1, input2, -1, -1)) {
1638 case B_ENTER:
1639 replace_yes = 1;
1640 break;
1641 case B_SKIP_REPLACE:
1642 replace_yes = 0;
1643 break;
1644 case B_REPLACE_ALL:
1645 edit->replace_mode=1;
1646 break;
1647 case B_CANCEL:
1648 replace_yes = 0;
1649 edit->replace_mode = -1;
1650 break;
1653 if (replace_yes) { /* delete then insert new */
1654 GString *repl_str, *tmp_str;
1655 tmp_str = g_string_new(input2);
1657 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1658 g_string_free(tmp_str, TRUE);
1659 if (edit->search->error != MC_SEARCH_E_OK)
1661 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1662 break;
1665 while (i--)
1666 edit_delete (edit, 1);
1668 while (++i < repl_str->len)
1669 edit_insert (edit, repl_str->str[i]);
1671 g_string_free(repl_str, TRUE);
1672 edit->found_len = i;
1674 /* so that we don't find the same string again */
1675 if (edit->replace_backwards) {
1676 last_search = edit->search_start;
1677 edit->search_start--;
1678 } else {
1679 edit->search_start += i;
1680 last_search = edit->last_byte;
1682 edit_scroll_screen_over_cursor (edit);
1683 } else {
1684 const char *msg = _(" Replace ");
1685 /* try and find from right here for next search */
1686 edit->search_start = edit->curs1;
1687 edit_update_curs_col (edit);
1689 edit->force |= REDRAW_PAGE;
1690 edit_render_keypress (edit);
1691 if (times_replaced) {
1692 message (D_NORMAL, msg, _(" %ld replacements made. "),
1693 times_replaced);
1694 } else
1695 query_dialog (msg, _(" Search string not found "),
1696 D_NORMAL, 1, _("&OK"));
1697 edit->replace_mode = -1;
1699 } while (edit->replace_mode >= 0);
1701 edit->force = REDRAW_COMPLETELY;
1702 edit_scroll_screen_over_cursor (edit);
1703 cleanup:
1704 g_free (input1);
1705 g_free (input2);
1709 void edit_search_cmd (WEdit * edit, int again)
1711 char *search_string = NULL, *search_string_dup = NULL;
1713 gsize len = 0;
1715 if (!edit)
1716 return;
1718 if (edit->search != NULL) {
1719 search_string = g_strndup(edit->search->original, edit->search->original_len);
1720 search_string_dup = search_string;
1721 } else {
1722 GList *history;
1723 history = history_get (MC_HISTORY_SHARED_SEARCH);
1724 if (history != NULL && history->data != NULL) {
1725 search_string_dup = search_string = (char *) g_strdup(history->data);
1726 history = g_list_first (history);
1727 g_list_foreach (history, (GFunc) g_free, NULL);
1728 g_list_free (history);
1730 edit->search_start = edit->curs1;
1733 if (!again) {
1734 #ifdef HAVE_CHARSET
1735 GString *tmp;
1736 if (search_string && *search_string) {
1737 tmp = str_convert_to_display (search_string);
1739 g_free(search_string_dup);
1740 search_string_dup = NULL;
1742 if (tmp && tmp->len)
1743 search_string = search_string_dup = tmp->str;
1744 g_string_free (tmp, FALSE);
1746 #endif /* HAVE_CHARSET */
1747 editcmd_dialog_search_show (edit, &search_string);
1748 #ifdef HAVE_CHARSET
1749 if (search_string && *search_string) {
1750 tmp = str_convert_to_input (search_string);
1751 if (tmp && tmp->len)
1752 search_string = tmp->str;
1754 g_string_free (tmp, FALSE);
1756 if (search_string_dup)
1757 g_free(search_string_dup);
1759 #endif /* HAVE_CHARSET */
1761 edit_push_action (edit, KEY_PRESS + edit->start_display);
1763 if (!search_string) {
1764 edit->force |= REDRAW_COMPLETELY;
1765 edit_scroll_screen_over_cursor (edit);
1766 return;
1769 if (edit->search) {
1770 mc_search_free(edit->search);
1771 edit->search = NULL;
1775 if (!edit->search) {
1776 edit->search = mc_search_new(search_string, -1);
1777 if (edit->search == NULL) {
1778 edit->search_start = edit->curs1;
1779 return;
1781 edit->search->search_type = edit->search_type;
1782 edit->search->is_all_charsets = edit->all_codepages;
1783 edit->search->is_case_sentitive = edit->replace_case;
1784 edit->search->whole_words = edit->whole_words;
1785 edit->search->search_fn = edit_search_cmd_callback;
1788 if (search_create_bookmark) {
1789 edit_search_cmd_search_create_bookmark(edit);
1790 } else {
1791 if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
1792 edit->search_start--;
1794 if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
1795 edit->search_start++;
1798 if (editcmd_find(edit, &len)) {
1799 edit->found_start = edit->search_start = edit->search->normal_offset;
1800 edit->found_len = len;
1801 edit->over_col = 0;
1802 edit_cursor_move (edit, edit->search_start - edit->curs1);
1803 edit_scroll_screen_over_cursor (edit);
1804 if (edit->replace_backwards)
1805 edit->search_start--;
1806 else
1807 edit->search_start++;
1808 } else {
1809 edit->search_start = edit->curs1;
1810 if (edit->search->error_str)
1811 edit_error_dialog (_ ("Search"), edit->search->error_str);
1815 edit->force |= REDRAW_COMPLETELY;
1816 edit_scroll_screen_over_cursor (edit);
1821 * Check if it's OK to close the editor. If there are unsaved changes,
1822 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
1825 edit_ok_to_exit (WEdit *edit)
1827 if (!edit->modified)
1828 return 1;
1830 if (!edit_check_newline (edit))
1831 return 0;
1833 switch (edit_query_dialog3
1834 (_("Quit"), _(" File was modified, Save with exit? "),
1835 _("&Cancel quit"), _("&Yes"), _("&No"))) {
1836 case 1:
1837 edit_push_markers (edit);
1838 edit_set_markers (edit, 0, 0, 0, 0);
1839 if (!edit_save_cmd (edit))
1840 return 0;
1841 break;
1842 case 2:
1843 break;
1844 case 0:
1845 case -1:
1846 return 0;
1849 return 1;
1852 /* Return a null terminated length of text. Result must be g_free'd */
1853 static unsigned char *
1854 edit_get_block (WEdit *edit, long start, long finish, int *l)
1856 unsigned char *s, *r;
1857 r = s = g_malloc0 (finish - start + 1);
1858 if (column_highlighting) {
1859 *l = 0;
1860 /* copy from buffer, excluding chars that are out of the column 'margins' */
1861 while (start < finish) {
1862 int c;
1863 long x;
1864 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
1865 start);
1866 c = edit_get_byte (edit, start);
1867 if ((x >= edit->column1 && x < edit->column2)
1868 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1869 *s++ = c;
1870 (*l)++;
1872 start++;
1874 } else {
1875 *l = finish - start;
1876 while (start < finish)
1877 *s++ = edit_get_byte (edit, start++);
1879 *s = 0;
1880 return r;
1883 /* save block, returns 1 on success */
1885 edit_save_block (WEdit * edit, const char *filename, long start,
1886 long finish)
1888 int len, file;
1890 if ((file =
1891 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
1892 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
1893 return 0;
1895 if (column_highlighting) {
1896 int r;
1897 r = mc_write (file, VERTICAL_MAGIC, sizeof(VERTICAL_MAGIC));
1898 if (r > 0) {
1899 unsigned char *block, *p;
1900 p = block = edit_get_block (edit, start, finish, &len);
1901 while (len) {
1902 r = mc_write (file, p, len);
1903 if (r < 0)
1904 break;
1905 p += r;
1906 len -= r;
1908 g_free (block);
1910 } else {
1911 unsigned char *buf;
1912 int i = start, end;
1913 len = finish - start;
1914 buf = g_malloc0 (TEMP_BUF_LEN);
1915 while (start != finish) {
1916 end = min (finish, start + TEMP_BUF_LEN);
1917 for (; i < end; i++)
1918 buf[i - start] = edit_get_byte (edit, i);
1919 len -= mc_write (file, (char *) buf, end - start);
1920 start = end;
1922 g_free (buf);
1924 mc_close (file);
1925 if (len)
1926 return 0;
1927 return 1;
1930 /* copies a block to clipboard file */
1931 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1933 int ret;
1934 gchar *tmp;
1935 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1936 ret = edit_save_block (edit, tmp, start, finish);
1937 g_free(tmp);
1938 return ret;
1942 void edit_paste_from_history (WEdit *edit)
1944 (void) edit;
1945 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
1948 int edit_copy_to_X_buf_cmd (WEdit * edit)
1950 long start_mark, end_mark;
1951 if (eval_marks (edit, &start_mark, &end_mark))
1952 return 0;
1953 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1954 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
1955 return 1;
1957 edit_mark_cmd (edit, 1);
1958 return 0;
1961 int edit_cut_to_X_buf_cmd (WEdit * edit)
1963 long start_mark, end_mark;
1964 if (eval_marks (edit, &start_mark, &end_mark))
1965 return 0;
1966 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1967 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
1968 return 1;
1970 edit_block_delete_cmd (edit);
1971 edit_mark_cmd (edit, 1);
1972 return 0;
1975 void edit_paste_from_X_buf_cmd (WEdit * edit)
1977 gchar *tmp;
1978 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1979 edit_insert_file (edit, tmp);
1980 g_free(tmp);
1985 * Ask user for the line and go to that line.
1986 * Negative numbers mean line from the end (i.e. -1 is the last line).
1988 void
1989 edit_goto_cmd (WEdit *edit)
1991 char *f;
1992 static long line = 0; /* line as typed, saved as default */
1993 long l;
1994 char *error;
1995 char s[32];
1997 g_snprintf (s, sizeof (s), "%ld", line);
1998 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
1999 line ? s : "");
2000 if (!f)
2001 return;
2003 if (!*f) {
2004 g_free (f);
2005 return;
2008 l = strtol (f, &error, 0);
2009 if (*error) {
2010 g_free (f);
2011 return;
2014 line = l;
2015 if (l < 0)
2016 l = edit->total_lines + l + 2;
2017 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2018 edit_move_to_line (edit, l - 1);
2019 edit->force |= REDRAW_COMPLETELY;
2020 g_free (f);
2024 /* Return 1 on success */
2026 edit_save_block_cmd (WEdit *edit)
2028 long start_mark, end_mark;
2029 char *exp, *tmp;
2031 if (eval_marks (edit, &start_mark, &end_mark))
2032 return 1;
2034 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2035 exp =
2036 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2037 MC_HISTORY_EDIT_SAVE_BLOCK,
2038 tmp);
2039 g_free(tmp);
2040 edit_push_action (edit, KEY_PRESS + edit->start_display);
2041 if (exp) {
2042 if (!*exp) {
2043 g_free (exp);
2044 return 0;
2045 } else {
2046 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2047 g_free (exp);
2048 edit->force |= REDRAW_COMPLETELY;
2049 return 1;
2050 } else {
2051 g_free (exp);
2052 edit_error_dialog (_(" Save Block "),
2053 get_sys_error (_
2054 (" Cannot save file. ")));
2058 edit->force |= REDRAW_COMPLETELY;
2059 return 0;
2063 /* returns 1 on success */
2065 edit_insert_file_cmd (WEdit *edit)
2067 gchar *tmp;
2068 char *exp;
2070 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2071 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2072 MC_HISTORY_EDIT_INSERT_FILE,
2073 tmp);
2074 g_free(tmp);
2075 edit_push_action (edit, KEY_PRESS + edit->start_display);
2076 if (exp) {
2077 if (!*exp) {
2078 g_free (exp);
2079 return 0;
2080 } else {
2081 if (edit_insert_file (edit, exp)) {
2082 g_free (exp);
2083 edit->force |= REDRAW_COMPLETELY;
2084 return 1;
2085 } else {
2086 g_free (exp);
2087 edit_error_dialog (_(" Insert File "),
2088 get_sys_error (_
2089 (" Cannot insert file. ")));
2093 edit->force |= REDRAW_COMPLETELY;
2094 return 0;
2097 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2098 int edit_sort_cmd (WEdit * edit)
2100 static char *old = 0;
2101 char *exp, *tmp;
2102 long start_mark, end_mark;
2103 int e;
2105 if (eval_marks (edit, &start_mark, &end_mark)) {
2106 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2107 return 0;
2110 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2111 edit_save_block (edit, tmp, start_mark, end_mark);
2112 g_free(tmp);
2114 exp = input_dialog (_(" Run Sort "),
2115 _(" Enter sort options (see manpage) separated by whitespace: "),
2116 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2118 if (!exp)
2119 return 1;
2120 g_free (old);
2121 old = exp;
2122 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2123 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2124 e = system (tmp);
2125 g_free(tmp);
2126 if (e) {
2127 if (e == -1 || e == 127) {
2128 edit_error_dialog (_(" Sort "),
2129 get_sys_error (_(" Cannot execute sort command ")));
2130 } else {
2131 char q[8];
2132 sprintf (q, "%d ", e);
2133 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
2134 edit_error_dialog (_(" Sort "), tmp);
2135 g_free(tmp);
2137 return -1;
2140 edit->force |= REDRAW_COMPLETELY;
2142 if (edit_block_delete_cmd (edit))
2143 return 1;
2144 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2145 edit_insert_file (edit, tmp);
2146 g_free(tmp);
2147 return 0;
2151 * Ask user for a command, execute it and paste its output back to the
2152 * editor.
2155 edit_ext_cmd (WEdit *edit)
2157 char *exp, *tmp;
2158 int e;
2160 exp =
2161 input_dialog (_("Paste output of external command"),
2162 _("Enter shell command(s):"),
2163 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2165 if (!exp)
2166 return 1;
2168 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2169 e = system (tmp);
2170 g_free(tmp);
2171 g_free (exp);
2173 if (e) {
2174 edit_error_dialog (_("External command"),
2175 get_sys_error (_("Cannot execute command")));
2176 return -1;
2179 edit->force |= REDRAW_COMPLETELY;
2180 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2181 edit_insert_file (edit, tmp);
2182 g_free(tmp);
2183 return 0;
2186 /* if block is 1, a block must be highlighted and the shell command
2187 processes it. If block is 0 the shell command is a straight system
2188 command, that just produces some output which is to be inserted */
2189 void
2190 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2192 long start_mark, end_mark;
2193 char buf[BUFSIZ];
2194 FILE *script_home = NULL;
2195 FILE *block_file = NULL;
2196 gchar *o, *h, *b, *tmp;
2197 char *quoted_name = NULL;
2199 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2200 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2201 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2203 script_home = fopen (h, "r");
2204 if (script_home == NULL) {
2205 FILE *script_src = NULL;
2207 script_home = fopen (h, "w");
2208 if (script_home == NULL) {
2209 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2210 edit_error_dialog ("", get_sys_error (tmp));
2211 g_free(tmp);
2212 goto edit_block_process_cmd__EXIT;
2215 script_src = fopen (o, "r");
2216 if (script_src == NULL) {
2217 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2218 script_src = fopen (o, "r");
2219 if (script_src == NULL) {
2220 fclose (script_home);
2221 unlink (h);
2222 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2223 edit_error_dialog ("", get_sys_error (tmp));
2224 g_free(tmp);
2225 goto edit_block_process_cmd__EXIT;
2228 while (fgets (buf, sizeof (buf), script_src))
2229 fputs (buf, script_home);
2230 fclose (script_src);
2232 if (fclose (script_home)) {
2233 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2234 edit_error_dialog ("", get_sys_error (tmp));
2235 g_free(tmp);
2236 goto edit_block_process_cmd__EXIT;
2238 chmod (h, 0700);
2239 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2240 edit_error_dialog ("", get_sys_error (tmp));
2241 g_free(tmp);
2244 open_error_pipe ();
2246 if (block) { /* for marked block run indent formatter */
2247 if (eval_marks (edit, &start_mark, &end_mark)) {
2248 edit_error_dialog (_("Process block"),
2250 (" You must first highlight a block of text. "));
2251 goto edit_block_process_cmd__EXIT;
2253 edit_save_block (edit, b, start_mark, end_mark);
2254 quoted_name = name_quote (edit->filename, 0);
2256 * Run script.
2257 * Initial space is to avoid polluting bash history.
2258 * Arguments:
2259 * $1 - name of the edited file (to check its extension etc).
2260 * $2 - file containing the current block.
2261 * $3 - file where error messages should be put
2262 * (for compatibility with old scripts).
2264 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2265 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2266 system (tmp);
2267 g_free(tmp);
2268 } else {
2270 * No block selected, just execute the command for the file.
2271 * Arguments:
2272 * $1 - name of the edited file.
2274 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2275 quoted_name, (char *) NULL);
2276 system (tmp);
2277 g_free(tmp);
2279 g_free (quoted_name);
2280 close_error_pipe (D_NORMAL, NULL);
2282 edit_refresh_cmd (edit);
2283 edit->force |= REDRAW_COMPLETELY;
2285 /* insert result block */
2286 if (block && !edit_block_delete_cmd (edit)) {
2287 edit_insert_file (edit, b);
2288 block_file = fopen (b, "w");
2289 if (block_file != NULL)
2290 fclose (block_file);
2293 edit_block_process_cmd__EXIT:
2294 g_free (b);
2295 g_free (h);
2296 g_free (o);
2299 /* prints at the cursor */
2300 /* returns the number of chars printed */
2301 int edit_print_string (WEdit * e, const char *s)
2303 size_t i = 0;
2304 while (s[i] != '\0')
2305 edit_execute_cmd (e, CK_Insert_Char, (unsigned char) s[i++]);
2306 e->force |= REDRAW_COMPLETELY;
2307 edit_update_screen (e);
2308 return i;
2312 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2314 FILE *p = 0;
2315 char *s;
2317 to = name_quote (to, 0);
2318 subject = name_quote (subject, 0);
2319 cc = name_quote (cc, 0);
2320 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2321 g_free (to);
2322 g_free (subject);
2323 g_free (cc);
2325 if (s) {
2326 p = popen (s, "w");
2327 g_free (s);
2330 if (p) {
2331 long i;
2332 for (i = 0; i < edit->last_byte; i++)
2333 fputc (edit_get_byte (edit, i), p);
2334 pclose (p);
2338 #define MAIL_DLG_HEIGHT 12
2340 void edit_mail_dialog (WEdit * edit)
2342 char *tmail_to;
2343 char *tmail_subject;
2344 char *tmail_cc;
2346 static char *mail_cc_last = 0;
2347 static char *mail_subject_last = 0;
2348 static char *mail_to_last = 0;
2350 QuickWidget quick_widgets[] =
2352 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2353 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2354 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2355 /* 3 */ QUICK_LABEL (2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to")),
2356 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2", &tmail_subject),
2357 /* 5 */ QUICK_LABEL (2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject")),
2358 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2359 /* 7 */ QUICK_LABEL (2, 50, 3, MAIL_DLG_HEIGHT, N_(" To")),
2360 /* 8 */ QUICK_LABEL (2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>")),
2361 QUICK_END
2364 QuickDialog Quick_input =
2366 50, MAIL_DLG_HEIGHT, -1, -1, N_(" Mail "),
2367 "[Input Line Keys]", quick_widgets, FALSE
2370 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2371 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2372 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2374 if (quick_dialog (&Quick_input) != B_CANCEL) {
2375 g_free (mail_cc_last);
2376 g_free (mail_subject_last);
2377 g_free (mail_to_last);
2378 mail_cc_last = tmail_cc;
2379 mail_subject_last = tmail_subject;
2380 mail_to_last = tmail_to;
2381 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2386 /*******************/
2387 /* Word Completion */
2388 /*******************/
2390 static gboolean is_break_char(char c)
2392 return (isspace(c) || strchr("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2395 /* find first character of current word */
2396 static int edit_find_word_start (WEdit *edit, long *word_start, gsize *word_len)
2398 int c, last;
2399 gsize i;
2401 /* return if at begin of file */
2402 if (edit->curs1 <= 0)
2403 return 0;
2405 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2406 /* return if not at end or in word */
2407 if (is_break_char(c))
2408 return 0;
2410 /* search start of word to be completed */
2411 for (i = 2;; i++) {
2412 /* return if at begin of file */
2413 if (edit->curs1 - i < 0)
2414 return 0;
2416 last = c;
2417 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2419 if (is_break_char(c)) {
2420 /* return if word starts with digit */
2421 if (isdigit (last))
2422 return 0;
2424 *word_start = edit->curs1 - (i - 1); /* start found */
2425 *word_len = i - 1;
2426 break;
2429 /* success */
2430 return 1;
2433 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2435 /* collect the possible completions */
2436 static gsize
2437 edit_collect_completions (WEdit *edit, long start, gsize word_len,
2438 char *match_expr, struct selection *compl,
2439 gsize *num)
2441 gsize len = 0;
2442 gsize max_len = 0;
2443 gsize i;
2444 int skip;
2445 GString *temp;
2446 mc_search_t *srch;
2448 long last_byte;
2450 srch = mc_search_new(match_expr, -1);
2451 if (srch == NULL)
2452 return 0;
2454 if (mc_config_get_bool(mc_main_config, CONFIG_APP_SECTION, "editor_wordcompletion_collect_entire_file", 0)){
2455 last_byte = edit->last_byte;
2456 } else {
2457 last_byte = start;
2460 srch->search_type = MC_SEARCH_T_REGEX;
2461 srch->is_case_sentitive = TRUE;
2462 srch->search_fn = edit_search_cmd_callback;
2464 /* collect max MAX_WORD_COMPLETIONS completions */
2465 start = -1;
2466 while (1) {
2467 /* get next match */
2468 if (mc_search_run (srch, (void *) edit, start+1, last_byte, &len) == FALSE)
2469 break;
2470 start = srch->normal_offset;
2472 /* add matched completion if not yet added */
2473 temp = g_string_new("");
2474 for (i = 0; i < len; i++){
2475 skip = edit_get_byte(edit, start+i);
2476 if (isspace(skip))
2477 continue;
2478 g_string_append_c (temp, skip);
2481 skip = 0;
2483 for (i = 0; i < (gsize) *num; i++) {
2484 if (strncmp
2486 (char *) &compl[i].text[word_len],
2487 (char *) &temp->str[word_len],
2488 max (len, compl[i].len) - (gsize)word_len
2489 ) == 0) {
2490 struct selection this = compl[i];
2491 for (++i; i < *num; i++) {
2492 compl[i - 1] = compl[i];
2494 compl[*num - 1] = this;
2495 skip = 1;
2496 break; /* skip it, already added */
2499 if (skip) {
2500 g_string_free(temp, TRUE);
2501 continue;
2503 if (*num == MAX_WORD_COMPLETIONS && MAX_WORD_COMPLETIONS) {
2504 g_free(compl[0].text);
2505 for (i = 1; i < *num; i++) {
2506 compl[i - 1] = compl[i];
2508 (*num)--;
2510 #ifdef HAVE_CHARSET
2512 GString *recoded;
2513 recoded = str_convert_to_display (temp->str);
2515 if (recoded && recoded->len){
2516 g_string_free(temp,TRUE);
2517 temp = recoded;
2518 } else
2519 g_string_free(recoded , TRUE);
2521 #endif
2522 compl[*num].text = temp->str;
2523 compl[*num].len = temp->len;
2524 (*num)++;
2525 start += len;
2526 g_string_free(temp, FALSE);
2528 /* note the maximal length needed for the completion dialog */
2529 if (len > max_len)
2530 max_len = len;
2532 mc_search_free(srch);
2533 return max_len;
2537 * Complete current word using regular expression search
2538 * backwards beginning at the current cursor position.
2540 void
2541 edit_complete_word_cmd (WEdit *edit)
2543 gsize i, max_len, word_len = 0, num_compl = 0;
2544 long word_start = 0;
2545 unsigned char *bufpos;
2546 char *match_expr;
2547 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2549 /* search start of word to be completed */
2550 if (!edit_find_word_start (edit, &word_start, &word_len))
2551 return;
2553 /* prepare match expression */
2554 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2555 [word_start & M_EDIT_BUF_SIZE];
2557 /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
2558 match_expr = g_strdup_printf ("(^|\\s+|\\b)%.*s[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+", (int)word_len, bufpos);
2560 /* collect the possible completions */
2561 /* start search from begin to end of file */
2562 max_len =
2563 edit_collect_completions (edit, word_start, word_len, match_expr,
2564 (struct selection *) &compl, &num_compl);
2566 if (num_compl > 0) {
2567 /* insert completed word if there is only one match */
2568 if (num_compl == 1) {
2569 for (i = word_len; i < compl[0].len; i++)
2570 edit_insert (edit, *(compl[0].text + i));
2572 /* more than one possible completion => ask the user */
2573 else {
2574 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2575 /* !!! pressed again the selection dialog pops up, but that !!! */
2576 /* !!! seems to require a further internal state !!! */
2577 /*tty_beep (); */
2579 /* let the user select the preferred completion */
2580 editcmd_dialog_completion_show (edit, max_len, word_len,
2581 (struct selection *) &compl,
2582 num_compl);
2586 g_free (match_expr);
2587 /* release memory before return */
2588 for (i = 0; i < num_compl; i++)
2589 g_free (compl[i].text);
2592 void
2593 edit_select_codepage_cmd (WEdit *edit)
2595 #ifdef HAVE_CHARSET
2596 const char *cp_id = NULL;
2597 if (do_select_codepage ()) {
2598 cp_id = get_codepage_id (source_codepage >= 0 ?
2599 source_codepage : display_codepage);
2601 if (cp_id != NULL) {
2602 GIConv conv;
2603 conv = str_crt_conv_from (cp_id);
2604 if (conv != INVALID_CONV) {
2605 if (edit->converter != str_cnv_from_term)
2606 str_close_conv (edit->converter);
2607 edit->converter = conv;
2611 if (cp_id != NULL)
2612 edit->utf8 = str_isutf8 (cp_id);
2615 edit->force = REDRAW_COMPLETELY;
2616 edit_refresh_cmd (edit);
2617 #else
2618 (void) edit;
2619 #endif
2622 void
2623 edit_insert_literal_cmd (WEdit *edit)
2625 int char_for_insertion =
2626 editcmd_dialog_raw_key_query (_(" Insert Literal "),
2627 _(" Press any key: "), 0);
2628 edit_execute_key_command (edit, -1,
2629 ascii_alpha_to_cntrl (char_for_insertion));
2632 void
2633 edit_execute_macro_cmd (WEdit *edit)
2635 int command =
2636 CK_Macro (editcmd_dialog_raw_key_query
2637 (_(" Execute Macro "), _(" Press macro hotkey: "),
2638 1));
2639 if (command == CK_Macro (0))
2640 command = CK_Insert_Char;
2642 edit_execute_key_command (edit, command, -1);
2645 void
2646 edit_begin_end_macro_cmd (WEdit *edit)
2648 /* edit is a pointer to the widget */
2649 if (edit) {
2650 unsigned long command = edit->macro_i < 0
2651 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2652 edit_execute_key_command (edit, command, -1);
2657 edit_load_forward_cmd (WEdit *edit)
2659 if (edit->modified) {
2660 if (edit_query_dialog2
2661 (_("Warning"),
2662 _(" Current text was modified without a file save. \n"
2663 " Continue discards these changes. "), _("C&ontinue"),
2664 _("&Cancel"))) {
2665 edit->force |= REDRAW_COMPLETELY;
2666 return 0;
2669 if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
2670 if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
2671 return 1;
2673 edit_stack_iterator++;
2674 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2675 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2676 edit_history_moveto[edit_stack_iterator].line);
2677 return 0;
2678 } else {
2679 return 1;
2681 } else {
2682 return 1;
2687 edit_load_back_cmd (WEdit *edit)
2689 if (edit->modified) {
2690 if (edit_query_dialog2
2691 (_("Warning"),
2692 _(" Current text was modified without a file save. \n"
2693 " Continue discards these changes. "), _("C&ontinue"),
2694 _("&Cancel"))) {
2695 edit->force |= REDRAW_COMPLETELY;
2696 return 0;
2699 if ( edit_stack_iterator > 0 ) {
2700 edit_stack_iterator--;
2701 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2702 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2703 edit_history_moveto[edit_stack_iterator].line);
2704 return 0;
2705 } else {
2706 return 1;
2708 } else {
2709 return 1;
2713 void
2714 edit_get_match_keyword_cmd (WEdit *edit)
2716 gsize word_len = 0, max_len = 0;
2717 int num_def = 0;
2718 int i;
2719 long word_start = 0;
2720 unsigned char *bufpos;
2721 char *match_expr;
2722 char *path = NULL;
2723 char *ptr = NULL;
2724 char *tagfile = NULL;
2726 etags_hash_t def_hash[MAX_DEFINITIONS];
2728 for ( i = 0; i < MAX_DEFINITIONS; i++) {
2729 def_hash[i].filename = NULL;
2732 /* search start of word to be completed */
2733 if (!edit_find_word_start (edit, &word_start, &word_len))
2734 return;
2736 /* prepare match expression */
2737 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2738 [word_start & M_EDIT_BUF_SIZE];
2739 match_expr = g_strdup_printf ("%.*s", (int)word_len, bufpos);
2741 ptr = g_get_current_dir ();
2742 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
2743 g_free (ptr);
2745 /* Recursive search file 'TAGS' in parent dirs */
2746 do {
2747 ptr = g_path_get_dirname (path);
2748 g_free(path); path = ptr;
2749 g_free (tagfile);
2750 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
2751 if ( exist_file (tagfile) )
2752 break;
2753 } while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
2755 if (tagfile){
2756 num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
2757 g_free (tagfile);
2759 g_free (path);
2761 max_len = MAX_WIDTH_DEF_DIALOG;
2762 word_len = 0;
2763 if ( num_def > 0 ) {
2764 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
2765 (etags_hash_t *) &def_hash,
2766 num_def);
2768 g_free (match_expr);
2771 void
2772 edit_move_block_to_right (WEdit * edit)
2774 long start_mark, end_mark;
2775 long cur_bol, start_bol;
2777 if ( eval_marks (edit, &start_mark, &end_mark) )
2778 return;
2780 start_bol = edit_bol (edit, start_mark);
2781 cur_bol = edit_bol (edit, end_mark - 1);
2782 do {
2783 edit_cursor_move (edit, cur_bol - edit->curs1);
2784 if ( option_fill_tabs_with_spaces ) {
2785 if ( option_fake_half_tabs ) {
2786 insert_spaces_tab (edit, 1);
2787 } else {
2788 insert_spaces_tab (edit, 0);
2790 } else {
2791 edit_insert (edit, '\t');
2793 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
2794 if ( cur_bol == 0 ) {
2795 break;
2797 cur_bol = edit_bol (edit, cur_bol - 1);
2798 } while (cur_bol >= start_bol) ;
2799 edit->force |= REDRAW_PAGE;
2802 void
2803 edit_move_block_to_left (WEdit * edit)
2805 long start_mark, end_mark;
2806 long cur_bol, start_bol;
2807 int i, del_tab_width;
2808 int next_char;
2810 if ( eval_marks (edit, &start_mark, &end_mark) )
2811 return;
2813 start_bol = edit_bol (edit, start_mark);
2814 cur_bol = edit_bol (edit, end_mark - 1);
2815 do {
2816 edit_cursor_move (edit, cur_bol - edit->curs1);
2817 if (option_fake_half_tabs) {
2818 del_tab_width = HALF_TAB_SIZE;
2819 } else {
2820 del_tab_width = option_tab_spacing;
2822 next_char = edit_get_byte (edit, edit->curs1);
2823 if ( next_char == '\t' ) {
2824 edit_delete (edit, 1);
2825 } else if ( next_char == ' ' ) {
2826 for (i = 1; i <= del_tab_width; i++) {
2827 if ( next_char == ' ' ) {
2828 edit_delete (edit, 1);
2830 next_char = edit_get_byte (edit, edit->curs1);
2833 if ( cur_bol == 0 ) {
2834 break;
2836 cur_bol = edit_bol (edit, cur_bol - 1);
2837 } while (cur_bol >= start_bol) ;
2838 edit->force |= REDRAW_PAGE;