Merge branch '1618_rpm_spec_fix'
[midnight-commander.git] / edit / editcmd.c
blobe71718ede981da995cac144b68cc95c0e670b368
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"
64 #include "../edit/edit-impl.h"
65 #include "../edit/edit.h"
66 #include "../edit/editlock.h"
67 #include "../src/cmddef.h"
68 #include "../edit/edit-widget.h"
69 #include "../edit/editcmd_dialogs.h"
70 #include "../edit/etags.h"
72 /* globals: */
74 /* search and replace: */
75 int search_create_bookmark = 0;
76 /* static int search_in_all_charsets = 0; */
78 /* queries on a save */
79 int edit_confirm_save = 1;
81 static int edit_save_cmd (WEdit *edit);
82 static unsigned char *edit_get_block (WEdit *edit, long start,
83 long finish, int *l);
85 static void
86 edit_search_cmd_search_create_bookmark(WEdit * edit)
88 int found = 0, books = 0;
89 int l = 0, l_last = -1;
90 long q = 0;
91 gsize len = 0;
93 search_create_bookmark = 0;
94 book_mark_flush (edit, -1);
96 for (;;) {
97 if (!mc_search_run(edit->search, (void *) edit, q, edit->last_byte, &len))
98 break;
99 if (found == 0)
100 edit->search_start = edit->search->normal_offset;
101 found++;
102 l += edit_count_lines (edit, q, edit->search->normal_offset);
103 if (l != l_last) {
104 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
105 books++;
107 l_last = l;
108 q = edit->search->normal_offset + 1;
111 if (found == 0) {
112 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
113 } else {
114 edit_cursor_move (edit, edit->search_start - edit->curs1);
115 edit_scroll_screen_over_cursor (edit);
119 static int
120 edit_search_cmd_callback(const void *user_data, gsize char_offset)
122 return edit_get_byte ((WEdit * )user_data, (long) char_offset);
125 void edit_help_cmd (WEdit * edit)
127 interactive_display (NULL, "[Internal File Editor]");
128 edit->force |= REDRAW_COMPLETELY;
131 void
132 edit_refresh_cmd (WEdit * edit)
134 #ifdef HAVE_SLANG
135 int color;
137 edit_get_syntax_color (edit, -1, &color);
138 tty_touch_screen ();
139 mc_refresh ();
140 #else
141 clr_scr ();
142 repaint_screen ();
143 #endif /* !HAVE_SLANG */
144 tty_keypad (TRUE);
147 /* If 0 (quick save) then a) create/truncate <filename> file,
148 b) save to <filename>;
149 if 1 (safe save) then a) save to <tempnam>,
150 b) rename <tempnam> to <filename>;
151 if 2 (do backups) then a) save to <tempnam>,
152 b) rename <filename> to <filename.backup_ext>,
153 c) rename <tempnam> to <filename>. */
155 /* returns 0 on error, -1 on abort */
156 static int
157 edit_save_file (WEdit *edit, const char *filename)
159 char *p;
160 gchar *tmp;
161 long filelen = 0;
162 char *savename = 0;
163 gchar *real_filename;
164 int this_save_mode, fd = -1;
166 if (!filename)
167 return 0;
168 if (!*filename)
169 return 0;
171 if (*filename != PATH_SEP && edit->dir) {
172 real_filename = concat_dir_and_file (edit->dir, filename);
173 } else {
174 real_filename = g_strdup(filename);
177 this_save_mode = option_save_mode;
178 if (this_save_mode != EDIT_QUICK_SAVE) {
179 if (!vfs_file_is_local (real_filename) ||
180 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1) {
182 * The file does not exists yet, so no safe save or
183 * backup are necessary.
185 this_save_mode = EDIT_QUICK_SAVE;
187 if (fd != -1)
188 mc_close (fd);
191 if (this_save_mode == EDIT_QUICK_SAVE &&
192 !edit->skip_detach_prompt) {
193 int rv;
194 struct stat sb;
196 rv = mc_stat (real_filename, &sb);
197 if (rv == 0 && sb.st_nlink > 1) {
198 rv = edit_query_dialog3 (_("Warning"),
199 _(" File has hard-links. Detach before saving? "),
200 _("&Yes"), _("&No"), _("&Cancel"));
201 switch (rv) {
202 case 0:
203 this_save_mode = EDIT_SAFE_SAVE;
204 /* fallthrough */
205 case 1:
206 edit->skip_detach_prompt = 1;
207 break;
208 default:
209 g_free(real_filename);
210 return -1;
214 /* Prevent overwriting changes from other editor sessions. */
215 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
217 /* The default action is "Cancel". */
218 query_set_sel(1);
220 rv = edit_query_dialog2 (
221 _("Warning"),
222 _("The file has been modified in the meantime. Save anyway?"),
223 _("&Yes"),
224 _("&Cancel"));
225 if (rv != 0){
226 g_free(real_filename);
227 return -1;
232 if (this_save_mode != EDIT_QUICK_SAVE) {
233 char *savedir, *saveprefix;
234 const char *slashpos;
235 slashpos = strrchr (real_filename, PATH_SEP);
236 if (slashpos) {
237 savedir = g_strdup (real_filename);
238 savedir[slashpos - real_filename + 1] = '\0';
239 } else
240 savedir = g_strdup (".");
241 saveprefix = concat_dir_and_file (savedir, "cooledit");
242 g_free (savedir);
243 fd = mc_mkstemps (&savename, saveprefix, NULL);
244 g_free (saveprefix);
245 if (!savename){
246 g_free(real_filename);
247 return 0;
249 /* FIXME:
250 * Close for now because mc_mkstemps use pure open system call
251 * to create temporary file and it needs to be reopened by
252 * VFS-aware mc_open().
254 close (fd);
255 } else
256 savename = g_strdup (real_filename);
258 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
259 mc_chmod (savename, edit->stat1.st_mode);
261 if ((fd =
262 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
263 edit->stat1.st_mode)) == -1)
264 goto error_save;
266 /* pipe save */
267 if ((p = edit_get_write_filter (savename, real_filename))) {
268 FILE *file;
270 mc_close (fd);
271 file = (FILE *) popen (p, "w");
273 if (file) {
274 filelen = edit_write_stream (edit, file);
275 #if 1
276 pclose (file);
277 #else
278 if (pclose (file) != 0) {
279 tmp = g_strconcat (_(" Error writing to pipe: "),
280 p, " ", (char *) NULL);
281 edit_error_dialog (_("Error"), tmp);
282 g_free(tmp);
283 g_free (p);
284 goto error_save;
286 #endif
287 } else {
288 tmp = g_strconcat (_(" Cannot open pipe for writing: "),
289 p, " ", (char *) NULL);
291 edit_error_dialog (_("Error"),
292 get_sys_error (tmp));
293 g_free (p);
294 g_free(tmp);
295 goto error_save;
297 g_free (p);
298 } else if (edit->lb == LB_ASIS) { /* do not change line breaks */
299 long buf;
300 buf = 0;
301 filelen = edit->last_byte;
302 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
303 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
304 != EDIT_BUF_SIZE) {
305 mc_close (fd);
306 goto error_save;
308 buf++;
310 if (mc_write
311 (fd, (char *) edit->buffers1[buf],
312 edit->curs1 & M_EDIT_BUF_SIZE) !=
313 (edit->curs1 & M_EDIT_BUF_SIZE)) {
314 filelen = -1;
315 } else if (edit->curs2) {
316 edit->curs2--;
317 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
318 if (mc_write
319 (fd,
320 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
321 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
322 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
323 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
324 filelen = -1;
325 } else {
326 while (--buf >= 0) {
327 if (mc_write
328 (fd, (char *) edit->buffers2[buf],
329 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
330 filelen = -1;
331 break;
335 edit->curs2++;
337 if (mc_close (fd))
338 goto error_save;
340 /* Update the file information, especially the mtime. */
341 if (mc_stat (savename, &edit->stat1) == -1)
342 goto error_save;
343 } else { /* change line breaks */
344 FILE *file;
346 mc_close (fd);
348 file = (FILE *) fopen (savename, "w");
350 if (file) {
351 filelen = edit_write_stream (edit, file);
352 fclose (file);
353 } else {
354 char *msg;
356 msg = g_strdup_printf (_(" Cannot open file for writing: %s "), savename);
357 edit_error_dialog (_("Error"), msg);
358 g_free (msg);
359 goto error_save;
363 if (filelen != edit->last_byte)
364 goto error_save;
366 if (this_save_mode == EDIT_DO_BACKUP) {
367 assert (option_backup_ext != NULL);
368 tmp = g_strconcat (real_filename, option_backup_ext,(char *) NULL);
369 if (mc_rename (real_filename, tmp) == -1){
370 g_free(tmp);
371 goto error_save;
375 if (this_save_mode != EDIT_QUICK_SAVE)
376 if (mc_rename (savename, real_filename) == -1)
377 goto error_save;
378 g_free (savename);
379 g_free(real_filename);
380 return 1;
381 error_save:
382 /* FIXME: Is this safe ?
383 * if (this_save_mode != EDIT_QUICK_SAVE)
384 * mc_unlink (savename);
386 g_free(real_filename);
387 g_free (savename);
388 return 0;
391 void
392 menu_save_mode_cmd (void)
394 /* diaog sizes */
395 const int DLG_X = 38;
396 const int DLG_Y = 10;
398 char *str_result;
400 const char *str[] =
402 N_("Quick save "),
403 N_("Safe save "),
404 N_("Do backups -->")
407 QuickWidget widgets[] =
409 /* 0 */ QUICK_BUTTON (18, DLG_X, 7, DLG_Y, N_("&Cancel"), B_CANCEL, NULL),
410 /* 1 */ QUICK_BUTTON ( 6, DLG_X, 7, DLG_Y, N_("&OK"), B_ENTER, NULL),
411 /* 2 */ QUICK_INPUT (23, DLG_X, 5, DLG_Y, option_backup_ext, 9, 0, "edit-backup-ext", &str_result),
412 /* 3 */ QUICK_LABEL (22, DLG_X, 4, DLG_Y, N_("Extension:")),
413 /* 4 */ QUICK_RADIO ( 4, DLG_X, 3, DLG_Y, 3, str, &option_save_mode),
414 QUICK_END
417 QuickDialog dialog =
419 DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "),
420 "[Edit Save Mode]", widgets, FALSE
423 size_t i;
424 size_t maxlen = 0;
425 int dlg_x;
426 size_t l1, w0, w1, w3;
428 assert (option_backup_ext != NULL);
430 /* OK/Cancel buttons */
431 w0 = str_term_width1 (_(widgets[0].u.button.text)) + 2;
432 w1 = str_term_width1 (_(widgets[1].u.button.text)) + 4; /* default batton */
434 w3 = str_term_width1 (_(widgets[3].u.label.text));
436 maxlen = l1 = w0 + w1 + 6;
438 for (i = 0; i < 3; i++) {
439 #ifdef ENABLE_NLS
440 str[i] = _(str[i]);
441 #endif
442 maxlen = max (maxlen, (size_t) str_term_width1 (str[i]) + 7);
445 dlg_x = maxlen + w3 + 5 + 2;
446 widgets[2].u.input.len = w3; /* input field length */
447 dlg_x = min (COLS, dlg_x);
448 dialog.xlen = dlg_x;
450 widgets[0].relative_x = dlg_x * 2/3 - w0/2;
451 widgets[1].relative_x = dlg_x/3 - w1/2;
452 widgets[2].relative_x = widgets[3].relative_x = maxlen + 3;
454 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
455 widgets[i].x_divisions = dlg_x;
457 if (quick_dialog (&dialog) != B_CANCEL) {
458 g_free (option_backup_ext);
459 option_backup_ext = str_result;
463 void
464 edit_set_filename (WEdit *edit, const char *f)
466 g_free (edit->filename);
467 if (!f)
468 f = "";
469 edit->filename = g_strdup (f);
470 if (edit->dir == NULL && *f != PATH_SEP)
471 #ifdef USE_VFS
472 edit->dir = g_strdup (vfs_get_current_dir ());
473 #else
474 edit->dir = g_get_current_dir ();
475 #endif
478 static char *
479 edit_get_save_file_as (WEdit *edit)
481 #define DLG_WIDTH 64
482 #define DLG_HEIGHT 14
484 static LineBreaks cur_lb = LB_ASIS;
486 char *filename = edit->filename;
488 const char *lb_names[LB_NAMES] =
490 N_("&Do not change"),
491 N_("&Unix format (LF)"),
492 N_("&Windows/DOS format (CR LF)"),
493 N_("&Macintosh format (CR)")
496 QuickWidget quick_widgets[] =
498 QUICK_BUTTON (6, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
499 QUICK_BUTTON (2, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
500 QUICK_RADIO (5, DLG_WIDTH, DLG_HEIGHT - 8, DLG_HEIGHT, LB_NAMES, lb_names, (int *) &cur_lb),
501 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 9, DLG_HEIGHT, N_("Change line breaks to:")),
502 QUICK_INPUT (3, DLG_WIDTH, DLG_HEIGHT - 11, DLG_HEIGHT, filename, DLG_WIDTH - 6, 0, "save-as", &filename),
503 QUICK_LABEL (2, DLG_WIDTH, DLG_HEIGHT - 12, DLG_HEIGHT, N_(" Enter file name: ")),
504 QUICK_END
507 QuickDialog Quick_options =
509 DLG_WIDTH, DLG_HEIGHT, -1, -1,
510 N_(" Save As "), "[Save File As]",
511 quick_widgets, FALSE
514 if (quick_dialog (&Quick_options) != B_CANCEL) {
515 edit->lb = cur_lb;
516 return filename;
519 return NULL;
521 #undef DLG_WIDTH
522 #undef DLG_HEIGHT
525 /* Here we want to warn the users of overwriting an existing file,
526 but only if they have made a change to the filename */
527 /* returns 1 on success */
529 edit_save_as_cmd (WEdit *edit)
531 /* This heads the 'Save As' dialog box */
532 char *exp;
533 int save_lock = 0;
534 int different_filename = 0;
536 exp = edit_get_save_file_as (edit);
537 edit_push_action (edit, KEY_PRESS + edit->start_display);
539 if (exp) {
540 if (!*exp) {
541 g_free (exp);
542 edit->force |= REDRAW_COMPLETELY;
543 return 0;
544 } else {
545 int rv;
546 if (strcmp (edit->filename, exp)) {
547 int file;
548 different_filename = 1;
549 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
550 /* the file exists */
551 mc_close (file);
552 /* Overwrite the current file or cancel the operation */
553 if (edit_query_dialog2
554 (_("Warning"),
555 _(" A file already exists with this name. "),
556 _("&Overwrite"), _("&Cancel"))) {
557 edit->force |= REDRAW_COMPLETELY;
558 g_free (exp);
559 return 0;
561 } else {
562 edit->stat1.st_mode |= S_IWUSR;
564 save_lock = edit_lock_file (exp);
565 } else {
566 /* filenames equal, check if already locked */
567 if (!edit->locked && !edit->delete_file)
568 save_lock = edit_lock_file (exp);
571 if (different_filename)
574 * Allow user to write into saved (under another name) file
575 * even if original file had r/o user permissions.
577 edit->stat1.st_mode |= S_IWRITE;
580 rv = edit_save_file (edit, exp);
581 switch (rv) {
582 case 1:
583 /* Succesful, so unlock both files */
584 if (different_filename) {
585 if (save_lock)
586 edit_unlock_file (exp);
587 if (edit->locked)
588 edit->locked = edit_unlock_file (edit->filename);
589 } else {
590 if (edit->locked || save_lock)
591 edit->locked = edit_unlock_file (edit->filename);
594 edit_set_filename (edit, exp);
595 if (edit->lb != LB_ASIS)
596 edit_reload(edit, exp);
597 g_free (exp);
598 edit->modified = 0;
599 edit->delete_file = 0;
600 if (different_filename)
601 edit_load_syntax (edit, NULL, option_syntax_type);
602 edit->force |= REDRAW_COMPLETELY;
603 return 1;
604 default:
605 edit_error_dialog (_(" Save As "),
606 get_sys_error (_
607 (" Cannot save file. ")));
608 /* fallthrough */
609 case -1:
610 /* Failed, so maintain modify (not save) lock */
611 if (save_lock)
612 edit_unlock_file (exp);
613 g_free (exp);
614 edit->force |= REDRAW_COMPLETELY;
615 return 0;
619 edit->force |= REDRAW_COMPLETELY;
620 return 0;
623 /* {{{ Macro stuff starts here */
625 /* creates a macro file if it doesn't exist */
626 static FILE *edit_open_macro_file (const char *r)
628 gchar *filename;
629 FILE *fd;
630 int file;
631 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
632 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
633 g_free(filename);
634 return 0;
636 close (file);
637 fd = fopen (filename, r);
638 g_free(filename);
639 return fd;
642 #define MAX_MACROS 1024
643 static int saved_macro[MAX_MACROS + 1];
644 static int saved_macros_loaded = 0;
647 This is just to stop the macro file be loaded over and over for keys
648 that aren't defined to anything. On slow systems this could be annoying.
650 static int
651 macro_exists (int k)
653 int i;
654 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
655 if (saved_macro[i] == k)
656 return i;
657 return -1;
660 /* returns 1 on error */
661 static int
662 edit_delete_macro (WEdit * edit, int k)
664 gchar *tmp, *tmp2;
665 struct macro macro[MAX_MACRO_LENGTH];
666 FILE *f, *g;
667 int s, i, n, j = 0;
669 (void) edit;
671 if (saved_macros_loaded)
672 if ((j = macro_exists (k)) < 0)
673 return 0;
674 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
675 g = fopen (tmp , "w");
676 g_free(tmp);
677 if (!g) {
678 edit_error_dialog (_(" Delete macro "),
679 get_sys_error (_(" Cannot open temp file ")));
680 return 1;
682 f = edit_open_macro_file ("r");
683 if (!f) {
684 edit_error_dialog (_(" Delete macro "),
685 get_sys_error (_(" Cannot open macro file ")));
686 fclose (g);
687 return 1;
689 for (;;) {
690 n = fscanf (f, ("key '%d 0': "), &s);
691 if (!n || n == EOF)
692 break;
693 n = 0;
694 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
695 n++;
696 fscanf (f, ";\n");
697 if (s != k) {
698 fprintf (g, ("key '%d 0': "), s);
699 for (i = 0; i < n; i++)
700 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
701 fprintf (g, ";\n");
704 fclose (f);
705 fclose (g);
706 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
707 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
708 if (rename ( tmp, tmp2) == -1) {
709 edit_error_dialog (_(" Delete macro "),
710 get_sys_error (_(" Cannot overwrite macro file ")));
711 g_free(tmp);
712 g_free(tmp2);
713 return 1;
715 g_free(tmp);
716 g_free(tmp2);
718 if (saved_macros_loaded)
719 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
720 return 0;
723 /* returns 0 on error */
724 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
726 FILE *f;
727 int s, i;
729 edit_push_action (edit, KEY_PRESS + edit->start_display);
730 s = editcmd_dialog_raw_key_query (_(" Save macro "),
731 _(" Press the macro's new hotkey: "), 1);
732 edit->force |= REDRAW_COMPLETELY;
733 if (s) {
734 if (edit_delete_macro (edit, s))
735 return 0;
736 f = edit_open_macro_file ("a+");
737 if (f) {
738 fprintf (f, ("key '%d 0': "), s);
739 for (i = 0; i < n; i++)
740 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
741 fprintf (f, ";\n");
742 fclose (f);
743 if (saved_macros_loaded) {
744 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
745 saved_macro[i] = s;
747 return 1;
748 } else
749 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
751 return 0;
754 void edit_delete_macro_cmd (WEdit * edit)
756 int command;
758 command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
759 _ (" Press macro hotkey: "), 1);
761 if (!command)
762 return;
764 edit_delete_macro (edit, command);
767 /* return 0 on error */
768 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
770 FILE *f;
771 int s, i = 0, found = 0;
773 (void) edit;
775 if (saved_macros_loaded)
776 if (macro_exists (k) < 0)
777 return 0;
779 if ((f = edit_open_macro_file ("r"))) {
780 struct macro dummy;
781 do {
782 int u;
783 u = fscanf (f, ("key '%d 0': "), &s);
784 if (!u || u == EOF)
785 break;
786 if (!saved_macros_loaded)
787 saved_macro[i++] = s;
788 if (!found) {
789 *n = 0;
790 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
791 (*n)++;
792 } else {
793 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
795 fscanf (f, ";\n");
796 if (s == k)
797 found = 1;
798 } while (!found || !saved_macros_loaded);
799 if (!saved_macros_loaded) {
800 saved_macro[i] = 0;
801 saved_macros_loaded = 1;
803 fclose (f);
804 return found;
805 } else
806 edit_error_dialog (_(" Load macro "),
807 get_sys_error (_(" Cannot open macro file ")));
808 return 0;
811 /* }}} Macro stuff starts here */
813 /* returns 1 on success */
814 int edit_save_confirm_cmd (WEdit * edit)
816 gchar *f = NULL;
818 if (edit_confirm_save) {
819 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", NULL);
820 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel"))){
821 g_free(f);
822 return 0;
824 g_free(f);
826 return edit_save_cmd (edit);
830 /* returns 1 on success */
831 static int
832 edit_save_cmd (WEdit *edit)
834 int res, save_lock = 0;
836 if (!edit->locked && !edit->delete_file)
837 save_lock = edit_lock_file (edit->filename);
838 res = edit_save_file (edit, edit->filename);
840 /* Maintain modify (not save) lock on failure */
841 if ((res > 0 && edit->locked) || save_lock)
842 edit->locked = edit_unlock_file (edit->filename);
844 /* On failure try 'save as', it does locking on its own */
845 if (!res)
846 return edit_save_as_cmd (edit);
847 edit->force |= REDRAW_COMPLETELY;
848 if (res > 0) {
849 edit->delete_file = 0;
850 edit->modified = 0;
853 return 1;
857 /* returns 1 on success */
858 int edit_new_cmd (WEdit * edit)
860 if (edit->modified) {
861 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
862 edit->force |= REDRAW_COMPLETELY;
863 return 0;
866 edit->force |= REDRAW_COMPLETELY;
868 return edit_renew (edit); /* if this gives an error, something has really screwed up */
871 /* returns 1 on error */
872 static int
873 edit_load_file_from_filename (WEdit * edit, char *exp)
875 int prev_locked = edit->locked;
876 char *prev_filename = g_strdup (edit->filename);
878 if (!edit_reload (edit, exp)) {
879 g_free (prev_filename);
880 return 1;
883 if (prev_locked)
884 edit_unlock_file (prev_filename);
885 g_free (prev_filename);
886 return 0;
889 static void
890 edit_load_syntax_file (WEdit * edit)
892 char *extdir;
893 int dir = 0;
895 if (geteuid () == 0) {
896 dir = query_dialog (_("Syntax file edit"),
897 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
898 _("&User"), _("&System Wide"));
901 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
902 if (!exist_file(extdir)) {
903 g_free (extdir);
904 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
907 if (dir == 0) {
908 char *buffer;
910 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
911 check_for_default (extdir, buffer);
912 edit_load_file_from_filename (edit, buffer);
913 g_free (buffer);
914 } else if (dir == 1)
915 edit_load_file_from_filename (edit, extdir);
917 g_free (extdir);
920 static void
921 edit_load_menu_file (WEdit * edit)
923 char *buffer;
924 char *menufile;
925 int dir = 0;
927 dir = query_dialog (
928 _(" Menu edit "),
929 _(" Which menu file do you want to edit? "), D_NORMAL,
930 geteuid() ? 2 : 3, _("&Local"), _("&User"), _("&System Wide")
933 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
935 if (!exist_file (menufile)) {
936 g_free (menufile);
937 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
940 switch (dir) {
941 case 0:
942 buffer = g_strdup (EDIT_LOCAL_MENU);
943 check_for_default (menufile, buffer);
944 chmod (buffer, 0600);
945 break;
947 case 1:
948 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
949 check_for_default (menufile, buffer);
950 break;
952 case 2:
953 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
954 if (!exist_file (buffer)) {
955 g_free (buffer);
956 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
958 break;
960 default:
961 g_free (menufile);
962 return;
965 edit_load_file_from_filename (edit, buffer);
967 g_free (buffer);
968 g_free (menufile);
972 edit_load_cmd (WEdit *edit, edit_current_file_t what)
974 char *exp;
976 if (edit->modified
977 && (edit_query_dialog2
978 (_("Warning"),
979 _(" Current text was modified without a file save. \n"
980 " Continue discards these changes. "),
981 _("C&ontinue"), _("&Cancel")) == 1)) {
982 edit->force |= REDRAW_COMPLETELY;
983 return 0;
986 switch (what) {
987 case EDIT_FILE_COMMON:
988 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
989 MC_HISTORY_EDIT_LOAD, edit->filename);
991 if (exp) {
992 if (*exp)
993 edit_load_file_from_filename (edit, exp);
994 g_free (exp);
996 break;
998 case EDIT_FILE_SYNTAX:
999 edit_load_syntax_file (edit);
1000 break;
1002 case EDIT_FILE_MENU:
1003 edit_load_menu_file (edit);
1004 break;
1006 default:
1007 break;
1010 edit->force |= REDRAW_COMPLETELY;
1011 return 0;
1015 if mark2 is -1 then marking is from mark1 to the cursor.
1016 Otherwise its between the markers. This handles this.
1017 Returns 1 if no text is marked.
1019 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
1021 if (edit->mark1 != edit->mark2) {
1022 if (edit->mark2 >= 0) {
1023 *start_mark = min (edit->mark1, edit->mark2);
1024 *end_mark = max (edit->mark1, edit->mark2);
1025 } else {
1026 *start_mark = min (edit->mark1, edit->curs1);
1027 *end_mark = max (edit->mark1, edit->curs1);
1028 edit->column2 = edit->curs_col + edit->over_col;
1030 return 0;
1031 } else {
1032 *start_mark = *end_mark = 0;
1033 edit->column2 = edit->column1 = 0;
1034 return 1;
1038 #define space_width 1
1040 void
1041 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
1043 long cursor;
1044 int i, col;
1045 cursor = edit->curs1;
1046 col = edit_get_col (edit);
1047 for (i = 0; i < size; i++) {
1048 if (data[i] == '\n') { /* fill in and move to next line */
1049 int l;
1050 long p;
1051 if (edit_get_byte (edit, edit->curs1) != '\n') {
1052 l = width - (edit_get_col (edit) - col);
1053 while (l > 0) {
1054 edit_insert (edit, ' ');
1055 l -= space_width;
1058 for (p = edit->curs1;; p++) {
1059 if (p == edit->last_byte) {
1060 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1061 edit_insert_ahead (edit, '\n');
1062 p++;
1063 break;
1065 if (edit_get_byte (edit, p) == '\n') {
1066 p++;
1067 break;
1070 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1071 l = col - edit_get_col (edit);
1072 while (l >= space_width) {
1073 edit_insert (edit, ' ');
1074 l -= space_width;
1076 continue;
1078 edit_insert (edit, data[i]);
1080 edit_cursor_move (edit, cursor - edit->curs1);
1083 #define TEMP_BUF_LEN 1024
1086 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1088 long cursor;
1089 int i, col;
1090 int blocklen = -1, width;
1091 unsigned char *data;
1092 cursor = edit->curs1;
1093 col = edit_get_col (edit);
1094 data = g_malloc (TEMP_BUF_LEN);
1095 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0) {
1096 for (width = 0; width < blocklen; width++) {
1097 if (data[width] == '\n')
1098 break;
1100 for (i = 0; i < blocklen; i++) {
1101 if (data[i] == '\n') { /* fill in and move to next line */
1102 int l;
1103 long p;
1104 if (edit_get_byte (edit, edit->curs1) != '\n') {
1105 l = width - (edit_get_col (edit) - col);
1106 while (l > 0) {
1107 edit_insert (edit, ' ');
1108 l -= space_width;
1111 for (p = edit->curs1;; p++) {
1112 if (p == edit->last_byte) {
1113 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1114 edit_insert_ahead (edit, '\n');
1115 p++;
1116 break;
1118 if (edit_get_byte (edit, p) == '\n') {
1119 p++;
1120 break;
1123 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1124 l = col - edit_get_col (edit);
1125 while (l >= space_width) {
1126 edit_insert (edit, ' ');
1127 l -= space_width;
1129 continue;
1131 edit_insert (edit, data[i]);
1134 edit_cursor_move (edit, cursor - edit->curs1);
1135 g_free(data);
1136 edit->force |= REDRAW_PAGE;
1137 return blocklen;
1140 void
1141 edit_block_copy_cmd (WEdit *edit)
1143 long start_mark, end_mark, current = edit->curs1;
1144 int size;
1145 unsigned char *copy_buf;
1147 edit_update_curs_col (edit);
1148 if (eval_marks (edit, &start_mark, &end_mark))
1149 return;
1151 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1153 /* all that gets pushed are deletes hence little space is used on the stack */
1155 edit_push_markers (edit);
1157 if (column_highlighting) {
1158 edit_insert_column_of_text (edit, copy_buf, size,
1159 abs (edit->column2 - edit->column1));
1160 } else {
1161 while (size--)
1162 edit_insert_ahead (edit, copy_buf[size]);
1165 g_free (copy_buf);
1166 edit_scroll_screen_over_cursor (edit);
1168 if (column_highlighting) {
1169 edit_set_markers (edit, 0, 0, 0, 0);
1170 edit_push_action (edit, COLUMN_ON);
1171 column_highlighting = 0;
1172 } else if (start_mark < current && end_mark > current)
1173 edit_set_markers (edit, start_mark,
1174 end_mark + end_mark - start_mark, 0, 0);
1176 edit->force |= REDRAW_PAGE;
1180 void
1181 edit_block_move_cmd (WEdit *edit)
1183 long count;
1184 long current;
1185 unsigned char *copy_buf;
1186 long start_mark, end_mark;
1187 int deleted = 0;
1188 int x = 0;
1190 if (eval_marks (edit, &start_mark, &end_mark))
1191 return;
1192 if (column_highlighting) {
1193 edit_update_curs_col (edit);
1194 x = edit->curs_col;
1195 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1196 if ((x > edit->column1 && x < edit->column2)
1197 || (x > edit->column2 && x < edit->column1))
1198 return;
1199 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1200 return;
1202 if ((end_mark - start_mark) > option_max_undo / 2)
1203 if (edit_query_dialog2
1204 (_("Warning"),
1206 (" Block is large, you may not be able to undo this action. "),
1207 _("C&ontinue"), _("&Cancel")))
1208 return;
1210 edit_push_markers (edit);
1211 current = edit->curs1;
1212 if (column_highlighting) {
1213 int size, c1, c2, line;
1214 line = edit->curs_line;
1215 if (edit->mark2 < 0)
1216 edit_mark_cmd (edit, 0);
1217 c1 = min (edit->column1, edit->column2);
1218 c2 = max (edit->column1, edit->column2);
1219 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1220 if (x < c2) {
1221 edit_block_delete_cmd (edit);
1222 deleted = 1;
1224 edit_move_to_line (edit, line);
1225 edit_cursor_move (edit,
1226 edit_move_forward3 (edit,
1227 edit_bol (edit, edit->curs1),
1228 x, 0) - edit->curs1);
1229 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1230 if (!deleted) {
1231 line = edit->curs_line;
1232 edit_update_curs_col (edit);
1233 x = edit->curs_col;
1234 edit_block_delete_cmd (edit);
1235 edit_move_to_line (edit, line);
1236 edit_cursor_move (edit,
1237 edit_move_forward3 (edit,
1238 edit_bol (edit,
1239 edit->curs1),
1240 x, 0) - edit->curs1);
1242 edit_set_markers (edit, 0, 0, 0, 0);
1243 edit_push_action (edit, COLUMN_ON);
1244 column_highlighting = 0;
1245 } else {
1246 copy_buf = g_malloc (end_mark - start_mark);
1247 edit_cursor_move (edit, start_mark - edit->curs1);
1248 edit_scroll_screen_over_cursor (edit);
1249 count = start_mark;
1250 while (count < end_mark) {
1251 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1252 count++;
1254 edit_scroll_screen_over_cursor (edit);
1255 edit_cursor_move (edit,
1256 current - edit->curs1 -
1257 (((current - edit->curs1) >
1258 0) ? end_mark - start_mark : 0));
1259 edit_scroll_screen_over_cursor (edit);
1260 while (count-- > start_mark)
1261 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1262 edit_set_markers (edit, edit->curs1,
1263 edit->curs1 + end_mark - start_mark, 0, 0);
1265 edit_scroll_screen_over_cursor (edit);
1266 g_free (copy_buf);
1267 edit->force |= REDRAW_PAGE;
1270 static void
1271 edit_delete_column_of_text (WEdit * edit)
1273 long p, q, r, m1, m2;
1274 int b, c, d;
1275 int n;
1277 eval_marks (edit, &m1, &m2);
1278 n = edit_move_forward (edit, m1, 0, m2) + 1;
1279 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1280 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1282 b = max(min (c, d), min (edit->column1, edit->column2));
1283 c = max (c, d + edit->over_col);
1285 while (n--) {
1286 r = edit_bol (edit, edit->curs1);
1287 p = edit_move_forward3 (edit, r, b, 0);
1288 q = edit_move_forward3 (edit, r, c, 0);
1289 if (p < m1)
1290 p = m1;
1291 if (q > m2)
1292 q = m2;
1293 edit_cursor_move (edit, p - edit->curs1);
1294 while (q > p) { /* delete line between margins */
1295 if (edit_get_byte (edit, edit->curs1) != '\n')
1296 edit_delete (edit, 1);
1297 q--;
1299 if (n) /* move to next line except on the last delete */
1300 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1304 /* if success return 0 */
1305 static int
1306 edit_block_delete (WEdit *edit)
1308 long count;
1309 long start_mark, end_mark;
1310 if (eval_marks (edit, &start_mark, &end_mark))
1311 return 0;
1312 if (column_highlighting && edit->mark2 < 0)
1313 edit_mark_cmd (edit, 0);
1314 if ((end_mark - start_mark) > option_max_undo / 2) {
1315 /* Warning message with a query to continue or cancel the operation */
1316 if (edit_query_dialog2
1317 (_("Warning"),
1319 (" Block is large, you may not be able to undo this action. "),
1320 _("C&ontinue"), _("&Cancel"))) {
1321 return 1;
1324 edit_push_markers (edit);
1325 edit_cursor_move (edit, start_mark - edit->curs1);
1326 edit_scroll_screen_over_cursor (edit);
1327 count = start_mark;
1328 if (start_mark < end_mark) {
1329 if (column_highlighting) {
1330 if (edit->mark2 < 0)
1331 edit_mark_cmd (edit, 0);
1332 edit_delete_column_of_text (edit);
1333 } else {
1334 while (count < end_mark) {
1335 edit_delete (edit, 1);
1336 count++;
1340 edit_set_markers (edit, 0, 0, 0, 0);
1341 edit->force |= REDRAW_PAGE;
1342 return 0;
1345 /* returns 1 if canceelled by user */
1346 int edit_block_delete_cmd (WEdit * edit)
1348 long start_mark, end_mark;
1349 if (eval_marks (edit, &start_mark, &end_mark)) {
1350 edit_delete_line (edit);
1351 return 0;
1353 return edit_block_delete (edit);
1356 #define INPUT_INDEX 9
1358 static gboolean
1359 editcmd_find (WEdit *edit, gsize *len)
1361 off_t search_start = edit->search_start;
1362 off_t search_end;
1363 long start_mark = 0;
1364 long end_mark = edit->last_byte;
1365 int mark_res = 0;
1367 if (edit->only_in_selection) {
1368 mark_res = eval_marks(edit, &start_mark, &end_mark);
1369 if (mark_res != 0) {
1370 edit->search->error = MC_SEARCH_E_NOTFOUND;
1371 edit->search->error_str = g_strdup(_(" Search string not found "));
1372 return FALSE;
1374 if (edit->replace_backwards) {
1375 if (search_start > end_mark || search_start <= start_mark) {
1376 search_start = end_mark;
1378 } else {
1379 if (search_start < start_mark || search_start >= end_mark) {
1380 search_start = start_mark;
1383 } else {
1384 if (edit->replace_backwards)
1385 end_mark = max(1, edit->curs1) - 1;
1387 if (edit->replace_backwards) {
1388 search_end = end_mark;
1389 while ((int) search_start >= start_mark) {
1390 if (search_end > search_start + edit->search->original_len
1391 && mc_search_is_fixed_search_str(edit->search)) {
1392 search_end = search_start + edit->search->original_len;
1394 if (mc_search_run(edit->search, (void *) edit, search_start, search_end, len)
1395 && edit->search->normal_offset == search_start ) {
1396 return TRUE;
1398 search_start--;
1400 edit->search->error_str = g_strdup(_(" Search string not found "));
1401 } else {
1402 return mc_search_run(edit->search, (void *) edit, search_start, end_mark, len);
1404 return FALSE;
1408 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1409 (and the above) routines to work properly - paul */
1411 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1413 static char *
1414 edit_replace_cmd__conv_to_display(char *str)
1416 #ifdef HAVE_CHARSET
1417 GString *tmp;
1418 tmp = str_convert_to_display (str);
1420 if (tmp && tmp->len){
1421 g_free(str);
1422 str = tmp->str;
1424 g_string_free (tmp, FALSE);
1425 return str;
1426 #else
1427 return g_strdup(str);
1428 #endif
1431 static char *
1432 edit_replace_cmd__conv_to_input(char *str)
1434 #ifdef HAVE_CHARSET
1435 GString *tmp;
1436 tmp = str_convert_to_input (str);
1438 if (tmp && tmp->len){
1439 g_free(str);
1440 str = tmp->str;
1442 g_string_free (tmp, FALSE);
1443 return str;
1444 #else
1445 return g_strdup(str);
1446 #endif
1448 /* call with edit = 0 before shutdown to close memory leaks */
1449 void
1450 edit_replace_cmd (WEdit *edit, int again)
1452 /* 1 = search string, 2 = replace with */
1453 static char *saved1 = NULL; /* saved default[123] */
1454 static char *saved2 = NULL;
1455 char *input1 = NULL; /* user input from the dialog */
1456 char *input2 = NULL;
1457 int replace_yes;
1458 long times_replaced = 0, last_search;
1459 gboolean once_found = FALSE;
1461 if (!edit) {
1462 g_free (saved1), saved1 = NULL;
1463 g_free (saved2), saved2 = NULL;
1464 return;
1467 last_search = edit->last_byte;
1469 edit->force |= REDRAW_COMPLETELY;
1471 if (again && !saved1 && !saved2)
1472 again = 0;
1474 if (again) {
1475 input1 = g_strdup (saved1 ? saved1 : "");
1476 input2 = g_strdup (saved2 ? saved2 : "");
1477 } else {
1478 char *disp1 = edit_replace_cmd__conv_to_display(g_strdup (saved1 ? saved1 : ""));
1479 char *disp2 = edit_replace_cmd__conv_to_display(g_strdup (saved2 ? saved2 : ""));
1481 edit_push_action (edit, KEY_PRESS + edit->start_display);
1483 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1485 g_free (disp1);
1486 g_free (disp2);
1488 if (input1 == NULL || *input1 == '\0') {
1489 edit->force = REDRAW_COMPLETELY;
1490 goto cleanup;
1493 input1 = edit_replace_cmd__conv_to_input(input1);
1494 input2 = edit_replace_cmd__conv_to_input(input2);
1496 g_free (saved1), saved1 = g_strdup (input1);
1497 g_free (saved2), saved2 = g_strdup (input2);
1499 if (edit->search) {
1500 mc_search_free(edit->search);
1501 edit->search = NULL;
1505 if (!edit->search) {
1506 edit->search = mc_search_new(input1, -1);
1507 if (edit->search == NULL) {
1508 edit->search_start = edit->curs1;
1509 return;
1511 edit->search->search_type = edit->search_type;
1512 edit->search->is_all_charsets = edit->all_codepages;
1513 edit->search->is_case_sentitive = edit->replace_case;
1514 edit->search->whole_words = edit->whole_words;
1515 edit->search->search_fn = edit_search_cmd_callback;
1518 if (edit->found_len && edit->search_start == edit->found_start + 1
1519 && edit->replace_backwards)
1520 edit->search_start--;
1522 if (edit->found_len && edit->search_start == edit->found_start - 1
1523 && !edit->replace_backwards)
1524 edit->search_start++;
1526 do {
1527 gsize len = 0;
1528 long new_start;
1530 if (! editcmd_find(edit, &len)) {
1531 if (!(edit->search->error == MC_SEARCH_E_OK ||
1532 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND))) {
1533 edit_error_dialog (_ ("Search"), edit->search->error_str);
1535 break;
1537 once_found = TRUE;
1538 new_start = edit->search->normal_offset;
1540 edit->search_start = new_start = edit->search->normal_offset;
1541 /*returns negative on not found or error in pattern */
1543 if (edit->search_start >= 0) {
1544 guint i;
1546 edit->found_start = edit->search_start;
1547 i = edit->found_len = len;
1549 edit_cursor_move (edit, edit->search_start - edit->curs1);
1550 edit_scroll_screen_over_cursor (edit);
1552 replace_yes = 1;
1554 if (edit->replace_mode == 0) {
1555 int l;
1556 l = edit->curs_row - edit->num_widget_lines / 3;
1557 if (l > 0)
1558 edit_scroll_downward (edit, l);
1559 if (l < 0)
1560 edit_scroll_upward (edit, -l);
1562 edit_scroll_screen_over_cursor (edit);
1563 edit->force |= REDRAW_PAGE;
1564 edit_render_keypress (edit);
1566 /*so that undo stops at each query */
1567 edit_push_key_press (edit);
1568 /* and prompt 2/3 down */
1569 switch (editcmd_dialog_replace_prompt_show (edit, input1, input2, -1, -1)) {
1570 case B_ENTER:
1571 replace_yes = 1;
1572 break;
1573 case B_SKIP_REPLACE:
1574 replace_yes = 0;
1575 break;
1576 case B_REPLACE_ALL:
1577 edit->replace_mode=1;
1578 break;
1579 case B_CANCEL:
1580 replace_yes = 0;
1581 edit->replace_mode = -1;
1582 break;
1585 if (replace_yes) { /* delete then insert new */
1586 GString *repl_str, *tmp_str;
1587 tmp_str = g_string_new(input2);
1589 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1590 g_string_free(tmp_str, TRUE);
1591 if (edit->search->error != MC_SEARCH_E_OK)
1593 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1594 break;
1597 while (i--)
1598 edit_delete (edit, 1);
1600 while (++i < repl_str->len)
1601 edit_insert (edit, repl_str->str[i]);
1603 g_string_free(repl_str, TRUE);
1604 edit->found_len = i;
1606 /* so that we don't find the same string again */
1607 if (edit->replace_backwards) {
1608 last_search = edit->search_start;
1609 edit->search_start--;
1610 } else {
1611 edit->search_start += i;
1612 last_search = edit->last_byte;
1614 edit_scroll_screen_over_cursor (edit);
1615 } else {
1616 const char *msg = _(" Replace ");
1617 /* try and find from right here for next search */
1618 edit->search_start = edit->curs1;
1619 edit_update_curs_col (edit);
1621 edit->force |= REDRAW_PAGE;
1622 edit_render_keypress (edit);
1623 if (times_replaced) {
1624 message (D_NORMAL, msg, _(" %ld replacements made. "),
1625 times_replaced);
1626 } else
1627 query_dialog (msg, _(" Search string not found "),
1628 D_NORMAL, 1, _("&OK"));
1629 edit->replace_mode = -1;
1631 } while (edit->replace_mode >= 0);
1633 edit->force = REDRAW_COMPLETELY;
1634 edit_scroll_screen_over_cursor (edit);
1635 cleanup:
1636 g_free (input1);
1637 g_free (input2);
1641 void edit_search_cmd (WEdit * edit, int again)
1643 char *search_string = NULL, *search_string_dup = NULL;
1645 gsize len = 0;
1647 if (!edit)
1648 return;
1650 if (edit->search != NULL) {
1651 search_string = g_strndup(edit->search->original, edit->search->original_len);
1652 search_string_dup = search_string;
1653 } else {
1654 GList *history;
1655 history = history_get (MC_HISTORY_SHARED_SEARCH);
1656 if (history != NULL && history->data != NULL) {
1657 search_string_dup = search_string = (char *) g_strdup(history->data);
1658 history = g_list_first (history);
1659 g_list_foreach (history, (GFunc) g_free, NULL);
1660 g_list_free (history);
1662 edit->search_start = edit->curs1;
1665 if (!again) {
1666 #ifdef HAVE_CHARSET
1667 GString *tmp;
1668 if (search_string && *search_string) {
1669 tmp = str_convert_to_display (search_string);
1671 g_free(search_string_dup);
1672 search_string_dup = NULL;
1674 if (tmp && tmp->len)
1675 search_string = search_string_dup = tmp->str;
1676 g_string_free (tmp, FALSE);
1678 #endif /* HAVE_CHARSET */
1679 editcmd_dialog_search_show (edit, &search_string);
1680 #ifdef HAVE_CHARSET
1681 if (search_string && *search_string) {
1682 tmp = str_convert_to_input (search_string);
1683 if (tmp && tmp->len)
1684 search_string = tmp->str;
1686 g_string_free (tmp, FALSE);
1688 if (search_string_dup)
1689 g_free(search_string_dup);
1691 #endif /* HAVE_CHARSET */
1693 edit_push_action (edit, KEY_PRESS + edit->start_display);
1695 if (!search_string) {
1696 edit->force |= REDRAW_COMPLETELY;
1697 edit_scroll_screen_over_cursor (edit);
1698 return;
1701 if (edit->search) {
1702 mc_search_free(edit->search);
1703 edit->search = NULL;
1707 if (!edit->search) {
1708 edit->search = mc_search_new(search_string, -1);
1709 if (edit->search == NULL) {
1710 edit->search_start = edit->curs1;
1711 return;
1713 edit->search->search_type = edit->search_type;
1714 edit->search->is_all_charsets = edit->all_codepages;
1715 edit->search->is_case_sentitive = edit->replace_case;
1716 edit->search->whole_words = edit->whole_words;
1717 edit->search->search_fn = edit_search_cmd_callback;
1720 if (search_create_bookmark) {
1721 edit_search_cmd_search_create_bookmark(edit);
1722 } else {
1723 if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
1724 edit->search_start--;
1726 if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
1727 edit->search_start++;
1730 if (editcmd_find(edit, &len)) {
1731 edit->found_start = edit->search_start = edit->search->normal_offset;
1732 edit->found_len = len;
1733 edit->over_col = 0;
1734 edit_cursor_move (edit, edit->search_start - edit->curs1);
1735 edit_scroll_screen_over_cursor (edit);
1736 if (edit->replace_backwards)
1737 edit->search_start--;
1738 else
1739 edit->search_start++;
1740 } else {
1741 edit->search_start = edit->curs1;
1742 if (edit->search->error_str)
1743 edit_error_dialog (_ ("Search"), edit->search->error_str);
1747 edit->force |= REDRAW_COMPLETELY;
1748 edit_scroll_screen_over_cursor (edit);
1753 * Check if it's OK to close the editor. If there are unsaved changes,
1754 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
1757 edit_ok_to_exit (WEdit *edit)
1759 if (!edit->modified)
1760 return 1;
1762 switch (edit_query_dialog3
1763 (_("Quit"), _(" File was modified, Save with exit? "),
1764 _("&Cancel quit"), _("&Yes"), _("&No"))) {
1765 case 1:
1766 edit_push_markers (edit);
1767 edit_set_markers (edit, 0, 0, 0, 0);
1768 if (!edit_save_cmd (edit))
1769 return 0;
1770 break;
1771 case 2:
1772 break;
1773 case 0:
1774 case -1:
1775 return 0;
1778 return 1;
1781 /* Return a null terminated length of text. Result must be g_free'd */
1782 static unsigned char *
1783 edit_get_block (WEdit *edit, long start, long finish, int *l)
1785 unsigned char *s, *r;
1786 r = s = g_malloc (finish - start + 1);
1787 if (column_highlighting) {
1788 *l = 0;
1789 /* copy from buffer, excluding chars that are out of the column 'margins' */
1790 while (start < finish) {
1791 int c, x;
1792 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
1793 start);
1794 c = edit_get_byte (edit, start);
1795 if ((x >= edit->column1 && x < edit->column2)
1796 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1797 *s++ = c;
1798 (*l)++;
1800 start++;
1802 } else {
1803 *l = finish - start;
1804 while (start < finish)
1805 *s++ = edit_get_byte (edit, start++);
1807 *s = 0;
1808 return r;
1811 /* save block, returns 1 on success */
1813 edit_save_block (WEdit * edit, const char *filename, long start,
1814 long finish)
1816 int len, file;
1818 if ((file =
1819 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
1820 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
1821 return 0;
1823 if (column_highlighting) {
1824 int r;
1825 r = mc_write (file, VERTICAL_MAGIC, sizeof(VERTICAL_MAGIC));
1826 if (r > 0) {
1827 unsigned char *block, *p;
1828 p = block = edit_get_block (edit, start, finish, &len);
1829 while (len) {
1830 r = mc_write (file, p, len);
1831 if (r < 0)
1832 break;
1833 p += r;
1834 len -= r;
1836 g_free (block);
1838 } else {
1839 unsigned char *buf;
1840 int i = start, end;
1841 len = finish - start;
1842 buf = g_malloc (TEMP_BUF_LEN);
1843 while (start != finish) {
1844 end = min (finish, start + TEMP_BUF_LEN);
1845 for (; i < end; i++)
1846 buf[i - start] = edit_get_byte (edit, i);
1847 len -= mc_write (file, (char *) buf, end - start);
1848 start = end;
1850 g_free (buf);
1852 mc_close (file);
1853 if (len)
1854 return 0;
1855 return 1;
1858 /* copies a block to clipboard file */
1859 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1861 int ret;
1862 gchar *tmp;
1863 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1864 ret = edit_save_block (edit, tmp, start, finish);
1865 g_free(tmp);
1866 return ret;
1870 void edit_paste_from_history (WEdit *edit)
1872 (void) edit;
1873 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
1876 int edit_copy_to_X_buf_cmd (WEdit * edit)
1878 long start_mark, end_mark;
1879 if (eval_marks (edit, &start_mark, &end_mark))
1880 return 0;
1881 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1882 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
1883 return 1;
1885 edit_mark_cmd (edit, 1);
1886 return 0;
1889 int edit_cut_to_X_buf_cmd (WEdit * edit)
1891 long start_mark, end_mark;
1892 if (eval_marks (edit, &start_mark, &end_mark))
1893 return 0;
1894 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1895 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
1896 return 1;
1898 edit_block_delete_cmd (edit);
1899 edit_mark_cmd (edit, 1);
1900 return 0;
1903 void edit_paste_from_X_buf_cmd (WEdit * edit)
1905 gchar *tmp;
1906 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1907 edit_insert_file (edit, tmp);
1908 g_free(tmp);
1913 * Ask user for the line and go to that line.
1914 * Negative numbers mean line from the end (i.e. -1 is the last line).
1916 void
1917 edit_goto_cmd (WEdit *edit)
1919 char *f;
1920 static long line = 0; /* line as typed, saved as default */
1921 long l;
1922 char *error;
1923 char s[32];
1925 g_snprintf (s, sizeof (s), "%ld", line);
1926 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
1927 line ? s : "");
1928 if (!f)
1929 return;
1931 if (!*f) {
1932 g_free (f);
1933 return;
1936 l = strtol (f, &error, 0);
1937 if (*error) {
1938 g_free (f);
1939 return;
1942 line = l;
1943 if (l < 0)
1944 l = edit->total_lines + l + 2;
1945 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
1946 edit_move_to_line (edit, l - 1);
1947 edit->force |= REDRAW_COMPLETELY;
1948 g_free (f);
1952 /* Return 1 on success */
1954 edit_save_block_cmd (WEdit *edit)
1956 long start_mark, end_mark;
1957 char *exp, *tmp;
1959 if (eval_marks (edit, &start_mark, &end_mark))
1960 return 1;
1962 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1963 exp =
1964 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
1965 MC_HISTORY_EDIT_SAVE_BLOCK,
1966 tmp);
1967 g_free(tmp);
1968 edit_push_action (edit, KEY_PRESS + edit->start_display);
1969 if (exp) {
1970 if (!*exp) {
1971 g_free (exp);
1972 return 0;
1973 } else {
1974 if (edit_save_block (edit, exp, start_mark, end_mark)) {
1975 g_free (exp);
1976 edit->force |= REDRAW_COMPLETELY;
1977 return 1;
1978 } else {
1979 g_free (exp);
1980 edit_error_dialog (_(" Save Block "),
1981 get_sys_error (_
1982 (" Cannot save file. ")));
1986 edit->force |= REDRAW_COMPLETELY;
1987 return 0;
1991 /* returns 1 on success */
1993 edit_insert_file_cmd (WEdit *edit)
1995 gchar *tmp;
1996 char *exp;
1998 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1999 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2000 MC_HISTORY_EDIT_INSERT_FILE,
2001 tmp);
2002 g_free(tmp);
2003 edit_push_action (edit, KEY_PRESS + edit->start_display);
2004 if (exp) {
2005 if (!*exp) {
2006 g_free (exp);
2007 return 0;
2008 } else {
2009 if (edit_insert_file (edit, exp)) {
2010 g_free (exp);
2011 edit->force |= REDRAW_COMPLETELY;
2012 return 1;
2013 } else {
2014 g_free (exp);
2015 edit_error_dialog (_(" Insert File "),
2016 get_sys_error (_
2017 (" Cannot insert file. ")));
2021 edit->force |= REDRAW_COMPLETELY;
2022 return 0;
2025 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2026 int edit_sort_cmd (WEdit * edit)
2028 static char *old = 0;
2029 char *exp, *tmp;
2030 long start_mark, end_mark;
2031 int e;
2033 if (eval_marks (edit, &start_mark, &end_mark)) {
2034 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2035 return 0;
2038 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2039 edit_save_block (edit, tmp, start_mark, end_mark);
2040 g_free(tmp);
2042 exp = input_dialog (_(" Run Sort "),
2043 _(" Enter sort options (see manpage) separated by whitespace: "),
2044 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2046 if (!exp)
2047 return 1;
2048 g_free (old);
2049 old = exp;
2050 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2051 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2052 e = system (tmp);
2053 g_free(tmp);
2054 if (e) {
2055 if (e == -1 || e == 127) {
2056 edit_error_dialog (_(" Sort "),
2057 get_sys_error (_(" Cannot execute sort command ")));
2058 } else {
2059 char q[8];
2060 sprintf (q, "%d ", e);
2061 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
2062 edit_error_dialog (_(" Sort "), tmp);
2063 g_free(tmp);
2065 return -1;
2068 edit->force |= REDRAW_COMPLETELY;
2070 if (edit_block_delete_cmd (edit))
2071 return 1;
2072 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2073 edit_insert_file (edit, tmp);
2074 g_free(tmp);
2075 return 0;
2079 * Ask user for a command, execute it and paste its output back to the
2080 * editor.
2083 edit_ext_cmd (WEdit *edit)
2085 char *exp, *tmp;
2086 int e;
2088 exp =
2089 input_dialog (_("Paste output of external command"),
2090 _("Enter shell command(s):"),
2091 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2093 if (!exp)
2094 return 1;
2096 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2097 e = system (tmp);
2098 g_free(tmp);
2099 g_free (exp);
2101 if (e) {
2102 edit_error_dialog (_("External command"),
2103 get_sys_error (_("Cannot execute command")));
2104 return -1;
2107 edit->force |= REDRAW_COMPLETELY;
2108 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2109 edit_insert_file (edit, tmp);
2110 g_free(tmp);
2111 return 0;
2114 /* if block is 1, a block must be highlighted and the shell command
2115 processes it. If block is 0 the shell command is a straight system
2116 command, that just produces some output which is to be inserted */
2117 void
2118 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2120 long start_mark, end_mark;
2121 char buf[BUFSIZ];
2122 FILE *script_home = NULL;
2123 FILE *script_src = NULL;
2124 FILE *block_file = NULL;
2125 gchar *o, *h, *b, *tmp;
2126 char *quoted_name = NULL;
2128 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2129 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2130 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2132 if (!(script_home = fopen (h, "r"))) {
2133 if (!(script_home = fopen (h, "w"))) {
2134 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2135 edit_error_dialog ("", get_sys_error (tmp));
2136 g_free(tmp);
2137 goto edit_block_process_cmd__EXIT;
2139 if (!(script_src = fopen (o, "r"))) {
2140 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2141 if (!(script_src = fopen (o, "r"))) {
2142 fclose (script_home);
2143 unlink (h);
2144 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2145 edit_error_dialog ("", get_sys_error (tmp));
2146 g_free(tmp);
2147 goto edit_block_process_cmd__EXIT;
2150 while (fgets (buf, sizeof (buf), script_src))
2151 fputs (buf, script_home);
2152 if (fclose (script_home)) {
2153 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2154 edit_error_dialog ("", get_sys_error (tmp));
2155 g_free(tmp);
2156 goto edit_block_process_cmd__EXIT;
2158 chmod (h, 0700);
2159 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2160 edit_error_dialog ("", get_sys_error (tmp));
2161 g_free(tmp);
2164 open_error_pipe ();
2166 if (block) { /* for marked block run indent formatter */
2167 if (eval_marks (edit, &start_mark, &end_mark)) {
2168 edit_error_dialog (_("Process block"),
2170 (" You must first highlight a block of text. "));
2171 goto edit_block_process_cmd__EXIT;
2173 edit_save_block (edit, b, start_mark, end_mark);
2174 quoted_name = name_quote (edit->filename, 0);
2176 * Run script.
2177 * Initial space is to avoid polluting bash history.
2178 * Arguments:
2179 * $1 - name of the edited file (to check its extension etc).
2180 * $2 - file containing the current block.
2181 * $3 - file where error messages should be put
2182 * (for compatibility with old scripts).
2184 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2185 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2186 system (tmp);
2187 g_free(tmp);
2188 } else {
2190 * No block selected, just execute the command for the file.
2191 * Arguments:
2192 * $1 - name of the edited file.
2194 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2195 quoted_name, (char *) NULL);
2196 system (tmp);
2197 g_free(tmp);
2199 g_free (quoted_name);
2200 close_error_pipe (D_NORMAL, NULL);
2202 edit_refresh_cmd (edit);
2203 edit->force |= REDRAW_COMPLETELY;
2205 /* insert result block */
2206 if (block) {
2207 if (edit_block_delete_cmd (edit))
2208 goto edit_block_process_cmd__EXIT;
2209 edit_insert_file (edit, b);
2210 if ((block_file = fopen (b, "w")))
2211 fclose (block_file);
2212 goto edit_block_process_cmd__EXIT;
2214 edit_block_process_cmd__EXIT:
2215 g_free(b);
2216 g_free(h);
2217 g_free(o);
2218 return;
2221 /* prints at the cursor */
2222 /* returns the number of chars printed */
2223 int edit_print_string (WEdit * e, const char *s)
2225 int i = 0;
2226 while (s[i])
2227 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2228 e->force |= REDRAW_COMPLETELY;
2229 edit_update_screen (e);
2230 return i;
2234 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2236 FILE *p = 0;
2237 char *s;
2239 to = name_quote (to, 0);
2240 subject = name_quote (subject, 0);
2241 cc = name_quote (cc, 0);
2242 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2243 g_free (to);
2244 g_free (subject);
2245 g_free (cc);
2247 if (s) {
2248 p = popen (s, "w");
2249 g_free (s);
2252 if (p) {
2253 long i;
2254 for (i = 0; i < edit->last_byte; i++)
2255 fputc (edit_get_byte (edit, i), p);
2256 pclose (p);
2260 #define MAIL_DLG_HEIGHT 12
2262 void edit_mail_dialog (WEdit * edit)
2264 char *tmail_to;
2265 char *tmail_subject;
2266 char *tmail_cc;
2268 static char *mail_cc_last = 0;
2269 static char *mail_subject_last = 0;
2270 static char *mail_to_last = 0;
2272 QuickWidget quick_widgets[] =
2274 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2275 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2276 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2277 /* 3 */ QUICK_LABEL (2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to")),
2278 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2", &tmail_subject),
2279 /* 5 */ QUICK_LABEL (2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject")),
2280 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2281 /* 7 */ QUICK_LABEL (2, 50, 3, MAIL_DLG_HEIGHT, N_(" To")),
2282 /* 8 */ QUICK_LABEL (2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>")),
2283 QUICK_END
2286 QuickDialog Quick_input =
2288 50, MAIL_DLG_HEIGHT, -1, -1, N_(" Mail "),
2289 "[Input Line Keys]", quick_widgets, FALSE
2292 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2293 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2294 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2296 if (quick_dialog (&Quick_input) != B_CANCEL) {
2297 g_free (mail_cc_last);
2298 g_free (mail_subject_last);
2299 g_free (mail_to_last);
2300 mail_cc_last = tmail_cc;
2301 mail_subject_last = tmail_subject;
2302 mail_to_last = tmail_to;
2303 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2308 /*******************/
2309 /* Word Completion */
2310 /*******************/
2312 static gboolean is_break_char(char c)
2314 return (isspace(c) || strchr("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2317 /* find first character of current word */
2318 static int edit_find_word_start (WEdit *edit, long *word_start, gsize *word_len)
2320 int c, last;
2321 gsize i;
2323 /* return if at begin of file */
2324 if (edit->curs1 <= 0)
2325 return 0;
2327 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2328 /* return if not at end or in word */
2329 if (is_break_char(c))
2330 return 0;
2332 /* search start of word to be completed */
2333 for (i = 2;; i++) {
2334 /* return if at begin of file */
2335 if (edit->curs1 - i < 0)
2336 return 0;
2338 last = c;
2339 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2341 if (is_break_char(c)) {
2342 /* return if word starts with digit */
2343 if (isdigit (last))
2344 return 0;
2346 *word_start = edit->curs1 - (i - 1); /* start found */
2347 *word_len = i - 1;
2348 break;
2351 /* success */
2352 return 1;
2355 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2357 /* collect the possible completions */
2358 static gsize
2359 edit_collect_completions (WEdit *edit, long start, gsize word_len,
2360 char *match_expr, struct selection *compl,
2361 gsize *num)
2363 gsize len = 0;
2364 gsize max_len = 0;
2365 gsize i;
2366 int skip;
2367 GString *temp;
2368 mc_search_t *srch;
2370 long last_byte;
2372 srch = mc_search_new(match_expr, -1);
2373 if (srch == NULL)
2374 return 0;
2376 if (mc_config_get_bool(mc_main_config, CONFIG_APP_SECTION, "editor_wordcompletion_collect_entire_file", 0)){
2377 last_byte = edit->last_byte;
2378 } else {
2379 last_byte = start;
2382 srch->search_type = MC_SEARCH_T_REGEX;
2383 srch->is_case_sentitive = TRUE;
2384 srch->search_fn = edit_search_cmd_callback;
2386 /* collect max MAX_WORD_COMPLETIONS completions */
2387 start = -1;
2388 while (1) {
2389 /* get next match */
2390 if (mc_search_run (srch, (void *) edit, start+1, last_byte, &len) == FALSE)
2391 break;
2392 start = srch->normal_offset;
2394 /* add matched completion if not yet added */
2395 temp = g_string_new("");
2396 for (i = 0; i < len; i++){
2397 skip = edit_get_byte(edit, start+i);
2398 if (isspace(skip))
2399 continue;
2400 g_string_append_c (temp, skip);
2403 skip = 0;
2405 for (i = 0; i < (gsize) *num; i++) {
2406 if (strncmp
2408 (char *) &compl[i].text[word_len],
2409 (char *) &temp->str[word_len],
2410 max (len, compl[i].len) - (gsize)word_len
2411 ) == 0) {
2412 struct selection this = compl[i];
2413 for (++i; i < *num; i++) {
2414 compl[i - 1] = compl[i];
2416 compl[*num - 1] = this;
2417 skip = 1;
2418 break; /* skip it, already added */
2421 if (skip) {
2422 g_string_free(temp, TRUE);
2423 continue;
2425 if (*num == MAX_WORD_COMPLETIONS && MAX_WORD_COMPLETIONS) {
2426 g_free(compl[0].text);
2427 for (i = 1; i < *num; i++) {
2428 compl[i - 1] = compl[i];
2430 (*num)--;
2432 #ifdef HAVE_CHARSET
2434 GString *recoded;
2435 recoded = str_convert_to_display (temp->str);
2437 if (recoded && recoded->len){
2438 g_string_free(temp,TRUE);
2439 temp = recoded;
2440 } else
2441 g_string_free(recoded , TRUE);
2443 #endif
2444 compl[*num].text = temp->str;
2445 compl[*num].len = temp->len;
2446 (*num)++;
2447 start += len;
2448 g_string_free(temp, FALSE);
2450 /* note the maximal length needed for the completion dialog */
2451 if (len > max_len)
2452 max_len = len;
2454 mc_search_free(srch);
2455 return max_len;
2459 * Complete current word using regular expression search
2460 * backwards beginning at the current cursor position.
2462 void
2463 edit_complete_word_cmd (WEdit *edit)
2465 gsize i, max_len, word_len = 0, num_compl = 0;
2466 long word_start = 0;
2467 unsigned char *bufpos;
2468 char *match_expr;
2469 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2471 /* search start of word to be completed */
2472 if (!edit_find_word_start (edit, &word_start, &word_len))
2473 return;
2475 /* prepare match expression */
2476 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2477 [word_start & M_EDIT_BUF_SIZE];
2479 /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
2480 match_expr = g_strdup_printf ("(^|\\s+|\\b)%.*s[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+", word_len, bufpos);
2482 /* collect the possible completions */
2483 /* start search from begin to end of file */
2484 max_len =
2485 edit_collect_completions (edit, word_start, word_len, match_expr,
2486 (struct selection *) &compl, &num_compl);
2488 if (num_compl > 0) {
2489 /* insert completed word if there is only one match */
2490 if (num_compl == 1) {
2491 for (i = word_len; i < compl[0].len; i++)
2492 edit_insert (edit, *(compl[0].text + i));
2494 /* more than one possible completion => ask the user */
2495 else {
2496 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2497 /* !!! pressed again the selection dialog pops up, but that !!! */
2498 /* !!! seems to require a further internal state !!! */
2499 /*tty_beep (); */
2501 /* let the user select the preferred completion */
2502 editcmd_dialog_completion_show (edit, max_len, word_len,
2503 (struct selection *) &compl,
2504 num_compl);
2508 g_free (match_expr);
2509 /* release memory before return */
2510 for (i = 0; i < num_compl; i++)
2511 g_free (compl[i].text);
2515 void
2516 edit_select_codepage_cmd (WEdit *edit)
2518 #ifdef HAVE_CHARSET
2519 const char *cp_id = NULL;
2520 if (do_select_codepage ()) {
2521 cp_id = get_codepage_id (source_codepage >= 0 ?
2522 source_codepage : display_codepage);
2524 if (cp_id != NULL) {
2525 GIConv conv;
2526 conv = str_crt_conv_from (cp_id);
2527 if (conv != INVALID_CONV) {
2528 if (edit->converter != str_cnv_from_term)
2529 str_close_conv (edit->converter);
2530 edit->converter = conv;
2535 if (cp_id != NULL)
2536 edit->utf8 = str_isutf8 (cp_id);
2539 edit->force = REDRAW_COMPLETELY;
2540 edit_refresh_cmd (edit);
2541 #endif
2544 void
2545 edit_insert_literal_cmd (WEdit *edit)
2547 int char_for_insertion =
2548 editcmd_dialog_raw_key_query (_(" Insert Literal "),
2549 _(" Press any key: "), 0);
2550 edit_execute_key_command (edit, -1,
2551 ascii_alpha_to_cntrl (char_for_insertion));
2554 void
2555 edit_execute_macro_cmd (WEdit *edit)
2557 int command =
2558 CK_Macro (editcmd_dialog_raw_key_query
2559 (_(" Execute Macro "), _(" Press macro hotkey: "),
2560 1));
2561 if (command == CK_Macro (0))
2562 command = CK_Insert_Char;
2564 edit_execute_key_command (edit, command, -1);
2567 void
2568 edit_begin_end_macro_cmd(WEdit *edit)
2570 int command;
2572 /* edit is a pointer to the widget */
2573 if (edit) {
2574 command =
2575 edit->macro_i <
2576 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2577 edit_execute_key_command (edit, command, -1);
2582 edit_load_forward_cmd (WEdit *edit)
2584 if (edit->modified) {
2585 if (edit_query_dialog2
2586 (_("Warning"),
2587 _(" Current text was modified without a file save. \n"
2588 " Continue discards these changes. "), _("C&ontinue"),
2589 _("&Cancel"))) {
2590 edit->force |= REDRAW_COMPLETELY;
2591 return 0;
2594 if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
2595 if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
2596 return 1;
2598 edit_stack_iterator++;
2599 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2600 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2601 edit_history_moveto[edit_stack_iterator].line);
2602 return 0;
2603 } else {
2604 return 1;
2606 } else {
2607 return 1;
2612 edit_load_back_cmd (WEdit *edit)
2614 if (edit->modified) {
2615 if (edit_query_dialog2
2616 (_("Warning"),
2617 _(" Current text was modified without a file save. \n"
2618 " Continue discards these changes. "), _("C&ontinue"),
2619 _("&Cancel"))) {
2620 edit->force |= REDRAW_COMPLETELY;
2621 return 0;
2624 if ( edit_stack_iterator > 0 ) {
2625 edit_stack_iterator--;
2626 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2627 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2628 edit_history_moveto[edit_stack_iterator].line);
2629 return 0;
2630 } else {
2631 return 1;
2633 } else {
2634 return 1;
2638 void
2639 edit_get_match_keyword_cmd (WEdit *edit)
2641 gsize word_len = 0, max_len = 0;
2642 int num_def = 0;
2643 int i;
2644 long word_start = 0;
2645 unsigned char *bufpos;
2646 char *match_expr;
2647 char *path = NULL;
2648 char *ptr = NULL;
2649 char *tagfile = NULL;
2651 etags_hash_t def_hash[MAX_DEFINITIONS];
2653 for ( i = 0; i < MAX_DEFINITIONS; i++) {
2654 def_hash[i].filename = NULL;
2657 /* search start of word to be completed */
2658 if (!edit_find_word_start (edit, &word_start, &word_len))
2659 return;
2661 /* prepare match expression */
2662 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2663 [word_start & M_EDIT_BUF_SIZE];
2664 match_expr = g_strdup_printf ("%.*s", word_len, bufpos);
2666 ptr = g_get_current_dir ();
2667 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
2668 g_free (ptr);
2670 /* Recursive search file 'TAGS' in parent dirs */
2671 do {
2672 ptr = g_path_get_dirname (path);
2673 g_free(path); path = ptr;
2674 g_free (tagfile);
2675 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
2676 if ( exist_file (tagfile) )
2677 break;
2678 } while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
2680 if (tagfile){
2681 num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
2682 g_free (tagfile);
2684 g_free (path);
2686 max_len = MAX_WIDTH_DEF_DIALOG;
2687 word_len = 0;
2688 if ( num_def > 0 ) {
2689 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
2690 (etags_hash_t *) &def_hash,
2691 num_def);
2693 g_free (match_expr);
2696 void
2697 edit_move_block_to_right (WEdit * edit)
2699 long start_mark, end_mark;
2700 long cur_bol, start_bol;
2702 if ( eval_marks (edit, &start_mark, &end_mark) )
2703 return;
2705 start_bol = edit_bol (edit, start_mark);
2706 cur_bol = edit_bol (edit, end_mark - 1);
2707 do {
2708 edit_cursor_move (edit, cur_bol - edit->curs1);
2709 if ( option_fill_tabs_with_spaces ) {
2710 if ( option_fake_half_tabs ) {
2711 insert_spaces_tab (edit, 1);
2712 } else {
2713 insert_spaces_tab (edit, 0);
2715 } else {
2716 edit_insert (edit, '\t');
2718 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
2719 if ( cur_bol == 0 ) {
2720 break;
2722 cur_bol = edit_bol (edit, cur_bol - 1);
2723 } while (cur_bol >= start_bol) ;
2724 edit->force |= REDRAW_PAGE;
2727 void
2728 edit_move_block_to_left (WEdit * edit)
2730 long start_mark, end_mark;
2731 long cur_bol, start_bol;
2732 int i, del_tab_width;
2733 int next_char;
2735 if ( eval_marks (edit, &start_mark, &end_mark) )
2736 return;
2738 start_bol = edit_bol (edit, start_mark);
2739 cur_bol = edit_bol (edit, end_mark - 1);
2740 do {
2741 edit_cursor_move (edit, cur_bol - edit->curs1);
2742 if (option_fake_half_tabs) {
2743 del_tab_width = HALF_TAB_SIZE;
2744 } else {
2745 del_tab_width = option_tab_spacing;
2747 next_char = edit_get_byte (edit, edit->curs1);
2748 if ( next_char == '\t' ) {
2749 edit_delete (edit, 1);
2750 } else if ( next_char == ' ' ) {
2751 for (i = 1; i <= del_tab_width; i++) {
2752 if ( next_char == ' ' ) {
2753 edit_delete (edit, 1);
2755 next_char = edit_get_byte (edit, edit->curs1);
2758 if ( cur_bol == 0 ) {
2759 break;
2761 cur_bol = edit_bol (edit, cur_bol - 1);
2762 } while (cur_bol >= start_bol) ;
2763 edit->force |= REDRAW_PAGE;