Ticket #1828: Improved symlink handling in ftpfs
[midnight-commander.git] / edit / editcmd.c
blobf3a2f2656ab0202bbf41b2d3f81d0b2d34ddc8a5
1 /* editor high level editing commands
3 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007 Free Software Foundation, Inc.
6 Authors: 1996, 1997 Paul Sheer
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
25 /** \file
26 * \brief Source: editor high level editing commands
27 * \author Paul Sheer
28 * \date 1996, 1997
31 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
33 #include <config.h>
35 #include <assert.h>
36 #include <ctype.h>
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <sys/stat.h>
45 #include <stdlib.h>
46 #include <fcntl.h>
48 #include "../src/global.h"
50 #include "../src/tty/tty.h"
51 #include "../src/tty/key.h" /* XCTRL */
53 #include "../src/history.h"
54 #include "../src/widget.h" /* listbox_new() */
55 #include "../src/layout.h" /* clr_scr() */
56 #include "../src/main.h" /* mc_home source_codepage */
57 #include "../src/help.h" /* interactive_display() */
58 #include "../src/wtools.h" /* message() */
59 #include "../src/charsets.h"
60 #include "../src/selcodepage.h"
61 #include "../src/strutil.h" /* utf string functions */
62 #include "../src/mcconfig/mcconfig.h"
63 #include "../src/skin/skin.h" /* mc_skin_color_get */
65 #include "../edit/edit-impl.h"
66 #include "../edit/edit.h"
67 #include "../edit/editlock.h"
68 #include "../src/cmddef.h"
69 #include "../edit/edit-widget.h"
70 #include "../edit/editcmd_dialogs.h"
71 #include "../edit/etags.h"
73 /* globals: */
75 /* search and replace: */
76 int search_create_bookmark = 0;
77 /* static int search_in_all_charsets = 0; */
79 /* queries on a save */
80 int edit_confirm_save = 1;
82 static int edit_save_cmd (WEdit *edit);
83 static unsigned char *edit_get_block (WEdit *edit, long start,
84 long finish, int *l);
86 static void
87 edit_search_cmd_search_create_bookmark(WEdit * edit)
89 int found = 0, books = 0;
90 int l = 0, l_last = -1;
91 long q = 0;
92 gsize len = 0;
94 search_create_bookmark = 0;
95 book_mark_flush (edit, -1);
97 for (;;) {
98 if (!mc_search_run(edit->search, (void *) edit, q, edit->last_byte, &len))
99 break;
100 if (found == 0)
101 edit->search_start = edit->search->normal_offset;
102 found++;
103 l += edit_count_lines (edit, q, edit->search->normal_offset);
104 if (l != l_last) {
105 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
106 books++;
108 l_last = l;
109 q = edit->search->normal_offset + 1;
112 if (found == 0) {
113 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
114 } else {
115 edit_cursor_move (edit, edit->search_start - edit->curs1);
116 edit_scroll_screen_over_cursor (edit);
120 static int
121 edit_search_cmd_callback(const void *user_data, gsize char_offset)
123 return edit_get_byte ((WEdit * )user_data, (long) char_offset);
126 void edit_help_cmd (WEdit * edit)
128 interactive_display (NULL, "[Internal File Editor]");
129 edit->force |= REDRAW_COMPLETELY;
132 void
133 edit_refresh_cmd (WEdit * edit)
135 #ifdef HAVE_SLANG
136 int color;
138 edit_get_syntax_color (edit, -1, &color);
139 tty_touch_screen ();
140 mc_refresh ();
141 #else
142 clr_scr ();
143 repaint_screen ();
144 #endif /* !HAVE_SLANG */
145 tty_keypad (TRUE);
148 /* If 0 (quick save) then a) create/truncate <filename> file,
149 b) save to <filename>;
150 if 1 (safe save) then a) save to <tempnam>,
151 b) rename <tempnam> to <filename>;
152 if 2 (do backups) then a) save to <tempnam>,
153 b) rename <filename> to <filename.backup_ext>,
154 c) rename <tempnam> to <filename>. */
156 /* returns 0 on error, -1 on abort */
157 static int
158 edit_save_file (WEdit *edit, const char *filename)
160 char *p;
161 gchar *tmp;
162 long filelen = 0;
163 char *savename = 0;
164 gchar *real_filename;
165 int this_save_mode, fd = -1;
167 if (!filename)
168 return 0;
169 if (!*filename)
170 return 0;
172 if (*filename != PATH_SEP && edit->dir) {
173 real_filename = concat_dir_and_file (edit->dir, filename);
174 } else {
175 real_filename = g_strdup(filename);
178 this_save_mode = option_save_mode;
179 if (this_save_mode != EDIT_QUICK_SAVE) {
180 if (!vfs_file_is_local (real_filename) ||
181 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1) {
183 * The file does not exists yet, so no safe save or
184 * backup are necessary.
186 this_save_mode = EDIT_QUICK_SAVE;
188 if (fd != -1)
189 mc_close (fd);
192 if (this_save_mode == EDIT_QUICK_SAVE &&
193 !edit->skip_detach_prompt) {
194 int rv;
195 struct stat sb;
197 rv = mc_stat (real_filename, &sb);
198 if (rv == 0 && sb.st_nlink > 1) {
199 rv = edit_query_dialog3 (_("Warning"),
200 _(" File has hard-links. Detach before saving? "),
201 _("&Yes"), _("&No"), _("&Cancel"));
202 switch (rv) {
203 case 0:
204 this_save_mode = EDIT_SAFE_SAVE;
205 /* fallthrough */
206 case 1:
207 edit->skip_detach_prompt = 1;
208 break;
209 default:
210 g_free(real_filename);
211 return -1;
215 /* Prevent overwriting changes from other editor sessions. */
216 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
218 /* The default action is "Cancel". */
219 query_set_sel(1);
221 rv = edit_query_dialog2 (
222 _("Warning"),
223 _("The file has been modified in the meantime. Save anyway?"),
224 _("&Yes"),
225 _("&Cancel"));
226 if (rv != 0){
227 g_free(real_filename);
228 return -1;
233 if (this_save_mode != EDIT_QUICK_SAVE) {
234 char *savedir, *saveprefix;
235 const char *slashpos;
236 slashpos = strrchr (real_filename, PATH_SEP);
237 if (slashpos) {
238 savedir = g_strdup (real_filename);
239 savedir[slashpos - real_filename + 1] = '\0';
240 } else
241 savedir = g_strdup (".");
242 saveprefix = concat_dir_and_file (savedir, "cooledit");
243 g_free (savedir);
244 fd = mc_mkstemps (&savename, saveprefix, NULL);
245 g_free (saveprefix);
246 if (!savename){
247 g_free(real_filename);
248 return 0;
250 /* FIXME:
251 * Close for now because mc_mkstemps use pure open system call
252 * to create temporary file and it needs to be reopened by
253 * VFS-aware mc_open().
255 close (fd);
256 } else
257 savename = g_strdup (real_filename);
259 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
260 mc_chmod (savename, edit->stat1.st_mode);
262 if ((fd =
263 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
264 edit->stat1.st_mode)) == -1)
265 goto error_save;
267 /* pipe save */
268 if ((p = edit_get_write_filter (savename, real_filename))) {
269 FILE *file;
271 mc_close (fd);
272 file = (FILE *) popen (p, "w");
274 if (file) {
275 filelen = edit_write_stream (edit, file);
276 #if 1
277 pclose (file);
278 #else
279 if (pclose (file) != 0) {
280 tmp = g_strconcat (_(" Error writing to pipe: "),
281 p, " ", (char *) NULL);
282 edit_error_dialog (_("Error"), tmp);
283 g_free(tmp);
284 g_free (p);
285 goto error_save;
287 #endif
288 } else {
289 tmp = g_strconcat (_(" Cannot open pipe for writing: "),
290 p, " ", (char *) NULL);
292 edit_error_dialog (_("Error"),
293 get_sys_error (tmp));
294 g_free (p);
295 g_free(tmp);
296 goto error_save;
298 g_free (p);
299 } else if (edit->lb == LB_ASIS) { /* do not change line breaks */
300 long buf;
301 buf = 0;
302 filelen = edit->last_byte;
303 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
304 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
305 != EDIT_BUF_SIZE) {
306 mc_close (fd);
307 goto error_save;
309 buf++;
311 if (mc_write
312 (fd, (char *) edit->buffers1[buf],
313 edit->curs1 & M_EDIT_BUF_SIZE) !=
314 (edit->curs1 & M_EDIT_BUF_SIZE)) {
315 filelen = -1;
316 } else if (edit->curs2) {
317 edit->curs2--;
318 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
319 if (mc_write
320 (fd,
321 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
322 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
323 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
324 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
325 filelen = -1;
326 } else {
327 while (--buf >= 0) {
328 if (mc_write
329 (fd, (char *) edit->buffers2[buf],
330 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
331 filelen = -1;
332 break;
336 edit->curs2++;
338 if (mc_close (fd))
339 goto error_save;
341 /* Update the file information, especially the mtime. */
342 if (mc_stat (savename, &edit->stat1) == -1)
343 goto error_save;
344 } else { /* change line breaks */
345 FILE *file;
347 mc_close (fd);
349 file = (FILE *) fopen (savename, "w");
351 if (file) {
352 filelen = edit_write_stream (edit, file);
353 fclose (file);
354 } else {
355 char *msg;
357 msg = g_strdup_printf (_(" Cannot open file for writing: %s "), savename);
358 edit_error_dialog (_("Error"), msg);
359 g_free (msg);
360 goto error_save;
364 if (filelen != edit->last_byte)
365 goto error_save;
367 if (this_save_mode == EDIT_DO_BACKUP) {
368 assert (option_backup_ext != NULL);
369 tmp = g_strconcat (real_filename, option_backup_ext, (char *) NULL);
370 if (mc_rename (real_filename, tmp) == -1){
371 g_free(tmp);
372 goto error_save;
376 if (this_save_mode != EDIT_QUICK_SAVE)
377 if (mc_rename (savename, real_filename) == -1)
378 goto error_save;
379 g_free (savename);
380 g_free(real_filename);
381 return 1;
382 error_save:
383 /* FIXME: Is this safe ?
384 * if (this_save_mode != EDIT_QUICK_SAVE)
385 * mc_unlink (savename);
387 g_free(real_filename);
388 g_free (savename);
389 return 0;
392 void
393 menu_save_mode_cmd (void)
395 /* diaog sizes */
396 const int DLG_X = 38;
397 const int DLG_Y = 13;
399 char *str_result;
401 const char *str[] =
403 N_("&Quick save"),
404 N_("&Safe save"),
405 N_("&Do backups with following extension:")
408 QuickWidget widgets[] =
410 /* 0 */
411 QUICK_BUTTON (18, DLG_X, DLG_Y - 3, DLG_Y, N_("&Cancel"), B_CANCEL, NULL),
412 /* 1 */
413 QUICK_BUTTON ( 6, DLG_X, DLG_Y - 3, DLG_Y, N_("&OK"), B_ENTER, NULL),
414 /* 2 */
415 QUICK_CHECKBOX ( 4, DLG_X, 8, DLG_Y, N_("Check &POSIX new line"), &option_check_nl_at_eof),
416 /* 3 */
417 QUICK_INPUT ( 8, DLG_X, 6, DLG_Y, option_backup_ext, 9, 0, "edit-backup-ext", &str_result),
418 /* 4 */
419 QUICK_RADIO ( 4, DLG_X, 3, DLG_Y, 3, str, &option_save_mode),
420 QUICK_END
423 QuickDialog dialog =
425 DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "),
426 "[Edit Save Mode]", widgets, FALSE
429 size_t i;
430 size_t maxlen = 0;
431 size_t w0, w1, b_len, w3;
433 assert (option_backup_ext != NULL);
435 /* OK/Cancel buttons */
436 w0 = str_term_width1 (_(widgets[0].u.button.text)) + 3;
437 w1 = str_term_width1 (_(widgets[1].u.button.text)) + 5; /* default button */
438 b_len = w0 + w1 + 3;
440 maxlen = max (b_len, (size_t) str_term_width1 (_(dialog.title)) + 2);
442 w3 = 0;
443 for (i = 0; i < 3; i++) {
444 #ifdef ENABLE_NLS
445 str[i] = _(str[i]);
446 #endif
447 w3 = max (w3, (size_t) str_term_width1 (str[i]));
450 maxlen = max (maxlen, w3 + 4);
452 dialog.xlen = min ((size_t) COLS, maxlen + 8);
454 widgets[3].u.input.len = w3;
455 widgets[1].relative_x = (dialog.xlen - b_len)/2;
456 widgets[0].relative_x = widgets[1].relative_x + w0 + 2;
458 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
459 widgets[i].x_divisions = dialog.xlen;
461 if (quick_dialog (&dialog) != B_CANCEL) {
462 g_free (option_backup_ext);
463 option_backup_ext = str_result;
467 void
468 edit_set_filename (WEdit *edit, const char *f)
470 g_free (edit->filename);
471 if (!f)
472 f = "";
473 edit->filename = g_strdup (f);
474 if (edit->dir == NULL && *f != PATH_SEP)
475 #ifdef USE_VFS
476 edit->dir = g_strdup (vfs_get_current_dir ());
477 #else
478 edit->dir = g_get_current_dir ();
479 #endif
482 static gboolean
483 edit_check_newline (WEdit *edit)
485 return !(option_check_nl_at_eof && edit->last_byte > 0
486 && edit_get_byte (edit, edit->last_byte - 1) != '\n'
487 && edit_query_dialog2 (_("Warning"),
488 _("The file you are saving is not finished with a newline"),
489 _("C&ontinue"), _("&Cancel")));
492 static char *
493 edit_get_save_file_as (WEdit *edit)
495 #define DLG_WIDTH 64
496 #define DLG_HEIGHT 14
498 static LineBreaks cur_lb = LB_ASIS;
500 char *filename = edit->filename;
502 const char *lb_names[LB_NAMES] =
504 N_("&Do not change"),
505 N_("&Unix format (LF)"),
506 N_("&Windows/DOS format (CR LF)"),
507 N_("&Macintosh format (CR)")
510 QuickWidget quick_widgets[] =
512 QUICK_BUTTON (6, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
513 QUICK_BUTTON (2, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
514 QUICK_RADIO (5, DLG_WIDTH, DLG_HEIGHT - 8, DLG_HEIGHT, LB_NAMES, lb_names, (int *) &cur_lb),
515 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 9, DLG_HEIGHT, N_("Change line breaks to:")),
516 QUICK_INPUT (3, DLG_WIDTH, DLG_HEIGHT - 11, DLG_HEIGHT, filename, DLG_WIDTH - 6, 0, "save-as", &filename),
517 QUICK_LABEL (2, DLG_WIDTH, DLG_HEIGHT - 12, DLG_HEIGHT, N_(" Enter file name: ")),
518 QUICK_END
521 QuickDialog Quick_options =
523 DLG_WIDTH, DLG_HEIGHT, -1, -1,
524 N_(" Save As "), "[Save File As]",
525 quick_widgets, FALSE
528 if (quick_dialog (&Quick_options) != B_CANCEL) {
529 edit->lb = cur_lb;
530 return filename;
533 return NULL;
535 #undef DLG_WIDTH
536 #undef DLG_HEIGHT
539 /* Here we want to warn the users of overwriting an existing file,
540 but only if they have made a change to the filename */
541 /* returns 1 on success */
543 edit_save_as_cmd (WEdit *edit)
545 /* This heads the 'Save As' dialog box */
546 char *exp;
547 int save_lock = 0;
548 int different_filename = 0;
550 if (!edit_check_newline (edit))
551 return 0;
553 exp = edit_get_save_file_as (edit);
554 edit_push_action (edit, KEY_PRESS + edit->start_display);
556 if (exp) {
557 if (!*exp) {
558 g_free (exp);
559 edit->force |= REDRAW_COMPLETELY;
560 return 0;
561 } else {
562 int rv;
563 if (strcmp (edit->filename, exp)) {
564 int file;
565 different_filename = 1;
566 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
567 /* the file exists */
568 mc_close (file);
569 /* Overwrite the current file or cancel the operation */
570 if (edit_query_dialog2
571 (_("Warning"),
572 _(" A file already exists with this name. "),
573 _("&Overwrite"), _("&Cancel"))) {
574 edit->force |= REDRAW_COMPLETELY;
575 g_free (exp);
576 return 0;
578 } else {
579 edit->stat1.st_mode |= S_IWUSR;
581 save_lock = edit_lock_file (exp);
582 } else {
583 /* filenames equal, check if already locked */
584 if (!edit->locked && !edit->delete_file)
585 save_lock = edit_lock_file (exp);
588 if (different_filename)
591 * Allow user to write into saved (under another name) file
592 * even if original file had r/o user permissions.
594 edit->stat1.st_mode |= S_IWRITE;
597 rv = edit_save_file (edit, exp);
598 switch (rv) {
599 case 1:
600 /* Succesful, so unlock both files */
601 if (different_filename) {
602 if (save_lock)
603 edit_unlock_file (exp);
604 if (edit->locked)
605 edit->locked = edit_unlock_file (edit->filename);
606 } else {
607 if (edit->locked || save_lock)
608 edit->locked = edit_unlock_file (edit->filename);
611 edit_set_filename (edit, exp);
612 if (edit->lb != LB_ASIS)
613 edit_reload(edit, exp);
614 g_free (exp);
615 edit->modified = 0;
616 edit->delete_file = 0;
617 if (different_filename)
618 edit_load_syntax (edit, NULL, option_syntax_type);
619 edit->force |= REDRAW_COMPLETELY;
620 return 1;
621 default:
622 edit_error_dialog (_(" Save As "),
623 get_sys_error (_
624 (" Cannot save file. ")));
625 /* fallthrough */
626 case -1:
627 /* Failed, so maintain modify (not save) lock */
628 if (save_lock)
629 edit_unlock_file (exp);
630 g_free (exp);
631 edit->force |= REDRAW_COMPLETELY;
632 return 0;
636 edit->force |= REDRAW_COMPLETELY;
637 return 0;
640 /* {{{ Macro stuff starts here */
642 /* creates a macro file if it doesn't exist */
643 static FILE *edit_open_macro_file (const char *r)
645 gchar *filename;
646 FILE *fd;
647 int file;
648 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
649 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
650 g_free(filename);
651 return 0;
653 close (file);
654 fd = fopen (filename, r);
655 g_free(filename);
656 return fd;
659 #define MAX_MACROS 1024
660 static int saved_macro[MAX_MACROS + 1];
661 static int saved_macros_loaded = 0;
664 This is just to stop the macro file be loaded over and over for keys
665 that aren't defined to anything. On slow systems this could be annoying.
667 static int
668 macro_exists (int k)
670 int i;
671 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
672 if (saved_macro[i] == k)
673 return i;
674 return -1;
677 /* returns 1 on error */
678 static int
679 edit_delete_macro (WEdit * edit, int k)
681 gchar *tmp, *tmp2;
682 struct macro macro[MAX_MACRO_LENGTH];
683 FILE *f, *g;
684 int s, i, n, j = 0;
686 (void) edit;
688 if (saved_macros_loaded)
689 if ((j = macro_exists (k)) < 0)
690 return 0;
691 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
692 g = fopen (tmp , "w");
693 g_free(tmp);
694 if (!g) {
695 edit_error_dialog (_(" Delete macro "),
696 get_sys_error (_(" Cannot open temp file ")));
697 return 1;
699 f = edit_open_macro_file ("r");
700 if (!f) {
701 edit_error_dialog (_(" Delete macro "),
702 get_sys_error (_(" Cannot open macro file ")));
703 fclose (g);
704 return 1;
706 for (;;) {
707 n = fscanf (f, ("key '%d 0': "), &s);
708 if (!n || n == EOF)
709 break;
710 n = 0;
711 while (fscanf (f, "%lu %d, ", &macro[n].command, &macro[n].ch))
712 n++;
713 fscanf (f, ";\n");
714 if (s != k) {
715 fprintf (g, ("key '%d 0': "), s);
716 for (i = 0; i < n; i++)
717 fprintf (g, "%lu %d, ", macro[i].command, macro[i].ch);
718 fprintf (g, ";\n");
721 fclose (f);
722 fclose (g);
723 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
724 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
725 if (rename ( tmp, tmp2) == -1) {
726 edit_error_dialog (_(" Delete macro "),
727 get_sys_error (_(" Cannot overwrite macro file ")));
728 g_free(tmp);
729 g_free(tmp2);
730 return 1;
732 g_free(tmp);
733 g_free(tmp2);
735 if (saved_macros_loaded)
736 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
737 return 0;
740 /* returns 0 on error */
741 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
743 FILE *f;
744 int s, i;
746 edit_push_action (edit, KEY_PRESS + edit->start_display);
747 s = editcmd_dialog_raw_key_query (_(" Save macro "),
748 _(" Press the macro's new hotkey: "), 1);
749 edit->force |= REDRAW_COMPLETELY;
750 if (s) {
751 if (edit_delete_macro (edit, s))
752 return 0;
753 f = edit_open_macro_file ("a+");
754 if (f) {
755 fprintf (f, ("key '%d 0': "), s);
756 for (i = 0; i < n; i++)
757 fprintf (f, "%lu %d, ", macro[i].command, macro[i].ch);
758 fprintf (f, ";\n");
759 fclose (f);
760 if (saved_macros_loaded) {
761 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
762 saved_macro[i] = s;
764 return 1;
765 } else
766 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
768 return 0;
771 void
772 edit_delete_macro_cmd (WEdit * edit)
774 int command;
776 command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
777 _ (" Press macro hotkey: "), 1);
779 if (command != 0)
780 edit_delete_macro (edit, command);
783 /* return 0 on error */
784 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
786 FILE *f;
787 int s, i = 0, found = 0;
789 (void) edit;
791 if (saved_macros_loaded)
792 if (macro_exists (k) < 0)
793 return 0;
795 if ((f = edit_open_macro_file ("r"))) {
796 struct macro dummy;
797 do {
798 int u;
799 u = fscanf (f, ("key '%d 0': "), &s);
800 if (!u || u == EOF)
801 break;
802 if (!saved_macros_loaded)
803 saved_macro[i++] = s;
804 if (!found) {
805 *n = 0;
806 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%lu %d, ", &macro[*n].command, &macro[*n].ch))
807 (*n)++;
808 } else {
809 while (2 == fscanf (f, "%lu %d, ", &dummy.command, &dummy.ch));
811 fscanf (f, ";\n");
812 if (s == k)
813 found = 1;
814 } while (!found || !saved_macros_loaded);
815 if (!saved_macros_loaded) {
816 saved_macro[i] = 0;
817 saved_macros_loaded = 1;
819 fclose (f);
820 return found;
821 } else
822 edit_error_dialog (_(" Load macro "),
823 get_sys_error (_(" Cannot open macro file ")));
824 return 0;
827 /* }}} Macro stuff starts here */
829 /* returns 1 on success */
830 int edit_save_confirm_cmd (WEdit * edit)
832 gchar *f = NULL;
834 if (!edit_check_newline (edit))
835 return 0;
837 if (edit_confirm_save) {
838 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", (char *) NULL);
839 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel"))){
840 g_free(f);
841 return 0;
843 g_free(f);
845 return edit_save_cmd (edit);
849 /* returns 1 on success */
850 static int
851 edit_save_cmd (WEdit *edit)
853 int res, save_lock = 0;
855 if (!edit->locked && !edit->delete_file)
856 save_lock = edit_lock_file (edit->filename);
857 res = edit_save_file (edit, edit->filename);
859 /* Maintain modify (not save) lock on failure */
860 if ((res > 0 && edit->locked) || save_lock)
861 edit->locked = edit_unlock_file (edit->filename);
863 /* On failure try 'save as', it does locking on its own */
864 if (!res)
865 return edit_save_as_cmd (edit);
866 edit->force |= REDRAW_COMPLETELY;
867 if (res > 0) {
868 edit->delete_file = 0;
869 edit->modified = 0;
872 return 1;
876 /* returns 1 on success */
877 int edit_new_cmd (WEdit * edit)
879 if (edit->modified) {
880 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
881 edit->force |= REDRAW_COMPLETELY;
882 return 0;
885 edit->force |= REDRAW_COMPLETELY;
887 return edit_renew (edit); /* if this gives an error, something has really screwed up */
890 /* returns 1 on error */
891 static int
892 edit_load_file_from_filename (WEdit * edit, char *exp)
894 int prev_locked = edit->locked;
895 char *prev_filename = g_strdup (edit->filename);
897 if (!edit_reload (edit, exp)) {
898 g_free (prev_filename);
899 return 1;
902 if (prev_locked)
903 edit_unlock_file (prev_filename);
904 g_free (prev_filename);
905 return 0;
908 static void
909 edit_load_syntax_file (WEdit * edit)
911 char *extdir;
912 int dir = 0;
914 if (geteuid () == 0) {
915 dir = query_dialog (_("Syntax file edit"),
916 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
917 _("&User"), _("&System Wide"));
920 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
921 if (!exist_file(extdir)) {
922 g_free (extdir);
923 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
926 if (dir == 0) {
927 char *buffer;
929 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
930 check_for_default (extdir, buffer);
931 edit_load_file_from_filename (edit, buffer);
932 g_free (buffer);
933 } else if (dir == 1)
934 edit_load_file_from_filename (edit, extdir);
936 g_free (extdir);
939 static void
940 edit_load_menu_file (WEdit * edit)
942 char *buffer;
943 char *menufile;
944 int dir = 0;
946 dir = query_dialog (
947 _(" Menu edit "),
948 _(" Which menu file do you want to edit? "), D_NORMAL,
949 geteuid() ? 2 : 3, _("&Local"), _("&User"), _("&System Wide")
952 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
954 if (!exist_file (menufile)) {
955 g_free (menufile);
956 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
959 switch (dir) {
960 case 0:
961 buffer = g_strdup (EDIT_LOCAL_MENU);
962 check_for_default (menufile, buffer);
963 chmod (buffer, 0600);
964 break;
966 case 1:
967 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
968 check_for_default (menufile, buffer);
969 break;
971 case 2:
972 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
973 if (!exist_file (buffer)) {
974 g_free (buffer);
975 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
977 break;
979 default:
980 g_free (menufile);
981 return;
984 edit_load_file_from_filename (edit, buffer);
986 g_free (buffer);
987 g_free (menufile);
991 edit_load_cmd (WEdit *edit, edit_current_file_t what)
993 char *exp;
995 if (edit->modified
996 && (edit_query_dialog2
997 (_("Warning"),
998 _(" Current text was modified without a file save. \n"
999 " Continue discards these changes. "),
1000 _("C&ontinue"), _("&Cancel")) == 1)) {
1001 edit->force |= REDRAW_COMPLETELY;
1002 return 0;
1005 switch (what) {
1006 case EDIT_FILE_COMMON:
1007 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
1008 MC_HISTORY_EDIT_LOAD, edit->filename);
1010 if (exp) {
1011 if (*exp)
1012 edit_load_file_from_filename (edit, exp);
1013 g_free (exp);
1015 break;
1017 case EDIT_FILE_SYNTAX:
1018 edit_load_syntax_file (edit);
1019 break;
1021 case EDIT_FILE_MENU:
1022 edit_load_menu_file (edit);
1023 break;
1025 default:
1026 break;
1029 edit->force |= REDRAW_COMPLETELY;
1030 return 0;
1034 if mark2 is -1 then marking is from mark1 to the cursor.
1035 Otherwise its between the markers. This handles this.
1036 Returns 1 if no text is marked.
1038 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
1040 if (edit->mark1 != edit->mark2) {
1041 long start_bol, start_eol;
1042 long end_bol, end_eol;
1043 long col1, col2;
1044 long diff1, diff2;
1045 if (edit->mark2 >= 0) {
1046 *start_mark = min (edit->mark1, edit->mark2);
1047 *end_mark = max (edit->mark1, edit->mark2);
1048 } else {
1049 *start_mark = min (edit->mark1, edit->curs1);
1050 *end_mark = max (edit->mark1, edit->curs1);
1051 edit->column2 = edit->curs_col + edit->over_col;
1053 if (column_highlighting
1054 && (((edit->mark1 > edit->curs1) && (edit->column1 < edit->column2))
1055 || ((edit->mark1 < edit->curs1) && (edit->column1 > edit->column2)))) {
1057 start_bol = edit_bol (edit, *start_mark);
1058 start_eol = edit_eol (edit, start_bol - 1) + 1;
1059 end_bol = edit_bol (edit, *end_mark);
1060 end_eol = edit_eol (edit, *end_mark);
1061 col1 = min (edit->column1, edit->column2);
1062 col2 = max (edit->column1, edit->column2);
1064 diff1 = edit_move_forward3 (edit, start_bol, col2, 0) - edit_move_forward3 (edit, start_bol, col1, 0);
1065 diff2 = edit_move_forward3 (edit, end_bol, col2, 0) - edit_move_forward3 (edit, end_bol, col1, 0);
1067 *start_mark -= diff1;
1068 *end_mark += diff2;
1069 *start_mark = max (*start_mark, start_eol);
1070 *end_mark = min (*end_mark, end_eol);
1072 return 0;
1073 } else {
1074 *start_mark = *end_mark = 0;
1075 edit->column2 = edit->column1 = 0;
1076 return 1;
1080 #define space_width 1
1082 void
1083 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
1085 long cursor;
1086 int i, col;
1087 cursor = edit->curs1;
1088 col = edit_get_col (edit);
1089 for (i = 0; i < size; i++) {
1090 if (data[i] == '\n') { /* fill in and move to next line */
1091 int l;
1092 long p;
1093 if (edit_get_byte (edit, edit->curs1) != '\n') {
1094 l = width - (edit_get_col (edit) - col);
1095 while (l > 0) {
1096 edit_insert (edit, ' ');
1097 l -= space_width;
1100 for (p = edit->curs1;; p++) {
1101 if (p == edit->last_byte) {
1102 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1103 edit_insert_ahead (edit, '\n');
1104 p++;
1105 break;
1107 if (edit_get_byte (edit, p) == '\n') {
1108 p++;
1109 break;
1112 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1113 l = col - edit_get_col (edit);
1114 while (l >= space_width) {
1115 edit_insert (edit, ' ');
1116 l -= space_width;
1118 continue;
1120 edit_insert (edit, data[i]);
1122 edit_cursor_move (edit, cursor - edit->curs1);
1125 #define TEMP_BUF_LEN 1024
1128 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1130 long cursor;
1131 int i, col;
1132 int blocklen = -1, width;
1133 unsigned char *data;
1134 cursor = edit->curs1;
1135 col = edit_get_col (edit);
1136 data = g_malloc0 (TEMP_BUF_LEN);
1137 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0) {
1138 for (width = 0; width < blocklen; width++) {
1139 if (data[width] == '\n')
1140 break;
1142 for (i = 0; i < blocklen; i++) {
1143 if (data[i] == '\n') { /* fill in and move to next line */
1144 int l;
1145 long p;
1146 if (edit_get_byte (edit, edit->curs1) != '\n') {
1147 l = width - (edit_get_col (edit) - col);
1148 while (l > 0) {
1149 edit_insert (edit, ' ');
1150 l -= space_width;
1153 for (p = edit->curs1;; p++) {
1154 if (p == edit->last_byte) {
1155 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1156 edit_insert_ahead (edit, '\n');
1157 p++;
1158 break;
1160 if (edit_get_byte (edit, p) == '\n') {
1161 p++;
1162 break;
1165 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1166 l = col - edit_get_col (edit);
1167 while (l >= space_width) {
1168 edit_insert (edit, ' ');
1169 l -= space_width;
1171 continue;
1173 edit_insert (edit, data[i]);
1176 edit_cursor_move (edit, cursor - edit->curs1);
1177 g_free(data);
1178 edit->force |= REDRAW_PAGE;
1179 return blocklen;
1182 void
1183 edit_block_copy_cmd (WEdit *edit)
1185 long start_mark, end_mark, current = edit->curs1;
1186 int size;
1187 unsigned char *copy_buf;
1189 edit_update_curs_col (edit);
1190 if (eval_marks (edit, &start_mark, &end_mark))
1191 return;
1193 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1195 /* all that gets pushed are deletes hence little space is used on the stack */
1197 edit_push_markers (edit);
1199 if (column_highlighting) {
1200 edit_insert_column_of_text (edit, copy_buf, size,
1201 abs (edit->column2 - edit->column1));
1202 } else {
1203 while (size--)
1204 edit_insert_ahead (edit, copy_buf[size]);
1207 g_free (copy_buf);
1208 edit_scroll_screen_over_cursor (edit);
1210 if (column_highlighting) {
1211 edit_set_markers (edit, 0, 0, 0, 0);
1212 edit_push_action (edit, COLUMN_ON);
1213 column_highlighting = 0;
1214 } else if (start_mark < current && end_mark > current)
1215 edit_set_markers (edit, start_mark,
1216 end_mark + end_mark - start_mark, 0, 0);
1218 edit->force |= REDRAW_PAGE;
1222 void
1223 edit_block_move_cmd (WEdit *edit)
1225 long count;
1226 long current;
1227 unsigned char *copy_buf;
1228 long start_mark, end_mark;
1229 int deleted = 0;
1230 int x = 0;
1232 if (eval_marks (edit, &start_mark, &end_mark))
1233 return;
1234 if (column_highlighting) {
1235 edit_update_curs_col (edit);
1236 x = edit->curs_col;
1237 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1238 if ((x > edit->column1 && x < edit->column2)
1239 || (x > edit->column2 && x < edit->column1))
1240 return;
1241 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1242 return;
1244 if ((end_mark - start_mark) > option_max_undo / 2)
1245 if (edit_query_dialog2
1246 (_("Warning"),
1248 (" Block is large, you may not be able to undo this action. "),
1249 _("C&ontinue"), _("&Cancel")))
1250 return;
1252 edit_push_markers (edit);
1253 current = edit->curs1;
1254 if (column_highlighting) {
1255 int size, c1, c2, line;
1256 line = edit->curs_line;
1257 if (edit->mark2 < 0)
1258 edit_mark_cmd (edit, 0);
1259 c1 = min (edit->column1, edit->column2);
1260 c2 = max (edit->column1, edit->column2);
1261 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1262 if (x < c2) {
1263 edit_block_delete_cmd (edit);
1264 deleted = 1;
1266 edit_move_to_line (edit, line);
1267 edit_cursor_move (edit,
1268 edit_move_forward3 (edit,
1269 edit_bol (edit, edit->curs1),
1270 x, 0) - edit->curs1);
1271 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1272 if (!deleted) {
1273 line = edit->curs_line;
1274 edit_update_curs_col (edit);
1275 x = edit->curs_col;
1276 edit_block_delete_cmd (edit);
1277 edit_move_to_line (edit, line);
1278 edit_cursor_move (edit,
1279 edit_move_forward3 (edit,
1280 edit_bol (edit,
1281 edit->curs1),
1282 x, 0) - edit->curs1);
1284 edit_set_markers (edit, 0, 0, 0, 0);
1285 edit_push_action (edit, COLUMN_ON);
1286 column_highlighting = 0;
1287 } else {
1288 copy_buf = g_malloc0 (end_mark - start_mark);
1289 edit_cursor_move (edit, start_mark - edit->curs1);
1290 edit_scroll_screen_over_cursor (edit);
1291 count = start_mark;
1292 while (count < end_mark) {
1293 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1294 count++;
1296 edit_scroll_screen_over_cursor (edit);
1297 edit_cursor_move (edit,
1298 current - edit->curs1 -
1299 (((current - edit->curs1) >
1300 0) ? end_mark - start_mark : 0));
1301 edit_scroll_screen_over_cursor (edit);
1302 while (count-- > start_mark)
1303 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1304 edit_set_markers (edit, edit->curs1,
1305 edit->curs1 + end_mark - start_mark, 0, 0);
1307 edit_scroll_screen_over_cursor (edit);
1308 g_free (copy_buf);
1309 edit->force |= REDRAW_PAGE;
1312 static void
1313 edit_delete_column_of_text (WEdit * edit)
1315 long p, q, r, m1, m2;
1316 int b, c, d;
1317 int n;
1319 eval_marks (edit, &m1, &m2);
1320 n = edit_move_forward (edit, m1, 0, m2) + 1;
1321 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1322 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1323 b = max (min (c, d), min (edit->column1, edit->column2));
1324 c = max (c, max (edit->column1, edit->column2));
1326 while (n--) {
1327 r = edit_bol (edit, edit->curs1);
1328 p = edit_move_forward3 (edit, r, b, 0);
1329 q = edit_move_forward3 (edit, r, c, 0);
1330 if (p < m1)
1331 p = m1;
1332 if (q > m2)
1333 q = m2;
1334 edit_cursor_move (edit, p - edit->curs1);
1335 while (q > p) {
1336 /* delete line between margins */
1337 if (edit_get_byte (edit, edit->curs1) != '\n')
1338 edit_delete (edit, 1);
1339 q--;
1341 if (n)
1342 /* move to next line except on the last delete */
1343 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1347 /* if success return 0 */
1348 static int
1349 edit_block_delete (WEdit *edit)
1351 long count;
1352 long start_mark, end_mark;
1353 int curs_pos, line_width;
1354 long curs_line, c1, c2;
1356 if (eval_marks (edit, &start_mark, &end_mark))
1357 return 0;
1358 if (column_highlighting && edit->mark2 < 0)
1359 edit_mark_cmd (edit, 0);
1360 if ((end_mark - start_mark) > option_max_undo / 2) {
1361 /* Warning message with a query to continue or cancel the operation */
1362 if (edit_query_dialog2
1363 (_("Warning"),
1365 (" Block is large, you may not be able to undo this action. "),
1366 _("C&ontinue"), _("&Cancel"))) {
1367 return 1;
1370 c1 = min (edit->column1, edit->column2);
1371 c2 = max (edit->column1, edit->column2);
1372 edit->column1 = c1;
1373 edit->column2 = c2;
1375 edit_push_markers (edit);
1377 curs_line = edit->curs_line;
1379 /* calculate line width and cursor position before cut */
1380 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1381 edit_eol (edit, edit->curs1));
1382 curs_pos = edit->curs_col + edit->over_col;
1384 /* move cursor to start of selection */
1385 edit_cursor_move (edit, start_mark - edit->curs1);
1386 edit_scroll_screen_over_cursor (edit);
1387 count = start_mark;
1388 if (start_mark < end_mark) {
1389 if (column_highlighting) {
1390 if (edit->mark2 < 0)
1391 edit_mark_cmd (edit, 0);
1392 edit_delete_column_of_text (edit);
1393 /* move cursor to the saved position */
1394 edit_move_to_line (edit, curs_line);
1395 /* calculate line width after cut */
1396 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1397 edit_eol (edit, edit->curs1));
1398 if (option_cursor_beyond_eol && curs_pos > line_width)
1399 edit->over_col = curs_pos - line_width;
1400 } else {
1401 while (count < end_mark) {
1402 edit_delete (edit, 1);
1403 count++;
1407 edit_set_markers (edit, 0, 0, 0, 0);
1408 edit->force |= REDRAW_PAGE;
1409 return 0;
1412 /* returns 1 if canceelled by user */
1413 int edit_block_delete_cmd (WEdit * edit)
1415 long start_mark, end_mark;
1416 if (eval_marks (edit, &start_mark, &end_mark)) {
1417 edit_delete_line (edit);
1418 return 0;
1420 return edit_block_delete (edit);
1423 #define INPUT_INDEX 9
1425 static gboolean
1426 editcmd_find (WEdit *edit, gsize *len)
1428 off_t search_start = edit->search_start;
1429 off_t search_end;
1430 long start_mark = 0;
1431 long end_mark = edit->last_byte;
1432 int mark_res = 0;
1434 if (edit->only_in_selection) {
1435 mark_res = eval_marks(edit, &start_mark, &end_mark);
1436 if (mark_res != 0) {
1437 edit->search->error = MC_SEARCH_E_NOTFOUND;
1438 edit->search->error_str = g_strdup(_(" Search string not found "));
1439 return FALSE;
1441 if (edit->replace_backwards) {
1442 if (search_start > end_mark || search_start <= start_mark) {
1443 search_start = end_mark;
1445 } else {
1446 if (search_start < start_mark || search_start >= end_mark) {
1447 search_start = start_mark;
1450 } else {
1451 if (edit->replace_backwards)
1452 end_mark = max(1, edit->curs1) - 1;
1454 if (edit->replace_backwards) {
1455 search_end = end_mark;
1456 while ((int) search_start >= start_mark) {
1457 if (search_end > search_start + edit->search->original_len
1458 && mc_search_is_fixed_search_str(edit->search)) {
1459 search_end = search_start + edit->search->original_len;
1461 if (mc_search_run(edit->search, (void *) edit, search_start, search_end, len)
1462 && edit->search->normal_offset == search_start ) {
1463 return TRUE;
1465 search_start--;
1467 edit->search->error_str = g_strdup(_(" Search string not found "));
1468 } else {
1469 return mc_search_run(edit->search, (void *) edit, search_start, end_mark, len);
1471 return FALSE;
1475 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1476 (and the above) routines to work properly - paul */
1478 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1480 static char *
1481 edit_replace_cmd__conv_to_display (char *str)
1483 #ifdef HAVE_CHARSET
1484 GString *tmp;
1485 tmp = str_convert_to_display (str);
1487 if (tmp && tmp->len){
1488 return g_string_free (tmp, FALSE);
1490 g_string_free (tmp, TRUE);
1491 #endif
1492 return g_strdup(str);
1495 static char *
1496 edit_replace_cmd__conv_to_input(char *str)
1498 #ifdef HAVE_CHARSET
1499 GString *tmp;
1500 tmp = str_convert_to_input (str);
1502 if (tmp && tmp->len){
1503 return g_string_free (tmp, FALSE);
1505 g_string_free (tmp, TRUE);
1506 return g_strdup(str);
1507 #endif
1508 return g_strdup(str);
1510 /* call with edit = 0 before shutdown to close memory leaks */
1511 void
1512 edit_replace_cmd (WEdit *edit, int again)
1514 /* 1 = search string, 2 = replace with */
1515 static char *saved1 = NULL; /* saved default[123] */
1516 static char *saved2 = NULL;
1517 char *input1 = NULL; /* user input from the dialog */
1518 char *input2 = NULL;
1519 int replace_yes;
1520 long times_replaced = 0, last_search;
1521 gboolean once_found = FALSE;
1523 if (!edit) {
1524 g_free (saved1), saved1 = NULL;
1525 g_free (saved2), saved2 = NULL;
1526 return;
1529 last_search = edit->last_byte;
1531 edit->force |= REDRAW_COMPLETELY;
1533 if (again && !saved1 && !saved2)
1534 again = 0;
1536 if (again) {
1537 input1 = g_strdup (saved1 ? saved1 : "");
1538 input2 = g_strdup (saved2 ? saved2 : "");
1539 } else {
1540 char *disp1 = edit_replace_cmd__conv_to_display (saved1 ? saved1 : (char *) "");
1541 char *disp2 = edit_replace_cmd__conv_to_display (saved2 ? saved2 : (char *) "");
1542 char *tmp_inp1, *tmp_inp2;
1544 edit_push_action (edit, KEY_PRESS + edit->start_display);
1546 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1548 g_free (disp1);
1549 g_free (disp2);
1551 if (input1 == NULL || *input1 == '\0') {
1552 edit->force = REDRAW_COMPLETELY;
1553 goto cleanup;
1556 tmp_inp1 = input1; tmp_inp2 = input2;
1557 input1 = edit_replace_cmd__conv_to_input(input1);
1558 input2 = edit_replace_cmd__conv_to_input(input2);
1559 g_free(tmp_inp1); g_free(tmp_inp2);
1561 g_free (saved1), saved1 = g_strdup (input1);
1562 g_free (saved2), saved2 = g_strdup (input2);
1564 if (edit->search) {
1565 mc_search_free(edit->search);
1566 edit->search = NULL;
1570 if (!edit->search) {
1571 edit->search = mc_search_new(input1, -1);
1572 if (edit->search == NULL) {
1573 edit->search_start = edit->curs1;
1574 return;
1576 edit->search->search_type = edit->search_type;
1577 edit->search->is_all_charsets = edit->all_codepages;
1578 edit->search->is_case_sentitive = edit->replace_case;
1579 edit->search->whole_words = edit->whole_words;
1580 edit->search->search_fn = edit_search_cmd_callback;
1583 if (edit->found_len && edit->search_start == edit->found_start + 1
1584 && edit->replace_backwards)
1585 edit->search_start--;
1587 if (edit->found_len && edit->search_start == edit->found_start - 1
1588 && !edit->replace_backwards)
1589 edit->search_start++;
1591 do {
1592 gsize len = 0;
1593 long new_start;
1595 if (! editcmd_find(edit, &len)) {
1596 if (!(edit->search->error == MC_SEARCH_E_OK ||
1597 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND))) {
1598 edit_error_dialog (_ ("Search"), edit->search->error_str);
1600 break;
1602 once_found = TRUE;
1603 new_start = edit->search->normal_offset;
1605 edit->search_start = new_start = edit->search->normal_offset;
1606 /*returns negative on not found or error in pattern */
1608 if (edit->search_start >= 0) {
1609 guint i;
1611 edit->found_start = edit->search_start;
1612 i = edit->found_len = len;
1614 edit_cursor_move (edit, edit->search_start - edit->curs1);
1615 edit_scroll_screen_over_cursor (edit);
1617 replace_yes = 1;
1619 if (edit->replace_mode == 0) {
1620 int l;
1621 l = edit->curs_row - edit->num_widget_lines / 3;
1622 if (l > 0)
1623 edit_scroll_downward (edit, l);
1624 if (l < 0)
1625 edit_scroll_upward (edit, -l);
1627 edit_scroll_screen_over_cursor (edit);
1628 edit->force |= REDRAW_PAGE;
1629 edit_render_keypress (edit);
1631 /*so that undo stops at each query */
1632 edit_push_key_press (edit);
1633 /* and prompt 2/3 down */
1634 switch (editcmd_dialog_replace_prompt_show (edit, input1, input2, -1, -1)) {
1635 case B_ENTER:
1636 replace_yes = 1;
1637 break;
1638 case B_SKIP_REPLACE:
1639 replace_yes = 0;
1640 break;
1641 case B_REPLACE_ALL:
1642 edit->replace_mode=1;
1643 break;
1644 case B_CANCEL:
1645 replace_yes = 0;
1646 edit->replace_mode = -1;
1647 break;
1650 if (replace_yes) { /* delete then insert new */
1651 GString *repl_str, *tmp_str;
1652 tmp_str = g_string_new(input2);
1654 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1655 g_string_free(tmp_str, TRUE);
1656 if (edit->search->error != MC_SEARCH_E_OK)
1658 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1659 break;
1662 while (i--)
1663 edit_delete (edit, 1);
1665 while (++i < repl_str->len)
1666 edit_insert (edit, repl_str->str[i]);
1668 g_string_free(repl_str, TRUE);
1669 edit->found_len = i;
1671 /* so that we don't find the same string again */
1672 if (edit->replace_backwards) {
1673 last_search = edit->search_start;
1674 edit->search_start--;
1675 } else {
1676 edit->search_start += i;
1677 last_search = edit->last_byte;
1679 edit_scroll_screen_over_cursor (edit);
1680 } else {
1681 const char *msg = _(" Replace ");
1682 /* try and find from right here for next search */
1683 edit->search_start = edit->curs1;
1684 edit_update_curs_col (edit);
1686 edit->force |= REDRAW_PAGE;
1687 edit_render_keypress (edit);
1688 if (times_replaced) {
1689 message (D_NORMAL, msg, _(" %ld replacements made. "),
1690 times_replaced);
1691 } else
1692 query_dialog (msg, _(" Search string not found "),
1693 D_NORMAL, 1, _("&OK"));
1694 edit->replace_mode = -1;
1696 } while (edit->replace_mode >= 0);
1698 edit->force = REDRAW_COMPLETELY;
1699 edit_scroll_screen_over_cursor (edit);
1700 cleanup:
1701 g_free (input1);
1702 g_free (input2);
1706 void edit_search_cmd (WEdit * edit, int again)
1708 char *search_string = NULL, *search_string_dup = NULL;
1710 gsize len = 0;
1712 if (!edit)
1713 return;
1715 if (edit->search != NULL) {
1716 search_string = g_strndup(edit->search->original, edit->search->original_len);
1717 search_string_dup = search_string;
1718 } else {
1719 GList *history;
1720 history = history_get (MC_HISTORY_SHARED_SEARCH);
1721 if (history != NULL && history->data != NULL) {
1722 search_string_dup = search_string = (char *) g_strdup(history->data);
1723 history = g_list_first (history);
1724 g_list_foreach (history, (GFunc) g_free, NULL);
1725 g_list_free (history);
1727 edit->search_start = edit->curs1;
1730 if (!again) {
1731 #ifdef HAVE_CHARSET
1732 GString *tmp;
1733 if (search_string && *search_string) {
1734 tmp = str_convert_to_display (search_string);
1736 g_free(search_string_dup);
1737 search_string_dup = NULL;
1739 if (tmp && tmp->len)
1740 search_string = search_string_dup = tmp->str;
1741 g_string_free (tmp, FALSE);
1743 #endif /* HAVE_CHARSET */
1744 editcmd_dialog_search_show (edit, &search_string);
1745 #ifdef HAVE_CHARSET
1746 if (search_string && *search_string) {
1747 tmp = str_convert_to_input (search_string);
1748 if (tmp && tmp->len)
1749 search_string = tmp->str;
1751 g_string_free (tmp, FALSE);
1753 if (search_string_dup)
1754 g_free(search_string_dup);
1756 #endif /* HAVE_CHARSET */
1758 edit_push_action (edit, KEY_PRESS + edit->start_display);
1760 if (!search_string) {
1761 edit->force |= REDRAW_COMPLETELY;
1762 edit_scroll_screen_over_cursor (edit);
1763 return;
1766 if (edit->search) {
1767 mc_search_free(edit->search);
1768 edit->search = NULL;
1772 if (!edit->search) {
1773 edit->search = mc_search_new(search_string, -1);
1774 if (edit->search == NULL) {
1775 edit->search_start = edit->curs1;
1776 return;
1778 edit->search->search_type = edit->search_type;
1779 edit->search->is_all_charsets = edit->all_codepages;
1780 edit->search->is_case_sentitive = edit->replace_case;
1781 edit->search->whole_words = edit->whole_words;
1782 edit->search->search_fn = edit_search_cmd_callback;
1785 if (search_create_bookmark) {
1786 edit_search_cmd_search_create_bookmark(edit);
1787 } else {
1788 if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
1789 edit->search_start--;
1791 if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
1792 edit->search_start++;
1795 if (editcmd_find(edit, &len)) {
1796 edit->found_start = edit->search_start = edit->search->normal_offset;
1797 edit->found_len = len;
1798 edit->over_col = 0;
1799 edit_cursor_move (edit, edit->search_start - edit->curs1);
1800 edit_scroll_screen_over_cursor (edit);
1801 if (edit->replace_backwards)
1802 edit->search_start--;
1803 else
1804 edit->search_start++;
1805 } else {
1806 edit->search_start = edit->curs1;
1807 if (edit->search->error_str)
1808 edit_error_dialog (_ ("Search"), edit->search->error_str);
1812 edit->force |= REDRAW_COMPLETELY;
1813 edit_scroll_screen_over_cursor (edit);
1818 * Check if it's OK to close the editor. If there are unsaved changes,
1819 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
1822 edit_ok_to_exit (WEdit *edit)
1824 if (!edit->modified)
1825 return 1;
1827 if (!edit_check_newline (edit))
1828 return 0;
1830 switch (edit_query_dialog3
1831 (_("Quit"), _(" File was modified, Save with exit? "),
1832 _("&Cancel quit"), _("&Yes"), _("&No"))) {
1833 case 1:
1834 edit_push_markers (edit);
1835 edit_set_markers (edit, 0, 0, 0, 0);
1836 if (!edit_save_cmd (edit))
1837 return 0;
1838 break;
1839 case 2:
1840 break;
1841 case 0:
1842 case -1:
1843 return 0;
1846 return 1;
1849 /* Return a null terminated length of text. Result must be g_free'd */
1850 static unsigned char *
1851 edit_get_block (WEdit *edit, long start, long finish, int *l)
1853 unsigned char *s, *r;
1854 r = s = g_malloc0 (finish - start + 1);
1855 if (column_highlighting) {
1856 *l = 0;
1857 /* copy from buffer, excluding chars that are out of the column 'margins' */
1858 while (start < finish) {
1859 int c, x;
1860 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
1861 start);
1862 c = edit_get_byte (edit, start);
1863 if ((x >= edit->column1 && x < edit->column2)
1864 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1865 *s++ = c;
1866 (*l)++;
1868 start++;
1870 } else {
1871 *l = finish - start;
1872 while (start < finish)
1873 *s++ = edit_get_byte (edit, start++);
1875 *s = 0;
1876 return r;
1879 /* save block, returns 1 on success */
1881 edit_save_block (WEdit * edit, const char *filename, long start,
1882 long finish)
1884 int len, file;
1886 if ((file =
1887 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
1888 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
1889 return 0;
1891 if (column_highlighting) {
1892 int r;
1893 r = mc_write (file, VERTICAL_MAGIC, sizeof(VERTICAL_MAGIC));
1894 if (r > 0) {
1895 unsigned char *block, *p;
1896 p = block = edit_get_block (edit, start, finish, &len);
1897 while (len) {
1898 r = mc_write (file, p, len);
1899 if (r < 0)
1900 break;
1901 p += r;
1902 len -= r;
1904 g_free (block);
1906 } else {
1907 unsigned char *buf;
1908 int i = start, end;
1909 len = finish - start;
1910 buf = g_malloc0 (TEMP_BUF_LEN);
1911 while (start != finish) {
1912 end = min (finish, start + TEMP_BUF_LEN);
1913 for (; i < end; i++)
1914 buf[i - start] = edit_get_byte (edit, i);
1915 len -= mc_write (file, (char *) buf, end - start);
1916 start = end;
1918 g_free (buf);
1920 mc_close (file);
1921 if (len)
1922 return 0;
1923 return 1;
1926 /* copies a block to clipboard file */
1927 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1929 int ret;
1930 gchar *tmp;
1931 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1932 ret = edit_save_block (edit, tmp, start, finish);
1933 g_free(tmp);
1934 return ret;
1938 void edit_paste_from_history (WEdit *edit)
1940 (void) edit;
1941 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
1944 int edit_copy_to_X_buf_cmd (WEdit * edit)
1946 long start_mark, end_mark;
1947 if (eval_marks (edit, &start_mark, &end_mark))
1948 return 0;
1949 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1950 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
1951 return 1;
1953 edit_mark_cmd (edit, 1);
1954 return 0;
1957 int edit_cut_to_X_buf_cmd (WEdit * edit)
1959 long start_mark, end_mark;
1960 if (eval_marks (edit, &start_mark, &end_mark))
1961 return 0;
1962 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1963 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
1964 return 1;
1966 edit_block_delete_cmd (edit);
1967 edit_mark_cmd (edit, 1);
1968 return 0;
1971 void edit_paste_from_X_buf_cmd (WEdit * edit)
1973 gchar *tmp;
1974 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1975 edit_insert_file (edit, tmp);
1976 g_free(tmp);
1981 * Ask user for the line and go to that line.
1982 * Negative numbers mean line from the end (i.e. -1 is the last line).
1984 void
1985 edit_goto_cmd (WEdit *edit)
1987 char *f;
1988 static long line = 0; /* line as typed, saved as default */
1989 long l;
1990 char *error;
1991 char s[32];
1993 g_snprintf (s, sizeof (s), "%ld", line);
1994 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
1995 line ? s : "");
1996 if (!f)
1997 return;
1999 if (!*f) {
2000 g_free (f);
2001 return;
2004 l = strtol (f, &error, 0);
2005 if (*error) {
2006 g_free (f);
2007 return;
2010 line = l;
2011 if (l < 0)
2012 l = edit->total_lines + l + 2;
2013 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2014 edit_move_to_line (edit, l - 1);
2015 edit->force |= REDRAW_COMPLETELY;
2016 g_free (f);
2020 /* Return 1 on success */
2022 edit_save_block_cmd (WEdit *edit)
2024 long start_mark, end_mark;
2025 char *exp, *tmp;
2027 if (eval_marks (edit, &start_mark, &end_mark))
2028 return 1;
2030 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2031 exp =
2032 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2033 MC_HISTORY_EDIT_SAVE_BLOCK,
2034 tmp);
2035 g_free(tmp);
2036 edit_push_action (edit, KEY_PRESS + edit->start_display);
2037 if (exp) {
2038 if (!*exp) {
2039 g_free (exp);
2040 return 0;
2041 } else {
2042 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2043 g_free (exp);
2044 edit->force |= REDRAW_COMPLETELY;
2045 return 1;
2046 } else {
2047 g_free (exp);
2048 edit_error_dialog (_(" Save Block "),
2049 get_sys_error (_
2050 (" Cannot save file. ")));
2054 edit->force |= REDRAW_COMPLETELY;
2055 return 0;
2059 /* returns 1 on success */
2061 edit_insert_file_cmd (WEdit *edit)
2063 gchar *tmp;
2064 char *exp;
2066 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2067 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2068 MC_HISTORY_EDIT_INSERT_FILE,
2069 tmp);
2070 g_free(tmp);
2071 edit_push_action (edit, KEY_PRESS + edit->start_display);
2072 if (exp) {
2073 if (!*exp) {
2074 g_free (exp);
2075 return 0;
2076 } else {
2077 if (edit_insert_file (edit, exp)) {
2078 g_free (exp);
2079 edit->force |= REDRAW_COMPLETELY;
2080 return 1;
2081 } else {
2082 g_free (exp);
2083 edit_error_dialog (_(" Insert File "),
2084 get_sys_error (_
2085 (" Cannot insert file. ")));
2089 edit->force |= REDRAW_COMPLETELY;
2090 return 0;
2093 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2094 int edit_sort_cmd (WEdit * edit)
2096 static char *old = 0;
2097 char *exp, *tmp;
2098 long start_mark, end_mark;
2099 int e;
2101 if (eval_marks (edit, &start_mark, &end_mark)) {
2102 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2103 return 0;
2106 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2107 edit_save_block (edit, tmp, start_mark, end_mark);
2108 g_free(tmp);
2110 exp = input_dialog (_(" Run Sort "),
2111 _(" Enter sort options (see manpage) separated by whitespace: "),
2112 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2114 if (!exp)
2115 return 1;
2116 g_free (old);
2117 old = exp;
2118 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2119 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2120 e = system (tmp);
2121 g_free(tmp);
2122 if (e) {
2123 if (e == -1 || e == 127) {
2124 edit_error_dialog (_(" Sort "),
2125 get_sys_error (_(" Cannot execute sort command ")));
2126 } else {
2127 char q[8];
2128 sprintf (q, "%d ", e);
2129 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
2130 edit_error_dialog (_(" Sort "), tmp);
2131 g_free(tmp);
2133 return -1;
2136 edit->force |= REDRAW_COMPLETELY;
2138 if (edit_block_delete_cmd (edit))
2139 return 1;
2140 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2141 edit_insert_file (edit, tmp);
2142 g_free(tmp);
2143 return 0;
2147 * Ask user for a command, execute it and paste its output back to the
2148 * editor.
2151 edit_ext_cmd (WEdit *edit)
2153 char *exp, *tmp;
2154 int e;
2156 exp =
2157 input_dialog (_("Paste output of external command"),
2158 _("Enter shell command(s):"),
2159 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2161 if (!exp)
2162 return 1;
2164 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2165 e = system (tmp);
2166 g_free(tmp);
2167 g_free (exp);
2169 if (e) {
2170 edit_error_dialog (_("External command"),
2171 get_sys_error (_("Cannot execute command")));
2172 return -1;
2175 edit->force |= REDRAW_COMPLETELY;
2176 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2177 edit_insert_file (edit, tmp);
2178 g_free(tmp);
2179 return 0;
2182 /* if block is 1, a block must be highlighted and the shell command
2183 processes it. If block is 0 the shell command is a straight system
2184 command, that just produces some output which is to be inserted */
2185 void
2186 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2188 long start_mark, end_mark;
2189 char buf[BUFSIZ];
2190 FILE *script_home = NULL;
2191 FILE *block_file = NULL;
2192 gchar *o, *h, *b, *tmp;
2193 char *quoted_name = NULL;
2195 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2196 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2197 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2199 script_home = fopen (h, "r");
2200 if (script_home == NULL) {
2201 FILE *script_src = NULL;
2203 script_home = fopen (h, "w");
2204 if (script_home == NULL) {
2205 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2206 edit_error_dialog ("", get_sys_error (tmp));
2207 g_free(tmp);
2208 goto edit_block_process_cmd__EXIT;
2211 script_src = fopen (o, "r");
2212 if (script_src == NULL) {
2213 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2214 script_src = fopen (o, "r");
2215 if (script_src == NULL) {
2216 fclose (script_home);
2217 unlink (h);
2218 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2219 edit_error_dialog ("", get_sys_error (tmp));
2220 g_free(tmp);
2221 goto edit_block_process_cmd__EXIT;
2224 while (fgets (buf, sizeof (buf), script_src))
2225 fputs (buf, script_home);
2226 fclose (script_src);
2228 if (fclose (script_home)) {
2229 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2230 edit_error_dialog ("", get_sys_error (tmp));
2231 g_free(tmp);
2232 goto edit_block_process_cmd__EXIT;
2234 chmod (h, 0700);
2235 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2236 edit_error_dialog ("", get_sys_error (tmp));
2237 g_free(tmp);
2240 open_error_pipe ();
2242 if (block) { /* for marked block run indent formatter */
2243 if (eval_marks (edit, &start_mark, &end_mark)) {
2244 edit_error_dialog (_("Process block"),
2246 (" You must first highlight a block of text. "));
2247 goto edit_block_process_cmd__EXIT;
2249 edit_save_block (edit, b, start_mark, end_mark);
2250 quoted_name = name_quote (edit->filename, 0);
2252 * Run script.
2253 * Initial space is to avoid polluting bash history.
2254 * Arguments:
2255 * $1 - name of the edited file (to check its extension etc).
2256 * $2 - file containing the current block.
2257 * $3 - file where error messages should be put
2258 * (for compatibility with old scripts).
2260 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2261 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2262 system (tmp);
2263 g_free(tmp);
2264 } else {
2266 * No block selected, just execute the command for the file.
2267 * Arguments:
2268 * $1 - name of the edited file.
2270 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2271 quoted_name, (char *) NULL);
2272 system (tmp);
2273 g_free(tmp);
2275 g_free (quoted_name);
2276 close_error_pipe (D_NORMAL, NULL);
2278 edit_refresh_cmd (edit);
2279 edit->force |= REDRAW_COMPLETELY;
2281 /* insert result block */
2282 if (block && !edit_block_delete_cmd (edit)) {
2283 edit_insert_file (edit, b);
2284 block_file = fopen (b, "w");
2285 if (block_file != NULL)
2286 fclose (block_file);
2289 edit_block_process_cmd__EXIT:
2290 g_free (b);
2291 g_free (h);
2292 g_free (o);
2295 /* prints at the cursor */
2296 /* returns the number of chars printed */
2297 int edit_print_string (WEdit * e, const char *s)
2299 size_t i = 0;
2300 while (s[i] != '\0')
2301 edit_execute_cmd (e, CK_Insert_Char, (unsigned char) s[i++]);
2302 e->force |= REDRAW_COMPLETELY;
2303 edit_update_screen (e);
2304 return i;
2308 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2310 FILE *p = 0;
2311 char *s;
2313 to = name_quote (to, 0);
2314 subject = name_quote (subject, 0);
2315 cc = name_quote (cc, 0);
2316 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2317 g_free (to);
2318 g_free (subject);
2319 g_free (cc);
2321 if (s) {
2322 p = popen (s, "w");
2323 g_free (s);
2326 if (p) {
2327 long i;
2328 for (i = 0; i < edit->last_byte; i++)
2329 fputc (edit_get_byte (edit, i), p);
2330 pclose (p);
2334 #define MAIL_DLG_HEIGHT 12
2336 void edit_mail_dialog (WEdit * edit)
2338 char *tmail_to;
2339 char *tmail_subject;
2340 char *tmail_cc;
2342 static char *mail_cc_last = 0;
2343 static char *mail_subject_last = 0;
2344 static char *mail_to_last = 0;
2346 QuickWidget quick_widgets[] =
2348 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2349 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2350 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2351 /* 3 */ QUICK_LABEL (2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to")),
2352 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2", &tmail_subject),
2353 /* 5 */ QUICK_LABEL (2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject")),
2354 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2355 /* 7 */ QUICK_LABEL (2, 50, 3, MAIL_DLG_HEIGHT, N_(" To")),
2356 /* 8 */ QUICK_LABEL (2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>")),
2357 QUICK_END
2360 QuickDialog Quick_input =
2362 50, MAIL_DLG_HEIGHT, -1, -1, N_(" Mail "),
2363 "[Input Line Keys]", quick_widgets, FALSE
2366 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2367 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2368 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2370 if (quick_dialog (&Quick_input) != B_CANCEL) {
2371 g_free (mail_cc_last);
2372 g_free (mail_subject_last);
2373 g_free (mail_to_last);
2374 mail_cc_last = tmail_cc;
2375 mail_subject_last = tmail_subject;
2376 mail_to_last = tmail_to;
2377 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2382 /*******************/
2383 /* Word Completion */
2384 /*******************/
2386 static gboolean is_break_char(char c)
2388 return (isspace(c) || strchr("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2391 /* find first character of current word */
2392 static int edit_find_word_start (WEdit *edit, long *word_start, gsize *word_len)
2394 int c, last;
2395 gsize i;
2397 /* return if at begin of file */
2398 if (edit->curs1 <= 0)
2399 return 0;
2401 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2402 /* return if not at end or in word */
2403 if (is_break_char(c))
2404 return 0;
2406 /* search start of word to be completed */
2407 for (i = 2;; i++) {
2408 /* return if at begin of file */
2409 if (edit->curs1 - i < 0)
2410 return 0;
2412 last = c;
2413 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2415 if (is_break_char(c)) {
2416 /* return if word starts with digit */
2417 if (isdigit (last))
2418 return 0;
2420 *word_start = edit->curs1 - (i - 1); /* start found */
2421 *word_len = i - 1;
2422 break;
2425 /* success */
2426 return 1;
2429 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2431 /* collect the possible completions */
2432 static gsize
2433 edit_collect_completions (WEdit *edit, long start, gsize word_len,
2434 char *match_expr, struct selection *compl,
2435 gsize *num)
2437 gsize len = 0;
2438 gsize max_len = 0;
2439 gsize i;
2440 int skip;
2441 GString *temp;
2442 mc_search_t *srch;
2444 long last_byte;
2446 srch = mc_search_new(match_expr, -1);
2447 if (srch == NULL)
2448 return 0;
2450 if (mc_config_get_bool(mc_main_config, CONFIG_APP_SECTION, "editor_wordcompletion_collect_entire_file", 0)){
2451 last_byte = edit->last_byte;
2452 } else {
2453 last_byte = start;
2456 srch->search_type = MC_SEARCH_T_REGEX;
2457 srch->is_case_sentitive = TRUE;
2458 srch->search_fn = edit_search_cmd_callback;
2460 /* collect max MAX_WORD_COMPLETIONS completions */
2461 start = -1;
2462 while (1) {
2463 /* get next match */
2464 if (mc_search_run (srch, (void *) edit, start+1, last_byte, &len) == FALSE)
2465 break;
2466 start = srch->normal_offset;
2468 /* add matched completion if not yet added */
2469 temp = g_string_new("");
2470 for (i = 0; i < len; i++){
2471 skip = edit_get_byte(edit, start+i);
2472 if (isspace(skip))
2473 continue;
2474 g_string_append_c (temp, skip);
2477 skip = 0;
2479 for (i = 0; i < (gsize) *num; i++) {
2480 if (strncmp
2482 (char *) &compl[i].text[word_len],
2483 (char *) &temp->str[word_len],
2484 max (len, compl[i].len) - (gsize)word_len
2485 ) == 0) {
2486 struct selection this = compl[i];
2487 for (++i; i < *num; i++) {
2488 compl[i - 1] = compl[i];
2490 compl[*num - 1] = this;
2491 skip = 1;
2492 break; /* skip it, already added */
2495 if (skip) {
2496 g_string_free(temp, TRUE);
2497 continue;
2499 if (*num == MAX_WORD_COMPLETIONS && MAX_WORD_COMPLETIONS) {
2500 g_free(compl[0].text);
2501 for (i = 1; i < *num; i++) {
2502 compl[i - 1] = compl[i];
2504 (*num)--;
2506 #ifdef HAVE_CHARSET
2508 GString *recoded;
2509 recoded = str_convert_to_display (temp->str);
2511 if (recoded && recoded->len){
2512 g_string_free(temp,TRUE);
2513 temp = recoded;
2514 } else
2515 g_string_free(recoded , TRUE);
2517 #endif
2518 compl[*num].text = temp->str;
2519 compl[*num].len = temp->len;
2520 (*num)++;
2521 start += len;
2522 g_string_free(temp, FALSE);
2524 /* note the maximal length needed for the completion dialog */
2525 if (len > max_len)
2526 max_len = len;
2528 mc_search_free(srch);
2529 return max_len;
2533 * Complete current word using regular expression search
2534 * backwards beginning at the current cursor position.
2536 void
2537 edit_complete_word_cmd (WEdit *edit)
2539 gsize i, max_len, word_len = 0, num_compl = 0;
2540 long word_start = 0;
2541 unsigned char *bufpos;
2542 char *match_expr;
2543 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2545 /* search start of word to be completed */
2546 if (!edit_find_word_start (edit, &word_start, &word_len))
2547 return;
2549 /* prepare match expression */
2550 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2551 [word_start & M_EDIT_BUF_SIZE];
2553 /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
2554 match_expr = g_strdup_printf ("(^|\\s+|\\b)%.*s[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+", (int)word_len, bufpos);
2556 /* collect the possible completions */
2557 /* start search from begin to end of file */
2558 max_len =
2559 edit_collect_completions (edit, word_start, word_len, match_expr,
2560 (struct selection *) &compl, &num_compl);
2562 if (num_compl > 0) {
2563 /* insert completed word if there is only one match */
2564 if (num_compl == 1) {
2565 for (i = word_len; i < compl[0].len; i++)
2566 edit_insert (edit, *(compl[0].text + i));
2568 /* more than one possible completion => ask the user */
2569 else {
2570 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2571 /* !!! pressed again the selection dialog pops up, but that !!! */
2572 /* !!! seems to require a further internal state !!! */
2573 /*tty_beep (); */
2575 /* let the user select the preferred completion */
2576 editcmd_dialog_completion_show (edit, max_len, word_len,
2577 (struct selection *) &compl,
2578 num_compl);
2582 g_free (match_expr);
2583 /* release memory before return */
2584 for (i = 0; i < num_compl; i++)
2585 g_free (compl[i].text);
2588 void
2589 edit_select_codepage_cmd (WEdit *edit)
2591 #ifdef HAVE_CHARSET
2592 const char *cp_id = NULL;
2593 if (do_select_codepage ()) {
2594 cp_id = get_codepage_id (source_codepage >= 0 ?
2595 source_codepage : display_codepage);
2597 if (cp_id != NULL) {
2598 GIConv conv;
2599 conv = str_crt_conv_from (cp_id);
2600 if (conv != INVALID_CONV) {
2601 if (edit->converter != str_cnv_from_term)
2602 str_close_conv (edit->converter);
2603 edit->converter = conv;
2607 if (cp_id != NULL)
2608 edit->utf8 = str_isutf8 (cp_id);
2611 edit->force = REDRAW_COMPLETELY;
2612 edit_refresh_cmd (edit);
2613 #else
2614 (void) edit;
2615 #endif
2618 void
2619 edit_insert_literal_cmd (WEdit *edit)
2621 int char_for_insertion =
2622 editcmd_dialog_raw_key_query (_(" Insert Literal "),
2623 _(" Press any key: "), 0);
2624 edit_execute_key_command (edit, -1,
2625 ascii_alpha_to_cntrl (char_for_insertion));
2628 void
2629 edit_execute_macro_cmd (WEdit *edit)
2631 int command =
2632 CK_Macro (editcmd_dialog_raw_key_query
2633 (_(" Execute Macro "), _(" Press macro hotkey: "),
2634 1));
2635 if (command == CK_Macro (0))
2636 command = CK_Insert_Char;
2638 edit_execute_key_command (edit, command, -1);
2641 void
2642 edit_begin_end_macro_cmd (WEdit *edit)
2644 /* edit is a pointer to the widget */
2645 if (edit) {
2646 unsigned long command = edit->macro_i < 0
2647 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2648 edit_execute_key_command (edit, command, -1);
2653 edit_load_forward_cmd (WEdit *edit)
2655 if (edit->modified) {
2656 if (edit_query_dialog2
2657 (_("Warning"),
2658 _(" Current text was modified without a file save. \n"
2659 " Continue discards these changes. "), _("C&ontinue"),
2660 _("&Cancel"))) {
2661 edit->force |= REDRAW_COMPLETELY;
2662 return 0;
2665 if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
2666 if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
2667 return 1;
2669 edit_stack_iterator++;
2670 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2671 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2672 edit_history_moveto[edit_stack_iterator].line);
2673 return 0;
2674 } else {
2675 return 1;
2677 } else {
2678 return 1;
2683 edit_load_back_cmd (WEdit *edit)
2685 if (edit->modified) {
2686 if (edit_query_dialog2
2687 (_("Warning"),
2688 _(" Current text was modified without a file save. \n"
2689 " Continue discards these changes. "), _("C&ontinue"),
2690 _("&Cancel"))) {
2691 edit->force |= REDRAW_COMPLETELY;
2692 return 0;
2695 if ( edit_stack_iterator > 0 ) {
2696 edit_stack_iterator--;
2697 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2698 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2699 edit_history_moveto[edit_stack_iterator].line);
2700 return 0;
2701 } else {
2702 return 1;
2704 } else {
2705 return 1;
2709 void
2710 edit_get_match_keyword_cmd (WEdit *edit)
2712 gsize word_len = 0, max_len = 0;
2713 int num_def = 0;
2714 int i;
2715 long word_start = 0;
2716 unsigned char *bufpos;
2717 char *match_expr;
2718 char *path = NULL;
2719 char *ptr = NULL;
2720 char *tagfile = NULL;
2722 etags_hash_t def_hash[MAX_DEFINITIONS];
2724 for ( i = 0; i < MAX_DEFINITIONS; i++) {
2725 def_hash[i].filename = NULL;
2728 /* search start of word to be completed */
2729 if (!edit_find_word_start (edit, &word_start, &word_len))
2730 return;
2732 /* prepare match expression */
2733 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2734 [word_start & M_EDIT_BUF_SIZE];
2735 match_expr = g_strdup_printf ("%.*s", (int)word_len, bufpos);
2737 ptr = g_get_current_dir ();
2738 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
2739 g_free (ptr);
2741 /* Recursive search file 'TAGS' in parent dirs */
2742 do {
2743 ptr = g_path_get_dirname (path);
2744 g_free(path); path = ptr;
2745 g_free (tagfile);
2746 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
2747 if ( exist_file (tagfile) )
2748 break;
2749 } while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
2751 if (tagfile){
2752 num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
2753 g_free (tagfile);
2755 g_free (path);
2757 max_len = MAX_WIDTH_DEF_DIALOG;
2758 word_len = 0;
2759 if ( num_def > 0 ) {
2760 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
2761 (etags_hash_t *) &def_hash,
2762 num_def);
2764 g_free (match_expr);
2767 void
2768 edit_move_block_to_right (WEdit * edit)
2770 long start_mark, end_mark;
2771 long cur_bol, start_bol;
2773 if ( eval_marks (edit, &start_mark, &end_mark) )
2774 return;
2776 start_bol = edit_bol (edit, start_mark);
2777 cur_bol = edit_bol (edit, end_mark - 1);
2778 do {
2779 edit_cursor_move (edit, cur_bol - edit->curs1);
2780 if ( option_fill_tabs_with_spaces ) {
2781 if ( option_fake_half_tabs ) {
2782 insert_spaces_tab (edit, 1);
2783 } else {
2784 insert_spaces_tab (edit, 0);
2786 } else {
2787 edit_insert (edit, '\t');
2789 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
2790 if ( cur_bol == 0 ) {
2791 break;
2793 cur_bol = edit_bol (edit, cur_bol - 1);
2794 } while (cur_bol >= start_bol) ;
2795 edit->force |= REDRAW_PAGE;
2798 void
2799 edit_move_block_to_left (WEdit * edit)
2801 long start_mark, end_mark;
2802 long cur_bol, start_bol;
2803 int i, del_tab_width;
2804 int next_char;
2806 if ( eval_marks (edit, &start_mark, &end_mark) )
2807 return;
2809 start_bol = edit_bol (edit, start_mark);
2810 cur_bol = edit_bol (edit, end_mark - 1);
2811 do {
2812 edit_cursor_move (edit, cur_bol - edit->curs1);
2813 if (option_fake_half_tabs) {
2814 del_tab_width = HALF_TAB_SIZE;
2815 } else {
2816 del_tab_width = option_tab_spacing;
2818 next_char = edit_get_byte (edit, edit->curs1);
2819 if ( next_char == '\t' ) {
2820 edit_delete (edit, 1);
2821 } else if ( next_char == ' ' ) {
2822 for (i = 1; i <= del_tab_width; i++) {
2823 if ( next_char == ' ' ) {
2824 edit_delete (edit, 1);
2826 next_char = edit_get_byte (edit, edit->curs1);
2829 if ( cur_bol == 0 ) {
2830 break;
2832 cur_bol = edit_bol (edit, cur_bol - 1);
2833 } while (cur_bol >= start_bol) ;
2834 edit->force |= REDRAW_PAGE;