lib/Makefile.am: added lib/skin.h into distribution
[midnight-commander.git] / src / editor / editcmd.c
blob096153ae7342a6f0683ffa61fda6269490711714
1 /* editor high level editing commands
3 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007 Free Software Foundation, Inc.
6 Authors: 1996, 1997 Paul Sheer
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
25 /** \file
26 * \brief Source: editor high level editing commands
27 * \author Paul Sheer
28 * \date 1996, 1997
31 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
33 #include <config.h>
35 #include <assert.h>
36 #include <ctype.h>
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <sys/stat.h>
45 #include <stdlib.h>
46 #include <fcntl.h>
48 #include "lib/global.h"
49 #include "lib/tty/tty.h"
50 #include "lib/tty/key.h" /* XCTRL */
51 #include "lib/mcconfig.h"
52 #include "lib/skin.h"
53 #include "lib/strutil.h" /* utf string functions */
55 #include "src/history.h"
56 #include "src/widget.h" /* listbox_new() */
57 #include "src/layout.h" /* clr_scr() */
58 #include "src/main.h" /* mc_home source_codepage */
59 #include "src/help.h" /* interactive_display() */
60 #include "src/wtools.h" /* message() */
61 #include "src/charsets.h"
62 #include "src/selcodepage.h"
63 #include "src/cmddef.h"
65 #include "lib/vfs/mc-vfs/vfs.h"
67 #include "src/editor/edit-impl.h"
68 #include "src/editor/edit.h"
69 #include "src/editor/editlock.h"
70 #include "src/editor/edit-widget.h"
71 #include "src/editor/editcmd_dialogs.h"
72 #include "src/editor/etags.h"
74 /* globals: */
76 /* search and replace: */
77 int search_create_bookmark = 0;
78 /* static int search_in_all_charsets = 0; */
80 /* queries on a save */
81 int edit_confirm_save = 1;
83 static int edit_save_cmd (WEdit *edit);
84 static unsigned char *edit_get_block (WEdit *edit, long start,
85 long finish, int *l);
87 static void
88 edit_search_cmd_search_create_bookmark(WEdit * edit)
90 int found = 0, books = 0;
91 long l = 0, l_last = -1;
92 long q = 0;
93 gsize len = 0;
95 search_create_bookmark = 0;
96 book_mark_flush (edit, -1);
98 for (;;) {
99 if (!mc_search_run(edit->search, (void *) edit, q, edit->last_byte, &len))
100 break;
101 if (found == 0)
102 edit->search_start = edit->search->normal_offset;
103 found++;
104 l += edit_count_lines (edit, q, edit->search->normal_offset);
105 if (l != l_last) {
106 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
107 books++;
109 l_last = l;
110 q = edit->search->normal_offset + 1;
113 if (found == 0) {
114 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
115 } else {
116 edit_cursor_move (edit, edit->search_start - edit->curs1);
117 edit_scroll_screen_over_cursor (edit);
121 static int
122 edit_search_cmd_callback(const void *user_data, gsize char_offset)
124 return edit_get_byte ((WEdit * )user_data, (long) char_offset);
127 void edit_help_cmd (WEdit * edit)
129 interactive_display (NULL, "[Internal File Editor]");
130 edit->force |= REDRAW_COMPLETELY;
133 void
134 edit_refresh_cmd (WEdit * edit)
136 #ifdef HAVE_SLANG
137 int color;
139 edit_get_syntax_color (edit, -1, &color);
140 tty_touch_screen ();
141 mc_refresh ();
142 #else
143 clr_scr ();
144 repaint_screen ();
145 #endif /* !HAVE_SLANG */
146 tty_keypad (TRUE);
149 /* If 0 (quick save) then a) create/truncate <filename> file,
150 b) save to <filename>;
151 if 1 (safe save) then a) save to <tempnam>,
152 b) rename <tempnam> to <filename>;
153 if 2 (do backups) then a) save to <tempnam>,
154 b) rename <filename> to <filename.backup_ext>,
155 c) rename <tempnam> to <filename>. */
157 /* returns 0 on error, -1 on abort */
158 static int
159 edit_save_file (WEdit *edit, const char *filename)
161 char *p;
162 gchar *tmp;
163 long filelen = 0;
164 char *savename = 0;
165 gchar *real_filename;
166 int this_save_mode, fd = -1;
168 if (!filename)
169 return 0;
170 if (!*filename)
171 return 0;
173 if (*filename != PATH_SEP && edit->dir) {
174 real_filename = concat_dir_and_file (edit->dir, filename);
175 } else {
176 real_filename = g_strdup(filename);
179 this_save_mode = option_save_mode;
180 if (this_save_mode != EDIT_QUICK_SAVE) {
181 if (!vfs_file_is_local (real_filename) ||
182 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1) {
184 * The file does not exists yet, so no safe save or
185 * backup are necessary.
187 this_save_mode = EDIT_QUICK_SAVE;
189 if (fd != -1)
190 mc_close (fd);
193 if (this_save_mode == EDIT_QUICK_SAVE &&
194 !edit->skip_detach_prompt) {
195 int rv;
196 struct stat sb;
198 rv = mc_stat (real_filename, &sb);
199 if (rv == 0 && sb.st_nlink > 1) {
200 rv = edit_query_dialog3 (_("Warning"),
201 _(" File has hard-links. Detach before saving? "),
202 _("&Yes"), _("&No"), _("&Cancel"));
203 switch (rv) {
204 case 0:
205 this_save_mode = EDIT_SAFE_SAVE;
206 /* fallthrough */
207 case 1:
208 edit->skip_detach_prompt = 1;
209 break;
210 default:
211 g_free(real_filename);
212 return -1;
216 /* Prevent overwriting changes from other editor sessions. */
217 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
219 /* The default action is "Cancel". */
220 query_set_sel(1);
222 rv = edit_query_dialog2 (
223 _("Warning"),
224 _("The file has been modified in the meantime. Save anyway?"),
225 _("&Yes"),
226 _("&Cancel"));
227 if (rv != 0){
228 g_free(real_filename);
229 return -1;
234 if (this_save_mode != EDIT_QUICK_SAVE) {
235 char *savedir, *saveprefix;
236 const char *slashpos;
237 slashpos = strrchr (real_filename, PATH_SEP);
238 if (slashpos) {
239 savedir = g_strdup (real_filename);
240 savedir[slashpos - real_filename + 1] = '\0';
241 } else
242 savedir = g_strdup (".");
243 saveprefix = concat_dir_and_file (savedir, "cooledit");
244 g_free (savedir);
245 fd = mc_mkstemps (&savename, saveprefix, NULL);
246 g_free (saveprefix);
247 if (!savename){
248 g_free(real_filename);
249 return 0;
251 /* FIXME:
252 * Close for now because mc_mkstemps use pure open system call
253 * to create temporary file and it needs to be reopened by
254 * VFS-aware mc_open().
256 close (fd);
257 } else
258 savename = g_strdup (real_filename);
260 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
261 mc_chmod (savename, edit->stat1.st_mode);
263 if ((fd =
264 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
265 edit->stat1.st_mode)) == -1)
266 goto error_save;
268 /* pipe save */
269 if ((p = edit_get_write_filter (savename, real_filename))) {
270 FILE *file;
272 mc_close (fd);
273 file = (FILE *) popen (p, "w");
275 if (file) {
276 filelen = edit_write_stream (edit, file);
277 #if 1
278 pclose (file);
279 #else
280 if (pclose (file) != 0) {
281 tmp = g_strconcat (_(" Error writing to pipe: "),
282 p, " ", (char *) NULL);
283 edit_error_dialog (_("Error"), tmp);
284 g_free(tmp);
285 g_free (p);
286 goto error_save;
288 #endif
289 } else {
290 tmp = g_strconcat (_(" Cannot open pipe for writing: "),
291 p, " ", (char *) NULL);
293 edit_error_dialog (_("Error"),
294 get_sys_error (tmp));
295 g_free (p);
296 g_free(tmp);
297 goto error_save;
299 g_free (p);
300 } else if (edit->lb == LB_ASIS) { /* do not change line breaks */
301 long buf;
302 buf = 0;
303 filelen = edit->last_byte;
304 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
305 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
306 != EDIT_BUF_SIZE) {
307 mc_close (fd);
308 goto error_save;
310 buf++;
312 if (mc_write
313 (fd, (char *) edit->buffers1[buf],
314 edit->curs1 & M_EDIT_BUF_SIZE) !=
315 (edit->curs1 & M_EDIT_BUF_SIZE)) {
316 filelen = -1;
317 } else if (edit->curs2) {
318 edit->curs2--;
319 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
320 if (mc_write
321 (fd,
322 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
323 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
324 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
325 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
326 filelen = -1;
327 } else {
328 while (--buf >= 0) {
329 if (mc_write
330 (fd, (char *) edit->buffers2[buf],
331 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
332 filelen = -1;
333 break;
337 edit->curs2++;
339 if (mc_close (fd))
340 goto error_save;
342 /* Update the file information, especially the mtime. */
343 if (mc_stat (savename, &edit->stat1) == -1)
344 goto error_save;
345 } else { /* change line breaks */
346 FILE *file;
348 mc_close (fd);
350 file = (FILE *) fopen (savename, "w");
352 if (file) {
353 filelen = edit_write_stream (edit, file);
354 fclose (file);
355 } else {
356 char *msg;
358 msg = g_strdup_printf (_(" Cannot open file for writing: %s "), savename);
359 edit_error_dialog (_("Error"), msg);
360 g_free (msg);
361 goto error_save;
365 if (filelen != edit->last_byte)
366 goto error_save;
368 if (this_save_mode == EDIT_DO_BACKUP) {
369 assert (option_backup_ext != NULL);
370 tmp = g_strconcat (real_filename, option_backup_ext, (char *) NULL);
371 if (mc_rename (real_filename, tmp) == -1){
372 g_free(tmp);
373 goto error_save;
377 if (this_save_mode != EDIT_QUICK_SAVE)
378 if (mc_rename (savename, real_filename) == -1)
379 goto error_save;
380 g_free (savename);
381 g_free(real_filename);
382 return 1;
383 error_save:
384 /* FIXME: Is this safe ?
385 * if (this_save_mode != EDIT_QUICK_SAVE)
386 * mc_unlink (savename);
388 g_free(real_filename);
389 g_free (savename);
390 return 0;
393 void
394 menu_save_mode_cmd (void)
396 /* diaog sizes */
397 const int DLG_X = 38;
398 const int DLG_Y = 13;
400 char *str_result;
402 const char *str[] =
404 N_("&Quick save"),
405 N_("&Safe save"),
406 N_("&Do backups with following extension:")
409 QuickWidget widgets[] =
411 /* 0 */
412 QUICK_BUTTON (18, DLG_X, DLG_Y - 3, DLG_Y, N_("&Cancel"), B_CANCEL, NULL),
413 /* 1 */
414 QUICK_BUTTON ( 6, DLG_X, DLG_Y - 3, DLG_Y, N_("&OK"), B_ENTER, NULL),
415 /* 2 */
416 QUICK_CHECKBOX ( 4, DLG_X, 8, DLG_Y, N_("Check &POSIX new line"), &option_check_nl_at_eof),
417 /* 3 */
418 QUICK_INPUT ( 8, DLG_X, 6, DLG_Y, option_backup_ext, 9, 0, "edit-backup-ext", &str_result),
419 /* 4 */
420 QUICK_RADIO ( 4, DLG_X, 3, DLG_Y, 3, str, &option_save_mode),
421 QUICK_END
424 QuickDialog dialog =
426 DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "),
427 "[Edit Save Mode]", widgets, FALSE
430 size_t i;
431 size_t maxlen = 0;
432 size_t w0, w1, b_len, w3;
434 assert (option_backup_ext != NULL);
436 /* OK/Cancel buttons */
437 w0 = str_term_width1 (_(widgets[0].u.button.text)) + 3;
438 w1 = str_term_width1 (_(widgets[1].u.button.text)) + 5; /* default button */
439 b_len = w0 + w1 + 3;
441 maxlen = max (b_len, (size_t) str_term_width1 (_(dialog.title)) + 2);
443 w3 = 0;
444 for (i = 0; i < 3; i++) {
445 #ifdef ENABLE_NLS
446 str[i] = _(str[i]);
447 #endif
448 w3 = max (w3, (size_t) str_term_width1 (str[i]));
451 maxlen = max (maxlen, w3 + 4);
453 dialog.xlen = min ((size_t) COLS, maxlen + 8);
455 widgets[3].u.input.len = w3;
456 widgets[1].relative_x = (dialog.xlen - b_len)/2;
457 widgets[0].relative_x = widgets[1].relative_x + w0 + 2;
459 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
460 widgets[i].x_divisions = dialog.xlen;
462 if (quick_dialog (&dialog) != B_CANCEL) {
463 g_free (option_backup_ext);
464 option_backup_ext = str_result;
468 void
469 edit_set_filename (WEdit *edit, const char *f)
471 g_free (edit->filename);
472 if (!f)
473 f = "";
474 edit->filename = g_strdup (f);
475 if (edit->dir == NULL && *f != PATH_SEP)
476 #ifdef ENABLE_VFS
477 edit->dir = g_strdup (vfs_get_current_dir ());
478 #else /* ENABLE_VFS */
479 edit->dir = g_get_current_dir ();
480 #endif /* ENABLE_VFS */
483 static gboolean
484 edit_check_newline (WEdit *edit)
486 return !(option_check_nl_at_eof && edit->last_byte > 0
487 && edit_get_byte (edit, edit->last_byte - 1) != '\n'
488 && edit_query_dialog2 (_("Warning"),
489 _("The file you are saving is not finished with a newline"),
490 _("C&ontinue"), _("&Cancel")));
493 static char *
494 edit_get_save_file_as (WEdit *edit)
496 #define DLG_WIDTH 64
497 #define DLG_HEIGHT 14
499 static LineBreaks cur_lb = LB_ASIS;
501 char *filename = edit->filename;
503 const char *lb_names[LB_NAMES] =
505 N_("&Do not change"),
506 N_("&Unix format (LF)"),
507 N_("&Windows/DOS format (CR LF)"),
508 N_("&Macintosh format (CR)")
511 QuickWidget quick_widgets[] =
513 QUICK_BUTTON (6, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
514 QUICK_BUTTON (2, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
515 QUICK_RADIO (5, DLG_WIDTH, DLG_HEIGHT - 8, DLG_HEIGHT, LB_NAMES, lb_names, (int *) &cur_lb),
516 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 9, DLG_HEIGHT, N_("Change line breaks to:")),
517 QUICK_INPUT (3, DLG_WIDTH, DLG_HEIGHT - 11, DLG_HEIGHT, filename, DLG_WIDTH - 6, 0, "save-as", &filename),
518 QUICK_LABEL (2, DLG_WIDTH, DLG_HEIGHT - 12, DLG_HEIGHT, N_(" Enter file name: ")),
519 QUICK_END
522 QuickDialog Quick_options =
524 DLG_WIDTH, DLG_HEIGHT, -1, -1,
525 N_(" Save As "), "[Save File As]",
526 quick_widgets, FALSE
529 if (quick_dialog (&Quick_options) != B_CANCEL) {
530 edit->lb = cur_lb;
531 return filename;
534 return NULL;
536 #undef DLG_WIDTH
537 #undef DLG_HEIGHT
540 /* Here we want to warn the users of overwriting an existing file,
541 but only if they have made a change to the filename */
542 /* returns 1 on success */
544 edit_save_as_cmd (WEdit *edit)
546 /* This heads the 'Save As' dialog box */
547 char *exp;
548 int save_lock = 0;
549 int different_filename = 0;
551 if (!edit_check_newline (edit))
552 return 0;
554 exp = edit_get_save_file_as (edit);
555 edit_push_action (edit, KEY_PRESS + edit->start_display);
557 if (exp) {
558 if (!*exp) {
559 g_free (exp);
560 edit->force |= REDRAW_COMPLETELY;
561 return 0;
562 } else {
563 int rv;
564 if (strcmp (edit->filename, exp)) {
565 int file;
566 different_filename = 1;
567 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
568 /* the file exists */
569 mc_close (file);
570 /* Overwrite the current file or cancel the operation */
571 if (edit_query_dialog2
572 (_("Warning"),
573 _(" A file already exists with this name. "),
574 _("&Overwrite"), _("&Cancel"))) {
575 edit->force |= REDRAW_COMPLETELY;
576 g_free (exp);
577 return 0;
579 } else {
580 edit->stat1.st_mode |= S_IWUSR;
582 save_lock = edit_lock_file (exp);
583 } else {
584 /* filenames equal, check if already locked */
585 if (!edit->locked && !edit->delete_file)
586 save_lock = edit_lock_file (exp);
589 if (different_filename)
592 * Allow user to write into saved (under another name) file
593 * even if original file had r/o user permissions.
595 edit->stat1.st_mode |= S_IWRITE;
598 rv = edit_save_file (edit, exp);
599 switch (rv) {
600 case 1:
601 /* Succesful, so unlock both files */
602 if (different_filename) {
603 if (save_lock)
604 edit_unlock_file (exp);
605 if (edit->locked)
606 edit->locked = edit_unlock_file (edit->filename);
607 } else {
608 if (edit->locked || save_lock)
609 edit->locked = edit_unlock_file (edit->filename);
612 edit_set_filename (edit, exp);
613 if (edit->lb != LB_ASIS)
614 edit_reload(edit, exp);
615 g_free (exp);
616 edit->modified = 0;
617 edit->delete_file = 0;
618 if (different_filename)
619 edit_load_syntax (edit, NULL, option_syntax_type);
620 edit->force |= REDRAW_COMPLETELY;
621 return 1;
622 default:
623 edit_error_dialog (_(" Save As "),
624 get_sys_error (_
625 (" Cannot save file. ")));
626 /* fallthrough */
627 case -1:
628 /* Failed, so maintain modify (not save) lock */
629 if (save_lock)
630 edit_unlock_file (exp);
631 g_free (exp);
632 edit->force |= REDRAW_COMPLETELY;
633 return 0;
637 edit->force |= REDRAW_COMPLETELY;
638 return 0;
641 /* {{{ Macro stuff starts here */
643 /* creates a macro file if it doesn't exist */
644 static FILE *edit_open_macro_file (const char *r)
646 gchar *filename;
647 FILE *fd;
648 int file;
649 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
650 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
651 g_free(filename);
652 return 0;
654 close (file);
655 fd = fopen (filename, r);
656 g_free(filename);
657 return fd;
660 #define MAX_MACROS 1024
661 static int saved_macro[MAX_MACROS + 1];
662 static int saved_macros_loaded = 0;
665 This is just to stop the macro file be loaded over and over for keys
666 that aren't defined to anything. On slow systems this could be annoying.
668 static int
669 macro_exists (int k)
671 int i;
672 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
673 if (saved_macro[i] == k)
674 return i;
675 return -1;
678 /* returns 1 on error */
679 static int
680 edit_delete_macro (WEdit * edit, int k)
682 gchar *tmp, *tmp2;
683 struct macro macro[MAX_MACRO_LENGTH];
684 FILE *f, *g;
685 int s, i, n, j = 0;
687 (void) edit;
689 if (saved_macros_loaded)
690 if ((j = macro_exists (k)) < 0)
691 return 0;
692 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
693 g = fopen (tmp , "w");
694 g_free(tmp);
695 if (!g) {
696 edit_error_dialog (_(" Delete macro "),
697 get_sys_error (_(" Cannot open temp file ")));
698 return 1;
700 f = edit_open_macro_file ("r");
701 if (!f) {
702 edit_error_dialog (_(" Delete macro "),
703 get_sys_error (_(" Cannot open macro file ")));
704 fclose (g);
705 return 1;
707 for (;;) {
708 n = fscanf (f, ("key '%d 0': "), &s);
709 if (!n || n == EOF)
710 break;
711 n = 0;
712 while (fscanf (f, "%lu %d, ", &macro[n].command, &macro[n].ch))
713 n++;
714 fscanf (f, ";\n");
715 if (s != k) {
716 fprintf (g, ("key '%d 0': "), s);
717 for (i = 0; i < n; i++)
718 fprintf (g, "%lu %d, ", macro[i].command, macro[i].ch);
719 fprintf (g, ";\n");
722 fclose (f);
723 fclose (g);
724 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
725 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
726 if (rename ( tmp, tmp2) == -1) {
727 edit_error_dialog (_(" Delete macro "),
728 get_sys_error (_(" Cannot overwrite macro file ")));
729 g_free(tmp);
730 g_free(tmp2);
731 return 1;
733 g_free(tmp);
734 g_free(tmp2);
736 if (saved_macros_loaded)
737 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
738 return 0;
741 /* returns 0 on error */
742 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
744 FILE *f;
745 int s, i;
747 edit_push_action (edit, KEY_PRESS + edit->start_display);
748 s = editcmd_dialog_raw_key_query (_(" Save macro "),
749 _(" Press the macro's new hotkey: "), 1);
750 edit->force |= REDRAW_COMPLETELY;
751 if (s) {
752 if (edit_delete_macro (edit, s))
753 return 0;
754 f = edit_open_macro_file ("a+");
755 if (f) {
756 fprintf (f, ("key '%d 0': "), s);
757 for (i = 0; i < n; i++)
758 fprintf (f, "%lu %d, ", macro[i].command, macro[i].ch);
759 fprintf (f, ";\n");
760 fclose (f);
761 if (saved_macros_loaded) {
762 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
763 saved_macro[i] = s;
765 return 1;
766 } else
767 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
769 return 0;
772 void
773 edit_delete_macro_cmd (WEdit * edit)
775 int command;
777 command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
778 _ (" Press macro hotkey: "), 1);
780 if (command != 0)
781 edit_delete_macro (edit, command);
784 /* return 0 on error */
785 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
787 FILE *f;
788 int s, i = 0, found = 0;
790 (void) edit;
792 if (saved_macros_loaded)
793 if (macro_exists (k) < 0)
794 return 0;
796 if ((f = edit_open_macro_file ("r"))) {
797 struct macro dummy;
798 do {
799 int u;
800 u = fscanf (f, ("key '%d 0': "), &s);
801 if (!u || u == EOF)
802 break;
803 if (!saved_macros_loaded)
804 saved_macro[i++] = s;
805 if (!found) {
806 *n = 0;
807 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%lu %d, ", &macro[*n].command, &macro[*n].ch))
808 (*n)++;
809 } else {
810 while (2 == fscanf (f, "%lu %d, ", &dummy.command, &dummy.ch));
812 fscanf (f, ";\n");
813 if (s == k)
814 found = 1;
815 } while (!found || !saved_macros_loaded);
816 if (!saved_macros_loaded) {
817 saved_macro[i] = 0;
818 saved_macros_loaded = 1;
820 fclose (f);
821 return found;
822 } else
823 edit_error_dialog (_(" Load macro "),
824 get_sys_error (_(" Cannot open macro file ")));
825 return 0;
828 /* }}} Macro stuff starts here */
830 /* returns 1 on success */
831 int edit_save_confirm_cmd (WEdit * edit)
833 gchar *f = NULL;
835 if (!edit_check_newline (edit))
836 return 0;
838 if (edit_confirm_save) {
839 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", (char *) NULL);
840 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel"))){
841 g_free(f);
842 return 0;
844 g_free(f);
846 return edit_save_cmd (edit);
850 /* returns 1 on success */
851 static int
852 edit_save_cmd (WEdit *edit)
854 int res, save_lock = 0;
856 if (!edit->locked && !edit->delete_file)
857 save_lock = edit_lock_file (edit->filename);
858 res = edit_save_file (edit, edit->filename);
860 /* Maintain modify (not save) lock on failure */
861 if ((res > 0 && edit->locked) || save_lock)
862 edit->locked = edit_unlock_file (edit->filename);
864 /* On failure try 'save as', it does locking on its own */
865 if (!res)
866 return edit_save_as_cmd (edit);
867 edit->force |= REDRAW_COMPLETELY;
868 if (res > 0) {
869 edit->delete_file = 0;
870 edit->modified = 0;
873 return 1;
877 /* returns 1 on success */
878 int edit_new_cmd (WEdit * edit)
880 if (edit->modified) {
881 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
882 edit->force |= REDRAW_COMPLETELY;
883 return 0;
886 edit->force |= REDRAW_COMPLETELY;
888 return edit_renew (edit); /* if this gives an error, something has really screwed up */
891 /* returns 1 on error */
892 static int
893 edit_load_file_from_filename (WEdit * edit, char *exp)
895 int prev_locked = edit->locked;
896 char *prev_filename = g_strdup (edit->filename);
898 if (!edit_reload (edit, exp)) {
899 g_free (prev_filename);
900 return 1;
903 if (prev_locked)
904 edit_unlock_file (prev_filename);
905 g_free (prev_filename);
906 return 0;
909 static void
910 edit_load_syntax_file (WEdit * edit)
912 char *extdir;
913 int dir = 0;
915 if (geteuid () == 0) {
916 dir = query_dialog (_("Syntax file edit"),
917 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
918 _("&User"), _("&System Wide"));
921 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
922 if (!exist_file(extdir)) {
923 g_free (extdir);
924 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
927 if (dir == 0) {
928 char *buffer;
930 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
931 check_for_default (extdir, buffer);
932 edit_load_file_from_filename (edit, buffer);
933 g_free (buffer);
934 } else if (dir == 1)
935 edit_load_file_from_filename (edit, extdir);
937 g_free (extdir);
940 static void
941 edit_load_menu_file (WEdit * edit)
943 char *buffer;
944 char *menufile;
945 int dir = 0;
947 dir = query_dialog (
948 _(" Menu edit "),
949 _(" Which menu file do you want to edit? "), D_NORMAL,
950 geteuid() ? 2 : 3, _("&Local"), _("&User"), _("&System Wide")
953 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
955 if (!exist_file (menufile)) {
956 g_free (menufile);
957 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
960 switch (dir) {
961 case 0:
962 buffer = g_strdup (EDIT_LOCAL_MENU);
963 check_for_default (menufile, buffer);
964 chmod (buffer, 0600);
965 break;
967 case 1:
968 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
969 check_for_default (menufile, buffer);
970 break;
972 case 2:
973 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
974 if (!exist_file (buffer)) {
975 g_free (buffer);
976 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
978 break;
980 default:
981 g_free (menufile);
982 return;
985 edit_load_file_from_filename (edit, buffer);
987 g_free (buffer);
988 g_free (menufile);
992 edit_load_cmd (WEdit *edit, edit_current_file_t what)
994 char *exp;
996 if (edit->modified
997 && (edit_query_dialog2
998 (_("Warning"),
999 _(" Current text was modified without a file save. \n"
1000 " Continue discards these changes. "),
1001 _("C&ontinue"), _("&Cancel")) == 1)) {
1002 edit->force |= REDRAW_COMPLETELY;
1003 return 0;
1006 switch (what) {
1007 case EDIT_FILE_COMMON:
1008 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
1009 MC_HISTORY_EDIT_LOAD, edit->filename);
1011 if (exp) {
1012 if (*exp)
1013 edit_load_file_from_filename (edit, exp);
1014 g_free (exp);
1016 break;
1018 case EDIT_FILE_SYNTAX:
1019 edit_load_syntax_file (edit);
1020 break;
1022 case EDIT_FILE_MENU:
1023 edit_load_menu_file (edit);
1024 break;
1026 default:
1027 break;
1030 edit->force |= REDRAW_COMPLETELY;
1031 return 0;
1035 if mark2 is -1 then marking is from mark1 to the cursor.
1036 Otherwise its between the markers. This handles this.
1037 Returns 1 if no text is marked.
1039 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
1041 if (edit->mark1 != edit->mark2) {
1042 long start_bol, start_eol;
1043 long end_bol, end_eol;
1044 long col1, col2;
1045 long diff1, diff2;
1046 if (edit->mark2 >= 0) {
1047 *start_mark = min (edit->mark1, edit->mark2);
1048 *end_mark = max (edit->mark1, edit->mark2);
1049 } else {
1050 *start_mark = min (edit->mark1, edit->curs1);
1051 *end_mark = max (edit->mark1, edit->curs1);
1052 edit->column2 = edit->curs_col + edit->over_col;
1054 if (column_highlighting
1055 && (((edit->mark1 > edit->curs1) && (edit->column1 < edit->column2))
1056 || ((edit->mark1 < edit->curs1) && (edit->column1 > edit->column2)))) {
1058 start_bol = edit_bol (edit, *start_mark);
1059 start_eol = edit_eol (edit, start_bol - 1) + 1;
1060 end_bol = edit_bol (edit, *end_mark);
1061 end_eol = edit_eol (edit, *end_mark);
1062 col1 = min (edit->column1, edit->column2);
1063 col2 = max (edit->column1, edit->column2);
1065 diff1 = edit_move_forward3 (edit, start_bol, col2, 0) - edit_move_forward3 (edit, start_bol, col1, 0);
1066 diff2 = edit_move_forward3 (edit, end_bol, col2, 0) - edit_move_forward3 (edit, end_bol, col1, 0);
1068 *start_mark -= diff1;
1069 *end_mark += diff2;
1070 *start_mark = max (*start_mark, start_eol);
1071 *end_mark = min (*end_mark, end_eol);
1073 return 0;
1074 } else {
1075 *start_mark = *end_mark = 0;
1076 edit->column2 = edit->column1 = 0;
1077 return 1;
1081 #define space_width 1
1083 void
1084 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
1086 long cursor;
1087 int i, col;
1088 cursor = edit->curs1;
1089 col = edit_get_col (edit);
1090 for (i = 0; i < size; i++) {
1091 if (data[i] == '\n') { /* fill in and move to next line */
1092 int l;
1093 long p;
1094 if (edit_get_byte (edit, edit->curs1) != '\n') {
1095 l = width - (edit_get_col (edit) - col);
1096 while (l > 0) {
1097 edit_insert (edit, ' ');
1098 l -= space_width;
1101 for (p = edit->curs1;; p++) {
1102 if (p == edit->last_byte) {
1103 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1104 edit_insert_ahead (edit, '\n');
1105 p++;
1106 break;
1108 if (edit_get_byte (edit, p) == '\n') {
1109 p++;
1110 break;
1113 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1114 l = col - edit_get_col (edit);
1115 while (l >= space_width) {
1116 edit_insert (edit, ' ');
1117 l -= space_width;
1119 continue;
1121 edit_insert (edit, data[i]);
1123 edit_cursor_move (edit, cursor - edit->curs1);
1126 #define TEMP_BUF_LEN 1024
1129 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1131 long cursor;
1132 int i, col;
1133 int blocklen = -1, width;
1134 unsigned char *data;
1135 cursor = edit->curs1;
1136 col = edit_get_col (edit);
1137 data = g_malloc0 (TEMP_BUF_LEN);
1138 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0) {
1139 for (width = 0; width < blocklen; width++) {
1140 if (data[width] == '\n')
1141 break;
1143 for (i = 0; i < blocklen; i++) {
1144 if (data[i] == '\n') { /* fill in and move to next line */
1145 int l;
1146 long p;
1147 if (edit_get_byte (edit, edit->curs1) != '\n') {
1148 l = width - (edit_get_col (edit) - col);
1149 while (l > 0) {
1150 edit_insert (edit, ' ');
1151 l -= space_width;
1154 for (p = edit->curs1;; p++) {
1155 if (p == edit->last_byte) {
1156 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1157 edit_insert_ahead (edit, '\n');
1158 p++;
1159 break;
1161 if (edit_get_byte (edit, p) == '\n') {
1162 p++;
1163 break;
1166 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1167 l = col - edit_get_col (edit);
1168 while (l >= space_width) {
1169 edit_insert (edit, ' ');
1170 l -= space_width;
1172 continue;
1174 edit_insert (edit, data[i]);
1177 edit_cursor_move (edit, cursor - edit->curs1);
1178 g_free(data);
1179 edit->force |= REDRAW_PAGE;
1180 return blocklen;
1183 void
1184 edit_block_copy_cmd (WEdit *edit)
1186 long start_mark, end_mark, current = edit->curs1;
1187 int size;
1188 unsigned char *copy_buf;
1190 edit_update_curs_col (edit);
1191 if (eval_marks (edit, &start_mark, &end_mark))
1192 return;
1194 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1196 /* all that gets pushed are deletes hence little space is used on the stack */
1198 edit_push_markers (edit);
1200 if (column_highlighting) {
1201 edit_insert_column_of_text (edit, copy_buf, size,
1202 abs (edit->column2 - edit->column1));
1203 } else {
1204 while (size--)
1205 edit_insert_ahead (edit, copy_buf[size]);
1208 g_free (copy_buf);
1209 edit_scroll_screen_over_cursor (edit);
1211 if (column_highlighting) {
1212 edit_set_markers (edit, 0, 0, 0, 0);
1213 edit_push_action (edit, COLUMN_ON);
1214 column_highlighting = 0;
1215 } else if (start_mark < current && end_mark > current)
1216 edit_set_markers (edit, start_mark,
1217 end_mark + end_mark - start_mark, 0, 0);
1219 edit->force |= REDRAW_PAGE;
1223 void
1224 edit_block_move_cmd (WEdit *edit)
1226 long count;
1227 long current;
1228 unsigned char *copy_buf;
1229 long start_mark, end_mark;
1230 int deleted = 0;
1231 int x = 0;
1233 if (eval_marks (edit, &start_mark, &end_mark))
1234 return;
1235 if (column_highlighting) {
1236 edit_update_curs_col (edit);
1237 x = edit->curs_col;
1238 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1239 if ((x > edit->column1 && x < edit->column2)
1240 || (x > edit->column2 && x < edit->column1))
1241 return;
1242 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1243 return;
1245 if ((end_mark - start_mark) > option_max_undo / 2)
1246 if (edit_query_dialog2
1247 (_("Warning"),
1249 (" Block is large, you may not be able to undo this action. "),
1250 _("C&ontinue"), _("&Cancel")))
1251 return;
1253 edit_push_markers (edit);
1254 current = edit->curs1;
1255 if (column_highlighting) {
1256 long line;
1257 int size, c1, c2;
1258 line = edit->curs_line;
1259 if (edit->mark2 < 0)
1260 edit_mark_cmd (edit, 0);
1261 c1 = min (edit->column1, edit->column2);
1262 c2 = max (edit->column1, edit->column2);
1263 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1264 if (x < c2) {
1265 edit_block_delete_cmd (edit);
1266 deleted = 1;
1268 edit_move_to_line (edit, line);
1269 edit_cursor_move (edit,
1270 edit_move_forward3 (edit,
1271 edit_bol (edit, edit->curs1),
1272 x, 0) - edit->curs1);
1273 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1274 if (!deleted) {
1275 line = edit->curs_line;
1276 edit_update_curs_col (edit);
1277 x = edit->curs_col;
1278 edit_block_delete_cmd (edit);
1279 edit_move_to_line (edit, line);
1280 edit_cursor_move (edit,
1281 edit_move_forward3 (edit,
1282 edit_bol (edit,
1283 edit->curs1),
1284 x, 0) - edit->curs1);
1286 edit_set_markers (edit, 0, 0, 0, 0);
1287 edit_push_action (edit, COLUMN_ON);
1288 column_highlighting = 0;
1289 } else {
1290 copy_buf = g_malloc0 (end_mark - start_mark);
1291 edit_cursor_move (edit, start_mark - edit->curs1);
1292 edit_scroll_screen_over_cursor (edit);
1293 count = start_mark;
1294 while (count < end_mark) {
1295 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1296 count++;
1298 edit_scroll_screen_over_cursor (edit);
1299 edit_cursor_move (edit,
1300 current - edit->curs1 -
1301 (((current - edit->curs1) >
1302 0) ? end_mark - start_mark : 0));
1303 edit_scroll_screen_over_cursor (edit);
1304 while (count-- > start_mark)
1305 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1306 edit_set_markers (edit, edit->curs1,
1307 edit->curs1 + end_mark - start_mark, 0, 0);
1309 edit_scroll_screen_over_cursor (edit);
1310 g_free (copy_buf);
1311 edit->force |= REDRAW_PAGE;
1314 static void
1315 edit_delete_column_of_text (WEdit * edit)
1317 long p, q, r, m1, m2;
1318 long b, c, d, n;
1320 eval_marks (edit, &m1, &m2);
1321 n = edit_move_forward (edit, m1, 0, m2) + 1;
1322 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1323 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1324 b = max (min (c, d), min (edit->column1, edit->column2));
1325 c = max (c, max (edit->column1, edit->column2));
1327 while (n--) {
1328 r = edit_bol (edit, edit->curs1);
1329 p = edit_move_forward3 (edit, r, b, 0);
1330 q = edit_move_forward3 (edit, r, c, 0);
1331 if (p < m1)
1332 p = m1;
1333 if (q > m2)
1334 q = m2;
1335 edit_cursor_move (edit, p - edit->curs1);
1336 while (q > p) {
1337 /* delete line between margins */
1338 if (edit_get_byte (edit, edit->curs1) != '\n')
1339 edit_delete (edit, 1);
1340 q--;
1342 if (n)
1343 /* move to next line except on the last delete */
1344 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1348 /* if success return 0 */
1349 static int
1350 edit_block_delete (WEdit *edit)
1352 long count;
1353 long start_mark, end_mark;
1354 int curs_pos, line_width;
1355 long curs_line, c1, c2;
1357 if (eval_marks (edit, &start_mark, &end_mark))
1358 return 0;
1359 if (column_highlighting && edit->mark2 < 0)
1360 edit_mark_cmd (edit, 0);
1361 if ((end_mark - start_mark) > option_max_undo / 2) {
1362 /* Warning message with a query to continue or cancel the operation */
1363 if (edit_query_dialog2
1364 (_("Warning"),
1366 (" Block is large, you may not be able to undo this action. "),
1367 _("C&ontinue"), _("&Cancel"))) {
1368 return 1;
1371 c1 = min (edit->column1, edit->column2);
1372 c2 = max (edit->column1, edit->column2);
1373 edit->column1 = c1;
1374 edit->column2 = c2;
1376 edit_push_markers (edit);
1378 curs_line = edit->curs_line;
1380 /* calculate line width and cursor position before cut */
1381 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1382 edit_eol (edit, edit->curs1));
1383 curs_pos = edit->curs_col + edit->over_col;
1385 /* move cursor to start of selection */
1386 edit_cursor_move (edit, start_mark - edit->curs1);
1387 edit_scroll_screen_over_cursor (edit);
1388 count = start_mark;
1389 if (start_mark < end_mark) {
1390 if (column_highlighting) {
1391 if (edit->mark2 < 0)
1392 edit_mark_cmd (edit, 0);
1393 edit_delete_column_of_text (edit);
1394 /* move cursor to the saved position */
1395 edit_move_to_line (edit, curs_line);
1396 /* calculate line width after cut */
1397 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1398 edit_eol (edit, edit->curs1));
1399 if (option_cursor_beyond_eol && curs_pos > line_width)
1400 edit->over_col = curs_pos - line_width;
1401 } else {
1402 while (count < end_mark) {
1403 edit_delete (edit, 1);
1404 count++;
1408 edit_set_markers (edit, 0, 0, 0, 0);
1409 edit->force |= REDRAW_PAGE;
1410 return 0;
1413 /* returns 1 if canceelled by user */
1414 int edit_block_delete_cmd (WEdit * edit)
1416 long start_mark, end_mark;
1417 if (eval_marks (edit, &start_mark, &end_mark)) {
1418 edit_delete_line (edit);
1419 return 0;
1421 return edit_block_delete (edit);
1424 #define INPUT_INDEX 9
1426 static gboolean
1427 editcmd_find (WEdit *edit, gsize *len)
1429 off_t search_start = edit->search_start;
1430 off_t search_end;
1431 long start_mark = 0;
1432 long end_mark = edit->last_byte;
1433 int mark_res = 0;
1435 if (edit->only_in_selection) {
1436 mark_res = eval_marks(edit, &start_mark, &end_mark);
1437 if (mark_res != 0) {
1438 edit->search->error = MC_SEARCH_E_NOTFOUND;
1439 edit->search->error_str = g_strdup(_(" Search string not found "));
1440 return FALSE;
1442 if (edit->replace_backwards) {
1443 if (search_start > end_mark || search_start <= start_mark) {
1444 search_start = end_mark;
1446 } else {
1447 if (search_start < start_mark || search_start >= end_mark) {
1448 search_start = start_mark;
1451 } else {
1452 if (edit->replace_backwards)
1453 end_mark = max(1, edit->curs1) - 1;
1455 if (edit->replace_backwards) {
1456 search_end = end_mark;
1457 while ((int) search_start >= start_mark) {
1458 if (search_end > search_start + edit->search->original_len
1459 && mc_search_is_fixed_search_str(edit->search)) {
1460 search_end = search_start + edit->search->original_len;
1462 if (mc_search_run(edit->search, (void *) edit, search_start, search_end, len)
1463 && edit->search->normal_offset == search_start ) {
1464 return TRUE;
1466 search_start--;
1468 edit->search->error_str = g_strdup(_(" Search string not found "));
1469 } else {
1470 return mc_search_run(edit->search, (void *) edit, search_start, end_mark, len);
1472 return FALSE;
1476 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1477 (and the above) routines to work properly - paul */
1479 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1481 static char *
1482 edit_replace_cmd__conv_to_display (char *str)
1484 #ifdef HAVE_CHARSET
1485 GString *tmp;
1486 tmp = str_convert_to_display (str);
1488 if (tmp && tmp->len){
1489 return g_string_free (tmp, FALSE);
1491 g_string_free (tmp, TRUE);
1492 #endif
1493 return g_strdup(str);
1496 static char *
1497 edit_replace_cmd__conv_to_input(char *str)
1499 #ifdef HAVE_CHARSET
1500 GString *tmp;
1501 tmp = str_convert_to_input (str);
1503 if (tmp && tmp->len){
1504 return g_string_free (tmp, FALSE);
1506 g_string_free (tmp, TRUE);
1507 return g_strdup(str);
1508 #endif
1509 return g_strdup(str);
1511 /* call with edit = 0 before shutdown to close memory leaks */
1512 void
1513 edit_replace_cmd (WEdit *edit, int again)
1515 /* 1 = search string, 2 = replace with */
1516 static char *saved1 = NULL; /* saved default[123] */
1517 static char *saved2 = NULL;
1518 char *input1 = NULL; /* user input from the dialog */
1519 char *input2 = NULL;
1520 int replace_yes;
1521 long times_replaced = 0, last_search;
1522 gboolean once_found = FALSE;
1524 if (!edit) {
1525 g_free (saved1), saved1 = NULL;
1526 g_free (saved2), saved2 = NULL;
1527 return;
1530 last_search = edit->last_byte;
1532 edit->force |= REDRAW_COMPLETELY;
1534 if (again && !saved1 && !saved2)
1535 again = 0;
1537 if (again) {
1538 input1 = g_strdup (saved1 ? saved1 : "");
1539 input2 = g_strdup (saved2 ? saved2 : "");
1540 } else {
1541 char *disp1 = edit_replace_cmd__conv_to_display (saved1 ? saved1 : (char *) "");
1542 char *disp2 = edit_replace_cmd__conv_to_display (saved2 ? saved2 : (char *) "");
1543 char *tmp_inp1, *tmp_inp2;
1545 edit_push_action (edit, KEY_PRESS + edit->start_display);
1547 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1549 g_free (disp1);
1550 g_free (disp2);
1552 if (input1 == NULL || *input1 == '\0') {
1553 edit->force = REDRAW_COMPLETELY;
1554 goto cleanup;
1557 tmp_inp1 = input1; tmp_inp2 = input2;
1558 input1 = edit_replace_cmd__conv_to_input(input1);
1559 input2 = edit_replace_cmd__conv_to_input(input2);
1560 g_free(tmp_inp1); g_free(tmp_inp2);
1562 g_free (saved1), saved1 = g_strdup (input1);
1563 g_free (saved2), saved2 = g_strdup (input2);
1565 if (edit->search) {
1566 mc_search_free(edit->search);
1567 edit->search = NULL;
1571 if (!edit->search) {
1572 edit->search = mc_search_new(input1, -1);
1573 if (edit->search == NULL) {
1574 edit->search_start = edit->curs1;
1575 return;
1577 edit->search->search_type = edit->search_type;
1578 edit->search->is_all_charsets = edit->all_codepages;
1579 edit->search->is_case_sentitive = edit->replace_case;
1580 edit->search->whole_words = edit->whole_words;
1581 edit->search->search_fn = edit_search_cmd_callback;
1584 if (edit->found_len && edit->search_start == edit->found_start + 1
1585 && edit->replace_backwards)
1586 edit->search_start--;
1588 if (edit->found_len && edit->search_start == edit->found_start - 1
1589 && !edit->replace_backwards)
1590 edit->search_start++;
1592 do {
1593 gsize len = 0;
1594 long new_start;
1596 if (! editcmd_find(edit, &len)) {
1597 if (!(edit->search->error == MC_SEARCH_E_OK ||
1598 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND))) {
1599 edit_error_dialog (_ ("Search"), edit->search->error_str);
1601 break;
1603 once_found = TRUE;
1604 new_start = edit->search->normal_offset;
1606 edit->search_start = new_start = edit->search->normal_offset;
1607 /*returns negative on not found or error in pattern */
1609 if (edit->search_start >= 0) {
1610 guint i;
1612 edit->found_start = edit->search_start;
1613 i = edit->found_len = len;
1615 edit_cursor_move (edit, edit->search_start - edit->curs1);
1616 edit_scroll_screen_over_cursor (edit);
1618 replace_yes = 1;
1620 if (edit->replace_mode == 0) {
1621 int l;
1622 l = edit->curs_row - edit->num_widget_lines / 3;
1623 if (l > 0)
1624 edit_scroll_downward (edit, l);
1625 if (l < 0)
1626 edit_scroll_upward (edit, -l);
1628 edit_scroll_screen_over_cursor (edit);
1629 edit->force |= REDRAW_PAGE;
1630 edit_render_keypress (edit);
1632 /*so that undo stops at each query */
1633 edit_push_key_press (edit);
1634 /* and prompt 2/3 down */
1635 switch (editcmd_dialog_replace_prompt_show (edit, input1, input2, -1, -1)) {
1636 case B_ENTER:
1637 replace_yes = 1;
1638 break;
1639 case B_SKIP_REPLACE:
1640 replace_yes = 0;
1641 break;
1642 case B_REPLACE_ALL:
1643 edit->replace_mode=1;
1644 break;
1645 case B_CANCEL:
1646 replace_yes = 0;
1647 edit->replace_mode = -1;
1648 break;
1651 if (replace_yes) { /* delete then insert new */
1652 GString *repl_str, *tmp_str;
1653 tmp_str = g_string_new(input2);
1655 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1656 g_string_free(tmp_str, TRUE);
1657 if (edit->search->error != MC_SEARCH_E_OK)
1659 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1660 break;
1663 while (i--)
1664 edit_delete (edit, 1);
1666 while (++i < repl_str->len)
1667 edit_insert (edit, repl_str->str[i]);
1669 g_string_free(repl_str, TRUE);
1670 edit->found_len = i;
1672 /* so that we don't find the same string again */
1673 if (edit->replace_backwards) {
1674 last_search = edit->search_start;
1675 edit->search_start--;
1676 } else {
1677 edit->search_start += i;
1678 last_search = edit->last_byte;
1680 edit_scroll_screen_over_cursor (edit);
1681 } else {
1682 const char *msg = _(" Replace ");
1683 /* try and find from right here for next search */
1684 edit->search_start = edit->curs1;
1685 edit_update_curs_col (edit);
1687 edit->force |= REDRAW_PAGE;
1688 edit_render_keypress (edit);
1689 if (times_replaced) {
1690 message (D_NORMAL, msg, _(" %ld replacements made. "),
1691 times_replaced);
1692 } else
1693 query_dialog (msg, _(" Search string not found "),
1694 D_NORMAL, 1, _("&OK"));
1695 edit->replace_mode = -1;
1697 } while (edit->replace_mode >= 0);
1699 edit->force = REDRAW_COMPLETELY;
1700 edit_scroll_screen_over_cursor (edit);
1701 cleanup:
1702 g_free (input1);
1703 g_free (input2);
1707 void edit_search_cmd (WEdit * edit, int again)
1709 char *search_string = NULL, *search_string_dup = NULL;
1711 gsize len = 0;
1713 if (!edit)
1714 return;
1716 if (edit->search != NULL) {
1717 search_string = g_strndup(edit->search->original, edit->search->original_len);
1718 search_string_dup = search_string;
1719 } else {
1720 GList *history;
1721 history = history_get (MC_HISTORY_SHARED_SEARCH);
1722 if (history != NULL && history->data != NULL) {
1723 search_string_dup = search_string = (char *) g_strdup(history->data);
1724 history = g_list_first (history);
1725 g_list_foreach (history, (GFunc) g_free, NULL);
1726 g_list_free (history);
1728 edit->search_start = edit->curs1;
1731 if (!again) {
1732 #ifdef HAVE_CHARSET
1733 GString *tmp;
1734 if (search_string && *search_string) {
1735 tmp = str_convert_to_display (search_string);
1737 g_free(search_string_dup);
1738 search_string_dup = NULL;
1740 if (tmp && tmp->len)
1741 search_string = search_string_dup = tmp->str;
1742 g_string_free (tmp, FALSE);
1744 #endif /* HAVE_CHARSET */
1745 editcmd_dialog_search_show (edit, &search_string);
1746 #ifdef HAVE_CHARSET
1747 if (search_string && *search_string) {
1748 tmp = str_convert_to_input (search_string);
1749 if (tmp && tmp->len)
1750 search_string = tmp->str;
1752 g_string_free (tmp, FALSE);
1754 if (search_string_dup)
1755 g_free(search_string_dup);
1757 #endif /* HAVE_CHARSET */
1759 edit_push_action (edit, KEY_PRESS + edit->start_display);
1761 if (!search_string) {
1762 edit->force |= REDRAW_COMPLETELY;
1763 edit_scroll_screen_over_cursor (edit);
1764 return;
1767 if (edit->search) {
1768 mc_search_free(edit->search);
1769 edit->search = NULL;
1773 if (!edit->search) {
1774 edit->search = mc_search_new(search_string, -1);
1775 if (edit->search == NULL) {
1776 edit->search_start = edit->curs1;
1777 return;
1779 edit->search->search_type = edit->search_type;
1780 edit->search->is_all_charsets = edit->all_codepages;
1781 edit->search->is_case_sentitive = edit->replace_case;
1782 edit->search->whole_words = edit->whole_words;
1783 edit->search->search_fn = edit_search_cmd_callback;
1786 if (search_create_bookmark) {
1787 edit_search_cmd_search_create_bookmark(edit);
1788 } else {
1789 if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
1790 edit->search_start--;
1792 if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
1793 edit->search_start++;
1796 if (editcmd_find(edit, &len)) {
1797 edit->found_start = edit->search_start = edit->search->normal_offset;
1798 edit->found_len = len;
1799 edit->over_col = 0;
1800 edit_cursor_move (edit, edit->search_start - edit->curs1);
1801 edit_scroll_screen_over_cursor (edit);
1802 if (edit->replace_backwards)
1803 edit->search_start--;
1804 else
1805 edit->search_start++;
1806 } else {
1807 edit->search_start = edit->curs1;
1808 if (edit->search->error_str)
1809 edit_error_dialog (_ ("Search"), edit->search->error_str);
1813 edit->force |= REDRAW_COMPLETELY;
1814 edit_scroll_screen_over_cursor (edit);
1819 * Check if it's OK to close the editor. If there are unsaved changes,
1820 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
1823 edit_ok_to_exit (WEdit *edit)
1825 if (!edit->modified)
1826 return 1;
1828 if (!edit_check_newline (edit))
1829 return 0;
1831 switch (edit_query_dialog3
1832 (_("Quit"), _(" File was modified, Save with exit? "),
1833 _("&Cancel quit"), _("&Yes"), _("&No"))) {
1834 case 1:
1835 edit_push_markers (edit);
1836 edit_set_markers (edit, 0, 0, 0, 0);
1837 if (!edit_save_cmd (edit))
1838 return 0;
1839 break;
1840 case 2:
1841 break;
1842 case 0:
1843 case -1:
1844 return 0;
1847 return 1;
1850 /* Return a null terminated length of text. Result must be g_free'd */
1851 static unsigned char *
1852 edit_get_block (WEdit *edit, long start, long finish, int *l)
1854 unsigned char *s, *r;
1855 r = s = g_malloc0 (finish - start + 1);
1856 if (column_highlighting) {
1857 *l = 0;
1858 /* copy from buffer, excluding chars that are out of the column 'margins' */
1859 while (start < finish) {
1860 int c;
1861 long x;
1862 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
1863 start);
1864 c = edit_get_byte (edit, start);
1865 if ((x >= edit->column1 && x < edit->column2)
1866 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1867 *s++ = c;
1868 (*l)++;
1870 start++;
1872 } else {
1873 *l = finish - start;
1874 while (start < finish)
1875 *s++ = edit_get_byte (edit, start++);
1877 *s = 0;
1878 return r;
1881 /* save block, returns 1 on success */
1883 edit_save_block (WEdit * edit, const char *filename, long start,
1884 long finish)
1886 int len, file;
1888 if ((file =
1889 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
1890 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
1891 return 0;
1893 if (column_highlighting) {
1894 int r;
1895 r = mc_write (file, VERTICAL_MAGIC, sizeof(VERTICAL_MAGIC));
1896 if (r > 0) {
1897 unsigned char *block, *p;
1898 p = block = edit_get_block (edit, start, finish, &len);
1899 while (len) {
1900 r = mc_write (file, p, len);
1901 if (r < 0)
1902 break;
1903 p += r;
1904 len -= r;
1906 g_free (block);
1908 } else {
1909 unsigned char *buf;
1910 int i = start, end;
1911 len = finish - start;
1912 buf = g_malloc0 (TEMP_BUF_LEN);
1913 while (start != finish) {
1914 end = min (finish, start + TEMP_BUF_LEN);
1915 for (; i < end; i++)
1916 buf[i - start] = edit_get_byte (edit, i);
1917 len -= mc_write (file, (char *) buf, end - start);
1918 start = end;
1920 g_free (buf);
1922 mc_close (file);
1923 if (len)
1924 return 0;
1925 return 1;
1928 /* copies a block to clipboard file */
1929 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1931 int ret;
1932 gchar *tmp;
1933 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1934 ret = edit_save_block (edit, tmp, start, finish);
1935 g_free(tmp);
1936 return ret;
1940 void edit_paste_from_history (WEdit *edit)
1942 (void) edit;
1943 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
1946 int edit_copy_to_X_buf_cmd (WEdit * edit)
1948 long start_mark, end_mark;
1949 if (eval_marks (edit, &start_mark, &end_mark))
1950 return 0;
1951 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1952 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
1953 return 1;
1955 edit_mark_cmd (edit, 1);
1956 return 0;
1959 int edit_cut_to_X_buf_cmd (WEdit * edit)
1961 long start_mark, end_mark;
1962 if (eval_marks (edit, &start_mark, &end_mark))
1963 return 0;
1964 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1965 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
1966 return 1;
1968 edit_block_delete_cmd (edit);
1969 edit_mark_cmd (edit, 1);
1970 return 0;
1973 void edit_paste_from_X_buf_cmd (WEdit * edit)
1975 gchar *tmp;
1976 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1977 edit_insert_file (edit, tmp);
1978 g_free(tmp);
1983 * Ask user for the line and go to that line.
1984 * Negative numbers mean line from the end (i.e. -1 is the last line).
1986 void
1987 edit_goto_cmd (WEdit *edit)
1989 char *f;
1990 static long line = 0; /* line as typed, saved as default */
1991 long l;
1992 char *error;
1993 char s[32];
1995 g_snprintf (s, sizeof (s), "%ld", line);
1996 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
1997 line ? s : "");
1998 if (!f)
1999 return;
2001 if (!*f) {
2002 g_free (f);
2003 return;
2006 l = strtol (f, &error, 0);
2007 if (*error) {
2008 g_free (f);
2009 return;
2012 line = l;
2013 if (l < 0)
2014 l = edit->total_lines + l + 2;
2015 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2016 edit_move_to_line (edit, l - 1);
2017 edit->force |= REDRAW_COMPLETELY;
2018 g_free (f);
2022 /* Return 1 on success */
2024 edit_save_block_cmd (WEdit *edit)
2026 long start_mark, end_mark;
2027 char *exp, *tmp;
2029 if (eval_marks (edit, &start_mark, &end_mark))
2030 return 1;
2032 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2033 exp =
2034 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2035 MC_HISTORY_EDIT_SAVE_BLOCK,
2036 tmp);
2037 g_free(tmp);
2038 edit_push_action (edit, KEY_PRESS + edit->start_display);
2039 if (exp) {
2040 if (!*exp) {
2041 g_free (exp);
2042 return 0;
2043 } else {
2044 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2045 g_free (exp);
2046 edit->force |= REDRAW_COMPLETELY;
2047 return 1;
2048 } else {
2049 g_free (exp);
2050 edit_error_dialog (_(" Save Block "),
2051 get_sys_error (_
2052 (" Cannot save file. ")));
2056 edit->force |= REDRAW_COMPLETELY;
2057 return 0;
2061 /* returns 1 on success */
2063 edit_insert_file_cmd (WEdit *edit)
2065 gchar *tmp;
2066 char *exp;
2068 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2069 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2070 MC_HISTORY_EDIT_INSERT_FILE,
2071 tmp);
2072 g_free(tmp);
2073 edit_push_action (edit, KEY_PRESS + edit->start_display);
2074 if (exp) {
2075 if (!*exp) {
2076 g_free (exp);
2077 return 0;
2078 } else {
2079 if (edit_insert_file (edit, exp)) {
2080 g_free (exp);
2081 edit->force |= REDRAW_COMPLETELY;
2082 return 1;
2083 } else {
2084 g_free (exp);
2085 edit_error_dialog (_(" Insert File "),
2086 get_sys_error (_
2087 (" Cannot insert file. ")));
2091 edit->force |= REDRAW_COMPLETELY;
2092 return 0;
2095 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2096 int edit_sort_cmd (WEdit * edit)
2098 static char *old = 0;
2099 char *exp, *tmp;
2100 long start_mark, end_mark;
2101 int e;
2103 if (eval_marks (edit, &start_mark, &end_mark)) {
2104 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2105 return 0;
2108 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2109 edit_save_block (edit, tmp, start_mark, end_mark);
2110 g_free(tmp);
2112 exp = input_dialog (_(" Run Sort "),
2113 _(" Enter sort options (see manpage) separated by whitespace: "),
2114 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2116 if (!exp)
2117 return 1;
2118 g_free (old);
2119 old = exp;
2120 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2121 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2122 e = system (tmp);
2123 g_free(tmp);
2124 if (e) {
2125 if (e == -1 || e == 127) {
2126 edit_error_dialog (_(" Sort "),
2127 get_sys_error (_(" Cannot execute sort command ")));
2128 } else {
2129 char q[8];
2130 sprintf (q, "%d ", e);
2131 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
2132 edit_error_dialog (_(" Sort "), tmp);
2133 g_free(tmp);
2135 return -1;
2138 edit->force |= REDRAW_COMPLETELY;
2140 if (edit_block_delete_cmd (edit))
2141 return 1;
2142 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2143 edit_insert_file (edit, tmp);
2144 g_free(tmp);
2145 return 0;
2149 * Ask user for a command, execute it and paste its output back to the
2150 * editor.
2153 edit_ext_cmd (WEdit *edit)
2155 char *exp, *tmp;
2156 int e;
2158 exp =
2159 input_dialog (_("Paste output of external command"),
2160 _("Enter shell command(s):"),
2161 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2163 if (!exp)
2164 return 1;
2166 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2167 e = system (tmp);
2168 g_free(tmp);
2169 g_free (exp);
2171 if (e) {
2172 edit_error_dialog (_("External command"),
2173 get_sys_error (_("Cannot execute command")));
2174 return -1;
2177 edit->force |= REDRAW_COMPLETELY;
2178 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2179 edit_insert_file (edit, tmp);
2180 g_free(tmp);
2181 return 0;
2184 /* if block is 1, a block must be highlighted and the shell command
2185 processes it. If block is 0 the shell command is a straight system
2186 command, that just produces some output which is to be inserted */
2187 void
2188 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2190 long start_mark, end_mark;
2191 char buf[BUFSIZ];
2192 FILE *script_home = NULL;
2193 FILE *block_file = NULL;
2194 gchar *o, *h, *b, *tmp;
2195 char *quoted_name = NULL;
2197 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2198 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2199 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2201 script_home = fopen (h, "r");
2202 if (script_home == NULL) {
2203 FILE *script_src = NULL;
2205 script_home = fopen (h, "w");
2206 if (script_home == NULL) {
2207 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2208 edit_error_dialog ("", get_sys_error (tmp));
2209 g_free(tmp);
2210 goto edit_block_process_cmd__EXIT;
2213 script_src = fopen (o, "r");
2214 if (script_src == NULL) {
2215 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2216 script_src = fopen (o, "r");
2217 if (script_src == NULL) {
2218 fclose (script_home);
2219 unlink (h);
2220 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2221 edit_error_dialog ("", get_sys_error (tmp));
2222 g_free(tmp);
2223 goto edit_block_process_cmd__EXIT;
2226 while (fgets (buf, sizeof (buf), script_src))
2227 fputs (buf, script_home);
2228 fclose (script_src);
2230 if (fclose (script_home)) {
2231 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2232 edit_error_dialog ("", get_sys_error (tmp));
2233 g_free(tmp);
2234 goto edit_block_process_cmd__EXIT;
2236 chmod (h, 0700);
2237 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2238 edit_error_dialog ("", get_sys_error (tmp));
2239 g_free(tmp);
2242 open_error_pipe ();
2244 if (block) { /* for marked block run indent formatter */
2245 if (eval_marks (edit, &start_mark, &end_mark)) {
2246 edit_error_dialog (_("Process block"),
2248 (" You must first highlight a block of text. "));
2249 goto edit_block_process_cmd__EXIT;
2251 edit_save_block (edit, b, start_mark, end_mark);
2252 quoted_name = name_quote (edit->filename, 0);
2254 * Run script.
2255 * Initial space is to avoid polluting bash history.
2256 * Arguments:
2257 * $1 - name of the edited file (to check its extension etc).
2258 * $2 - file containing the current block.
2259 * $3 - file where error messages should be put
2260 * (for compatibility with old scripts).
2262 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2263 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2264 system (tmp);
2265 g_free(tmp);
2266 } else {
2268 * No block selected, just execute the command for the file.
2269 * Arguments:
2270 * $1 - name of the edited file.
2272 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2273 quoted_name, (char *) NULL);
2274 system (tmp);
2275 g_free(tmp);
2277 g_free (quoted_name);
2278 close_error_pipe (D_NORMAL, NULL);
2280 edit_refresh_cmd (edit);
2281 edit->force |= REDRAW_COMPLETELY;
2283 /* insert result block */
2284 if (block && !edit_block_delete_cmd (edit)) {
2285 edit_insert_file (edit, b);
2286 block_file = fopen (b, "w");
2287 if (block_file != NULL)
2288 fclose (block_file);
2291 edit_block_process_cmd__EXIT:
2292 g_free (b);
2293 g_free (h);
2294 g_free (o);
2297 /* prints at the cursor */
2298 /* returns the number of chars printed */
2299 int edit_print_string (WEdit * e, const char *s)
2301 size_t i = 0;
2302 while (s[i] != '\0')
2303 edit_execute_cmd (e, CK_Insert_Char, (unsigned char) s[i++]);
2304 e->force |= REDRAW_COMPLETELY;
2305 edit_update_screen (e);
2306 return i;
2310 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2312 FILE *p = 0;
2313 char *s;
2315 to = name_quote (to, 0);
2316 subject = name_quote (subject, 0);
2317 cc = name_quote (cc, 0);
2318 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2319 g_free (to);
2320 g_free (subject);
2321 g_free (cc);
2323 if (s) {
2324 p = popen (s, "w");
2325 g_free (s);
2328 if (p) {
2329 long i;
2330 for (i = 0; i < edit->last_byte; i++)
2331 fputc (edit_get_byte (edit, i), p);
2332 pclose (p);
2336 #define MAIL_DLG_HEIGHT 12
2338 void edit_mail_dialog (WEdit * edit)
2340 char *tmail_to;
2341 char *tmail_subject;
2342 char *tmail_cc;
2344 static char *mail_cc_last = 0;
2345 static char *mail_subject_last = 0;
2346 static char *mail_to_last = 0;
2348 QuickWidget quick_widgets[] =
2350 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2351 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2352 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2353 /* 3 */ QUICK_LABEL (2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to")),
2354 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2", &tmail_subject),
2355 /* 5 */ QUICK_LABEL (2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject")),
2356 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2357 /* 7 */ QUICK_LABEL (2, 50, 3, MAIL_DLG_HEIGHT, N_(" To")),
2358 /* 8 */ QUICK_LABEL (2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>")),
2359 QUICK_END
2362 QuickDialog Quick_input =
2364 50, MAIL_DLG_HEIGHT, -1, -1, N_(" Mail "),
2365 "[Input Line Keys]", quick_widgets, FALSE
2368 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2369 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2370 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2372 if (quick_dialog (&Quick_input) != B_CANCEL) {
2373 g_free (mail_cc_last);
2374 g_free (mail_subject_last);
2375 g_free (mail_to_last);
2376 mail_cc_last = tmail_cc;
2377 mail_subject_last = tmail_subject;
2378 mail_to_last = tmail_to;
2379 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2384 /*******************/
2385 /* Word Completion */
2386 /*******************/
2388 static gboolean is_break_char(char c)
2390 return (isspace(c) || strchr("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2393 /* find first character of current word */
2394 static int edit_find_word_start (WEdit *edit, long *word_start, gsize *word_len)
2396 int c, last;
2397 gsize i;
2399 /* return if at begin of file */
2400 if (edit->curs1 <= 0)
2401 return 0;
2403 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2404 /* return if not at end or in word */
2405 if (is_break_char(c))
2406 return 0;
2408 /* search start of word to be completed */
2409 for (i = 2;; i++) {
2410 /* return if at begin of file */
2411 if (edit->curs1 - i < 0)
2412 return 0;
2414 last = c;
2415 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2417 if (is_break_char(c)) {
2418 /* return if word starts with digit */
2419 if (isdigit (last))
2420 return 0;
2422 *word_start = edit->curs1 - (i - 1); /* start found */
2423 *word_len = i - 1;
2424 break;
2427 /* success */
2428 return 1;
2431 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2433 /* collect the possible completions */
2434 static gsize
2435 edit_collect_completions (WEdit *edit, long start, gsize word_len,
2436 char *match_expr, struct selection *compl,
2437 gsize *num)
2439 gsize len = 0;
2440 gsize max_len = 0;
2441 gsize i;
2442 int skip;
2443 GString *temp;
2444 mc_search_t *srch;
2446 long last_byte;
2448 srch = mc_search_new(match_expr, -1);
2449 if (srch == NULL)
2450 return 0;
2452 if (mc_config_get_bool(mc_main_config, CONFIG_APP_SECTION, "editor_wordcompletion_collect_entire_file", 0)){
2453 last_byte = edit->last_byte;
2454 } else {
2455 last_byte = start;
2458 srch->search_type = MC_SEARCH_T_REGEX;
2459 srch->is_case_sentitive = TRUE;
2460 srch->search_fn = edit_search_cmd_callback;
2462 /* collect max MAX_WORD_COMPLETIONS completions */
2463 start = -1;
2464 while (1) {
2465 /* get next match */
2466 if (mc_search_run (srch, (void *) edit, start+1, last_byte, &len) == FALSE)
2467 break;
2468 start = srch->normal_offset;
2470 /* add matched completion if not yet added */
2471 temp = g_string_new("");
2472 for (i = 0; i < len; i++){
2473 skip = edit_get_byte(edit, start+i);
2474 if (isspace(skip))
2475 continue;
2476 g_string_append_c (temp, skip);
2479 skip = 0;
2481 for (i = 0; i < (gsize) *num; i++) {
2482 if (strncmp
2484 (char *) &compl[i].text[word_len],
2485 (char *) &temp->str[word_len],
2486 max (len, compl[i].len) - (gsize)word_len
2487 ) == 0) {
2488 struct selection this = compl[i];
2489 for (++i; i < *num; i++) {
2490 compl[i - 1] = compl[i];
2492 compl[*num - 1] = this;
2493 skip = 1;
2494 break; /* skip it, already added */
2497 if (skip) {
2498 g_string_free(temp, TRUE);
2499 continue;
2501 if (*num == MAX_WORD_COMPLETIONS && MAX_WORD_COMPLETIONS) {
2502 g_free(compl[0].text);
2503 for (i = 1; i < *num; i++) {
2504 compl[i - 1] = compl[i];
2506 (*num)--;
2508 #ifdef HAVE_CHARSET
2510 GString *recoded;
2511 recoded = str_convert_to_display (temp->str);
2513 if (recoded && recoded->len){
2514 g_string_free(temp,TRUE);
2515 temp = recoded;
2516 } else
2517 g_string_free(recoded , TRUE);
2519 #endif
2520 compl[*num].text = temp->str;
2521 compl[*num].len = temp->len;
2522 (*num)++;
2523 start += len;
2524 g_string_free(temp, FALSE);
2526 /* note the maximal length needed for the completion dialog */
2527 if (len > max_len)
2528 max_len = len;
2530 mc_search_free(srch);
2531 return max_len;
2535 * Complete current word using regular expression search
2536 * backwards beginning at the current cursor position.
2538 void
2539 edit_complete_word_cmd (WEdit *edit)
2541 gsize i, max_len, word_len = 0, num_compl = 0;
2542 long word_start = 0;
2543 unsigned char *bufpos;
2544 char *match_expr;
2545 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2547 /* search start of word to be completed */
2548 if (!edit_find_word_start (edit, &word_start, &word_len))
2549 return;
2551 /* prepare match expression */
2552 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2553 [word_start & M_EDIT_BUF_SIZE];
2555 /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
2556 match_expr = g_strdup_printf ("(^|\\s+|\\b)%.*s[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+", (int)word_len, bufpos);
2558 /* collect the possible completions */
2559 /* start search from begin to end of file */
2560 max_len =
2561 edit_collect_completions (edit, word_start, word_len, match_expr,
2562 (struct selection *) &compl, &num_compl);
2564 if (num_compl > 0) {
2565 /* insert completed word if there is only one match */
2566 if (num_compl == 1) {
2567 for (i = word_len; i < compl[0].len; i++)
2568 edit_insert (edit, *(compl[0].text + i));
2570 /* more than one possible completion => ask the user */
2571 else {
2572 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2573 /* !!! pressed again the selection dialog pops up, but that !!! */
2574 /* !!! seems to require a further internal state !!! */
2575 /*tty_beep (); */
2577 /* let the user select the preferred completion */
2578 editcmd_dialog_completion_show (edit, max_len, word_len,
2579 (struct selection *) &compl,
2580 num_compl);
2584 g_free (match_expr);
2585 /* release memory before return */
2586 for (i = 0; i < num_compl; i++)
2587 g_free (compl[i].text);
2590 void
2591 edit_select_codepage_cmd (WEdit *edit)
2593 #ifdef HAVE_CHARSET
2594 const char *cp_id = NULL;
2595 if (do_select_codepage ()) {
2596 cp_id = get_codepage_id (source_codepage >= 0 ?
2597 source_codepage : display_codepage);
2599 if (cp_id != NULL) {
2600 GIConv conv;
2601 conv = str_crt_conv_from (cp_id);
2602 if (conv != INVALID_CONV) {
2603 if (edit->converter != str_cnv_from_term)
2604 str_close_conv (edit->converter);
2605 edit->converter = conv;
2609 if (cp_id != NULL)
2610 edit->utf8 = str_isutf8 (cp_id);
2613 edit->force = REDRAW_COMPLETELY;
2614 edit_refresh_cmd (edit);
2615 #else
2616 (void) edit;
2617 #endif
2620 void
2621 edit_insert_literal_cmd (WEdit *edit)
2623 int char_for_insertion =
2624 editcmd_dialog_raw_key_query (_(" Insert Literal "),
2625 _(" Press any key: "), 0);
2626 edit_execute_key_command (edit, -1,
2627 ascii_alpha_to_cntrl (char_for_insertion));
2630 void
2631 edit_execute_macro_cmd (WEdit *edit)
2633 int command =
2634 CK_Macro (editcmd_dialog_raw_key_query
2635 (_(" Execute Macro "), _(" Press macro hotkey: "),
2636 1));
2637 if (command == CK_Macro (0))
2638 command = CK_Insert_Char;
2640 edit_execute_key_command (edit, command, -1);
2643 void
2644 edit_begin_end_macro_cmd (WEdit *edit)
2646 /* edit is a pointer to the widget */
2647 if (edit) {
2648 unsigned long command = edit->macro_i < 0
2649 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2650 edit_execute_key_command (edit, command, -1);
2655 edit_load_forward_cmd (WEdit *edit)
2657 if (edit->modified) {
2658 if (edit_query_dialog2
2659 (_("Warning"),
2660 _(" Current text was modified without a file save. \n"
2661 " Continue discards these changes. "), _("C&ontinue"),
2662 _("&Cancel"))) {
2663 edit->force |= REDRAW_COMPLETELY;
2664 return 0;
2667 if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
2668 if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
2669 return 1;
2671 edit_stack_iterator++;
2672 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2673 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2674 edit_history_moveto[edit_stack_iterator].line);
2675 return 0;
2676 } else {
2677 return 1;
2679 } else {
2680 return 1;
2685 edit_load_back_cmd (WEdit *edit)
2687 if (edit->modified) {
2688 if (edit_query_dialog2
2689 (_("Warning"),
2690 _(" Current text was modified without a file save. \n"
2691 " Continue discards these changes. "), _("C&ontinue"),
2692 _("&Cancel"))) {
2693 edit->force |= REDRAW_COMPLETELY;
2694 return 0;
2697 if ( edit_stack_iterator > 0 ) {
2698 edit_stack_iterator--;
2699 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2700 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2701 edit_history_moveto[edit_stack_iterator].line);
2702 return 0;
2703 } else {
2704 return 1;
2706 } else {
2707 return 1;
2711 void
2712 edit_get_match_keyword_cmd (WEdit *edit)
2714 gsize word_len = 0, max_len = 0;
2715 int num_def = 0;
2716 int i;
2717 long word_start = 0;
2718 unsigned char *bufpos;
2719 char *match_expr;
2720 char *path = NULL;
2721 char *ptr = NULL;
2722 char *tagfile = NULL;
2724 etags_hash_t def_hash[MAX_DEFINITIONS];
2726 for ( i = 0; i < MAX_DEFINITIONS; i++) {
2727 def_hash[i].filename = NULL;
2730 /* search start of word to be completed */
2731 if (!edit_find_word_start (edit, &word_start, &word_len))
2732 return;
2734 /* prepare match expression */
2735 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2736 [word_start & M_EDIT_BUF_SIZE];
2737 match_expr = g_strdup_printf ("%.*s", (int)word_len, bufpos);
2739 ptr = g_get_current_dir ();
2740 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
2741 g_free (ptr);
2743 /* Recursive search file 'TAGS' in parent dirs */
2744 do {
2745 ptr = g_path_get_dirname (path);
2746 g_free(path); path = ptr;
2747 g_free (tagfile);
2748 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
2749 if ( exist_file (tagfile) )
2750 break;
2751 } while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
2753 if (tagfile){
2754 num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
2755 g_free (tagfile);
2757 g_free (path);
2759 max_len = MAX_WIDTH_DEF_DIALOG;
2760 word_len = 0;
2761 if ( num_def > 0 ) {
2762 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
2763 (etags_hash_t *) &def_hash,
2764 num_def);
2766 g_free (match_expr);
2769 void
2770 edit_move_block_to_right (WEdit * edit)
2772 long start_mark, end_mark;
2773 long cur_bol, start_bol;
2775 if ( eval_marks (edit, &start_mark, &end_mark) )
2776 return;
2778 start_bol = edit_bol (edit, start_mark);
2779 cur_bol = edit_bol (edit, end_mark - 1);
2780 do {
2781 edit_cursor_move (edit, cur_bol - edit->curs1);
2782 if ( option_fill_tabs_with_spaces ) {
2783 if ( option_fake_half_tabs ) {
2784 insert_spaces_tab (edit, 1);
2785 } else {
2786 insert_spaces_tab (edit, 0);
2788 } else {
2789 edit_insert (edit, '\t');
2791 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
2792 if ( cur_bol == 0 ) {
2793 break;
2795 cur_bol = edit_bol (edit, cur_bol - 1);
2796 } while (cur_bol >= start_bol) ;
2797 edit->force |= REDRAW_PAGE;
2800 void
2801 edit_move_block_to_left (WEdit * edit)
2803 long start_mark, end_mark;
2804 long cur_bol, start_bol;
2805 int i, del_tab_width;
2806 int next_char;
2808 if ( eval_marks (edit, &start_mark, &end_mark) )
2809 return;
2811 start_bol = edit_bol (edit, start_mark);
2812 cur_bol = edit_bol (edit, end_mark - 1);
2813 do {
2814 edit_cursor_move (edit, cur_bol - edit->curs1);
2815 if (option_fake_half_tabs) {
2816 del_tab_width = HALF_TAB_SIZE;
2817 } else {
2818 del_tab_width = option_tab_spacing;
2820 next_char = edit_get_byte (edit, edit->curs1);
2821 if ( next_char == '\t' ) {
2822 edit_delete (edit, 1);
2823 } else if ( next_char == ' ' ) {
2824 for (i = 1; i <= del_tab_width; i++) {
2825 if ( next_char == ' ' ) {
2826 edit_delete (edit, 1);
2828 next_char = edit_get_byte (edit, edit->curs1);
2831 if ( cur_bol == 0 ) {
2832 break;
2834 cur_bol = edit_bol (edit, cur_bol - 1);
2835 } while (cur_bol >= start_bol) ;
2836 edit->force |= REDRAW_PAGE;