Ticket #1823
[midnight-commander.git] / edit / editcmd.c
blob47cdf635114b4b7ec30972438c1559661f09114e
1 /* editor high level editing commands
3 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007 Free Software Foundation, Inc.
6 Authors: 1996, 1997 Paul Sheer
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
25 /** \file
26 * \brief Source: editor high level editing commands
27 * \author Paul Sheer
28 * \date 1996, 1997
31 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
33 #include <config.h>
35 #include <assert.h>
36 #include <ctype.h>
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <sys/stat.h>
45 #include <stdlib.h>
46 #include <fcntl.h>
48 #include "../src/global.h"
50 #include "../src/tty/tty.h"
51 #include "../src/tty/key.h" /* XCTRL */
53 #include "../src/mcconfig/mcconfig.h"
55 #include "../src/skin/skin.h"
57 #include "../src/history.h"
58 #include "../src/widget.h" /* listbox_new() */
59 #include "../src/layout.h" /* clr_scr() */
60 #include "../src/main.h" /* mc_home source_codepage */
61 #include "../src/help.h" /* interactive_display() */
62 #include "../src/wtools.h" /* message() */
63 #include "../src/charsets.h"
64 #include "../src/selcodepage.h"
65 #include "../src/strutil.h" /* utf string functions */
66 #include "../src/cmddef.h"
68 #include "../vfs/vfs.h"
70 #include "../edit/edit-impl.h"
71 #include "../edit/edit.h"
72 #include "../edit/editlock.h"
73 #include "../edit/edit-widget.h"
74 #include "../edit/editcmd_dialogs.h"
75 #include "../edit/etags.h"
77 /* globals: */
79 /* search and replace: */
80 int search_create_bookmark = 0;
81 /* static int search_in_all_charsets = 0; */
83 /* queries on a save */
84 int edit_confirm_save = 1;
86 static int edit_save_cmd (WEdit *edit);
87 static unsigned char *edit_get_block (WEdit *edit, long start,
88 long finish, int *l);
90 static void
91 edit_search_cmd_search_create_bookmark(WEdit * edit)
93 int found = 0, books = 0;
94 long l = 0, l_last = -1;
95 long q = 0;
96 gsize len = 0;
98 search_create_bookmark = 0;
99 book_mark_flush (edit, -1);
101 for (;;) {
102 if (!mc_search_run(edit->search, (void *) edit, q, edit->last_byte, &len))
103 break;
104 if (found == 0)
105 edit->search_start = edit->search->normal_offset;
106 found++;
107 l += edit_count_lines (edit, q, edit->search->normal_offset);
108 if (l != l_last) {
109 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
110 books++;
112 l_last = l;
113 q = edit->search->normal_offset + 1;
116 if (found == 0) {
117 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
118 } else {
119 edit_cursor_move (edit, edit->search_start - edit->curs1);
120 edit_scroll_screen_over_cursor (edit);
124 static int
125 edit_search_cmd_callback(const void *user_data, gsize char_offset)
127 return edit_get_byte ((WEdit * )user_data, (long) char_offset);
130 void 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 clr_scr ();
147 repaint_screen ();
148 #endif /* !HAVE_SLANG */
149 tty_keypad (TRUE);
152 /* If 0 (quick save) then a) create/truncate <filename> file,
153 b) save to <filename>;
154 if 1 (safe save) then a) save to <tempnam>,
155 b) rename <tempnam> to <filename>;
156 if 2 (do backups) then a) save to <tempnam>,
157 b) rename <filename> to <filename.backup_ext>,
158 c) rename <tempnam> to <filename>. */
160 /* returns 0 on error, -1 on abort */
161 static int
162 edit_save_file (WEdit *edit, const char *filename)
164 char *p;
165 gchar *tmp;
166 long filelen = 0;
167 char *savename = 0;
168 gchar *real_filename;
169 int this_save_mode, fd = -1;
171 if (!filename)
172 return 0;
173 if (!*filename)
174 return 0;
176 if (*filename != PATH_SEP && edit->dir) {
177 real_filename = concat_dir_and_file (edit->dir, filename);
178 } else {
179 real_filename = g_strdup(filename);
182 this_save_mode = option_save_mode;
183 if (this_save_mode != EDIT_QUICK_SAVE) {
184 if (!vfs_file_is_local (real_filename) ||
185 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1) {
187 * The file does not exists yet, so no safe save or
188 * backup are necessary.
190 this_save_mode = EDIT_QUICK_SAVE;
192 if (fd != -1)
193 mc_close (fd);
196 if (this_save_mode == EDIT_QUICK_SAVE &&
197 !edit->skip_detach_prompt) {
198 int rv;
199 struct stat sb;
201 rv = mc_stat (real_filename, &sb);
202 if (rv == 0 && sb.st_nlink > 1) {
203 rv = edit_query_dialog3 (_("Warning"),
204 _(" File has hard-links. Detach before saving? "),
205 _("&Yes"), _("&No"), _("&Cancel"));
206 switch (rv) {
207 case 0:
208 this_save_mode = EDIT_SAFE_SAVE;
209 /* fallthrough */
210 case 1:
211 edit->skip_detach_prompt = 1;
212 break;
213 default:
214 g_free(real_filename);
215 return -1;
219 /* Prevent overwriting changes from other editor sessions. */
220 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
222 /* The default action is "Cancel". */
223 query_set_sel(1);
225 rv = edit_query_dialog2 (
226 _("Warning"),
227 _("The file has been modified in the meantime. Save anyway?"),
228 _("&Yes"),
229 _("&Cancel"));
230 if (rv != 0){
231 g_free(real_filename);
232 return -1;
237 if (this_save_mode != EDIT_QUICK_SAVE) {
238 char *savedir, *saveprefix;
239 const char *slashpos;
240 slashpos = strrchr (real_filename, PATH_SEP);
241 if (slashpos) {
242 savedir = g_strdup (real_filename);
243 savedir[slashpos - real_filename + 1] = '\0';
244 } else
245 savedir = g_strdup (".");
246 saveprefix = concat_dir_and_file (savedir, "cooledit");
247 g_free (savedir);
248 fd = mc_mkstemps (&savename, saveprefix, NULL);
249 g_free (saveprefix);
250 if (!savename){
251 g_free(real_filename);
252 return 0;
254 /* FIXME:
255 * Close for now because mc_mkstemps use pure open system call
256 * to create temporary file and it needs to be reopened by
257 * VFS-aware mc_open().
259 close (fd);
260 } else
261 savename = g_strdup (real_filename);
263 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
264 mc_chmod (savename, edit->stat1.st_mode);
266 if ((fd =
267 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
268 edit->stat1.st_mode)) == -1)
269 goto error_save;
271 /* pipe save */
272 if ((p = edit_get_write_filter (savename, real_filename))) {
273 FILE *file;
275 mc_close (fd);
276 file = (FILE *) popen (p, "w");
278 if (file) {
279 filelen = edit_write_stream (edit, file);
280 #if 1
281 pclose (file);
282 #else
283 if (pclose (file) != 0) {
284 tmp = g_strconcat (_(" Error writing to pipe: "),
285 p, " ", (char *) NULL);
286 edit_error_dialog (_("Error"), tmp);
287 g_free(tmp);
288 g_free (p);
289 goto error_save;
291 #endif
292 } else {
293 tmp = g_strconcat (_(" Cannot open pipe for writing: "),
294 p, " ", (char *) NULL);
296 edit_error_dialog (_("Error"),
297 get_sys_error (tmp));
298 g_free (p);
299 g_free(tmp);
300 goto error_save;
302 g_free (p);
303 } else if (edit->lb == LB_ASIS) { /* do not change line breaks */
304 long buf;
305 buf = 0;
306 filelen = edit->last_byte;
307 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
308 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
309 != EDIT_BUF_SIZE) {
310 mc_close (fd);
311 goto error_save;
313 buf++;
315 if (mc_write
316 (fd, (char *) edit->buffers1[buf],
317 edit->curs1 & M_EDIT_BUF_SIZE) !=
318 (edit->curs1 & M_EDIT_BUF_SIZE)) {
319 filelen = -1;
320 } else if (edit->curs2) {
321 edit->curs2--;
322 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
323 if (mc_write
324 (fd,
325 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
326 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
327 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
328 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
329 filelen = -1;
330 } else {
331 while (--buf >= 0) {
332 if (mc_write
333 (fd, (char *) edit->buffers2[buf],
334 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
335 filelen = -1;
336 break;
340 edit->curs2++;
342 if (mc_close (fd))
343 goto error_save;
345 /* Update the file information, especially the mtime. */
346 if (mc_stat (savename, &edit->stat1) == -1)
347 goto error_save;
348 } else { /* change line breaks */
349 FILE *file;
351 mc_close (fd);
353 file = (FILE *) fopen (savename, "w");
355 if (file) {
356 filelen = edit_write_stream (edit, file);
357 fclose (file);
358 } else {
359 char *msg;
361 msg = g_strdup_printf (_(" Cannot open file for writing: %s "), savename);
362 edit_error_dialog (_("Error"), msg);
363 g_free (msg);
364 goto error_save;
368 if (filelen != edit->last_byte)
369 goto error_save;
371 if (this_save_mode == EDIT_DO_BACKUP) {
372 assert (option_backup_ext != NULL);
373 tmp = g_strconcat (real_filename, option_backup_ext, (char *) NULL);
374 if (mc_rename (real_filename, tmp) == -1){
375 g_free(tmp);
376 goto error_save;
380 if (this_save_mode != EDIT_QUICK_SAVE)
381 if (mc_rename (savename, real_filename) == -1)
382 goto error_save;
383 g_free (savename);
384 g_free(real_filename);
385 return 1;
386 error_save:
387 /* FIXME: Is this safe ?
388 * if (this_save_mode != EDIT_QUICK_SAVE)
389 * mc_unlink (savename);
391 g_free(real_filename);
392 g_free (savename);
393 return 0;
396 void
397 menu_save_mode_cmd (void)
399 /* diaog sizes */
400 const int DLG_X = 38;
401 const int DLG_Y = 13;
403 char *str_result;
405 const char *str[] =
407 N_("&Quick save"),
408 N_("&Safe save"),
409 N_("&Do backups with following extension:")
412 QuickWidget widgets[] =
414 /* 0 */
415 QUICK_BUTTON (18, DLG_X, DLG_Y - 3, DLG_Y, N_("&Cancel"), B_CANCEL, NULL),
416 /* 1 */
417 QUICK_BUTTON ( 6, DLG_X, DLG_Y - 3, DLG_Y, N_("&OK"), B_ENTER, NULL),
418 /* 2 */
419 QUICK_CHECKBOX ( 4, DLG_X, 8, DLG_Y, N_("Check &POSIX new line"), &option_check_nl_at_eof),
420 /* 3 */
421 QUICK_INPUT ( 8, DLG_X, 6, DLG_Y, option_backup_ext, 9, 0, "edit-backup-ext", &str_result),
422 /* 4 */
423 QUICK_RADIO ( 4, DLG_X, 3, DLG_Y, 3, str, &option_save_mode),
424 QUICK_END
427 QuickDialog dialog =
429 DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "),
430 "[Edit Save Mode]", widgets, FALSE
433 size_t i;
434 size_t maxlen = 0;
435 size_t w0, w1, b_len, w3;
437 assert (option_backup_ext != NULL);
439 /* OK/Cancel buttons */
440 w0 = str_term_width1 (_(widgets[0].u.button.text)) + 3;
441 w1 = str_term_width1 (_(widgets[1].u.button.text)) + 5; /* default button */
442 b_len = w0 + w1 + 3;
444 maxlen = max (b_len, (size_t) str_term_width1 (_(dialog.title)) + 2);
446 w3 = 0;
447 for (i = 0; i < 3; i++) {
448 #ifdef ENABLE_NLS
449 str[i] = _(str[i]);
450 #endif
451 w3 = max (w3, (size_t) str_term_width1 (str[i]));
454 maxlen = max (maxlen, w3 + 4);
456 dialog.xlen = min ((size_t) COLS, maxlen + 8);
458 widgets[3].u.input.len = w3;
459 widgets[1].relative_x = (dialog.xlen - b_len)/2;
460 widgets[0].relative_x = widgets[1].relative_x + w0 + 2;
462 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
463 widgets[i].x_divisions = dialog.xlen;
465 if (quick_dialog (&dialog) != B_CANCEL) {
466 g_free (option_backup_ext);
467 option_backup_ext = str_result;
471 void
472 edit_set_filename (WEdit *edit, const char *f)
474 g_free (edit->filename);
475 if (!f)
476 f = "";
477 edit->filename = g_strdup (f);
478 if (edit->dir == NULL && *f != PATH_SEP)
479 #ifdef ENABLE_VFS
480 edit->dir = g_strdup (vfs_get_current_dir ());
481 #else /* ENABLE_VFS */
482 edit->dir = g_get_current_dir ();
483 #endif /* ENABLE_VFS */
486 static gboolean
487 edit_check_newline (WEdit *edit)
489 return !(option_check_nl_at_eof && edit->last_byte > 0
490 && edit_get_byte (edit, edit->last_byte - 1) != '\n'
491 && edit_query_dialog2 (_("Warning"),
492 _("The file you are saving is not finished with a newline"),
493 _("C&ontinue"), _("&Cancel")));
496 static char *
497 edit_get_save_file_as (WEdit *edit)
499 #define DLG_WIDTH 64
500 #define DLG_HEIGHT 14
502 static LineBreaks cur_lb = LB_ASIS;
504 char *filename = edit->filename;
506 const char *lb_names[LB_NAMES] =
508 N_("&Do not change"),
509 N_("&Unix format (LF)"),
510 N_("&Windows/DOS format (CR LF)"),
511 N_("&Macintosh format (CR)")
514 QuickWidget quick_widgets[] =
516 QUICK_BUTTON (6, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
517 QUICK_BUTTON (2, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
518 QUICK_RADIO (5, DLG_WIDTH, DLG_HEIGHT - 8, DLG_HEIGHT, LB_NAMES, lb_names, (int *) &cur_lb),
519 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 9, DLG_HEIGHT, N_("Change line breaks to:")),
520 QUICK_INPUT (3, DLG_WIDTH, DLG_HEIGHT - 11, DLG_HEIGHT, filename, DLG_WIDTH - 6, 0, "save-as", &filename),
521 QUICK_LABEL (2, DLG_WIDTH, DLG_HEIGHT - 12, DLG_HEIGHT, N_(" Enter file name: ")),
522 QUICK_END
525 QuickDialog Quick_options =
527 DLG_WIDTH, DLG_HEIGHT, -1, -1,
528 N_(" Save As "), "[Save File As]",
529 quick_widgets, FALSE
532 if (quick_dialog (&Quick_options) != B_CANCEL) {
533 edit->lb = cur_lb;
534 return filename;
537 return NULL;
539 #undef DLG_WIDTH
540 #undef DLG_HEIGHT
543 /* Here we want to warn the users of overwriting an existing file,
544 but only if they have made a change to the filename */
545 /* returns 1 on success */
547 edit_save_as_cmd (WEdit *edit)
549 /* This heads the 'Save As' dialog box */
550 char *exp;
551 int save_lock = 0;
552 int different_filename = 0;
554 if (!edit_check_newline (edit))
555 return 0;
557 exp = edit_get_save_file_as (edit);
558 edit_push_action (edit, KEY_PRESS + edit->start_display);
560 if (exp) {
561 if (!*exp) {
562 g_free (exp);
563 edit->force |= REDRAW_COMPLETELY;
564 return 0;
565 } else {
566 int rv;
567 if (strcmp (edit->filename, exp)) {
568 int file;
569 different_filename = 1;
570 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
571 /* the file exists */
572 mc_close (file);
573 /* Overwrite the current file or cancel the operation */
574 if (edit_query_dialog2
575 (_("Warning"),
576 _(" A file already exists with this name. "),
577 _("&Overwrite"), _("&Cancel"))) {
578 edit->force |= REDRAW_COMPLETELY;
579 g_free (exp);
580 return 0;
582 } else {
583 edit->stat1.st_mode |= S_IWUSR;
585 save_lock = edit_lock_file (exp);
586 } else {
587 /* filenames equal, check if already locked */
588 if (!edit->locked && !edit->delete_file)
589 save_lock = edit_lock_file (exp);
592 if (different_filename)
595 * Allow user to write into saved (under another name) file
596 * even if original file had r/o user permissions.
598 edit->stat1.st_mode |= S_IWRITE;
601 rv = edit_save_file (edit, exp);
602 switch (rv) {
603 case 1:
604 /* Succesful, so unlock both files */
605 if (different_filename) {
606 if (save_lock)
607 edit_unlock_file (exp);
608 if (edit->locked)
609 edit->locked = edit_unlock_file (edit->filename);
610 } else {
611 if (edit->locked || save_lock)
612 edit->locked = edit_unlock_file (edit->filename);
615 edit_set_filename (edit, exp);
616 if (edit->lb != LB_ASIS)
617 edit_reload(edit, exp);
618 g_free (exp);
619 edit->modified = 0;
620 edit->delete_file = 0;
621 if (different_filename)
622 edit_load_syntax (edit, NULL, option_syntax_type);
623 edit->force |= REDRAW_COMPLETELY;
624 return 1;
625 default:
626 edit_error_dialog (_(" Save As "),
627 get_sys_error (_
628 (" Cannot save file. ")));
629 /* fallthrough */
630 case -1:
631 /* Failed, so maintain modify (not save) lock */
632 if (save_lock)
633 edit_unlock_file (exp);
634 g_free (exp);
635 edit->force |= REDRAW_COMPLETELY;
636 return 0;
640 edit->force |= REDRAW_COMPLETELY;
641 return 0;
644 /* {{{ Macro stuff starts here */
646 /* creates a macro file if it doesn't exist */
647 static FILE *edit_open_macro_file (const char *r)
649 gchar *filename;
650 FILE *fd;
651 int file;
652 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
653 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
654 g_free(filename);
655 return 0;
657 close (file);
658 fd = fopen (filename, r);
659 g_free(filename);
660 return fd;
663 #define MAX_MACROS 1024
664 static int saved_macro[MAX_MACROS + 1];
665 static int saved_macros_loaded = 0;
668 This is just to stop the macro file be loaded over and over for keys
669 that aren't defined to anything. On slow systems this could be annoying.
671 static int
672 macro_exists (int k)
674 int i;
675 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
676 if (saved_macro[i] == k)
677 return i;
678 return -1;
681 /* returns 1 on error */
682 static int
683 edit_delete_macro (WEdit * edit, int k)
685 gchar *tmp, *tmp2;
686 struct macro macro[MAX_MACRO_LENGTH];
687 FILE *f, *g;
688 int s, i, n, j = 0;
690 (void) edit;
692 if (saved_macros_loaded)
693 if ((j = macro_exists (k)) < 0)
694 return 0;
695 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
696 g = fopen (tmp , "w");
697 g_free(tmp);
698 if (!g) {
699 edit_error_dialog (_(" Delete macro "),
700 get_sys_error (_(" Cannot open temp file ")));
701 return 1;
703 f = edit_open_macro_file ("r");
704 if (!f) {
705 edit_error_dialog (_(" Delete macro "),
706 get_sys_error (_(" Cannot open macro file ")));
707 fclose (g);
708 return 1;
710 for (;;) {
711 n = fscanf (f, ("key '%d 0': "), &s);
712 if (!n || n == EOF)
713 break;
714 n = 0;
715 while (fscanf (f, "%lu %d, ", &macro[n].command, &macro[n].ch))
716 n++;
717 fscanf (f, ";\n");
718 if (s != k) {
719 fprintf (g, ("key '%d 0': "), s);
720 for (i = 0; i < n; i++)
721 fprintf (g, "%lu %d, ", macro[i].command, macro[i].ch);
722 fprintf (g, ";\n");
725 fclose (f);
726 fclose (g);
727 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
728 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
729 if (rename ( tmp, tmp2) == -1) {
730 edit_error_dialog (_(" Delete macro "),
731 get_sys_error (_(" Cannot overwrite macro file ")));
732 g_free(tmp);
733 g_free(tmp2);
734 return 1;
736 g_free(tmp);
737 g_free(tmp2);
739 if (saved_macros_loaded)
740 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
741 return 0;
744 /* returns 0 on error */
745 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
747 FILE *f;
748 int s, i;
750 edit_push_action (edit, KEY_PRESS + edit->start_display);
751 s = editcmd_dialog_raw_key_query (_(" Save macro "),
752 _(" Press the macro's new hotkey: "), 1);
753 edit->force |= REDRAW_COMPLETELY;
754 if (s) {
755 if (edit_delete_macro (edit, s))
756 return 0;
757 f = edit_open_macro_file ("a+");
758 if (f) {
759 fprintf (f, ("key '%d 0': "), s);
760 for (i = 0; i < n; i++)
761 fprintf (f, "%lu %d, ", macro[i].command, macro[i].ch);
762 fprintf (f, ";\n");
763 fclose (f);
764 if (saved_macros_loaded) {
765 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
766 saved_macro[i] = s;
768 return 1;
769 } else
770 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
772 return 0;
775 void
776 edit_delete_macro_cmd (WEdit * edit)
778 int command;
780 command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
781 _ (" Press macro hotkey: "), 1);
783 if (command != 0)
784 edit_delete_macro (edit, command);
787 /* return 0 on error */
788 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
790 FILE *f;
791 int s, i = 0, found = 0;
793 (void) edit;
795 if (saved_macros_loaded)
796 if (macro_exists (k) < 0)
797 return 0;
799 if ((f = edit_open_macro_file ("r"))) {
800 struct macro dummy;
801 do {
802 int u;
803 u = fscanf (f, ("key '%d 0': "), &s);
804 if (!u || u == EOF)
805 break;
806 if (!saved_macros_loaded)
807 saved_macro[i++] = s;
808 if (!found) {
809 *n = 0;
810 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%lu %d, ", &macro[*n].command, &macro[*n].ch))
811 (*n)++;
812 } else {
813 while (2 == fscanf (f, "%lu %d, ", &dummy.command, &dummy.ch));
815 fscanf (f, ";\n");
816 if (s == k)
817 found = 1;
818 } while (!found || !saved_macros_loaded);
819 if (!saved_macros_loaded) {
820 saved_macro[i] = 0;
821 saved_macros_loaded = 1;
823 fclose (f);
824 return found;
825 } else
826 edit_error_dialog (_(" Load macro "),
827 get_sys_error (_(" Cannot open macro file ")));
828 return 0;
831 /* }}} Macro stuff starts here */
833 /* returns 1 on success */
834 int edit_save_confirm_cmd (WEdit * edit)
836 gchar *f = NULL;
838 if (!edit_check_newline (edit))
839 return 0;
841 if (edit_confirm_save) {
842 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", (char *) NULL);
843 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel"))){
844 g_free(f);
845 return 0;
847 g_free(f);
849 return edit_save_cmd (edit);
853 /* returns 1 on success */
854 static int
855 edit_save_cmd (WEdit *edit)
857 int res, save_lock = 0;
859 if (!edit->locked && !edit->delete_file)
860 save_lock = edit_lock_file (edit->filename);
861 res = edit_save_file (edit, edit->filename);
863 /* Maintain modify (not save) lock on failure */
864 if ((res > 0 && edit->locked) || save_lock)
865 edit->locked = edit_unlock_file (edit->filename);
867 /* On failure try 'save as', it does locking on its own */
868 if (!res)
869 return edit_save_as_cmd (edit);
870 edit->force |= REDRAW_COMPLETELY;
871 if (res > 0) {
872 edit->delete_file = 0;
873 edit->modified = 0;
876 return 1;
880 /* returns 1 on success */
881 int edit_new_cmd (WEdit * edit)
883 if (edit->modified) {
884 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
885 edit->force |= REDRAW_COMPLETELY;
886 return 0;
889 edit->force |= REDRAW_COMPLETELY;
891 return edit_renew (edit); /* if this gives an error, something has really screwed up */
894 /* returns 1 on error */
895 static int
896 edit_load_file_from_filename (WEdit * edit, char *exp)
898 int prev_locked = edit->locked;
899 char *prev_filename = g_strdup (edit->filename);
901 if (!edit_reload (edit, exp)) {
902 g_free (prev_filename);
903 return 1;
906 if (prev_locked)
907 edit_unlock_file (prev_filename);
908 g_free (prev_filename);
909 return 0;
912 static void
913 edit_load_syntax_file (WEdit * edit)
915 char *extdir;
916 int dir = 0;
918 if (geteuid () == 0) {
919 dir = query_dialog (_("Syntax file edit"),
920 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
921 _("&User"), _("&System Wide"));
924 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
925 if (!exist_file(extdir)) {
926 g_free (extdir);
927 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
930 if (dir == 0) {
931 char *buffer;
933 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
934 check_for_default (extdir, buffer);
935 edit_load_file_from_filename (edit, buffer);
936 g_free (buffer);
937 } else if (dir == 1)
938 edit_load_file_from_filename (edit, extdir);
940 g_free (extdir);
943 static void
944 edit_load_menu_file (WEdit * edit)
946 char *buffer;
947 char *menufile;
948 int dir = 0;
950 dir = query_dialog (
951 _(" Menu edit "),
952 _(" Which menu file do you want to edit? "), D_NORMAL,
953 geteuid() ? 2 : 3, _("&Local"), _("&User"), _("&System Wide")
956 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
958 if (!exist_file (menufile)) {
959 g_free (menufile);
960 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
963 switch (dir) {
964 case 0:
965 buffer = g_strdup (EDIT_LOCAL_MENU);
966 check_for_default (menufile, buffer);
967 chmod (buffer, 0600);
968 break;
970 case 1:
971 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
972 check_for_default (menufile, buffer);
973 break;
975 case 2:
976 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
977 if (!exist_file (buffer)) {
978 g_free (buffer);
979 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
981 break;
983 default:
984 g_free (menufile);
985 return;
988 edit_load_file_from_filename (edit, buffer);
990 g_free (buffer);
991 g_free (menufile);
995 edit_load_cmd (WEdit *edit, edit_current_file_t what)
997 char *exp;
999 if (edit->modified
1000 && (edit_query_dialog2
1001 (_("Warning"),
1002 _(" Current text was modified without a file save. \n"
1003 " Continue discards these changes. "),
1004 _("C&ontinue"), _("&Cancel")) == 1)) {
1005 edit->force |= REDRAW_COMPLETELY;
1006 return 0;
1009 switch (what) {
1010 case EDIT_FILE_COMMON:
1011 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
1012 MC_HISTORY_EDIT_LOAD, edit->filename);
1014 if (exp) {
1015 if (*exp)
1016 edit_load_file_from_filename (edit, exp);
1017 g_free (exp);
1019 break;
1021 case EDIT_FILE_SYNTAX:
1022 edit_load_syntax_file (edit);
1023 break;
1025 case EDIT_FILE_MENU:
1026 edit_load_menu_file (edit);
1027 break;
1029 default:
1030 break;
1033 edit->force |= REDRAW_COMPLETELY;
1034 return 0;
1038 if mark2 is -1 then marking is from mark1 to the cursor.
1039 Otherwise its between the markers. This handles this.
1040 Returns 1 if no text is marked.
1042 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
1044 if (edit->mark1 != edit->mark2) {
1045 long start_bol, start_eol;
1046 long end_bol, end_eol;
1047 long col1, col2;
1048 long diff1, diff2;
1049 if (edit->mark2 >= 0) {
1050 *start_mark = min (edit->mark1, edit->mark2);
1051 *end_mark = max (edit->mark1, edit->mark2);
1052 } else {
1053 *start_mark = min (edit->mark1, edit->curs1);
1054 *end_mark = max (edit->mark1, edit->curs1);
1055 edit->column2 = edit->curs_col + edit->over_col;
1057 if (column_highlighting
1058 && (((edit->mark1 > edit->curs1) && (edit->column1 < edit->column2))
1059 || ((edit->mark1 < edit->curs1) && (edit->column1 > edit->column2)))) {
1061 start_bol = edit_bol (edit, *start_mark);
1062 start_eol = edit_eol (edit, start_bol - 1) + 1;
1063 end_bol = edit_bol (edit, *end_mark);
1064 end_eol = edit_eol (edit, *end_mark);
1065 col1 = min (edit->column1, edit->column2);
1066 col2 = max (edit->column1, edit->column2);
1068 diff1 = edit_move_forward3 (edit, start_bol, col2, 0) - edit_move_forward3 (edit, start_bol, col1, 0);
1069 diff2 = edit_move_forward3 (edit, end_bol, col2, 0) - edit_move_forward3 (edit, end_bol, col1, 0);
1071 *start_mark -= diff1;
1072 *end_mark += diff2;
1073 *start_mark = max (*start_mark, start_eol);
1074 *end_mark = min (*end_mark, end_eol);
1076 return 0;
1077 } else {
1078 *start_mark = *end_mark = 0;
1079 edit->column2 = edit->column1 = 0;
1080 return 1;
1084 #define space_width 1
1086 void
1087 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
1089 long cursor;
1090 int i, col;
1091 cursor = edit->curs1;
1092 col = edit_get_col (edit);
1093 for (i = 0; i < size; i++) {
1094 if (data[i] == '\n') { /* fill in and move to next line */
1095 int l;
1096 long p;
1097 if (edit_get_byte (edit, edit->curs1) != '\n') {
1098 l = width - (edit_get_col (edit) - col);
1099 while (l > 0) {
1100 edit_insert (edit, ' ');
1101 l -= space_width;
1104 for (p = edit->curs1;; p++) {
1105 if (p == edit->last_byte) {
1106 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1107 edit_insert_ahead (edit, '\n');
1108 p++;
1109 break;
1111 if (edit_get_byte (edit, p) == '\n') {
1112 p++;
1113 break;
1116 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1117 l = col - edit_get_col (edit);
1118 while (l >= space_width) {
1119 edit_insert (edit, ' ');
1120 l -= space_width;
1122 continue;
1124 edit_insert (edit, data[i]);
1126 edit_cursor_move (edit, cursor - edit->curs1);
1129 #define TEMP_BUF_LEN 1024
1132 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1134 long cursor;
1135 int i, col;
1136 int blocklen = -1, width;
1137 unsigned char *data;
1138 cursor = edit->curs1;
1139 col = edit_get_col (edit);
1140 data = g_malloc0 (TEMP_BUF_LEN);
1141 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0) {
1142 for (width = 0; width < blocklen; width++) {
1143 if (data[width] == '\n')
1144 break;
1146 for (i = 0; i < blocklen; i++) {
1147 if (data[i] == '\n') { /* fill in and move to next line */
1148 int l;
1149 long p;
1150 if (edit_get_byte (edit, edit->curs1) != '\n') {
1151 l = width - (edit_get_col (edit) - col);
1152 while (l > 0) {
1153 edit_insert (edit, ' ');
1154 l -= space_width;
1157 for (p = edit->curs1;; p++) {
1158 if (p == edit->last_byte) {
1159 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1160 edit_insert_ahead (edit, '\n');
1161 p++;
1162 break;
1164 if (edit_get_byte (edit, p) == '\n') {
1165 p++;
1166 break;
1169 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1170 l = col - edit_get_col (edit);
1171 while (l >= space_width) {
1172 edit_insert (edit, ' ');
1173 l -= space_width;
1175 continue;
1177 edit_insert (edit, data[i]);
1180 edit_cursor_move (edit, cursor - edit->curs1);
1181 g_free(data);
1182 edit->force |= REDRAW_PAGE;
1183 return blocklen;
1186 void
1187 edit_block_copy_cmd (WEdit *edit)
1189 long start_mark, end_mark, current = edit->curs1;
1190 int size;
1191 unsigned char *copy_buf;
1193 edit_update_curs_col (edit);
1194 if (eval_marks (edit, &start_mark, &end_mark))
1195 return;
1197 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1199 /* all that gets pushed are deletes hence little space is used on the stack */
1201 edit_push_markers (edit);
1203 if (column_highlighting) {
1204 edit_insert_column_of_text (edit, copy_buf, size,
1205 abs (edit->column2 - edit->column1));
1206 } else {
1207 while (size--)
1208 edit_insert_ahead (edit, copy_buf[size]);
1211 g_free (copy_buf);
1212 edit_scroll_screen_over_cursor (edit);
1214 if (column_highlighting) {
1215 edit_set_markers (edit, 0, 0, 0, 0);
1216 edit_push_action (edit, COLUMN_ON);
1217 column_highlighting = 0;
1218 } else if (start_mark < current && end_mark > current)
1219 edit_set_markers (edit, start_mark,
1220 end_mark + end_mark - start_mark, 0, 0);
1222 edit->force |= REDRAW_PAGE;
1226 void
1227 edit_block_move_cmd (WEdit *edit)
1229 long count;
1230 long current;
1231 unsigned char *copy_buf;
1232 long start_mark, end_mark;
1233 int deleted = 0;
1234 int x = 0;
1236 if (eval_marks (edit, &start_mark, &end_mark))
1237 return;
1238 if (column_highlighting) {
1239 edit_update_curs_col (edit);
1240 x = edit->curs_col;
1241 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1242 if ((x > edit->column1 && x < edit->column2)
1243 || (x > edit->column2 && x < edit->column1))
1244 return;
1245 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1246 return;
1248 if ((end_mark - start_mark) > option_max_undo / 2)
1249 if (edit_query_dialog2
1250 (_("Warning"),
1252 (" Block is large, you may not be able to undo this action. "),
1253 _("C&ontinue"), _("&Cancel")))
1254 return;
1256 edit_push_markers (edit);
1257 current = edit->curs1;
1258 if (column_highlighting) {
1259 long line;
1260 int size, c1, c2;
1261 line = edit->curs_line;
1262 if (edit->mark2 < 0)
1263 edit_mark_cmd (edit, 0);
1264 c1 = min (edit->column1, edit->column2);
1265 c2 = max (edit->column1, edit->column2);
1266 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1267 if (x < c2) {
1268 edit_block_delete_cmd (edit);
1269 deleted = 1;
1271 edit_move_to_line (edit, line);
1272 edit_cursor_move (edit,
1273 edit_move_forward3 (edit,
1274 edit_bol (edit, edit->curs1),
1275 x, 0) - edit->curs1);
1276 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1277 if (!deleted) {
1278 line = edit->curs_line;
1279 edit_update_curs_col (edit);
1280 x = edit->curs_col;
1281 edit_block_delete_cmd (edit);
1282 edit_move_to_line (edit, line);
1283 edit_cursor_move (edit,
1284 edit_move_forward3 (edit,
1285 edit_bol (edit,
1286 edit->curs1),
1287 x, 0) - edit->curs1);
1289 edit_set_markers (edit, 0, 0, 0, 0);
1290 edit_push_action (edit, COLUMN_ON);
1291 column_highlighting = 0;
1292 } else {
1293 copy_buf = g_malloc0 (end_mark - start_mark);
1294 edit_cursor_move (edit, start_mark - edit->curs1);
1295 edit_scroll_screen_over_cursor (edit);
1296 count = start_mark;
1297 while (count < end_mark) {
1298 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1299 count++;
1301 edit_scroll_screen_over_cursor (edit);
1302 edit_cursor_move (edit,
1303 current - edit->curs1 -
1304 (((current - edit->curs1) >
1305 0) ? end_mark - start_mark : 0));
1306 edit_scroll_screen_over_cursor (edit);
1307 while (count-- > start_mark)
1308 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1309 edit_set_markers (edit, edit->curs1,
1310 edit->curs1 + end_mark - start_mark, 0, 0);
1312 edit_scroll_screen_over_cursor (edit);
1313 g_free (copy_buf);
1314 edit->force |= REDRAW_PAGE;
1317 static void
1318 edit_delete_column_of_text (WEdit * edit)
1320 long p, q, r, m1, m2;
1321 long b, c, d, n;
1323 eval_marks (edit, &m1, &m2);
1324 n = edit_move_forward (edit, m1, 0, m2) + 1;
1325 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1326 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1327 b = max (min (c, d), min (edit->column1, edit->column2));
1328 c = max (c, max (edit->column1, edit->column2));
1330 while (n--) {
1331 r = edit_bol (edit, edit->curs1);
1332 p = edit_move_forward3 (edit, r, b, 0);
1333 q = edit_move_forward3 (edit, r, c, 0);
1334 if (p < m1)
1335 p = m1;
1336 if (q > m2)
1337 q = m2;
1338 edit_cursor_move (edit, p - edit->curs1);
1339 while (q > p) {
1340 /* delete line between margins */
1341 if (edit_get_byte (edit, edit->curs1) != '\n')
1342 edit_delete (edit, 1);
1343 q--;
1345 if (n)
1346 /* move to next line except on the last delete */
1347 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1351 /* if success return 0 */
1352 static int
1353 edit_block_delete (WEdit *edit)
1355 long count;
1356 long start_mark, end_mark;
1357 int curs_pos, line_width;
1358 long curs_line, c1, c2;
1360 if (eval_marks (edit, &start_mark, &end_mark))
1361 return 0;
1362 if (column_highlighting && edit->mark2 < 0)
1363 edit_mark_cmd (edit, 0);
1364 if ((end_mark - start_mark) > option_max_undo / 2) {
1365 /* Warning message with a query to continue or cancel the operation */
1366 if (edit_query_dialog2
1367 (_("Warning"),
1369 (" Block is large, you may not be able to undo this action. "),
1370 _("C&ontinue"), _("&Cancel"))) {
1371 return 1;
1374 c1 = min (edit->column1, edit->column2);
1375 c2 = max (edit->column1, edit->column2);
1376 edit->column1 = c1;
1377 edit->column2 = c2;
1379 edit_push_markers (edit);
1381 curs_line = edit->curs_line;
1383 /* calculate line width and cursor position before cut */
1384 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1385 edit_eol (edit, edit->curs1));
1386 curs_pos = edit->curs_col + edit->over_col;
1388 /* move cursor to start of selection */
1389 edit_cursor_move (edit, start_mark - edit->curs1);
1390 edit_scroll_screen_over_cursor (edit);
1391 count = start_mark;
1392 if (start_mark < end_mark) {
1393 if (column_highlighting) {
1394 if (edit->mark2 < 0)
1395 edit_mark_cmd (edit, 0);
1396 edit_delete_column_of_text (edit);
1397 /* move cursor to the saved position */
1398 edit_move_to_line (edit, curs_line);
1399 /* calculate line width after cut */
1400 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1401 edit_eol (edit, edit->curs1));
1402 if (option_cursor_beyond_eol && curs_pos > line_width)
1403 edit->over_col = curs_pos - line_width;
1404 } else {
1405 while (count < end_mark) {
1406 edit_delete (edit, 1);
1407 count++;
1411 edit_set_markers (edit, 0, 0, 0, 0);
1412 edit->force |= REDRAW_PAGE;
1413 return 0;
1416 /* returns 1 if canceelled by user */
1417 int edit_block_delete_cmd (WEdit * edit)
1419 long start_mark, end_mark;
1420 if (eval_marks (edit, &start_mark, &end_mark)) {
1421 edit_delete_line (edit);
1422 return 0;
1424 return edit_block_delete (edit);
1427 #define INPUT_INDEX 9
1429 static gboolean
1430 editcmd_find (WEdit *edit, gsize *len)
1432 off_t search_start = edit->search_start;
1433 off_t search_end;
1434 long start_mark = 0;
1435 long end_mark = edit->last_byte;
1436 int mark_res = 0;
1438 if (edit->only_in_selection) {
1439 mark_res = eval_marks(edit, &start_mark, &end_mark);
1440 if (mark_res != 0) {
1441 edit->search->error = MC_SEARCH_E_NOTFOUND;
1442 edit->search->error_str = g_strdup(_(" Search string not found "));
1443 return FALSE;
1445 if (edit->replace_backwards) {
1446 if (search_start > end_mark || search_start <= start_mark) {
1447 search_start = end_mark;
1449 } else {
1450 if (search_start < start_mark || search_start >= end_mark) {
1451 search_start = start_mark;
1454 } else {
1455 if (edit->replace_backwards)
1456 end_mark = max(1, edit->curs1) - 1;
1458 if (edit->replace_backwards) {
1459 search_end = end_mark;
1460 while ((int) search_start >= start_mark) {
1461 if (search_end > search_start + edit->search->original_len
1462 && mc_search_is_fixed_search_str(edit->search)) {
1463 search_end = search_start + edit->search->original_len;
1465 if (mc_search_run(edit->search, (void *) edit, search_start, search_end, len)
1466 && edit->search->normal_offset == search_start ) {
1467 return TRUE;
1469 search_start--;
1471 edit->search->error_str = g_strdup(_(" Search string not found "));
1472 } else {
1473 return mc_search_run(edit->search, (void *) edit, search_start, end_mark, len);
1475 return FALSE;
1479 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1480 (and the above) routines to work properly - paul */
1482 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1484 static char *
1485 edit_replace_cmd__conv_to_display (char *str)
1487 #ifdef HAVE_CHARSET
1488 GString *tmp;
1489 tmp = str_convert_to_display (str);
1491 if (tmp && tmp->len){
1492 return g_string_free (tmp, FALSE);
1494 g_string_free (tmp, TRUE);
1495 #endif
1496 return g_strdup(str);
1499 static char *
1500 edit_replace_cmd__conv_to_input(char *str)
1502 #ifdef HAVE_CHARSET
1503 GString *tmp;
1504 tmp = str_convert_to_input (str);
1506 if (tmp && tmp->len){
1507 return g_string_free (tmp, FALSE);
1509 g_string_free (tmp, TRUE);
1510 return g_strdup(str);
1511 #endif
1512 return g_strdup(str);
1514 /* call with edit = 0 before shutdown to close memory leaks */
1515 void
1516 edit_replace_cmd (WEdit *edit, int again)
1518 /* 1 = search string, 2 = replace with */
1519 static char *saved1 = NULL; /* saved default[123] */
1520 static char *saved2 = NULL;
1521 char *input1 = NULL; /* user input from the dialog */
1522 char *input2 = NULL;
1523 int replace_yes;
1524 long times_replaced = 0, last_search;
1525 gboolean once_found = FALSE;
1527 if (!edit) {
1528 g_free (saved1), saved1 = NULL;
1529 g_free (saved2), saved2 = NULL;
1530 return;
1533 last_search = edit->last_byte;
1535 edit->force |= REDRAW_COMPLETELY;
1537 if (again && !saved1 && !saved2)
1538 again = 0;
1540 if (again) {
1541 input1 = g_strdup (saved1 ? saved1 : "");
1542 input2 = g_strdup (saved2 ? saved2 : "");
1543 } else {
1544 char *disp1 = edit_replace_cmd__conv_to_display (saved1 ? saved1 : (char *) "");
1545 char *disp2 = edit_replace_cmd__conv_to_display (saved2 ? saved2 : (char *) "");
1546 char *tmp_inp1, *tmp_inp2;
1548 edit_push_action (edit, KEY_PRESS + edit->start_display);
1550 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1552 g_free (disp1);
1553 g_free (disp2);
1555 if (input1 == NULL || *input1 == '\0') {
1556 edit->force = REDRAW_COMPLETELY;
1557 goto cleanup;
1560 tmp_inp1 = input1; tmp_inp2 = input2;
1561 input1 = edit_replace_cmd__conv_to_input(input1);
1562 input2 = edit_replace_cmd__conv_to_input(input2);
1563 g_free(tmp_inp1); g_free(tmp_inp2);
1565 g_free (saved1), saved1 = g_strdup (input1);
1566 g_free (saved2), saved2 = g_strdup (input2);
1568 if (edit->search) {
1569 mc_search_free(edit->search);
1570 edit->search = NULL;
1574 if (!edit->search) {
1575 edit->search = mc_search_new(input1, -1);
1576 if (edit->search == NULL) {
1577 edit->search_start = edit->curs1;
1578 return;
1580 edit->search->search_type = edit->search_type;
1581 edit->search->is_all_charsets = edit->all_codepages;
1582 edit->search->is_case_sentitive = edit->replace_case;
1583 edit->search->whole_words = edit->whole_words;
1584 edit->search->search_fn = edit_search_cmd_callback;
1587 if (edit->found_len && edit->search_start == edit->found_start + 1
1588 && edit->replace_backwards)
1589 edit->search_start--;
1591 if (edit->found_len && edit->search_start == edit->found_start - 1
1592 && !edit->replace_backwards)
1593 edit->search_start++;
1595 do {
1596 gsize len = 0;
1597 long new_start;
1599 if (! editcmd_find(edit, &len)) {
1600 if (!(edit->search->error == MC_SEARCH_E_OK ||
1601 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND))) {
1602 edit_error_dialog (_ ("Search"), edit->search->error_str);
1604 break;
1606 once_found = TRUE;
1607 new_start = edit->search->normal_offset;
1609 edit->search_start = new_start = edit->search->normal_offset;
1610 /*returns negative on not found or error in pattern */
1612 if (edit->search_start >= 0) {
1613 guint i;
1615 edit->found_start = edit->search_start;
1616 i = edit->found_len = len;
1618 edit_cursor_move (edit, edit->search_start - edit->curs1);
1619 edit_scroll_screen_over_cursor (edit);
1621 replace_yes = 1;
1623 if (edit->replace_mode == 0) {
1624 int l;
1625 l = edit->curs_row - edit->num_widget_lines / 3;
1626 if (l > 0)
1627 edit_scroll_downward (edit, l);
1628 if (l < 0)
1629 edit_scroll_upward (edit, -l);
1631 edit_scroll_screen_over_cursor (edit);
1632 edit->force |= REDRAW_PAGE;
1633 edit_render_keypress (edit);
1635 /*so that undo stops at each query */
1636 edit_push_key_press (edit);
1637 /* and prompt 2/3 down */
1638 switch (editcmd_dialog_replace_prompt_show (edit, input1, input2, -1, -1)) {
1639 case B_ENTER:
1640 replace_yes = 1;
1641 break;
1642 case B_SKIP_REPLACE:
1643 replace_yes = 0;
1644 break;
1645 case B_REPLACE_ALL:
1646 edit->replace_mode=1;
1647 break;
1648 case B_CANCEL:
1649 replace_yes = 0;
1650 edit->replace_mode = -1;
1651 break;
1654 if (replace_yes) { /* delete then insert new */
1655 GString *repl_str, *tmp_str;
1656 tmp_str = g_string_new(input2);
1658 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1659 g_string_free(tmp_str, TRUE);
1660 if (edit->search->error != MC_SEARCH_E_OK)
1662 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1663 break;
1666 while (i--)
1667 edit_delete (edit, 1);
1669 while (++i < repl_str->len)
1670 edit_insert (edit, repl_str->str[i]);
1672 g_string_free(repl_str, TRUE);
1673 edit->found_len = i;
1675 /* so that we don't find the same string again */
1676 if (edit->replace_backwards) {
1677 last_search = edit->search_start;
1678 edit->search_start--;
1679 } else {
1680 edit->search_start += i;
1681 last_search = edit->last_byte;
1683 edit_scroll_screen_over_cursor (edit);
1684 } else {
1685 const char *msg = _(" Replace ");
1686 /* try and find from right here for next search */
1687 edit->search_start = edit->curs1;
1688 edit_update_curs_col (edit);
1690 edit->force |= REDRAW_PAGE;
1691 edit_render_keypress (edit);
1692 if (times_replaced) {
1693 message (D_NORMAL, msg, _(" %ld replacements made. "),
1694 times_replaced);
1695 } else
1696 query_dialog (msg, _(" Search string not found "),
1697 D_NORMAL, 1, _("&OK"));
1698 edit->replace_mode = -1;
1700 } while (edit->replace_mode >= 0);
1702 edit->force = REDRAW_COMPLETELY;
1703 edit_scroll_screen_over_cursor (edit);
1704 cleanup:
1705 g_free (input1);
1706 g_free (input2);
1710 void edit_search_cmd (WEdit * edit, int again)
1712 char *search_string = NULL, *search_string_dup = NULL;
1714 gsize len = 0;
1716 if (!edit)
1717 return;
1719 if (edit->search != NULL) {
1720 search_string = g_strndup(edit->search->original, edit->search->original_len);
1721 search_string_dup = search_string;
1722 } else {
1723 GList *history;
1724 history = history_get (MC_HISTORY_SHARED_SEARCH);
1725 if (history != NULL && history->data != NULL) {
1726 search_string_dup = search_string = (char *) g_strdup(history->data);
1727 history = g_list_first (history);
1728 g_list_foreach (history, (GFunc) g_free, NULL);
1729 g_list_free (history);
1731 edit->search_start = edit->curs1;
1734 if (!again) {
1735 #ifdef HAVE_CHARSET
1736 GString *tmp;
1737 if (search_string && *search_string) {
1738 tmp = str_convert_to_display (search_string);
1740 g_free(search_string_dup);
1741 search_string_dup = NULL;
1743 if (tmp && tmp->len)
1744 search_string = search_string_dup = tmp->str;
1745 g_string_free (tmp, FALSE);
1747 #endif /* HAVE_CHARSET */
1748 editcmd_dialog_search_show (edit, &search_string);
1749 #ifdef HAVE_CHARSET
1750 if (search_string && *search_string) {
1751 tmp = str_convert_to_input (search_string);
1752 if (tmp && tmp->len)
1753 search_string = tmp->str;
1755 g_string_free (tmp, FALSE);
1757 if (search_string_dup)
1758 g_free(search_string_dup);
1760 #endif /* HAVE_CHARSET */
1762 edit_push_action (edit, KEY_PRESS + edit->start_display);
1764 if (!search_string) {
1765 edit->force |= REDRAW_COMPLETELY;
1766 edit_scroll_screen_over_cursor (edit);
1767 return;
1770 if (edit->search) {
1771 mc_search_free(edit->search);
1772 edit->search = NULL;
1776 if (!edit->search) {
1777 edit->search = mc_search_new(search_string, -1);
1778 if (edit->search == NULL) {
1779 edit->search_start = edit->curs1;
1780 return;
1782 edit->search->search_type = edit->search_type;
1783 edit->search->is_all_charsets = edit->all_codepages;
1784 edit->search->is_case_sentitive = edit->replace_case;
1785 edit->search->whole_words = edit->whole_words;
1786 edit->search->search_fn = edit_search_cmd_callback;
1789 if (search_create_bookmark) {
1790 edit_search_cmd_search_create_bookmark(edit);
1791 } else {
1792 if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
1793 edit->search_start--;
1795 if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
1796 edit->search_start++;
1799 if (editcmd_find(edit, &len)) {
1800 edit->found_start = edit->search_start = edit->search->normal_offset;
1801 edit->found_len = len;
1802 edit->over_col = 0;
1803 edit_cursor_move (edit, edit->search_start - edit->curs1);
1804 edit_scroll_screen_over_cursor (edit);
1805 if (edit->replace_backwards)
1806 edit->search_start--;
1807 else
1808 edit->search_start++;
1809 } else {
1810 edit->search_start = edit->curs1;
1811 if (edit->search->error_str)
1812 edit_error_dialog (_ ("Search"), edit->search->error_str);
1816 edit->force |= REDRAW_COMPLETELY;
1817 edit_scroll_screen_over_cursor (edit);
1822 * Check if it's OK to close the editor. If there are unsaved changes,
1823 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
1826 edit_ok_to_exit (WEdit *edit)
1828 if (!edit->modified)
1829 return 1;
1831 if (!edit_check_newline (edit))
1832 return 0;
1834 switch (edit_query_dialog3
1835 (_("Quit"), _(" File was modified, Save with exit? "),
1836 _("&Cancel quit"), _("&Yes"), _("&No"))) {
1837 case 1:
1838 edit_push_markers (edit);
1839 edit_set_markers (edit, 0, 0, 0, 0);
1840 if (!edit_save_cmd (edit))
1841 return 0;
1842 break;
1843 case 2:
1844 break;
1845 case 0:
1846 case -1:
1847 return 0;
1850 return 1;
1853 /* Return a null terminated length of text. Result must be g_free'd */
1854 static unsigned char *
1855 edit_get_block (WEdit *edit, long start, long finish, int *l)
1857 unsigned char *s, *r;
1858 r = s = g_malloc0 (finish - start + 1);
1859 if (column_highlighting) {
1860 *l = 0;
1861 /* copy from buffer, excluding chars that are out of the column 'margins' */
1862 while (start < finish) {
1863 int c;
1864 long x;
1865 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
1866 start);
1867 c = edit_get_byte (edit, start);
1868 if ((x >= edit->column1 && x < edit->column2)
1869 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1870 *s++ = c;
1871 (*l)++;
1873 start++;
1875 } else {
1876 *l = finish - start;
1877 while (start < finish)
1878 *s++ = edit_get_byte (edit, start++);
1880 *s = 0;
1881 return r;
1884 /* save block, returns 1 on success */
1886 edit_save_block (WEdit * edit, const char *filename, long start,
1887 long finish)
1889 int len, file;
1891 if ((file =
1892 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
1893 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
1894 return 0;
1896 if (column_highlighting) {
1897 int r;
1898 r = mc_write (file, VERTICAL_MAGIC, sizeof(VERTICAL_MAGIC));
1899 if (r > 0) {
1900 unsigned char *block, *p;
1901 p = block = edit_get_block (edit, start, finish, &len);
1902 while (len) {
1903 r = mc_write (file, p, len);
1904 if (r < 0)
1905 break;
1906 p += r;
1907 len -= r;
1909 g_free (block);
1911 } else {
1912 unsigned char *buf;
1913 int i = start, end;
1914 len = finish - start;
1915 buf = g_malloc0 (TEMP_BUF_LEN);
1916 while (start != finish) {
1917 end = min (finish, start + TEMP_BUF_LEN);
1918 for (; i < end; i++)
1919 buf[i - start] = edit_get_byte (edit, i);
1920 len -= mc_write (file, (char *) buf, end - start);
1921 start = end;
1923 g_free (buf);
1925 mc_close (file);
1926 if (len)
1927 return 0;
1928 return 1;
1931 /* copies a block to clipboard file */
1932 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1934 int ret;
1935 gchar *tmp;
1936 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1937 ret = edit_save_block (edit, tmp, start, finish);
1938 g_free(tmp);
1939 return ret;
1943 void edit_paste_from_history (WEdit *edit)
1945 (void) edit;
1946 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
1949 int edit_copy_to_X_buf_cmd (WEdit * edit)
1951 long start_mark, end_mark;
1952 if (eval_marks (edit, &start_mark, &end_mark))
1953 return 0;
1954 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1955 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
1956 return 1;
1958 edit_mark_cmd (edit, 1);
1959 return 0;
1962 int edit_cut_to_X_buf_cmd (WEdit * edit)
1964 long start_mark, end_mark;
1965 if (eval_marks (edit, &start_mark, &end_mark))
1966 return 0;
1967 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1968 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
1969 return 1;
1971 edit_block_delete_cmd (edit);
1972 edit_mark_cmd (edit, 1);
1973 return 0;
1976 void edit_paste_from_X_buf_cmd (WEdit * edit)
1978 gchar *tmp;
1979 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1980 edit_insert_file (edit, tmp);
1981 g_free(tmp);
1986 * Ask user for the line and go to that line.
1987 * Negative numbers mean line from the end (i.e. -1 is the last line).
1989 void
1990 edit_goto_cmd (WEdit *edit)
1992 char *f;
1993 static long line = 0; /* line as typed, saved as default */
1994 long l;
1995 char *error;
1996 char s[32];
1998 g_snprintf (s, sizeof (s), "%ld", line);
1999 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
2000 line ? s : "");
2001 if (!f)
2002 return;
2004 if (!*f) {
2005 g_free (f);
2006 return;
2009 l = strtol (f, &error, 0);
2010 if (*error) {
2011 g_free (f);
2012 return;
2015 /* show prev line number by default */
2016 line = edit->curs_line + 1;
2017 if (l < 0)
2018 l = edit->total_lines + l + 2;
2019 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2020 edit_move_to_line (edit, l - 1);
2021 edit->force |= REDRAW_COMPLETELY;
2022 g_free (f);
2026 /* Return 1 on success */
2028 edit_save_block_cmd (WEdit *edit)
2030 long start_mark, end_mark;
2031 char *exp, *tmp;
2033 if (eval_marks (edit, &start_mark, &end_mark))
2034 return 1;
2036 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2037 exp =
2038 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2039 MC_HISTORY_EDIT_SAVE_BLOCK,
2040 tmp);
2041 g_free(tmp);
2042 edit_push_action (edit, KEY_PRESS + edit->start_display);
2043 if (exp) {
2044 if (!*exp) {
2045 g_free (exp);
2046 return 0;
2047 } else {
2048 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2049 g_free (exp);
2050 edit->force |= REDRAW_COMPLETELY;
2051 return 1;
2052 } else {
2053 g_free (exp);
2054 edit_error_dialog (_(" Save Block "),
2055 get_sys_error (_
2056 (" Cannot save file. ")));
2060 edit->force |= REDRAW_COMPLETELY;
2061 return 0;
2065 /* returns 1 on success */
2067 edit_insert_file_cmd (WEdit *edit)
2069 gchar *tmp;
2070 char *exp;
2072 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2073 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2074 MC_HISTORY_EDIT_INSERT_FILE,
2075 tmp);
2076 g_free(tmp);
2077 edit_push_action (edit, KEY_PRESS + edit->start_display);
2078 if (exp) {
2079 if (!*exp) {
2080 g_free (exp);
2081 return 0;
2082 } else {
2083 if (edit_insert_file (edit, exp)) {
2084 g_free (exp);
2085 edit->force |= REDRAW_COMPLETELY;
2086 return 1;
2087 } else {
2088 g_free (exp);
2089 edit_error_dialog (_(" Insert File "),
2090 get_sys_error (_
2091 (" Cannot insert file. ")));
2095 edit->force |= REDRAW_COMPLETELY;
2096 return 0;
2099 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2100 int edit_sort_cmd (WEdit * edit)
2102 static char *old = 0;
2103 char *exp, *tmp;
2104 long start_mark, end_mark;
2105 int e;
2107 if (eval_marks (edit, &start_mark, &end_mark)) {
2108 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2109 return 0;
2112 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2113 edit_save_block (edit, tmp, start_mark, end_mark);
2114 g_free(tmp);
2116 exp = input_dialog (_(" Run Sort "),
2117 _(" Enter sort options (see manpage) separated by whitespace: "),
2118 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2120 if (!exp)
2121 return 1;
2122 g_free (old);
2123 old = exp;
2124 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2125 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2126 e = system (tmp);
2127 g_free(tmp);
2128 if (e) {
2129 if (e == -1 || e == 127) {
2130 edit_error_dialog (_(" Sort "),
2131 get_sys_error (_(" Cannot execute sort command ")));
2132 } else {
2133 char q[8];
2134 sprintf (q, "%d ", e);
2135 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
2136 edit_error_dialog (_(" Sort "), tmp);
2137 g_free(tmp);
2139 return -1;
2142 edit->force |= REDRAW_COMPLETELY;
2144 if (edit_block_delete_cmd (edit))
2145 return 1;
2146 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2147 edit_insert_file (edit, tmp);
2148 g_free(tmp);
2149 return 0;
2153 * Ask user for a command, execute it and paste its output back to the
2154 * editor.
2157 edit_ext_cmd (WEdit *edit)
2159 char *exp, *tmp;
2160 int e;
2162 exp =
2163 input_dialog (_("Paste output of external command"),
2164 _("Enter shell command(s):"),
2165 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2167 if (!exp)
2168 return 1;
2170 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2171 e = system (tmp);
2172 g_free(tmp);
2173 g_free (exp);
2175 if (e) {
2176 edit_error_dialog (_("External command"),
2177 get_sys_error (_("Cannot execute command")));
2178 return -1;
2181 edit->force |= REDRAW_COMPLETELY;
2182 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2183 edit_insert_file (edit, tmp);
2184 g_free(tmp);
2185 return 0;
2188 /* if block is 1, a block must be highlighted and the shell command
2189 processes it. If block is 0 the shell command is a straight system
2190 command, that just produces some output which is to be inserted */
2191 void
2192 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2194 long start_mark, end_mark;
2195 char buf[BUFSIZ];
2196 FILE *script_home = NULL;
2197 FILE *block_file = NULL;
2198 gchar *o, *h, *b, *tmp;
2199 char *quoted_name = NULL;
2201 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2202 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2203 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2205 script_home = fopen (h, "r");
2206 if (script_home == NULL) {
2207 FILE *script_src = NULL;
2209 script_home = fopen (h, "w");
2210 if (script_home == NULL) {
2211 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2212 edit_error_dialog ("", get_sys_error (tmp));
2213 g_free(tmp);
2214 goto edit_block_process_cmd__EXIT;
2217 script_src = fopen (o, "r");
2218 if (script_src == NULL) {
2219 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2220 script_src = fopen (o, "r");
2221 if (script_src == NULL) {
2222 fclose (script_home);
2223 unlink (h);
2224 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2225 edit_error_dialog ("", get_sys_error (tmp));
2226 g_free(tmp);
2227 goto edit_block_process_cmd__EXIT;
2230 while (fgets (buf, sizeof (buf), script_src))
2231 fputs (buf, script_home);
2232 fclose (script_src);
2234 if (fclose (script_home)) {
2235 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2236 edit_error_dialog ("", get_sys_error (tmp));
2237 g_free(tmp);
2238 goto edit_block_process_cmd__EXIT;
2240 chmod (h, 0700);
2241 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2242 edit_error_dialog ("", get_sys_error (tmp));
2243 g_free(tmp);
2246 open_error_pipe ();
2248 if (block) { /* for marked block run indent formatter */
2249 if (eval_marks (edit, &start_mark, &end_mark)) {
2250 edit_error_dialog (_("Process block"),
2252 (" You must first highlight a block of text. "));
2253 goto edit_block_process_cmd__EXIT;
2255 edit_save_block (edit, b, start_mark, end_mark);
2256 quoted_name = name_quote (edit->filename, 0);
2258 * Run script.
2259 * Initial space is to avoid polluting bash history.
2260 * Arguments:
2261 * $1 - name of the edited file (to check its extension etc).
2262 * $2 - file containing the current block.
2263 * $3 - file where error messages should be put
2264 * (for compatibility with old scripts).
2266 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2267 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2268 system (tmp);
2269 g_free(tmp);
2270 } else {
2272 * No block selected, just execute the command for the file.
2273 * Arguments:
2274 * $1 - name of the edited file.
2276 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2277 quoted_name, (char *) NULL);
2278 system (tmp);
2279 g_free(tmp);
2281 g_free (quoted_name);
2282 close_error_pipe (D_NORMAL, NULL);
2284 edit_refresh_cmd (edit);
2285 edit->force |= REDRAW_COMPLETELY;
2287 /* insert result block */
2288 if (block && !edit_block_delete_cmd (edit)) {
2289 edit_insert_file (edit, b);
2290 block_file = fopen (b, "w");
2291 if (block_file != NULL)
2292 fclose (block_file);
2295 edit_block_process_cmd__EXIT:
2296 g_free (b);
2297 g_free (h);
2298 g_free (o);
2301 /* prints at the cursor */
2302 /* returns the number of chars printed */
2303 int edit_print_string (WEdit * e, const char *s)
2305 size_t i = 0;
2306 while (s[i] != '\0')
2307 edit_execute_cmd (e, CK_Insert_Char, (unsigned char) s[i++]);
2308 e->force |= REDRAW_COMPLETELY;
2309 edit_update_screen (e);
2310 return i;
2314 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2316 FILE *p = 0;
2317 char *s;
2319 to = name_quote (to, 0);
2320 subject = name_quote (subject, 0);
2321 cc = name_quote (cc, 0);
2322 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2323 g_free (to);
2324 g_free (subject);
2325 g_free (cc);
2327 if (s) {
2328 p = popen (s, "w");
2329 g_free (s);
2332 if (p) {
2333 long i;
2334 for (i = 0; i < edit->last_byte; i++)
2335 fputc (edit_get_byte (edit, i), p);
2336 pclose (p);
2340 #define MAIL_DLG_HEIGHT 12
2342 void edit_mail_dialog (WEdit * edit)
2344 char *tmail_to;
2345 char *tmail_subject;
2346 char *tmail_cc;
2348 static char *mail_cc_last = 0;
2349 static char *mail_subject_last = 0;
2350 static char *mail_to_last = 0;
2352 QuickWidget quick_widgets[] =
2354 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2355 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2356 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2357 /* 3 */ QUICK_LABEL (2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to")),
2358 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2", &tmail_subject),
2359 /* 5 */ QUICK_LABEL (2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject")),
2360 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2361 /* 7 */ QUICK_LABEL (2, 50, 3, MAIL_DLG_HEIGHT, N_(" To")),
2362 /* 8 */ QUICK_LABEL (2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>")),
2363 QUICK_END
2366 QuickDialog Quick_input =
2368 50, MAIL_DLG_HEIGHT, -1, -1, N_(" Mail "),
2369 "[Input Line Keys]", quick_widgets, FALSE
2372 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2373 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2374 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2376 if (quick_dialog (&Quick_input) != B_CANCEL) {
2377 g_free (mail_cc_last);
2378 g_free (mail_subject_last);
2379 g_free (mail_to_last);
2380 mail_cc_last = tmail_cc;
2381 mail_subject_last = tmail_subject;
2382 mail_to_last = tmail_to;
2383 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2388 /*******************/
2389 /* Word Completion */
2390 /*******************/
2392 static gboolean is_break_char(char c)
2394 return (isspace(c) || strchr("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2397 /* find first character of current word */
2398 static int edit_find_word_start (WEdit *edit, long *word_start, gsize *word_len)
2400 int c, last;
2401 gsize i;
2403 /* return if at begin of file */
2404 if (edit->curs1 <= 0)
2405 return 0;
2407 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2408 /* return if not at end or in word */
2409 if (is_break_char(c))
2410 return 0;
2412 /* search start of word to be completed */
2413 for (i = 2;; i++) {
2414 /* return if at begin of file */
2415 if (edit->curs1 - i < 0)
2416 return 0;
2418 last = c;
2419 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2421 if (is_break_char(c)) {
2422 /* return if word starts with digit */
2423 if (isdigit (last))
2424 return 0;
2426 *word_start = edit->curs1 - (i - 1); /* start found */
2427 *word_len = i - 1;
2428 break;
2431 /* success */
2432 return 1;
2435 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2437 /* collect the possible completions */
2438 static gsize
2439 edit_collect_completions (WEdit *edit, long start, gsize word_len,
2440 char *match_expr, struct selection *compl,
2441 gsize *num)
2443 gsize len = 0;
2444 gsize max_len = 0;
2445 gsize i;
2446 int skip;
2447 GString *temp;
2448 mc_search_t *srch;
2450 long last_byte;
2452 srch = mc_search_new(match_expr, -1);
2453 if (srch == NULL)
2454 return 0;
2456 if (mc_config_get_bool(mc_main_config, CONFIG_APP_SECTION, "editor_wordcompletion_collect_entire_file", 0)){
2457 last_byte = edit->last_byte;
2458 } else {
2459 last_byte = start;
2462 srch->search_type = MC_SEARCH_T_REGEX;
2463 srch->is_case_sentitive = TRUE;
2464 srch->search_fn = edit_search_cmd_callback;
2466 /* collect max MAX_WORD_COMPLETIONS completions */
2467 start = -1;
2468 while (1) {
2469 /* get next match */
2470 if (mc_search_run (srch, (void *) edit, start+1, last_byte, &len) == FALSE)
2471 break;
2472 start = srch->normal_offset;
2474 /* add matched completion if not yet added */
2475 temp = g_string_new("");
2476 for (i = 0; i < len; i++){
2477 skip = edit_get_byte(edit, start+i);
2478 if (isspace(skip))
2479 continue;
2480 g_string_append_c (temp, skip);
2483 skip = 0;
2485 for (i = 0; i < (gsize) *num; i++) {
2486 if (strncmp
2488 (char *) &compl[i].text[word_len],
2489 (char *) &temp->str[word_len],
2490 max (len, compl[i].len) - (gsize)word_len
2491 ) == 0) {
2492 struct selection this = compl[i];
2493 for (++i; i < *num; i++) {
2494 compl[i - 1] = compl[i];
2496 compl[*num - 1] = this;
2497 skip = 1;
2498 break; /* skip it, already added */
2501 if (skip) {
2502 g_string_free(temp, TRUE);
2503 continue;
2505 if (*num == MAX_WORD_COMPLETIONS && MAX_WORD_COMPLETIONS) {
2506 g_free(compl[0].text);
2507 for (i = 1; i < *num; i++) {
2508 compl[i - 1] = compl[i];
2510 (*num)--;
2512 #ifdef HAVE_CHARSET
2514 GString *recoded;
2515 recoded = str_convert_to_display (temp->str);
2517 if (recoded && recoded->len){
2518 g_string_free(temp,TRUE);
2519 temp = recoded;
2520 } else
2521 g_string_free(recoded , TRUE);
2523 #endif
2524 compl[*num].text = temp->str;
2525 compl[*num].len = temp->len;
2526 (*num)++;
2527 start += len;
2528 g_string_free(temp, FALSE);
2530 /* note the maximal length needed for the completion dialog */
2531 if (len > max_len)
2532 max_len = len;
2534 mc_search_free(srch);
2535 return max_len;
2539 * Complete current word using regular expression search
2540 * backwards beginning at the current cursor position.
2542 void
2543 edit_complete_word_cmd (WEdit *edit)
2545 gsize i, max_len, word_len = 0, num_compl = 0;
2546 long word_start = 0;
2547 unsigned char *bufpos;
2548 char *match_expr;
2549 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2551 /* search start of word to be completed */
2552 if (!edit_find_word_start (edit, &word_start, &word_len))
2553 return;
2555 /* prepare match expression */
2556 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2557 [word_start & M_EDIT_BUF_SIZE];
2559 /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
2560 match_expr = g_strdup_printf ("(^|\\s+|\\b)%.*s[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+", (int)word_len, bufpos);
2562 /* collect the possible completions */
2563 /* start search from begin to end of file */
2564 max_len =
2565 edit_collect_completions (edit, word_start, word_len, match_expr,
2566 (struct selection *) &compl, &num_compl);
2568 if (num_compl > 0) {
2569 /* insert completed word if there is only one match */
2570 if (num_compl == 1) {
2571 for (i = word_len; i < compl[0].len; i++)
2572 edit_insert (edit, *(compl[0].text + i));
2574 /* more than one possible completion => ask the user */
2575 else {
2576 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2577 /* !!! pressed again the selection dialog pops up, but that !!! */
2578 /* !!! seems to require a further internal state !!! */
2579 /*tty_beep (); */
2581 /* let the user select the preferred completion */
2582 editcmd_dialog_completion_show (edit, max_len, word_len,
2583 (struct selection *) &compl,
2584 num_compl);
2588 g_free (match_expr);
2589 /* release memory before return */
2590 for (i = 0; i < num_compl; i++)
2591 g_free (compl[i].text);
2594 void
2595 edit_select_codepage_cmd (WEdit *edit)
2597 #ifdef HAVE_CHARSET
2598 const char *cp_id = NULL;
2599 if (do_select_codepage ()) {
2600 cp_id = get_codepage_id (source_codepage >= 0 ?
2601 source_codepage : display_codepage);
2603 if (cp_id != NULL) {
2604 GIConv conv;
2605 conv = str_crt_conv_from (cp_id);
2606 if (conv != INVALID_CONV) {
2607 if (edit->converter != str_cnv_from_term)
2608 str_close_conv (edit->converter);
2609 edit->converter = conv;
2613 if (cp_id != NULL)
2614 edit->utf8 = str_isutf8 (cp_id);
2617 edit->force = REDRAW_COMPLETELY;
2618 edit_refresh_cmd (edit);
2619 #else
2620 (void) edit;
2621 #endif
2624 void
2625 edit_insert_literal_cmd (WEdit *edit)
2627 int char_for_insertion =
2628 editcmd_dialog_raw_key_query (_(" Insert Literal "),
2629 _(" Press any key: "), 0);
2630 edit_execute_key_command (edit, -1,
2631 ascii_alpha_to_cntrl (char_for_insertion));
2634 void
2635 edit_execute_macro_cmd (WEdit *edit)
2637 int command =
2638 CK_Macro (editcmd_dialog_raw_key_query
2639 (_(" Execute Macro "), _(" Press macro hotkey: "),
2640 1));
2641 if (command == CK_Macro (0))
2642 command = CK_Insert_Char;
2644 edit_execute_key_command (edit, command, -1);
2647 void
2648 edit_begin_end_macro_cmd (WEdit *edit)
2650 /* edit is a pointer to the widget */
2651 if (edit) {
2652 unsigned long command = edit->macro_i < 0
2653 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2654 edit_execute_key_command (edit, command, -1);
2659 edit_load_forward_cmd (WEdit *edit)
2661 if (edit->modified) {
2662 if (edit_query_dialog2
2663 (_("Warning"),
2664 _(" Current text was modified without a file save. \n"
2665 " Continue discards these changes. "), _("C&ontinue"),
2666 _("&Cancel"))) {
2667 edit->force |= REDRAW_COMPLETELY;
2668 return 0;
2671 if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
2672 if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
2673 return 1;
2675 edit_stack_iterator++;
2676 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2677 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2678 edit_history_moveto[edit_stack_iterator].line);
2679 return 0;
2680 } else {
2681 return 1;
2683 } else {
2684 return 1;
2689 edit_load_back_cmd (WEdit *edit)
2691 if (edit->modified) {
2692 if (edit_query_dialog2
2693 (_("Warning"),
2694 _(" Current text was modified without a file save. \n"
2695 " Continue discards these changes. "), _("C&ontinue"),
2696 _("&Cancel"))) {
2697 edit->force |= REDRAW_COMPLETELY;
2698 return 0;
2701 if ( edit_stack_iterator > 0 ) {
2702 edit_stack_iterator--;
2703 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2704 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2705 edit_history_moveto[edit_stack_iterator].line);
2706 return 0;
2707 } else {
2708 return 1;
2710 } else {
2711 return 1;
2715 void
2716 edit_get_match_keyword_cmd (WEdit *edit)
2718 gsize word_len = 0, max_len = 0;
2719 int num_def = 0;
2720 int i;
2721 long word_start = 0;
2722 unsigned char *bufpos;
2723 char *match_expr;
2724 char *path = NULL;
2725 char *ptr = NULL;
2726 char *tagfile = NULL;
2728 etags_hash_t def_hash[MAX_DEFINITIONS];
2730 for ( i = 0; i < MAX_DEFINITIONS; i++) {
2731 def_hash[i].filename = NULL;
2734 /* search start of word to be completed */
2735 if (!edit_find_word_start (edit, &word_start, &word_len))
2736 return;
2738 /* prepare match expression */
2739 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2740 [word_start & M_EDIT_BUF_SIZE];
2741 match_expr = g_strdup_printf ("%.*s", (int)word_len, bufpos);
2743 ptr = g_get_current_dir ();
2744 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
2745 g_free (ptr);
2747 /* Recursive search file 'TAGS' in parent dirs */
2748 do {
2749 ptr = g_path_get_dirname (path);
2750 g_free(path); path = ptr;
2751 g_free (tagfile);
2752 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
2753 if ( exist_file (tagfile) )
2754 break;
2755 } while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
2757 if (tagfile){
2758 num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
2759 g_free (tagfile);
2761 g_free (path);
2763 max_len = MAX_WIDTH_DEF_DIALOG;
2764 word_len = 0;
2765 if ( num_def > 0 ) {
2766 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
2767 (etags_hash_t *) &def_hash,
2768 num_def);
2770 g_free (match_expr);
2773 void
2774 edit_move_block_to_right (WEdit * edit)
2776 long start_mark, end_mark;
2777 long cur_bol, start_bol;
2779 if ( eval_marks (edit, &start_mark, &end_mark) )
2780 return;
2782 start_bol = edit_bol (edit, start_mark);
2783 cur_bol = edit_bol (edit, end_mark - 1);
2784 do {
2785 edit_cursor_move (edit, cur_bol - edit->curs1);
2786 if ( option_fill_tabs_with_spaces ) {
2787 if ( option_fake_half_tabs ) {
2788 insert_spaces_tab (edit, 1);
2789 } else {
2790 insert_spaces_tab (edit, 0);
2792 } else {
2793 edit_insert (edit, '\t');
2795 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
2796 if ( cur_bol == 0 ) {
2797 break;
2799 cur_bol = edit_bol (edit, cur_bol - 1);
2800 } while (cur_bol >= start_bol) ;
2801 edit->force |= REDRAW_PAGE;
2804 void
2805 edit_move_block_to_left (WEdit * edit)
2807 long start_mark, end_mark;
2808 long cur_bol, start_bol;
2809 int i, del_tab_width;
2810 int next_char;
2812 if ( eval_marks (edit, &start_mark, &end_mark) )
2813 return;
2815 start_bol = edit_bol (edit, start_mark);
2816 cur_bol = edit_bol (edit, end_mark - 1);
2817 do {
2818 edit_cursor_move (edit, cur_bol - edit->curs1);
2819 if (option_fake_half_tabs) {
2820 del_tab_width = HALF_TAB_SIZE;
2821 } else {
2822 del_tab_width = option_tab_spacing;
2824 next_char = edit_get_byte (edit, edit->curs1);
2825 if ( next_char == '\t' ) {
2826 edit_delete (edit, 1);
2827 } else if ( next_char == ' ' ) {
2828 for (i = 1; i <= del_tab_width; i++) {
2829 if ( next_char == ' ' ) {
2830 edit_delete (edit, 1);
2832 next_char = edit_get_byte (edit, edit->curs1);
2835 if ( cur_bol == 0 ) {
2836 break;
2838 cur_bol = edit_bol (edit, cur_bol - 1);
2839 } while (cur_bol >= start_bol) ;
2840 edit->force |= REDRAW_PAGE;