x86_64: Cleanup of code for master
[midnight-commander.git] / src / editor / editcmd.c
blobf7e224b5ad0e5eebbc12604b99fff366f368ff86
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 */
54 #include "lib/vfs/mc-vfs/vfs.h"
56 #include "src/history.h"
57 #include "src/widget.h" /* listbox_new() */
58 #include "src/layout.h" /* clr_scr() */
59 #include "src/main.h" /* mc_home source_codepage */
60 #include "src/help.h" /* interactive_display() */
61 #include "src/wtools.h" /* message() */
62 #include "src/charsets.h"
63 #include "src/selcodepage.h"
64 #include "src/cmddef.h"
66 #include "src/editor/edit-impl.h"
67 #include "src/editor/editlock.h"
68 #include "src/editor/edit-widget.h"
69 #include "src/editor/editcmd_dialogs.h"
70 #include "src/editor/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 long 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 (void) edit;
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_search_options.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_search_options.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_search_options.backwards)
1453 end_mark = max(1, edit->curs1) - 1;
1455 if (edit_search_options.backwards) {
1456 search_end = end_mark;
1457 while ((int) search_start >= start_mark) {
1458 if (search_end > (off_t) (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 char *disp1 = NULL;
1521 char *disp2 = NULL;
1522 int replace_yes;
1523 long times_replaced = 0, last_search;
1524 gboolean once_found = FALSE;
1526 if (!edit) {
1527 g_free (saved1), saved1 = NULL;
1528 g_free (saved2), saved2 = NULL;
1529 return;
1532 last_search = edit->last_byte;
1534 edit->force |= REDRAW_COMPLETELY;
1536 if (again && !saved1 && !saved2)
1537 again = 0;
1539 if (again) {
1540 input1 = g_strdup (saved1 ? saved1 : "");
1541 input2 = g_strdup (saved2 ? saved2 : "");
1542 } else {
1543 char *tmp_inp1, *tmp_inp2;
1544 disp1 = edit_replace_cmd__conv_to_display (saved1 ? saved1 : (char *) "");
1545 disp2 = edit_replace_cmd__conv_to_display (saved2 ? saved2 : (char *) "");
1547 edit_push_action (edit, KEY_PRESS + edit->start_display);
1549 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1551 g_free (disp1);
1552 g_free (disp2);
1554 if (input1 == NULL || *input1 == '\0') {
1555 edit->force = REDRAW_COMPLETELY;
1556 goto cleanup;
1559 tmp_inp1 = input1; tmp_inp2 = input2;
1560 input1 = edit_replace_cmd__conv_to_input(input1);
1561 input2 = edit_replace_cmd__conv_to_input(input2);
1562 g_free(tmp_inp1); g_free(tmp_inp2);
1564 g_free (saved1), saved1 = g_strdup (input1);
1565 g_free (saved2), saved2 = g_strdup (input2);
1567 if (edit->search) {
1568 mc_search_free(edit->search);
1569 edit->search = NULL;
1573 if (!edit->search) {
1574 edit->search = mc_search_new(input1, -1);
1575 if (edit->search == NULL) {
1576 edit->search_start = edit->curs1;
1577 return;
1579 edit->search->search_type = edit_search_options.type;
1580 edit->search->is_all_charsets = edit_search_options.all_codepages;
1581 edit->search->is_case_sentitive = edit_search_options.case_sens;
1582 edit->search->whole_words = edit_search_options.whole_words;
1583 edit->search->search_fn = edit_search_cmd_callback;
1586 if (edit->found_len && edit->search_start == edit->found_start + 1
1587 && edit_search_options.backwards)
1588 edit->search_start--;
1590 if (edit->found_len && edit->search_start == edit->found_start - 1
1591 && !edit_search_options.backwards)
1592 edit->search_start++;
1594 do {
1595 gsize len = 0;
1596 long new_start;
1598 if (! editcmd_find(edit, &len)) {
1599 if (!(edit->search->error == MC_SEARCH_E_OK ||
1600 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND))) {
1601 edit_error_dialog (_ ("Search"), edit->search->error_str);
1603 break;
1605 once_found = TRUE;
1606 new_start = edit->search->normal_offset;
1608 edit->search_start = new_start = edit->search->normal_offset;
1609 /*returns negative on not found or error in pattern */
1611 if (edit->search_start >= 0) {
1612 guint i;
1614 edit->found_start = edit->search_start;
1615 i = edit->found_len = len;
1617 edit_cursor_move (edit, edit->search_start - edit->curs1);
1618 edit_scroll_screen_over_cursor (edit);
1620 replace_yes = 1;
1622 if (edit->replace_mode == 0) {
1623 int l;
1624 l = edit->curs_row - edit->num_widget_lines / 3;
1625 if (l > 0)
1626 edit_scroll_downward (edit, l);
1627 if (l < 0)
1628 edit_scroll_upward (edit, -l);
1630 edit_scroll_screen_over_cursor (edit);
1631 edit->force |= REDRAW_PAGE;
1632 edit_render_keypress (edit);
1634 /*so that undo stops at each query */
1635 edit_push_key_press (edit);
1636 /* and prompt 2/3 down */
1637 disp1 = edit_replace_cmd__conv_to_display (saved1);
1638 disp2 = edit_replace_cmd__conv_to_display (saved2);
1639 switch (editcmd_dialog_replace_prompt_show (edit, disp1, disp2, -1, -1)) {
1640 case B_ENTER:
1641 replace_yes = 1;
1642 break;
1643 case B_SKIP_REPLACE:
1644 replace_yes = 0;
1645 break;
1646 case B_REPLACE_ALL:
1647 edit->replace_mode=1;
1648 break;
1649 case B_CANCEL:
1650 replace_yes = 0;
1651 edit->replace_mode = -1;
1652 break;
1654 g_free (disp1);
1655 g_free (disp2);
1657 if (replace_yes) { /* delete then insert new */
1658 GString *repl_str, *tmp_str;
1659 tmp_str = g_string_new(input2);
1661 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1662 g_string_free(tmp_str, TRUE);
1663 if (edit->search->error != MC_SEARCH_E_OK)
1665 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1666 break;
1669 while (i--)
1670 edit_delete (edit, 1);
1672 while (++i < repl_str->len)
1673 edit_insert (edit, repl_str->str[i]);
1675 g_string_free(repl_str, TRUE);
1676 edit->found_len = i;
1678 /* so that we don't find the same string again */
1679 if (edit_search_options.backwards) {
1680 last_search = edit->search_start;
1681 edit->search_start--;
1682 } else {
1683 edit->search_start += i;
1684 last_search = edit->last_byte;
1686 edit_scroll_screen_over_cursor (edit);
1687 } else {
1688 const char *msg = _(" Replace ");
1689 /* try and find from right here for next search */
1690 edit->search_start = edit->curs1;
1691 edit_update_curs_col (edit);
1693 edit->force |= REDRAW_PAGE;
1694 edit_render_keypress (edit);
1695 if (times_replaced) {
1696 message (D_NORMAL, msg, _(" %ld replacements made. "),
1697 times_replaced);
1698 } else
1699 query_dialog (msg, _(" Search string not found "),
1700 D_NORMAL, 1, _("&OK"));
1701 edit->replace_mode = -1;
1703 } while (edit->replace_mode >= 0);
1705 edit->force = REDRAW_COMPLETELY;
1706 edit_scroll_screen_over_cursor (edit);
1707 cleanup:
1708 g_free (input1);
1709 g_free (input2);
1713 void edit_search_cmd (WEdit * edit, int again)
1715 char *search_string = NULL, *search_string_dup = NULL;
1717 gsize len = 0;
1719 if (!edit)
1720 return;
1722 if (edit->search != NULL) {
1723 search_string = g_strndup(edit->search->original, edit->search->original_len);
1724 search_string_dup = search_string;
1725 } else {
1726 GList *history;
1727 history = history_get (MC_HISTORY_SHARED_SEARCH);
1728 if (history != NULL && history->data != NULL) {
1729 search_string_dup = search_string = (char *) g_strdup(history->data);
1730 history = g_list_first (history);
1731 g_list_foreach (history, (GFunc) g_free, NULL);
1732 g_list_free (history);
1734 edit->search_start = edit->curs1;
1737 if (!again) {
1738 #ifdef HAVE_CHARSET
1739 GString *tmp;
1740 if (search_string && *search_string) {
1741 tmp = str_convert_to_display (search_string);
1743 g_free(search_string_dup);
1744 search_string_dup = NULL;
1746 if (tmp && tmp->len)
1747 search_string = search_string_dup = tmp->str;
1748 g_string_free (tmp, FALSE);
1750 #endif /* HAVE_CHARSET */
1751 editcmd_dialog_search_show (edit, &search_string);
1752 #ifdef HAVE_CHARSET
1753 if (search_string && *search_string) {
1754 tmp = str_convert_to_input (search_string);
1755 if (tmp && tmp->len)
1756 search_string = tmp->str;
1758 g_string_free (tmp, FALSE);
1760 if (search_string_dup)
1761 g_free(search_string_dup);
1763 #endif /* HAVE_CHARSET */
1765 edit_push_action (edit, KEY_PRESS + edit->start_display);
1767 if (!search_string) {
1768 edit->force |= REDRAW_COMPLETELY;
1769 edit_scroll_screen_over_cursor (edit);
1770 return;
1773 if (edit->search) {
1774 mc_search_free(edit->search);
1775 edit->search = NULL;
1779 if (!edit->search) {
1780 edit->search = mc_search_new(search_string, -1);
1781 if (edit->search == NULL) {
1782 edit->search_start = edit->curs1;
1783 return;
1785 edit->search->search_type = edit_search_options.type;
1786 edit->search->is_all_charsets = edit_search_options.all_codepages;
1787 edit->search->is_case_sentitive = edit_search_options.case_sens;
1788 edit->search->whole_words = edit_search_options.whole_words;
1789 edit->search->search_fn = edit_search_cmd_callback;
1792 if (search_create_bookmark) {
1793 edit_search_cmd_search_create_bookmark(edit);
1794 } else {
1795 if (edit->found_len && edit->search_start == edit->found_start + 1
1796 && edit_search_options.backwards)
1797 edit->search_start--;
1799 if (edit->found_len && edit->search_start == edit->found_start - 1
1800 && !edit_search_options.backwards)
1801 edit->search_start++;
1803 if (editcmd_find(edit, &len)) {
1804 edit->found_start = edit->search_start = edit->search->normal_offset;
1805 edit->found_len = len;
1806 edit->over_col = 0;
1807 edit_cursor_move (edit, edit->search_start - edit->curs1);
1808 edit_scroll_screen_over_cursor (edit);
1809 if (edit_search_options.backwards)
1810 edit->search_start--;
1811 else
1812 edit->search_start++;
1813 } else {
1814 edit->search_start = edit->curs1;
1815 if (edit->search->error_str)
1816 edit_error_dialog (_ ("Search"), edit->search->error_str);
1820 edit->force |= REDRAW_COMPLETELY;
1821 edit_scroll_screen_over_cursor (edit);
1826 * Check if it's OK to close the editor. If there are unsaved changes,
1827 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
1830 edit_ok_to_exit (WEdit *edit)
1832 if (!edit->modified)
1833 return 1;
1835 if (!edit_check_newline (edit))
1836 return 0;
1838 switch (edit_query_dialog3
1839 (_("Quit"), _(" File was modified, Save with exit? "),
1840 _("&Cancel quit"), _("&Yes"), _("&No"))) {
1841 case 1:
1842 edit_push_markers (edit);
1843 edit_set_markers (edit, 0, 0, 0, 0);
1844 if (!edit_save_cmd (edit))
1845 return 0;
1846 break;
1847 case 2:
1848 break;
1849 case 0:
1850 case -1:
1851 return 0;
1854 return 1;
1857 /* Return a null terminated length of text. Result must be g_free'd */
1858 static unsigned char *
1859 edit_get_block (WEdit *edit, long start, long finish, int *l)
1861 unsigned char *s, *r;
1862 r = s = g_malloc0 (finish - start + 1);
1863 if (column_highlighting) {
1864 *l = 0;
1865 /* copy from buffer, excluding chars that are out of the column 'margins' */
1866 while (start < finish) {
1867 int c;
1868 long x;
1869 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
1870 start);
1871 c = edit_get_byte (edit, start);
1872 if ((x >= edit->column1 && x < edit->column2)
1873 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1874 *s++ = c;
1875 (*l)++;
1877 start++;
1879 } else {
1880 *l = finish - start;
1881 while (start < finish)
1882 *s++ = edit_get_byte (edit, start++);
1884 *s = 0;
1885 return r;
1888 /* save block, returns 1 on success */
1890 edit_save_block (WEdit * edit, const char *filename, long start,
1891 long finish)
1893 int len, file;
1895 if ((file =
1896 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
1897 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
1898 return 0;
1900 if (column_highlighting) {
1901 int r;
1902 r = mc_write (file, VERTICAL_MAGIC, sizeof(VERTICAL_MAGIC));
1903 if (r > 0) {
1904 unsigned char *block, *p;
1905 p = block = edit_get_block (edit, start, finish, &len);
1906 while (len) {
1907 r = mc_write (file, p, len);
1908 if (r < 0)
1909 break;
1910 p += r;
1911 len -= r;
1913 g_free (block);
1915 } else {
1916 unsigned char *buf;
1917 int i = start, end;
1918 len = finish - start;
1919 buf = g_malloc0 (TEMP_BUF_LEN);
1920 while (start != finish) {
1921 end = min (finish, start + TEMP_BUF_LEN);
1922 for (; i < end; i++)
1923 buf[i - start] = edit_get_byte (edit, i);
1924 len -= mc_write (file, (char *) buf, end - start);
1925 start = end;
1927 g_free (buf);
1929 mc_close (file);
1930 if (len)
1931 return 0;
1932 return 1;
1935 /* copies a block to clipboard file */
1936 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1938 int ret;
1939 gchar *tmp;
1940 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1941 ret = edit_save_block (edit, tmp, start, finish);
1942 g_free(tmp);
1943 return ret;
1947 void edit_paste_from_history (WEdit *edit)
1949 (void) edit;
1950 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
1953 int edit_copy_to_X_buf_cmd (WEdit * edit)
1955 long start_mark, end_mark;
1956 if (eval_marks (edit, &start_mark, &end_mark))
1957 return 0;
1958 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1959 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
1960 return 1;
1962 edit_mark_cmd (edit, 1);
1963 return 0;
1966 int edit_cut_to_X_buf_cmd (WEdit * edit)
1968 long start_mark, end_mark;
1969 if (eval_marks (edit, &start_mark, &end_mark))
1970 return 0;
1971 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1972 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
1973 return 1;
1975 edit_block_delete_cmd (edit);
1976 edit_mark_cmd (edit, 1);
1977 return 0;
1980 void edit_paste_from_X_buf_cmd (WEdit * edit)
1982 gchar *tmp;
1983 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1984 edit_insert_file (edit, tmp);
1985 g_free(tmp);
1990 * Ask user for the line and go to that line.
1991 * Negative numbers mean line from the end (i.e. -1 is the last line).
1993 void
1994 edit_goto_cmd (WEdit *edit)
1996 char *f;
1997 static long line = 0; /* line as typed, saved as default */
1998 long l;
1999 char *error;
2000 char s[32];
2002 g_snprintf (s, sizeof (s), "%ld", line);
2003 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
2004 line ? s : "");
2005 if (!f)
2006 return;
2008 if (!*f) {
2009 g_free (f);
2010 return;
2013 l = strtol (f, &error, 0);
2014 if (*error) {
2015 g_free (f);
2016 return;
2019 line = l;
2020 if (l < 0)
2021 l = edit->total_lines + l + 2;
2022 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2023 edit_move_to_line (edit, l - 1);
2024 edit->force |= REDRAW_COMPLETELY;
2025 g_free (f);
2029 /* Return 1 on success */
2031 edit_save_block_cmd (WEdit *edit)
2033 long start_mark, end_mark;
2034 char *exp, *tmp;
2036 if (eval_marks (edit, &start_mark, &end_mark))
2037 return 1;
2039 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2040 exp =
2041 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
2042 MC_HISTORY_EDIT_SAVE_BLOCK,
2043 tmp);
2044 g_free(tmp);
2045 edit_push_action (edit, KEY_PRESS + edit->start_display);
2046 if (exp) {
2047 if (!*exp) {
2048 g_free (exp);
2049 return 0;
2050 } else {
2051 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2052 g_free (exp);
2053 edit->force |= REDRAW_COMPLETELY;
2054 return 1;
2055 } else {
2056 g_free (exp);
2057 edit_error_dialog (_(" Save Block "),
2058 get_sys_error (_
2059 (" Cannot save file. ")));
2063 edit->force |= REDRAW_COMPLETELY;
2064 return 0;
2068 /* returns 1 on success */
2070 edit_insert_file_cmd (WEdit *edit)
2072 gchar *tmp;
2073 char *exp;
2075 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2076 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2077 MC_HISTORY_EDIT_INSERT_FILE,
2078 tmp);
2079 g_free(tmp);
2080 edit_push_action (edit, KEY_PRESS + edit->start_display);
2081 if (exp) {
2082 if (!*exp) {
2083 g_free (exp);
2084 return 0;
2085 } else {
2086 if (edit_insert_file (edit, exp)) {
2087 g_free (exp);
2088 edit->force |= REDRAW_COMPLETELY;
2089 return 1;
2090 } else {
2091 g_free (exp);
2092 edit_error_dialog (_(" Insert File "),
2093 get_sys_error (_
2094 (" Cannot insert file. ")));
2098 edit->force |= REDRAW_COMPLETELY;
2099 return 0;
2102 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2103 int edit_sort_cmd (WEdit * edit)
2105 static char *old = 0;
2106 char *exp, *tmp;
2107 long start_mark, end_mark;
2108 int e;
2110 if (eval_marks (edit, &start_mark, &end_mark)) {
2111 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2112 return 0;
2115 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2116 edit_save_block (edit, tmp, start_mark, end_mark);
2117 g_free(tmp);
2119 exp = input_dialog (_(" Run Sort "),
2120 _(" Enter sort options (see manpage) separated by whitespace: "),
2121 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2123 if (!exp)
2124 return 1;
2125 g_free (old);
2126 old = exp;
2127 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2128 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2129 e = system (tmp);
2130 g_free(tmp);
2131 if (e) {
2132 if (e == -1 || e == 127) {
2133 edit_error_dialog (_(" Sort "),
2134 get_sys_error (_(" Cannot execute sort command ")));
2135 } else {
2136 char q[8];
2137 sprintf (q, "%d ", e);
2138 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
2139 edit_error_dialog (_(" Sort "), tmp);
2140 g_free(tmp);
2142 return -1;
2145 edit->force |= REDRAW_COMPLETELY;
2147 if (edit_block_delete_cmd (edit))
2148 return 1;
2149 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2150 edit_insert_file (edit, tmp);
2151 g_free(tmp);
2152 return 0;
2156 * Ask user for a command, execute it and paste its output back to the
2157 * editor.
2160 edit_ext_cmd (WEdit *edit)
2162 char *exp, *tmp;
2163 int e;
2165 exp =
2166 input_dialog (_("Paste output of external command"),
2167 _("Enter shell command(s):"),
2168 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2170 if (!exp)
2171 return 1;
2173 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2174 e = system (tmp);
2175 g_free(tmp);
2176 g_free (exp);
2178 if (e) {
2179 edit_error_dialog (_("External command"),
2180 get_sys_error (_("Cannot execute command")));
2181 return -1;
2184 edit->force |= REDRAW_COMPLETELY;
2185 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2186 edit_insert_file (edit, tmp);
2187 g_free(tmp);
2188 return 0;
2191 /* if block is 1, a block must be highlighted and the shell command
2192 processes it. If block is 0 the shell command is a straight system
2193 command, that just produces some output which is to be inserted */
2194 void
2195 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2197 long start_mark, end_mark;
2198 char buf[BUFSIZ];
2199 FILE *script_home = NULL;
2200 FILE *block_file = NULL;
2201 gchar *o, *h, *b, *tmp;
2202 char *quoted_name = NULL;
2204 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2205 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2206 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2208 script_home = fopen (h, "r");
2209 if (script_home == NULL) {
2210 FILE *script_src = NULL;
2212 script_home = fopen (h, "w");
2213 if (script_home == NULL) {
2214 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2215 edit_error_dialog ("", get_sys_error (tmp));
2216 g_free(tmp);
2217 goto edit_block_process_cmd__EXIT;
2220 script_src = fopen (o, "r");
2221 if (script_src == NULL) {
2222 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2223 script_src = fopen (o, "r");
2224 if (script_src == NULL) {
2225 fclose (script_home);
2226 unlink (h);
2227 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2228 edit_error_dialog ("", get_sys_error (tmp));
2229 g_free(tmp);
2230 goto edit_block_process_cmd__EXIT;
2233 while (fgets (buf, sizeof (buf), script_src))
2234 fputs (buf, script_home);
2235 fclose (script_src);
2237 if (fclose (script_home)) {
2238 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2239 edit_error_dialog ("", get_sys_error (tmp));
2240 g_free(tmp);
2241 goto edit_block_process_cmd__EXIT;
2243 chmod (h, 0700);
2244 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2245 edit_error_dialog ("", get_sys_error (tmp));
2246 g_free(tmp);
2249 open_error_pipe ();
2251 if (block) { /* for marked block run indent formatter */
2252 if (eval_marks (edit, &start_mark, &end_mark)) {
2253 edit_error_dialog (_("Process block"),
2255 (" You must first highlight a block of text. "));
2256 goto edit_block_process_cmd__EXIT;
2258 edit_save_block (edit, b, start_mark, end_mark);
2259 quoted_name = name_quote (edit->filename, 0);
2261 * Run script.
2262 * Initial space is to avoid polluting bash history.
2263 * Arguments:
2264 * $1 - name of the edited file (to check its extension etc).
2265 * $2 - file containing the current block.
2266 * $3 - file where error messages should be put
2267 * (for compatibility with old scripts).
2269 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2270 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2271 system (tmp);
2272 g_free(tmp);
2273 } else {
2275 * No block selected, just execute the command for the file.
2276 * Arguments:
2277 * $1 - name of the edited file.
2279 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2280 quoted_name, (char *) NULL);
2281 system (tmp);
2282 g_free(tmp);
2284 g_free (quoted_name);
2285 close_error_pipe (D_NORMAL, NULL);
2287 edit_refresh_cmd (edit);
2288 edit->force |= REDRAW_COMPLETELY;
2290 /* insert result block */
2291 if (block && !edit_block_delete_cmd (edit)) {
2292 edit_insert_file (edit, b);
2293 block_file = fopen (b, "w");
2294 if (block_file != NULL)
2295 fclose (block_file);
2298 edit_block_process_cmd__EXIT:
2299 g_free (b);
2300 g_free (h);
2301 g_free (o);
2304 /* prints at the cursor */
2305 /* returns the number of chars printed */
2306 int edit_print_string (WEdit * e, const char *s)
2308 size_t i = 0;
2309 while (s[i] != '\0')
2310 edit_execute_cmd (e, CK_Insert_Char, (unsigned char) s[i++]);
2311 e->force |= REDRAW_COMPLETELY;
2312 edit_update_screen (e);
2313 return i;
2317 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2319 FILE *p = 0;
2320 char *s;
2322 to = name_quote (to, 0);
2323 subject = name_quote (subject, 0);
2324 cc = name_quote (cc, 0);
2325 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2326 g_free (to);
2327 g_free (subject);
2328 g_free (cc);
2330 if (s) {
2331 p = popen (s, "w");
2332 g_free (s);
2335 if (p) {
2336 long i;
2337 for (i = 0; i < edit->last_byte; i++)
2338 fputc (edit_get_byte (edit, i), p);
2339 pclose (p);
2343 #define MAIL_DLG_HEIGHT 12
2345 void edit_mail_dialog (WEdit * edit)
2347 char *tmail_to;
2348 char *tmail_subject;
2349 char *tmail_cc;
2351 static char *mail_cc_last = 0;
2352 static char *mail_subject_last = 0;
2353 static char *mail_to_last = 0;
2355 QuickWidget quick_widgets[] =
2357 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2358 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2359 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2360 /* 3 */ QUICK_LABEL (2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to")),
2361 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2", &tmail_subject),
2362 /* 5 */ QUICK_LABEL (2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject")),
2363 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2364 /* 7 */ QUICK_LABEL (2, 50, 3, MAIL_DLG_HEIGHT, N_(" To")),
2365 /* 8 */ QUICK_LABEL (2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>")),
2366 QUICK_END
2369 QuickDialog Quick_input =
2371 50, MAIL_DLG_HEIGHT, -1, -1, N_(" Mail "),
2372 "[Input Line Keys]", quick_widgets, FALSE
2375 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2376 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2377 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2379 if (quick_dialog (&Quick_input) != B_CANCEL) {
2380 g_free (mail_cc_last);
2381 g_free (mail_subject_last);
2382 g_free (mail_to_last);
2383 mail_cc_last = tmail_cc;
2384 mail_subject_last = tmail_subject;
2385 mail_to_last = tmail_to;
2386 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2391 /*******************/
2392 /* Word Completion */
2393 /*******************/
2395 static gboolean is_break_char(char c)
2397 return (isspace(c) || strchr("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2400 /* find first character of current word */
2401 static int edit_find_word_start (WEdit *edit, long *word_start, gsize *word_len)
2403 int c, last;
2404 gsize i;
2406 /* return if at begin of file */
2407 if (edit->curs1 <= 0)
2408 return 0;
2410 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2411 /* return if not at end or in word */
2412 if (is_break_char(c))
2413 return 0;
2415 /* search start of word to be completed */
2416 for (i = 2;; i++) {
2417 /* return if at begin of file */
2418 if ((gsize)edit->curs1 < i)
2419 return 0;
2421 last = c;
2422 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2424 if (is_break_char(c)) {
2425 /* return if word starts with digit */
2426 if (isdigit (last))
2427 return 0;
2429 *word_start = edit->curs1 - (i - 1); /* start found */
2430 *word_len = i - 1;
2431 break;
2434 /* success */
2435 return 1;
2438 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2440 /* collect the possible completions */
2441 static gsize
2442 edit_collect_completions (WEdit *edit, long start, gsize word_len,
2443 char *match_expr, struct selection *compl,
2444 gsize *num)
2446 gsize len = 0;
2447 gsize max_len = 0;
2448 gsize i;
2449 int skip;
2450 GString *temp;
2451 mc_search_t *srch;
2453 long last_byte;
2455 srch = mc_search_new(match_expr, -1);
2456 if (srch == NULL)
2457 return 0;
2459 if (mc_config_get_bool(mc_main_config, CONFIG_APP_SECTION, "editor_wordcompletion_collect_entire_file", 0)){
2460 last_byte = edit->last_byte;
2461 } else {
2462 last_byte = start;
2465 srch->search_type = MC_SEARCH_T_REGEX;
2466 srch->is_case_sentitive = TRUE;
2467 srch->search_fn = edit_search_cmd_callback;
2469 /* collect max MAX_WORD_COMPLETIONS completions */
2470 start = -1;
2471 while (1) {
2472 /* get next match */
2473 if (mc_search_run (srch, (void *) edit, start+1, last_byte, &len) == FALSE)
2474 break;
2475 start = srch->normal_offset;
2477 /* add matched completion if not yet added */
2478 temp = g_string_new("");
2479 for (i = 0; i < len; i++){
2480 skip = edit_get_byte(edit, start+i);
2481 if (isspace(skip))
2482 continue;
2483 g_string_append_c (temp, skip);
2486 skip = 0;
2488 for (i = 0; i < (gsize) *num; i++) {
2489 if (strncmp
2491 (char *) &compl[i].text[word_len],
2492 (char *) &temp->str[word_len],
2493 max (len, compl[i].len) - (gsize)word_len
2494 ) == 0) {
2495 struct selection this = compl[i];
2496 for (++i; i < *num; i++) {
2497 compl[i - 1] = compl[i];
2499 compl[*num - 1] = this;
2500 skip = 1;
2501 break; /* skip it, already added */
2504 if (skip) {
2505 g_string_free(temp, TRUE);
2506 continue;
2508 if (*num == MAX_WORD_COMPLETIONS && MAX_WORD_COMPLETIONS) {
2509 g_free(compl[0].text);
2510 for (i = 1; i < *num; i++) {
2511 compl[i - 1] = compl[i];
2513 (*num)--;
2515 #ifdef HAVE_CHARSET
2517 GString *recoded;
2518 recoded = str_convert_to_display (temp->str);
2520 if (recoded && recoded->len){
2521 g_string_free(temp,TRUE);
2522 temp = recoded;
2523 } else
2524 g_string_free(recoded , TRUE);
2526 #endif
2527 compl[*num].text = temp->str;
2528 compl[*num].len = temp->len;
2529 (*num)++;
2530 start += len;
2531 g_string_free(temp, FALSE);
2533 /* note the maximal length needed for the completion dialog */
2534 if (len > max_len)
2535 max_len = len;
2537 mc_search_free(srch);
2538 return max_len;
2542 * Complete current word using regular expression search
2543 * backwards beginning at the current cursor position.
2545 void
2546 edit_complete_word_cmd (WEdit *edit)
2548 gsize i, max_len, word_len = 0, num_compl = 0;
2549 long word_start = 0;
2550 unsigned char *bufpos;
2551 char *match_expr;
2552 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2554 /* search start of word to be completed */
2555 if (!edit_find_word_start (edit, &word_start, &word_len))
2556 return;
2558 /* prepare match expression */
2559 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2560 [word_start & M_EDIT_BUF_SIZE];
2562 /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
2563 match_expr = g_strdup_printf ("(^|\\s+|\\b)%.*s[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+", (int)word_len, bufpos);
2565 /* collect the possible completions */
2566 /* start search from begin to end of file */
2567 max_len =
2568 edit_collect_completions (edit, word_start, word_len, match_expr,
2569 (struct selection *) &compl, &num_compl);
2571 if (num_compl > 0) {
2572 /* insert completed word if there is only one match */
2573 if (num_compl == 1) {
2574 for (i = word_len; i < compl[0].len; i++)
2575 edit_insert (edit, *(compl[0].text + i));
2577 /* more than one possible completion => ask the user */
2578 else {
2579 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2580 /* !!! pressed again the selection dialog pops up, but that !!! */
2581 /* !!! seems to require a further internal state !!! */
2582 /*tty_beep (); */
2584 /* let the user select the preferred completion */
2585 editcmd_dialog_completion_show (edit, max_len, word_len,
2586 (struct selection *) &compl,
2587 num_compl);
2591 g_free (match_expr);
2592 /* release memory before return */
2593 for (i = 0; i < num_compl; i++)
2594 g_free (compl[i].text);
2597 void
2598 edit_select_codepage_cmd (WEdit *edit)
2600 #ifdef HAVE_CHARSET
2601 const char *cp_id = NULL;
2602 if (do_select_codepage ()) {
2603 cp_id = get_codepage_id (source_codepage >= 0 ?
2604 source_codepage : display_codepage);
2606 if (cp_id != NULL) {
2607 GIConv conv;
2608 conv = str_crt_conv_from (cp_id);
2609 if (conv != INVALID_CONV) {
2610 if (edit->converter != str_cnv_from_term)
2611 str_close_conv (edit->converter);
2612 edit->converter = conv;
2616 if (cp_id != NULL)
2617 edit->utf8 = str_isutf8 (cp_id);
2620 edit->force = REDRAW_COMPLETELY;
2621 edit_refresh_cmd (edit);
2622 #else
2623 (void) edit;
2624 #endif
2627 void
2628 edit_insert_literal_cmd (WEdit *edit)
2630 int char_for_insertion =
2631 editcmd_dialog_raw_key_query (_(" Insert Literal "),
2632 _(" Press any key: "), 0);
2633 edit_execute_key_command (edit, -1,
2634 ascii_alpha_to_cntrl (char_for_insertion));
2637 void
2638 edit_execute_macro_cmd (WEdit *edit)
2640 int command =
2641 CK_Macro (editcmd_dialog_raw_key_query
2642 (_(" Execute Macro "), _(" Press macro hotkey: "),
2643 1));
2644 if (command == CK_Macro (0))
2645 command = CK_Insert_Char;
2647 edit_execute_key_command (edit, command, -1);
2650 void
2651 edit_begin_end_macro_cmd (WEdit *edit)
2653 /* edit is a pointer to the widget */
2654 if (edit) {
2655 unsigned long command = edit->macro_i < 0
2656 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2657 edit_execute_key_command (edit, command, -1);
2662 edit_load_forward_cmd (WEdit *edit)
2664 if (edit->modified) {
2665 if (edit_query_dialog2
2666 (_("Warning"),
2667 _(" Current text was modified without a file save. \n"
2668 " Continue discards these changes. "), _("C&ontinue"),
2669 _("&Cancel"))) {
2670 edit->force |= REDRAW_COMPLETELY;
2671 return 0;
2674 if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
2675 if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
2676 return 1;
2678 edit_stack_iterator++;
2679 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2680 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2681 edit_history_moveto[edit_stack_iterator].line);
2682 return 0;
2683 } else {
2684 return 1;
2686 } else {
2687 return 1;
2692 edit_load_back_cmd (WEdit *edit)
2694 if (edit->modified) {
2695 if (edit_query_dialog2
2696 (_("Warning"),
2697 _(" Current text was modified without a file save. \n"
2698 " Continue discards these changes. "), _("C&ontinue"),
2699 _("&Cancel"))) {
2700 edit->force |= REDRAW_COMPLETELY;
2701 return 0;
2704 if ( edit_stack_iterator > 0 ) {
2705 edit_stack_iterator--;
2706 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2707 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2708 edit_history_moveto[edit_stack_iterator].line);
2709 return 0;
2710 } else {
2711 return 1;
2713 } else {
2714 return 1;
2718 void
2719 edit_get_match_keyword_cmd (WEdit *edit)
2721 gsize word_len = 0, max_len = 0;
2722 int num_def = 0;
2723 int i;
2724 long word_start = 0;
2725 unsigned char *bufpos;
2726 char *match_expr;
2727 char *path = NULL;
2728 char *ptr = NULL;
2729 char *tagfile = NULL;
2731 etags_hash_t def_hash[MAX_DEFINITIONS];
2733 for ( i = 0; i < MAX_DEFINITIONS; i++) {
2734 def_hash[i].filename = NULL;
2737 /* search start of word to be completed */
2738 if (!edit_find_word_start (edit, &word_start, &word_len))
2739 return;
2741 /* prepare match expression */
2742 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2743 [word_start & M_EDIT_BUF_SIZE];
2744 match_expr = g_strdup_printf ("%.*s", (int)word_len, bufpos);
2746 ptr = g_get_current_dir ();
2747 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
2748 g_free (ptr);
2750 /* Recursive search file 'TAGS' in parent dirs */
2751 do {
2752 ptr = g_path_get_dirname (path);
2753 g_free(path); path = ptr;
2754 g_free (tagfile);
2755 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
2756 if ( exist_file (tagfile) )
2757 break;
2758 } while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
2760 if (tagfile){
2761 num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
2762 g_free (tagfile);
2764 g_free (path);
2766 max_len = MAX_WIDTH_DEF_DIALOG;
2767 word_len = 0;
2768 if ( num_def > 0 ) {
2769 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
2770 (etags_hash_t *) &def_hash,
2771 num_def);
2773 g_free (match_expr);
2776 void
2777 edit_move_block_to_right (WEdit * edit)
2779 long start_mark, end_mark;
2780 long cur_bol, start_bol;
2782 if ( eval_marks (edit, &start_mark, &end_mark) )
2783 return;
2785 start_bol = edit_bol (edit, start_mark);
2786 cur_bol = edit_bol (edit, end_mark - 1);
2787 do {
2788 edit_cursor_move (edit, cur_bol - edit->curs1);
2789 if ( option_fill_tabs_with_spaces ) {
2790 if ( option_fake_half_tabs ) {
2791 insert_spaces_tab (edit, 1);
2792 } else {
2793 insert_spaces_tab (edit, 0);
2795 } else {
2796 edit_insert (edit, '\t');
2798 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
2799 if ( cur_bol == 0 ) {
2800 break;
2802 cur_bol = edit_bol (edit, cur_bol - 1);
2803 } while (cur_bol >= start_bol) ;
2804 edit->force |= REDRAW_PAGE;
2807 void
2808 edit_move_block_to_left (WEdit * edit)
2810 long start_mark, end_mark;
2811 long cur_bol, start_bol;
2812 int i, del_tab_width;
2813 int next_char;
2815 if ( eval_marks (edit, &start_mark, &end_mark) )
2816 return;
2818 start_bol = edit_bol (edit, start_mark);
2819 cur_bol = edit_bol (edit, end_mark - 1);
2820 do {
2821 edit_cursor_move (edit, cur_bol - edit->curs1);
2822 if (option_fake_half_tabs) {
2823 del_tab_width = HALF_TAB_SIZE;
2824 } else {
2825 del_tab_width = option_tab_spacing;
2827 next_char = edit_get_byte (edit, edit->curs1);
2828 if ( next_char == '\t' ) {
2829 edit_delete (edit, 1);
2830 } else if ( next_char == ' ' ) {
2831 for (i = 1; i <= del_tab_width; i++) {
2832 if ( next_char == ' ' ) {
2833 edit_delete (edit, 1);
2835 next_char = edit_get_byte (edit, edit->curs1);
2838 if ( cur_bol == 0 ) {
2839 break;
2841 cur_bol = edit_bol (edit, cur_bol - 1);
2842 } while (cur_bol >= start_bol) ;
2843 edit->force |= REDRAW_PAGE;