Merge branch '1708_ftp_permission'
[midnight-commander.git] / edit / editcmd.c
blob48f1db6b5f5d7687fc6be9d49c3da4beb6d7e04e
1 /* editor high level editing commands
3 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007 Free Software Foundation, Inc.
6 Authors: 1996, 1997 Paul Sheer
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
25 /** \file
26 * \brief Source: editor high level editing commands
27 * \author Paul Sheer
28 * \date 1996, 1997
31 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
33 #include <config.h>
35 #include <assert.h>
36 #include <ctype.h>
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <sys/stat.h>
45 #include <stdlib.h>
46 #include <fcntl.h>
48 #include "../src/global.h"
50 #include "../src/tty/tty.h"
51 #include "../src/tty/key.h" /* XCTRL */
53 #include "../src/history.h"
54 #include "../src/widget.h" /* listbox_new() */
55 #include "../src/layout.h" /* clr_scr() */
56 #include "../src/main.h" /* mc_home source_codepage */
57 #include "../src/help.h" /* interactive_display() */
58 #include "../src/wtools.h" /* message() */
59 #include "../src/charsets.h"
60 #include "../src/selcodepage.h"
61 #include "../src/strutil.h" /* utf string functions */
62 #include "../src/mcconfig/mcconfig.h"
63 #include "../src/skin/skin.h" /* mc_skin_color_get */
65 #include "../edit/edit-impl.h"
66 #include "../edit/edit.h"
67 #include "../edit/editlock.h"
68 #include "../src/cmddef.h"
69 #include "../edit/edit-widget.h"
70 #include "../edit/editcmd_dialogs.h"
71 #include "../edit/etags.h"
73 /* globals: */
75 /* search and replace: */
76 int search_create_bookmark = 0;
77 /* static int search_in_all_charsets = 0; */
79 /* queries on a save */
80 int edit_confirm_save = 1;
82 static int edit_save_cmd (WEdit *edit);
83 static unsigned char *edit_get_block (WEdit *edit, long start,
84 long finish, int *l);
86 static void
87 edit_search_cmd_search_create_bookmark(WEdit * edit)
89 int found = 0, books = 0;
90 int l = 0, l_last = -1;
91 long q = 0;
92 gsize len = 0;
94 search_create_bookmark = 0;
95 book_mark_flush (edit, -1);
97 for (;;) {
98 if (!mc_search_run(edit->search, (void *) edit, q, edit->last_byte, &len))
99 break;
100 if (found == 0)
101 edit->search_start = edit->search->normal_offset;
102 found++;
103 l += edit_count_lines (edit, q, edit->search->normal_offset);
104 if (l != l_last) {
105 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
106 books++;
108 l_last = l;
109 q = edit->search->normal_offset + 1;
112 if (found == 0) {
113 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
114 } else {
115 edit_cursor_move (edit, edit->search_start - edit->curs1);
116 edit_scroll_screen_over_cursor (edit);
120 static int
121 edit_search_cmd_callback(const void *user_data, gsize char_offset)
123 return edit_get_byte ((WEdit * )user_data, (long) char_offset);
126 void edit_help_cmd (WEdit * edit)
128 interactive_display (NULL, "[Internal File Editor]");
129 edit->force |= REDRAW_COMPLETELY;
132 void
133 edit_refresh_cmd (WEdit * edit)
135 #ifdef HAVE_SLANG
136 int color;
138 edit_get_syntax_color (edit, -1, &color);
139 tty_touch_screen ();
140 mc_refresh ();
141 #else
142 clr_scr ();
143 repaint_screen ();
144 #endif /* !HAVE_SLANG */
145 tty_keypad (TRUE);
148 /* If 0 (quick save) then a) create/truncate <filename> file,
149 b) save to <filename>;
150 if 1 (safe save) then a) save to <tempnam>,
151 b) rename <tempnam> to <filename>;
152 if 2 (do backups) then a) save to <tempnam>,
153 b) rename <filename> to <filename.backup_ext>,
154 c) rename <tempnam> to <filename>. */
156 /* returns 0 on error, -1 on abort */
157 static int
158 edit_save_file (WEdit *edit, const char *filename)
160 char *p;
161 gchar *tmp;
162 long filelen = 0;
163 char *savename = 0;
164 gchar *real_filename;
165 int this_save_mode, fd = -1;
167 if (!filename)
168 return 0;
169 if (!*filename)
170 return 0;
172 if (*filename != PATH_SEP && edit->dir) {
173 real_filename = concat_dir_and_file (edit->dir, filename);
174 } else {
175 real_filename = g_strdup(filename);
178 this_save_mode = option_save_mode;
179 if (this_save_mode != EDIT_QUICK_SAVE) {
180 if (!vfs_file_is_local (real_filename) ||
181 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1) {
183 * The file does not exists yet, so no safe save or
184 * backup are necessary.
186 this_save_mode = EDIT_QUICK_SAVE;
188 if (fd != -1)
189 mc_close (fd);
192 if (this_save_mode == EDIT_QUICK_SAVE &&
193 !edit->skip_detach_prompt) {
194 int rv;
195 struct stat sb;
197 rv = mc_stat (real_filename, &sb);
198 if (rv == 0 && sb.st_nlink > 1) {
199 rv = edit_query_dialog3 (_("Warning"),
200 _(" File has hard-links. Detach before saving? "),
201 _("&Yes"), _("&No"), _("&Cancel"));
202 switch (rv) {
203 case 0:
204 this_save_mode = EDIT_SAFE_SAVE;
205 /* fallthrough */
206 case 1:
207 edit->skip_detach_prompt = 1;
208 break;
209 default:
210 g_free(real_filename);
211 return -1;
215 /* Prevent overwriting changes from other editor sessions. */
216 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
218 /* The default action is "Cancel". */
219 query_set_sel(1);
221 rv = edit_query_dialog2 (
222 _("Warning"),
223 _("The file has been modified in the meantime. Save anyway?"),
224 _("&Yes"),
225 _("&Cancel"));
226 if (rv != 0){
227 g_free(real_filename);
228 return -1;
233 if (this_save_mode != EDIT_QUICK_SAVE) {
234 char *savedir, *saveprefix;
235 const char *slashpos;
236 slashpos = strrchr (real_filename, PATH_SEP);
237 if (slashpos) {
238 savedir = g_strdup (real_filename);
239 savedir[slashpos - real_filename + 1] = '\0';
240 } else
241 savedir = g_strdup (".");
242 saveprefix = concat_dir_and_file (savedir, "cooledit");
243 g_free (savedir);
244 fd = mc_mkstemps (&savename, saveprefix, NULL);
245 g_free (saveprefix);
246 if (!savename){
247 g_free(real_filename);
248 return 0;
250 /* FIXME:
251 * Close for now because mc_mkstemps use pure open system call
252 * to create temporary file and it needs to be reopened by
253 * VFS-aware mc_open().
255 close (fd);
256 } else
257 savename = g_strdup (real_filename);
259 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
260 mc_chmod (savename, edit->stat1.st_mode);
262 if ((fd =
263 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
264 edit->stat1.st_mode)) == -1)
265 goto error_save;
267 /* pipe save */
268 if ((p = edit_get_write_filter (savename, real_filename))) {
269 FILE *file;
271 mc_close (fd);
272 file = (FILE *) popen (p, "w");
274 if (file) {
275 filelen = edit_write_stream (edit, file);
276 #if 1
277 pclose (file);
278 #else
279 if (pclose (file) != 0) {
280 tmp = g_strconcat (_(" Error writing to pipe: "),
281 p, " ", (char *) NULL);
282 edit_error_dialog (_("Error"), tmp);
283 g_free(tmp);
284 g_free (p);
285 goto error_save;
287 #endif
288 } else {
289 tmp = g_strconcat (_(" Cannot open pipe for writing: "),
290 p, " ", (char *) NULL);
292 edit_error_dialog (_("Error"),
293 get_sys_error (tmp));
294 g_free (p);
295 g_free(tmp);
296 goto error_save;
298 g_free (p);
299 } else if (edit->lb == LB_ASIS) { /* do not change line breaks */
300 long buf;
301 buf = 0;
302 filelen = edit->last_byte;
303 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
304 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
305 != EDIT_BUF_SIZE) {
306 mc_close (fd);
307 goto error_save;
309 buf++;
311 if (mc_write
312 (fd, (char *) edit->buffers1[buf],
313 edit->curs1 & M_EDIT_BUF_SIZE) !=
314 (edit->curs1 & M_EDIT_BUF_SIZE)) {
315 filelen = -1;
316 } else if (edit->curs2) {
317 edit->curs2--;
318 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
319 if (mc_write
320 (fd,
321 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
322 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
323 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
324 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
325 filelen = -1;
326 } else {
327 while (--buf >= 0) {
328 if (mc_write
329 (fd, (char *) edit->buffers2[buf],
330 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
331 filelen = -1;
332 break;
336 edit->curs2++;
338 if (mc_close (fd))
339 goto error_save;
341 /* Update the file information, especially the mtime. */
342 if (mc_stat (savename, &edit->stat1) == -1)
343 goto error_save;
344 } else { /* change line breaks */
345 FILE *file;
347 mc_close (fd);
349 file = (FILE *) fopen (savename, "w");
351 if (file) {
352 filelen = edit_write_stream (edit, file);
353 fclose (file);
354 } else {
355 char *msg;
357 msg = g_strdup_printf (_(" Cannot open file for writing: %s "), savename);
358 edit_error_dialog (_("Error"), msg);
359 g_free (msg);
360 goto error_save;
364 if (filelen != edit->last_byte)
365 goto error_save;
367 if (this_save_mode == EDIT_DO_BACKUP) {
368 assert (option_backup_ext != NULL);
369 tmp = g_strconcat (real_filename, option_backup_ext,(char *) NULL);
370 if (mc_rename (real_filename, tmp) == -1){
371 g_free(tmp);
372 goto error_save;
376 if (this_save_mode != EDIT_QUICK_SAVE)
377 if (mc_rename (savename, real_filename) == -1)
378 goto error_save;
379 g_free (savename);
380 g_free(real_filename);
381 return 1;
382 error_save:
383 /* FIXME: Is this safe ?
384 * if (this_save_mode != EDIT_QUICK_SAVE)
385 * mc_unlink (savename);
387 g_free(real_filename);
388 g_free (savename);
389 return 0;
392 void
393 menu_save_mode_cmd (void)
395 /* diaog sizes */
396 const int DLG_X = 38;
397 const int DLG_Y = 13;
399 char *str_result;
401 const char *str[] =
403 N_("&Quick save"),
404 N_("&Safe save"),
405 N_("&Do backups with following extension:")
408 QuickWidget widgets[] =
410 /* 0 */
411 QUICK_BUTTON (18, DLG_X, DLG_Y - 3, DLG_Y, N_("&Cancel"), B_CANCEL, NULL),
412 /* 1 */
413 QUICK_BUTTON ( 6, DLG_X, DLG_Y - 3, DLG_Y, N_("&OK"), B_ENTER, NULL),
414 /* 2 */
415 QUICK_CHECKBOX ( 4, DLG_X, 8, DLG_Y, N_("Check &POSIX new line"), &option_check_nl_at_eof),
416 /* 3 */
417 QUICK_INPUT ( 8, DLG_X, 6, DLG_Y, option_backup_ext, 9, 0, "edit-backup-ext", &str_result),
418 /* 4 */
419 QUICK_RADIO ( 4, DLG_X, 3, DLG_Y, 3, str, &option_save_mode),
420 QUICK_END
423 QuickDialog dialog =
425 DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "),
426 "[Edit Save Mode]", widgets, FALSE
429 size_t i;
430 size_t maxlen = 0;
431 size_t w0, w1, b_len, w3;
433 assert (option_backup_ext != NULL);
435 /* OK/Cancel buttons */
436 w0 = str_term_width1 (_(widgets[0].u.button.text)) + 3;
437 w1 = str_term_width1 (_(widgets[1].u.button.text)) + 5; /* default button */
438 b_len = w0 + w1 + 3;
440 maxlen = max (b_len, (size_t) str_term_width1 (_(dialog.title)) + 2);
442 w3 = 0;
443 for (i = 0; i < 3; i++) {
444 #ifdef ENABLE_NLS
445 str[i] = _(str[i]);
446 #endif
447 w3 = max (w3, (size_t) str_term_width1 (str[i]));
450 maxlen = max (maxlen, w3 + 4);
452 dialog.xlen = min ((size_t) COLS, maxlen + 8);
454 widgets[3].u.input.len = w3;
455 widgets[1].relative_x = (dialog.xlen - b_len)/2;
456 widgets[0].relative_x = widgets[1].relative_x + w0 + 2;
458 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
459 widgets[i].x_divisions = dialog.xlen;
461 if (quick_dialog (&dialog) != B_CANCEL) {
462 g_free (option_backup_ext);
463 option_backup_ext = str_result;
467 void
468 edit_set_filename (WEdit *edit, const char *f)
470 g_free (edit->filename);
471 if (!f)
472 f = "";
473 edit->filename = g_strdup (f);
474 if (edit->dir == NULL && *f != PATH_SEP)
475 #ifdef USE_VFS
476 edit->dir = g_strdup (vfs_get_current_dir ());
477 #else
478 edit->dir = g_get_current_dir ();
479 #endif
482 static gboolean
483 edit_check_newline (WEdit *edit)
485 return !(option_check_nl_at_eof && edit->last_byte > 0
486 && edit_get_byte (edit, edit->last_byte - 1) != '\n'
487 && edit_query_dialog2 (_("Warning"),
488 _("The file you are saving is not finished with a newline"),
489 _("C&ontinue"), _("&Cancel")));
492 static char *
493 edit_get_save_file_as (WEdit *edit)
495 #define DLG_WIDTH 64
496 #define DLG_HEIGHT 14
498 static LineBreaks cur_lb = LB_ASIS;
500 char *filename = edit->filename;
502 const char *lb_names[LB_NAMES] =
504 N_("&Do not change"),
505 N_("&Unix format (LF)"),
506 N_("&Windows/DOS format (CR LF)"),
507 N_("&Macintosh format (CR)")
510 QuickWidget quick_widgets[] =
512 QUICK_BUTTON (6, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
513 QUICK_BUTTON (2, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
514 QUICK_RADIO (5, DLG_WIDTH, DLG_HEIGHT - 8, DLG_HEIGHT, LB_NAMES, lb_names, (int *) &cur_lb),
515 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 9, DLG_HEIGHT, N_("Change line breaks to:")),
516 QUICK_INPUT (3, DLG_WIDTH, DLG_HEIGHT - 11, DLG_HEIGHT, filename, DLG_WIDTH - 6, 0, "save-as", &filename),
517 QUICK_LABEL (2, DLG_WIDTH, DLG_HEIGHT - 12, DLG_HEIGHT, N_(" Enter file name: ")),
518 QUICK_END
521 QuickDialog Quick_options =
523 DLG_WIDTH, DLG_HEIGHT, -1, -1,
524 N_(" Save As "), "[Save File As]",
525 quick_widgets, FALSE
528 if (quick_dialog (&Quick_options) != B_CANCEL) {
529 edit->lb = cur_lb;
530 return filename;
533 return NULL;
535 #undef DLG_WIDTH
536 #undef DLG_HEIGHT
539 /* Here we want to warn the users of overwriting an existing file,
540 but only if they have made a change to the filename */
541 /* returns 1 on success */
543 edit_save_as_cmd (WEdit *edit)
545 /* This heads the 'Save As' dialog box */
546 char *exp;
547 int save_lock = 0;
548 int different_filename = 0;
550 if (!edit_check_newline (edit))
551 return 0;
553 exp = edit_get_save_file_as (edit);
554 edit_push_action (edit, KEY_PRESS + edit->start_display);
556 if (exp) {
557 if (!*exp) {
558 g_free (exp);
559 edit->force |= REDRAW_COMPLETELY;
560 return 0;
561 } else {
562 int rv;
563 if (strcmp (edit->filename, exp)) {
564 int file;
565 different_filename = 1;
566 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
567 /* the file exists */
568 mc_close (file);
569 /* Overwrite the current file or cancel the operation */
570 if (edit_query_dialog2
571 (_("Warning"),
572 _(" A file already exists with this name. "),
573 _("&Overwrite"), _("&Cancel"))) {
574 edit->force |= REDRAW_COMPLETELY;
575 g_free (exp);
576 return 0;
578 } else {
579 edit->stat1.st_mode |= S_IWUSR;
581 save_lock = edit_lock_file (exp);
582 } else {
583 /* filenames equal, check if already locked */
584 if (!edit->locked && !edit->delete_file)
585 save_lock = edit_lock_file (exp);
588 if (different_filename)
591 * Allow user to write into saved (under another name) file
592 * even if original file had r/o user permissions.
594 edit->stat1.st_mode |= S_IWRITE;
597 rv = edit_save_file (edit, exp);
598 switch (rv) {
599 case 1:
600 /* Succesful, so unlock both files */
601 if (different_filename) {
602 if (save_lock)
603 edit_unlock_file (exp);
604 if (edit->locked)
605 edit->locked = edit_unlock_file (edit->filename);
606 } else {
607 if (edit->locked || save_lock)
608 edit->locked = edit_unlock_file (edit->filename);
611 edit_set_filename (edit, exp);
612 if (edit->lb != LB_ASIS)
613 edit_reload(edit, exp);
614 g_free (exp);
615 edit->modified = 0;
616 edit->delete_file = 0;
617 if (different_filename)
618 edit_load_syntax (edit, NULL, option_syntax_type);
619 edit->force |= REDRAW_COMPLETELY;
620 return 1;
621 default:
622 edit_error_dialog (_(" Save As "),
623 get_sys_error (_
624 (" Cannot save file. ")));
625 /* fallthrough */
626 case -1:
627 /* Failed, so maintain modify (not save) lock */
628 if (save_lock)
629 edit_unlock_file (exp);
630 g_free (exp);
631 edit->force |= REDRAW_COMPLETELY;
632 return 0;
636 edit->force |= REDRAW_COMPLETELY;
637 return 0;
640 /* {{{ Macro stuff starts here */
642 /* creates a macro file if it doesn't exist */
643 static FILE *edit_open_macro_file (const char *r)
645 gchar *filename;
646 FILE *fd;
647 int file;
648 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
649 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
650 g_free(filename);
651 return 0;
653 close (file);
654 fd = fopen (filename, r);
655 g_free(filename);
656 return fd;
659 #define MAX_MACROS 1024
660 static int saved_macro[MAX_MACROS + 1];
661 static int saved_macros_loaded = 0;
664 This is just to stop the macro file be loaded over and over for keys
665 that aren't defined to anything. On slow systems this could be annoying.
667 static int
668 macro_exists (int k)
670 int i;
671 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
672 if (saved_macro[i] == k)
673 return i;
674 return -1;
677 /* returns 1 on error */
678 static int
679 edit_delete_macro (WEdit * edit, int k)
681 gchar *tmp, *tmp2;
682 struct macro macro[MAX_MACRO_LENGTH];
683 FILE *f, *g;
684 int s, i, n, j = 0;
686 (void) edit;
688 if (saved_macros_loaded)
689 if ((j = macro_exists (k)) < 0)
690 return 0;
691 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
692 g = fopen (tmp , "w");
693 g_free(tmp);
694 if (!g) {
695 edit_error_dialog (_(" Delete macro "),
696 get_sys_error (_(" Cannot open temp file ")));
697 return 1;
699 f = edit_open_macro_file ("r");
700 if (!f) {
701 edit_error_dialog (_(" Delete macro "),
702 get_sys_error (_(" Cannot open macro file ")));
703 fclose (g);
704 return 1;
706 for (;;) {
707 n = fscanf (f, ("key '%d 0': "), &s);
708 if (!n || n == EOF)
709 break;
710 n = 0;
711 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
712 n++;
713 fscanf (f, ";\n");
714 if (s != k) {
715 fprintf (g, ("key '%d 0': "), s);
716 for (i = 0; i < n; i++)
717 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
718 fprintf (g, ";\n");
721 fclose (f);
722 fclose (g);
723 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
724 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
725 if (rename ( tmp, tmp2) == -1) {
726 edit_error_dialog (_(" Delete macro "),
727 get_sys_error (_(" Cannot overwrite macro file ")));
728 g_free(tmp);
729 g_free(tmp2);
730 return 1;
732 g_free(tmp);
733 g_free(tmp2);
735 if (saved_macros_loaded)
736 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
737 return 0;
740 /* returns 0 on error */
741 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
743 FILE *f;
744 int s, i;
746 edit_push_action (edit, KEY_PRESS + edit->start_display);
747 s = editcmd_dialog_raw_key_query (_(" Save macro "),
748 _(" Press the macro's new hotkey: "), 1);
749 edit->force |= REDRAW_COMPLETELY;
750 if (s) {
751 if (edit_delete_macro (edit, s))
752 return 0;
753 f = edit_open_macro_file ("a+");
754 if (f) {
755 fprintf (f, ("key '%d 0': "), s);
756 for (i = 0; i < n; i++)
757 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
758 fprintf (f, ";\n");
759 fclose (f);
760 if (saved_macros_loaded) {
761 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
762 saved_macro[i] = s;
764 return 1;
765 } else
766 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
768 return 0;
771 void edit_delete_macro_cmd (WEdit * edit)
773 int command;
775 command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
776 _ (" Press macro hotkey: "), 1);
778 if (!command)
779 return;
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, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
808 (*n)++;
809 } else {
810 while (2 == fscanf (f, "%hd %hd, ", &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, " ", 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 if (edit->mark2 >= 0) {
1043 *start_mark = min (edit->mark1, edit->mark2);
1044 *end_mark = max (edit->mark1, edit->mark2);
1045 } else {
1046 int diff;
1047 *start_mark = min (edit->mark1, edit->curs1);
1048 *end_mark = max (edit->mark1, edit->curs1);
1049 diff = (*start_mark - edit_bol (edit, *start_mark)) -
1050 (*end_mark - edit_bol (edit, *end_mark));
1051 if (diff > 0) {
1052 *start_mark -= diff;
1053 *end_mark += diff;
1055 edit->column2 = edit->curs_col + edit->over_col;
1057 return 0;
1058 } else {
1059 *start_mark = *end_mark = 0;
1060 edit->column2 = edit->column1 = 0;
1061 return 1;
1065 #define space_width 1
1067 void
1068 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
1070 long cursor;
1071 int i, col;
1072 cursor = edit->curs1;
1073 col = edit_get_col (edit);
1074 for (i = 0; i < size; i++) {
1075 if (data[i] == '\n') { /* fill in and move to next line */
1076 int l;
1077 long p;
1078 if (edit_get_byte (edit, edit->curs1) != '\n') {
1079 l = width - (edit_get_col (edit) - col);
1080 while (l > 0) {
1081 edit_insert (edit, ' ');
1082 l -= space_width;
1085 for (p = edit->curs1;; p++) {
1086 if (p == edit->last_byte) {
1087 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1088 edit_insert_ahead (edit, '\n');
1089 p++;
1090 break;
1092 if (edit_get_byte (edit, p) == '\n') {
1093 p++;
1094 break;
1097 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1098 l = col - edit_get_col (edit);
1099 while (l >= space_width) {
1100 edit_insert (edit, ' ');
1101 l -= space_width;
1103 continue;
1105 edit_insert (edit, data[i]);
1107 edit_cursor_move (edit, cursor - edit->curs1);
1110 #define TEMP_BUF_LEN 1024
1113 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1115 long cursor;
1116 int i, col;
1117 int blocklen = -1, width;
1118 unsigned char *data;
1119 cursor = edit->curs1;
1120 col = edit_get_col (edit);
1121 data = g_malloc (TEMP_BUF_LEN);
1122 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0) {
1123 for (width = 0; width < blocklen; width++) {
1124 if (data[width] == '\n')
1125 break;
1127 for (i = 0; i < blocklen; i++) {
1128 if (data[i] == '\n') { /* fill in and move to next line */
1129 int l;
1130 long p;
1131 if (edit_get_byte (edit, edit->curs1) != '\n') {
1132 l = width - (edit_get_col (edit) - col);
1133 while (l > 0) {
1134 edit_insert (edit, ' ');
1135 l -= space_width;
1138 for (p = edit->curs1;; p++) {
1139 if (p == edit->last_byte) {
1140 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1141 edit_insert_ahead (edit, '\n');
1142 p++;
1143 break;
1145 if (edit_get_byte (edit, p) == '\n') {
1146 p++;
1147 break;
1150 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1151 l = col - edit_get_col (edit);
1152 while (l >= space_width) {
1153 edit_insert (edit, ' ');
1154 l -= space_width;
1156 continue;
1158 edit_insert (edit, data[i]);
1161 edit_cursor_move (edit, cursor - edit->curs1);
1162 g_free(data);
1163 edit->force |= REDRAW_PAGE;
1164 return blocklen;
1167 void
1168 edit_block_copy_cmd (WEdit *edit)
1170 long start_mark, end_mark, current = edit->curs1;
1171 int size;
1172 unsigned char *copy_buf;
1174 edit_update_curs_col (edit);
1175 if (eval_marks (edit, &start_mark, &end_mark))
1176 return;
1178 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1180 /* all that gets pushed are deletes hence little space is used on the stack */
1182 edit_push_markers (edit);
1184 if (column_highlighting) {
1185 edit_insert_column_of_text (edit, copy_buf, size,
1186 abs (edit->column2 - edit->column1));
1187 } else {
1188 while (size--)
1189 edit_insert_ahead (edit, copy_buf[size]);
1192 g_free (copy_buf);
1193 edit_scroll_screen_over_cursor (edit);
1195 if (column_highlighting) {
1196 edit_set_markers (edit, 0, 0, 0, 0);
1197 edit_push_action (edit, COLUMN_ON);
1198 column_highlighting = 0;
1199 } else if (start_mark < current && end_mark > current)
1200 edit_set_markers (edit, start_mark,
1201 end_mark + end_mark - start_mark, 0, 0);
1203 edit->force |= REDRAW_PAGE;
1207 void
1208 edit_block_move_cmd (WEdit *edit)
1210 long count;
1211 long current;
1212 unsigned char *copy_buf;
1213 long start_mark, end_mark;
1214 int deleted = 0;
1215 int x = 0;
1217 if (eval_marks (edit, &start_mark, &end_mark))
1218 return;
1219 if (column_highlighting) {
1220 edit_update_curs_col (edit);
1221 x = edit->curs_col;
1222 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1223 if ((x > edit->column1 && x < edit->column2)
1224 || (x > edit->column2 && x < edit->column1))
1225 return;
1226 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1227 return;
1229 if ((end_mark - start_mark) > option_max_undo / 2)
1230 if (edit_query_dialog2
1231 (_("Warning"),
1233 (" Block is large, you may not be able to undo this action. "),
1234 _("C&ontinue"), _("&Cancel")))
1235 return;
1237 edit_push_markers (edit);
1238 current = edit->curs1;
1239 if (column_highlighting) {
1240 int size, c1, c2, line;
1241 line = edit->curs_line;
1242 if (edit->mark2 < 0)
1243 edit_mark_cmd (edit, 0);
1244 c1 = min (edit->column1, edit->column2);
1245 c2 = max (edit->column1, edit->column2);
1246 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1247 if (x < c2) {
1248 edit_block_delete_cmd (edit);
1249 deleted = 1;
1251 edit_move_to_line (edit, line);
1252 edit_cursor_move (edit,
1253 edit_move_forward3 (edit,
1254 edit_bol (edit, edit->curs1),
1255 x, 0) - edit->curs1);
1256 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1257 if (!deleted) {
1258 line = edit->curs_line;
1259 edit_update_curs_col (edit);
1260 x = edit->curs_col;
1261 edit_block_delete_cmd (edit);
1262 edit_move_to_line (edit, line);
1263 edit_cursor_move (edit,
1264 edit_move_forward3 (edit,
1265 edit_bol (edit,
1266 edit->curs1),
1267 x, 0) - edit->curs1);
1269 edit_set_markers (edit, 0, 0, 0, 0);
1270 edit_push_action (edit, COLUMN_ON);
1271 column_highlighting = 0;
1272 } else {
1273 copy_buf = g_malloc (end_mark - start_mark);
1274 edit_cursor_move (edit, start_mark - edit->curs1);
1275 edit_scroll_screen_over_cursor (edit);
1276 count = start_mark;
1277 while (count < end_mark) {
1278 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1279 count++;
1281 edit_scroll_screen_over_cursor (edit);
1282 edit_cursor_move (edit,
1283 current - edit->curs1 -
1284 (((current - edit->curs1) >
1285 0) ? end_mark - start_mark : 0));
1286 edit_scroll_screen_over_cursor (edit);
1287 while (count-- > start_mark)
1288 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1289 edit_set_markers (edit, edit->curs1,
1290 edit->curs1 + end_mark - start_mark, 0, 0);
1292 edit_scroll_screen_over_cursor (edit);
1293 g_free (copy_buf);
1294 edit->force |= REDRAW_PAGE;
1297 static void
1298 edit_delete_column_of_text (WEdit * edit)
1300 long p, q, r, m1, m2;
1301 int b, c, d;
1302 int n;
1304 eval_marks (edit, &m1, &m2);
1305 n = edit_move_forward (edit, m1, 0, m2) + 1;
1306 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1307 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1309 b = max(min (c, d), min (edit->column1, edit->column2));
1310 c = max (c, d + edit->over_col);
1312 while (n--) {
1313 r = edit_bol (edit, edit->curs1);
1314 p = edit_move_forward3 (edit, r, b, 0);
1315 q = edit_move_forward3 (edit, r, c, 0);
1316 if (p < m1)
1317 p = m1;
1318 if (q > m2)
1319 q = m2;
1320 edit_cursor_move (edit, p - edit->curs1);
1321 while (q > p) { /* delete line between margins */
1322 if (edit_get_byte (edit, edit->curs1) != '\n')
1323 edit_delete (edit, 1);
1324 q--;
1326 if (n) /* move to next line except on the last delete */
1327 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1331 /* if success return 0 */
1332 static int
1333 edit_block_delete (WEdit *edit)
1335 long count;
1336 long start_mark, end_mark;
1337 if (eval_marks (edit, &start_mark, &end_mark))
1338 return 0;
1339 if (column_highlighting && edit->mark2 < 0)
1340 edit_mark_cmd (edit, 0);
1341 if ((end_mark - start_mark) > option_max_undo / 2) {
1342 /* Warning message with a query to continue or cancel the operation */
1343 if (edit_query_dialog2
1344 (_("Warning"),
1346 (" Block is large, you may not be able to undo this action. "),
1347 _("C&ontinue"), _("&Cancel"))) {
1348 return 1;
1351 edit_push_markers (edit);
1352 edit_cursor_move (edit, start_mark - edit->curs1);
1353 edit_scroll_screen_over_cursor (edit);
1354 count = start_mark;
1355 if (start_mark < end_mark) {
1356 if (column_highlighting) {
1357 if (edit->mark2 < 0)
1358 edit_mark_cmd (edit, 0);
1359 edit_delete_column_of_text (edit);
1360 } else {
1361 while (count < end_mark) {
1362 edit_delete (edit, 1);
1363 count++;
1367 edit_set_markers (edit, 0, 0, 0, 0);
1368 edit->force |= REDRAW_PAGE;
1369 return 0;
1372 /* returns 1 if canceelled by user */
1373 int edit_block_delete_cmd (WEdit * edit)
1375 long start_mark, end_mark;
1376 if (eval_marks (edit, &start_mark, &end_mark)) {
1377 edit_delete_line (edit);
1378 return 0;
1380 return edit_block_delete (edit);
1383 #define INPUT_INDEX 9
1385 static gboolean
1386 editcmd_find (WEdit *edit, gsize *len)
1388 off_t search_start = edit->search_start;
1389 off_t search_end;
1390 long start_mark = 0;
1391 long end_mark = edit->last_byte;
1392 int mark_res = 0;
1394 if (edit->only_in_selection) {
1395 mark_res = eval_marks(edit, &start_mark, &end_mark);
1396 if (mark_res != 0) {
1397 edit->search->error = MC_SEARCH_E_NOTFOUND;
1398 edit->search->error_str = g_strdup(_(" Search string not found "));
1399 return FALSE;
1401 if (edit->replace_backwards) {
1402 if (search_start > end_mark || search_start <= start_mark) {
1403 search_start = end_mark;
1405 } else {
1406 if (search_start < start_mark || search_start >= end_mark) {
1407 search_start = start_mark;
1410 } else {
1411 if (edit->replace_backwards)
1412 end_mark = max(1, edit->curs1) - 1;
1414 if (edit->replace_backwards) {
1415 search_end = end_mark;
1416 while ((int) search_start >= start_mark) {
1417 if (search_end > search_start + edit->search->original_len
1418 && mc_search_is_fixed_search_str(edit->search)) {
1419 search_end = search_start + edit->search->original_len;
1421 if (mc_search_run(edit->search, (void *) edit, search_start, search_end, len)
1422 && edit->search->normal_offset == search_start ) {
1423 return TRUE;
1425 search_start--;
1427 edit->search->error_str = g_strdup(_(" Search string not found "));
1428 } else {
1429 return mc_search_run(edit->search, (void *) edit, search_start, end_mark, len);
1431 return FALSE;
1435 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1436 (and the above) routines to work properly - paul */
1438 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1440 static char *
1441 edit_replace_cmd__conv_to_display(char *str)
1443 #ifdef HAVE_CHARSET
1444 GString *tmp;
1445 tmp = str_convert_to_display (str);
1447 if (tmp && tmp->len){
1448 g_free(str);
1449 str = tmp->str;
1451 g_string_free (tmp, FALSE);
1452 return str;
1453 #else
1454 return g_strdup(str);
1455 #endif
1458 static char *
1459 edit_replace_cmd__conv_to_input(char *str)
1461 #ifdef HAVE_CHARSET
1462 GString *tmp;
1463 tmp = str_convert_to_input (str);
1465 if (tmp && tmp->len){
1466 g_free(str);
1467 str = tmp->str;
1469 g_string_free (tmp, FALSE);
1470 return str;
1471 #else
1472 return g_strdup(str);
1473 #endif
1475 /* call with edit = 0 before shutdown to close memory leaks */
1476 void
1477 edit_replace_cmd (WEdit *edit, int again)
1479 /* 1 = search string, 2 = replace with */
1480 static char *saved1 = NULL; /* saved default[123] */
1481 static char *saved2 = NULL;
1482 char *input1 = NULL; /* user input from the dialog */
1483 char *input2 = NULL;
1484 int replace_yes;
1485 long times_replaced = 0, last_search;
1486 gboolean once_found = FALSE;
1488 if (!edit) {
1489 g_free (saved1), saved1 = NULL;
1490 g_free (saved2), saved2 = NULL;
1491 return;
1494 last_search = edit->last_byte;
1496 edit->force |= REDRAW_COMPLETELY;
1498 if (again && !saved1 && !saved2)
1499 again = 0;
1501 if (again) {
1502 input1 = g_strdup (saved1 ? saved1 : "");
1503 input2 = g_strdup (saved2 ? saved2 : "");
1504 } else {
1505 char *disp1 = edit_replace_cmd__conv_to_display(g_strdup (saved1 ? saved1 : ""));
1506 char *disp2 = edit_replace_cmd__conv_to_display(g_strdup (saved2 ? saved2 : ""));
1508 edit_push_action (edit, KEY_PRESS + edit->start_display);
1510 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1512 g_free (disp1);
1513 g_free (disp2);
1515 if (input1 == NULL || *input1 == '\0') {
1516 edit->force = REDRAW_COMPLETELY;
1517 goto cleanup;
1520 input1 = edit_replace_cmd__conv_to_input(input1);
1521 input2 = edit_replace_cmd__conv_to_input(input2);
1523 g_free (saved1), saved1 = g_strdup (input1);
1524 g_free (saved2), saved2 = g_strdup (input2);
1526 if (edit->search) {
1527 mc_search_free(edit->search);
1528 edit->search = NULL;
1532 if (!edit->search) {
1533 edit->search = mc_search_new(input1, -1);
1534 if (edit->search == NULL) {
1535 edit->search_start = edit->curs1;
1536 return;
1538 edit->search->search_type = edit->search_type;
1539 edit->search->is_all_charsets = edit->all_codepages;
1540 edit->search->is_case_sentitive = edit->replace_case;
1541 edit->search->whole_words = edit->whole_words;
1542 edit->search->search_fn = edit_search_cmd_callback;
1545 if (edit->found_len && edit->search_start == edit->found_start + 1
1546 && edit->replace_backwards)
1547 edit->search_start--;
1549 if (edit->found_len && edit->search_start == edit->found_start - 1
1550 && !edit->replace_backwards)
1551 edit->search_start++;
1553 do {
1554 gsize len = 0;
1555 long new_start;
1557 if (! editcmd_find(edit, &len)) {
1558 if (!(edit->search->error == MC_SEARCH_E_OK ||
1559 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND))) {
1560 edit_error_dialog (_ ("Search"), edit->search->error_str);
1562 break;
1564 once_found = TRUE;
1565 new_start = edit->search->normal_offset;
1567 edit->search_start = new_start = edit->search->normal_offset;
1568 /*returns negative on not found or error in pattern */
1570 if (edit->search_start >= 0) {
1571 guint i;
1573 edit->found_start = edit->search_start;
1574 i = edit->found_len = len;
1576 edit_cursor_move (edit, edit->search_start - edit->curs1);
1577 edit_scroll_screen_over_cursor (edit);
1579 replace_yes = 1;
1581 if (edit->replace_mode == 0) {
1582 int l;
1583 l = edit->curs_row - edit->num_widget_lines / 3;
1584 if (l > 0)
1585 edit_scroll_downward (edit, l);
1586 if (l < 0)
1587 edit_scroll_upward (edit, -l);
1589 edit_scroll_screen_over_cursor (edit);
1590 edit->force |= REDRAW_PAGE;
1591 edit_render_keypress (edit);
1593 /*so that undo stops at each query */
1594 edit_push_key_press (edit);
1595 /* and prompt 2/3 down */
1596 switch (editcmd_dialog_replace_prompt_show (edit, input1, input2, -1, -1)) {
1597 case B_ENTER:
1598 replace_yes = 1;
1599 break;
1600 case B_SKIP_REPLACE:
1601 replace_yes = 0;
1602 break;
1603 case B_REPLACE_ALL:
1604 edit->replace_mode=1;
1605 break;
1606 case B_CANCEL:
1607 replace_yes = 0;
1608 edit->replace_mode = -1;
1609 break;
1612 if (replace_yes) { /* delete then insert new */
1613 GString *repl_str, *tmp_str;
1614 tmp_str = g_string_new(input2);
1616 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1617 g_string_free(tmp_str, TRUE);
1618 if (edit->search->error != MC_SEARCH_E_OK)
1620 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1621 break;
1624 while (i--)
1625 edit_delete (edit, 1);
1627 while (++i < repl_str->len)
1628 edit_insert (edit, repl_str->str[i]);
1630 g_string_free(repl_str, TRUE);
1631 edit->found_len = i;
1633 /* so that we don't find the same string again */
1634 if (edit->replace_backwards) {
1635 last_search = edit->search_start;
1636 edit->search_start--;
1637 } else {
1638 edit->search_start += i;
1639 last_search = edit->last_byte;
1641 edit_scroll_screen_over_cursor (edit);
1642 } else {
1643 const char *msg = _(" Replace ");
1644 /* try and find from right here for next search */
1645 edit->search_start = edit->curs1;
1646 edit_update_curs_col (edit);
1648 edit->force |= REDRAW_PAGE;
1649 edit_render_keypress (edit);
1650 if (times_replaced) {
1651 message (D_NORMAL, msg, _(" %ld replacements made. "),
1652 times_replaced);
1653 } else
1654 query_dialog (msg, _(" Search string not found "),
1655 D_NORMAL, 1, _("&OK"));
1656 edit->replace_mode = -1;
1658 } while (edit->replace_mode >= 0);
1660 edit->force = REDRAW_COMPLETELY;
1661 edit_scroll_screen_over_cursor (edit);
1662 cleanup:
1663 g_free (input1);
1664 g_free (input2);
1668 void edit_search_cmd (WEdit * edit, int again)
1670 char *search_string = NULL, *search_string_dup = NULL;
1672 gsize len = 0;
1674 if (!edit)
1675 return;
1677 if (edit->search != NULL) {
1678 search_string = g_strndup(edit->search->original, edit->search->original_len);
1679 search_string_dup = search_string;
1680 } else {
1681 GList *history;
1682 history = history_get (MC_HISTORY_SHARED_SEARCH);
1683 if (history != NULL && history->data != NULL) {
1684 search_string_dup = search_string = (char *) g_strdup(history->data);
1685 history = g_list_first (history);
1686 g_list_foreach (history, (GFunc) g_free, NULL);
1687 g_list_free (history);
1689 edit->search_start = edit->curs1;
1692 if (!again) {
1693 #ifdef HAVE_CHARSET
1694 GString *tmp;
1695 if (search_string && *search_string) {
1696 tmp = str_convert_to_display (search_string);
1698 g_free(search_string_dup);
1699 search_string_dup = NULL;
1701 if (tmp && tmp->len)
1702 search_string = search_string_dup = tmp->str;
1703 g_string_free (tmp, FALSE);
1705 #endif /* HAVE_CHARSET */
1706 editcmd_dialog_search_show (edit, &search_string);
1707 #ifdef HAVE_CHARSET
1708 if (search_string && *search_string) {
1709 tmp = str_convert_to_input (search_string);
1710 if (tmp && tmp->len)
1711 search_string = tmp->str;
1713 g_string_free (tmp, FALSE);
1715 if (search_string_dup)
1716 g_free(search_string_dup);
1718 #endif /* HAVE_CHARSET */
1720 edit_push_action (edit, KEY_PRESS + edit->start_display);
1722 if (!search_string) {
1723 edit->force |= REDRAW_COMPLETELY;
1724 edit_scroll_screen_over_cursor (edit);
1725 return;
1728 if (edit->search) {
1729 mc_search_free(edit->search);
1730 edit->search = NULL;
1734 if (!edit->search) {
1735 edit->search = mc_search_new(search_string, -1);
1736 if (edit->search == NULL) {
1737 edit->search_start = edit->curs1;
1738 return;
1740 edit->search->search_type = edit->search_type;
1741 edit->search->is_all_charsets = edit->all_codepages;
1742 edit->search->is_case_sentitive = edit->replace_case;
1743 edit->search->whole_words = edit->whole_words;
1744 edit->search->search_fn = edit_search_cmd_callback;
1747 if (search_create_bookmark) {
1748 edit_search_cmd_search_create_bookmark(edit);
1749 } else {
1750 if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
1751 edit->search_start--;
1753 if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
1754 edit->search_start++;
1757 if (editcmd_find(edit, &len)) {
1758 edit->found_start = edit->search_start = edit->search->normal_offset;
1759 edit->found_len = len;
1760 edit->over_col = 0;
1761 edit_cursor_move (edit, edit->search_start - edit->curs1);
1762 edit_scroll_screen_over_cursor (edit);
1763 if (edit->replace_backwards)
1764 edit->search_start--;
1765 else
1766 edit->search_start++;
1767 } else {
1768 edit->search_start = edit->curs1;
1769 if (edit->search->error_str)
1770 edit_error_dialog (_ ("Search"), edit->search->error_str);
1774 edit->force |= REDRAW_COMPLETELY;
1775 edit_scroll_screen_over_cursor (edit);
1780 * Check if it's OK to close the editor. If there are unsaved changes,
1781 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
1784 edit_ok_to_exit (WEdit *edit)
1786 if (!edit->modified)
1787 return 1;
1789 if (!edit_check_newline (edit))
1790 return 0;
1792 switch (edit_query_dialog3
1793 (_("Quit"), _(" File was modified, Save with exit? "),
1794 _("&Cancel quit"), _("&Yes"), _("&No"))) {
1795 case 1:
1796 edit_push_markers (edit);
1797 edit_set_markers (edit, 0, 0, 0, 0);
1798 if (!edit_save_cmd (edit))
1799 return 0;
1800 break;
1801 case 2:
1802 break;
1803 case 0:
1804 case -1:
1805 return 0;
1808 return 1;
1811 /* Return a null terminated length of text. Result must be g_free'd */
1812 static unsigned char *
1813 edit_get_block (WEdit *edit, long start, long finish, int *l)
1815 unsigned char *s, *r;
1816 r = s = g_malloc (finish - start + 1);
1817 if (column_highlighting) {
1818 *l = 0;
1819 /* copy from buffer, excluding chars that are out of the column 'margins' */
1820 while (start < finish) {
1821 int c, x;
1822 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
1823 start);
1824 c = edit_get_byte (edit, start);
1825 if ((x >= edit->column1 && x < edit->column2)
1826 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1827 *s++ = c;
1828 (*l)++;
1830 start++;
1832 } else {
1833 *l = finish - start;
1834 while (start < finish)
1835 *s++ = edit_get_byte (edit, start++);
1837 *s = 0;
1838 return r;
1841 /* save block, returns 1 on success */
1843 edit_save_block (WEdit * edit, const char *filename, long start,
1844 long finish)
1846 int len, file;
1848 if ((file =
1849 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
1850 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
1851 return 0;
1853 if (column_highlighting) {
1854 int r;
1855 r = mc_write (file, VERTICAL_MAGIC, sizeof(VERTICAL_MAGIC));
1856 if (r > 0) {
1857 unsigned char *block, *p;
1858 p = block = edit_get_block (edit, start, finish, &len);
1859 while (len) {
1860 r = mc_write (file, p, len);
1861 if (r < 0)
1862 break;
1863 p += r;
1864 len -= r;
1866 g_free (block);
1868 } else {
1869 unsigned char *buf;
1870 int i = start, end;
1871 len = finish - start;
1872 buf = g_malloc (TEMP_BUF_LEN);
1873 while (start != finish) {
1874 end = min (finish, start + TEMP_BUF_LEN);
1875 for (; i < end; i++)
1876 buf[i - start] = edit_get_byte (edit, i);
1877 len -= mc_write (file, (char *) buf, end - start);
1878 start = end;
1880 g_free (buf);
1882 mc_close (file);
1883 if (len)
1884 return 0;
1885 return 1;
1888 /* copies a block to clipboard file */
1889 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1891 int ret;
1892 gchar *tmp;
1893 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1894 ret = edit_save_block (edit, tmp, start, finish);
1895 g_free(tmp);
1896 return ret;
1900 void edit_paste_from_history (WEdit *edit)
1902 (void) edit;
1903 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
1906 int edit_copy_to_X_buf_cmd (WEdit * edit)
1908 long start_mark, end_mark;
1909 if (eval_marks (edit, &start_mark, &end_mark))
1910 return 0;
1911 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1912 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
1913 return 1;
1915 edit_mark_cmd (edit, 1);
1916 return 0;
1919 int edit_cut_to_X_buf_cmd (WEdit * edit)
1921 long start_mark, end_mark;
1922 if (eval_marks (edit, &start_mark, &end_mark))
1923 return 0;
1924 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1925 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
1926 return 1;
1928 edit_block_delete_cmd (edit);
1929 edit_mark_cmd (edit, 1);
1930 return 0;
1933 void edit_paste_from_X_buf_cmd (WEdit * edit)
1935 gchar *tmp;
1936 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1937 edit_insert_file (edit, tmp);
1938 g_free(tmp);
1943 * Ask user for the line and go to that line.
1944 * Negative numbers mean line from the end (i.e. -1 is the last line).
1946 void
1947 edit_goto_cmd (WEdit *edit)
1949 char *f;
1950 static long line = 0; /* line as typed, saved as default */
1951 long l;
1952 char *error;
1953 char s[32];
1955 g_snprintf (s, sizeof (s), "%ld", line);
1956 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
1957 line ? s : "");
1958 if (!f)
1959 return;
1961 if (!*f) {
1962 g_free (f);
1963 return;
1966 l = strtol (f, &error, 0);
1967 if (*error) {
1968 g_free (f);
1969 return;
1972 line = l;
1973 if (l < 0)
1974 l = edit->total_lines + l + 2;
1975 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
1976 edit_move_to_line (edit, l - 1);
1977 edit->force |= REDRAW_COMPLETELY;
1978 g_free (f);
1982 /* Return 1 on success */
1984 edit_save_block_cmd (WEdit *edit)
1986 long start_mark, end_mark;
1987 char *exp, *tmp;
1989 if (eval_marks (edit, &start_mark, &end_mark))
1990 return 1;
1992 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1993 exp =
1994 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
1995 MC_HISTORY_EDIT_SAVE_BLOCK,
1996 tmp);
1997 g_free(tmp);
1998 edit_push_action (edit, KEY_PRESS + edit->start_display);
1999 if (exp) {
2000 if (!*exp) {
2001 g_free (exp);
2002 return 0;
2003 } else {
2004 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2005 g_free (exp);
2006 edit->force |= REDRAW_COMPLETELY;
2007 return 1;
2008 } else {
2009 g_free (exp);
2010 edit_error_dialog (_(" Save Block "),
2011 get_sys_error (_
2012 (" Cannot save file. ")));
2016 edit->force |= REDRAW_COMPLETELY;
2017 return 0;
2021 /* returns 1 on success */
2023 edit_insert_file_cmd (WEdit *edit)
2025 gchar *tmp;
2026 char *exp;
2028 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2029 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2030 MC_HISTORY_EDIT_INSERT_FILE,
2031 tmp);
2032 g_free(tmp);
2033 edit_push_action (edit, KEY_PRESS + edit->start_display);
2034 if (exp) {
2035 if (!*exp) {
2036 g_free (exp);
2037 return 0;
2038 } else {
2039 if (edit_insert_file (edit, exp)) {
2040 g_free (exp);
2041 edit->force |= REDRAW_COMPLETELY;
2042 return 1;
2043 } else {
2044 g_free (exp);
2045 edit_error_dialog (_(" Insert File "),
2046 get_sys_error (_
2047 (" Cannot insert file. ")));
2051 edit->force |= REDRAW_COMPLETELY;
2052 return 0;
2055 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2056 int edit_sort_cmd (WEdit * edit)
2058 static char *old = 0;
2059 char *exp, *tmp;
2060 long start_mark, end_mark;
2061 int e;
2063 if (eval_marks (edit, &start_mark, &end_mark)) {
2064 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2065 return 0;
2068 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2069 edit_save_block (edit, tmp, start_mark, end_mark);
2070 g_free(tmp);
2072 exp = input_dialog (_(" Run Sort "),
2073 _(" Enter sort options (see manpage) separated by whitespace: "),
2074 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2076 if (!exp)
2077 return 1;
2078 g_free (old);
2079 old = exp;
2080 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2081 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2082 e = system (tmp);
2083 g_free(tmp);
2084 if (e) {
2085 if (e == -1 || e == 127) {
2086 edit_error_dialog (_(" Sort "),
2087 get_sys_error (_(" Cannot execute sort command ")));
2088 } else {
2089 char q[8];
2090 sprintf (q, "%d ", e);
2091 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
2092 edit_error_dialog (_(" Sort "), tmp);
2093 g_free(tmp);
2095 return -1;
2098 edit->force |= REDRAW_COMPLETELY;
2100 if (edit_block_delete_cmd (edit))
2101 return 1;
2102 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2103 edit_insert_file (edit, tmp);
2104 g_free(tmp);
2105 return 0;
2109 * Ask user for a command, execute it and paste its output back to the
2110 * editor.
2113 edit_ext_cmd (WEdit *edit)
2115 char *exp, *tmp;
2116 int e;
2118 exp =
2119 input_dialog (_("Paste output of external command"),
2120 _("Enter shell command(s):"),
2121 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2123 if (!exp)
2124 return 1;
2126 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2127 e = system (tmp);
2128 g_free(tmp);
2129 g_free (exp);
2131 if (e) {
2132 edit_error_dialog (_("External command"),
2133 get_sys_error (_("Cannot execute command")));
2134 return -1;
2137 edit->force |= REDRAW_COMPLETELY;
2138 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2139 edit_insert_file (edit, tmp);
2140 g_free(tmp);
2141 return 0;
2144 /* if block is 1, a block must be highlighted and the shell command
2145 processes it. If block is 0 the shell command is a straight system
2146 command, that just produces some output which is to be inserted */
2147 void
2148 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2150 long start_mark, end_mark;
2151 char buf[BUFSIZ];
2152 FILE *script_home = NULL;
2153 FILE *script_src = NULL;
2154 FILE *block_file = NULL;
2155 gchar *o, *h, *b, *tmp;
2156 char *quoted_name = NULL;
2158 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2159 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2160 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2162 if (!(script_home = fopen (h, "r"))) {
2163 if (!(script_home = fopen (h, "w"))) {
2164 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2165 edit_error_dialog ("", get_sys_error (tmp));
2166 g_free(tmp);
2167 goto edit_block_process_cmd__EXIT;
2169 if (!(script_src = fopen (o, "r"))) {
2170 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2171 if (!(script_src = fopen (o, "r"))) {
2172 fclose (script_home);
2173 unlink (h);
2174 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2175 edit_error_dialog ("", get_sys_error (tmp));
2176 g_free(tmp);
2177 goto edit_block_process_cmd__EXIT;
2180 while (fgets (buf, sizeof (buf), script_src))
2181 fputs (buf, script_home);
2182 if (fclose (script_home)) {
2183 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2184 edit_error_dialog ("", get_sys_error (tmp));
2185 g_free(tmp);
2186 goto edit_block_process_cmd__EXIT;
2188 chmod (h, 0700);
2189 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2190 edit_error_dialog ("", get_sys_error (tmp));
2191 g_free(tmp);
2194 open_error_pipe ();
2196 if (block) { /* for marked block run indent formatter */
2197 if (eval_marks (edit, &start_mark, &end_mark)) {
2198 edit_error_dialog (_("Process block"),
2200 (" You must first highlight a block of text. "));
2201 goto edit_block_process_cmd__EXIT;
2203 edit_save_block (edit, b, start_mark, end_mark);
2204 quoted_name = name_quote (edit->filename, 0);
2206 * Run script.
2207 * Initial space is to avoid polluting bash history.
2208 * Arguments:
2209 * $1 - name of the edited file (to check its extension etc).
2210 * $2 - file containing the current block.
2211 * $3 - file where error messages should be put
2212 * (for compatibility with old scripts).
2214 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2215 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2216 system (tmp);
2217 g_free(tmp);
2218 } else {
2220 * No block selected, just execute the command for the file.
2221 * Arguments:
2222 * $1 - name of the edited file.
2224 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2225 quoted_name, (char *) NULL);
2226 system (tmp);
2227 g_free(tmp);
2229 g_free (quoted_name);
2230 close_error_pipe (D_NORMAL, NULL);
2232 edit_refresh_cmd (edit);
2233 edit->force |= REDRAW_COMPLETELY;
2235 /* insert result block */
2236 if (block) {
2237 if (edit_block_delete_cmd (edit))
2238 goto edit_block_process_cmd__EXIT;
2239 edit_insert_file (edit, b);
2240 if ((block_file = fopen (b, "w")))
2241 fclose (block_file);
2242 goto edit_block_process_cmd__EXIT;
2244 edit_block_process_cmd__EXIT:
2245 g_free(b);
2246 g_free(h);
2247 g_free(o);
2248 return;
2251 /* prints at the cursor */
2252 /* returns the number of chars printed */
2253 int edit_print_string (WEdit * e, const char *s)
2255 int i = 0;
2256 while (s[i])
2257 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2258 e->force |= REDRAW_COMPLETELY;
2259 edit_update_screen (e);
2260 return i;
2264 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2266 FILE *p = 0;
2267 char *s;
2269 to = name_quote (to, 0);
2270 subject = name_quote (subject, 0);
2271 cc = name_quote (cc, 0);
2272 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2273 g_free (to);
2274 g_free (subject);
2275 g_free (cc);
2277 if (s) {
2278 p = popen (s, "w");
2279 g_free (s);
2282 if (p) {
2283 long i;
2284 for (i = 0; i < edit->last_byte; i++)
2285 fputc (edit_get_byte (edit, i), p);
2286 pclose (p);
2290 #define MAIL_DLG_HEIGHT 12
2292 void edit_mail_dialog (WEdit * edit)
2294 char *tmail_to;
2295 char *tmail_subject;
2296 char *tmail_cc;
2298 static char *mail_cc_last = 0;
2299 static char *mail_subject_last = 0;
2300 static char *mail_to_last = 0;
2302 QuickWidget quick_widgets[] =
2304 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2305 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2306 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2307 /* 3 */ QUICK_LABEL (2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to")),
2308 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2", &tmail_subject),
2309 /* 5 */ QUICK_LABEL (2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject")),
2310 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2311 /* 7 */ QUICK_LABEL (2, 50, 3, MAIL_DLG_HEIGHT, N_(" To")),
2312 /* 8 */ QUICK_LABEL (2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>")),
2313 QUICK_END
2316 QuickDialog Quick_input =
2318 50, MAIL_DLG_HEIGHT, -1, -1, N_(" Mail "),
2319 "[Input Line Keys]", quick_widgets, FALSE
2322 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2323 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2324 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2326 if (quick_dialog (&Quick_input) != B_CANCEL) {
2327 g_free (mail_cc_last);
2328 g_free (mail_subject_last);
2329 g_free (mail_to_last);
2330 mail_cc_last = tmail_cc;
2331 mail_subject_last = tmail_subject;
2332 mail_to_last = tmail_to;
2333 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2338 /*******************/
2339 /* Word Completion */
2340 /*******************/
2342 static gboolean is_break_char(char c)
2344 return (isspace(c) || strchr("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2347 /* find first character of current word */
2348 static int edit_find_word_start (WEdit *edit, long *word_start, gsize *word_len)
2350 int c, last;
2351 gsize i;
2353 /* return if at begin of file */
2354 if (edit->curs1 <= 0)
2355 return 0;
2357 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2358 /* return if not at end or in word */
2359 if (is_break_char(c))
2360 return 0;
2362 /* search start of word to be completed */
2363 for (i = 2;; i++) {
2364 /* return if at begin of file */
2365 if (edit->curs1 - i < 0)
2366 return 0;
2368 last = c;
2369 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2371 if (is_break_char(c)) {
2372 /* return if word starts with digit */
2373 if (isdigit (last))
2374 return 0;
2376 *word_start = edit->curs1 - (i - 1); /* start found */
2377 *word_len = i - 1;
2378 break;
2381 /* success */
2382 return 1;
2385 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2387 /* collect the possible completions */
2388 static gsize
2389 edit_collect_completions (WEdit *edit, long start, gsize word_len,
2390 char *match_expr, struct selection *compl,
2391 gsize *num)
2393 gsize len = 0;
2394 gsize max_len = 0;
2395 gsize i;
2396 int skip;
2397 GString *temp;
2398 mc_search_t *srch;
2400 long last_byte;
2402 srch = mc_search_new(match_expr, -1);
2403 if (srch == NULL)
2404 return 0;
2406 if (mc_config_get_bool(mc_main_config, CONFIG_APP_SECTION, "editor_wordcompletion_collect_entire_file", 0)){
2407 last_byte = edit->last_byte;
2408 } else {
2409 last_byte = start;
2412 srch->search_type = MC_SEARCH_T_REGEX;
2413 srch->is_case_sentitive = TRUE;
2414 srch->search_fn = edit_search_cmd_callback;
2416 /* collect max MAX_WORD_COMPLETIONS completions */
2417 start = -1;
2418 while (1) {
2419 /* get next match */
2420 if (mc_search_run (srch, (void *) edit, start+1, last_byte, &len) == FALSE)
2421 break;
2422 start = srch->normal_offset;
2424 /* add matched completion if not yet added */
2425 temp = g_string_new("");
2426 for (i = 0; i < len; i++){
2427 skip = edit_get_byte(edit, start+i);
2428 if (isspace(skip))
2429 continue;
2430 g_string_append_c (temp, skip);
2433 skip = 0;
2435 for (i = 0; i < (gsize) *num; i++) {
2436 if (strncmp
2438 (char *) &compl[i].text[word_len],
2439 (char *) &temp->str[word_len],
2440 max (len, compl[i].len) - (gsize)word_len
2441 ) == 0) {
2442 struct selection this = compl[i];
2443 for (++i; i < *num; i++) {
2444 compl[i - 1] = compl[i];
2446 compl[*num - 1] = this;
2447 skip = 1;
2448 break; /* skip it, already added */
2451 if (skip) {
2452 g_string_free(temp, TRUE);
2453 continue;
2455 if (*num == MAX_WORD_COMPLETIONS && MAX_WORD_COMPLETIONS) {
2456 g_free(compl[0].text);
2457 for (i = 1; i < *num; i++) {
2458 compl[i - 1] = compl[i];
2460 (*num)--;
2462 #ifdef HAVE_CHARSET
2464 GString *recoded;
2465 recoded = str_convert_to_display (temp->str);
2467 if (recoded && recoded->len){
2468 g_string_free(temp,TRUE);
2469 temp = recoded;
2470 } else
2471 g_string_free(recoded , TRUE);
2473 #endif
2474 compl[*num].text = temp->str;
2475 compl[*num].len = temp->len;
2476 (*num)++;
2477 start += len;
2478 g_string_free(temp, FALSE);
2480 /* note the maximal length needed for the completion dialog */
2481 if (len > max_len)
2482 max_len = len;
2484 mc_search_free(srch);
2485 return max_len;
2489 * Complete current word using regular expression search
2490 * backwards beginning at the current cursor position.
2492 void
2493 edit_complete_word_cmd (WEdit *edit)
2495 gsize i, max_len, word_len = 0, num_compl = 0;
2496 long word_start = 0;
2497 unsigned char *bufpos;
2498 char *match_expr;
2499 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2501 /* search start of word to be completed */
2502 if (!edit_find_word_start (edit, &word_start, &word_len))
2503 return;
2505 /* prepare match expression */
2506 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2507 [word_start & M_EDIT_BUF_SIZE];
2509 /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
2510 match_expr = g_strdup_printf ("(^|\\s+|\\b)%.*s[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+", word_len, bufpos);
2512 /* collect the possible completions */
2513 /* start search from begin to end of file */
2514 max_len =
2515 edit_collect_completions (edit, word_start, word_len, match_expr,
2516 (struct selection *) &compl, &num_compl);
2518 if (num_compl > 0) {
2519 /* insert completed word if there is only one match */
2520 if (num_compl == 1) {
2521 for (i = word_len; i < compl[0].len; i++)
2522 edit_insert (edit, *(compl[0].text + i));
2524 /* more than one possible completion => ask the user */
2525 else {
2526 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2527 /* !!! pressed again the selection dialog pops up, but that !!! */
2528 /* !!! seems to require a further internal state !!! */
2529 /*tty_beep (); */
2531 /* let the user select the preferred completion */
2532 editcmd_dialog_completion_show (edit, max_len, word_len,
2533 (struct selection *) &compl,
2534 num_compl);
2538 g_free (match_expr);
2539 /* release memory before return */
2540 for (i = 0; i < num_compl; i++)
2541 g_free (compl[i].text);
2545 void
2546 edit_select_codepage_cmd (WEdit *edit)
2548 #ifdef HAVE_CHARSET
2549 const char *cp_id = NULL;
2550 if (do_select_codepage ()) {
2551 cp_id = get_codepage_id (source_codepage >= 0 ?
2552 source_codepage : display_codepage);
2554 if (cp_id != NULL) {
2555 GIConv conv;
2556 conv = str_crt_conv_from (cp_id);
2557 if (conv != INVALID_CONV) {
2558 if (edit->converter != str_cnv_from_term)
2559 str_close_conv (edit->converter);
2560 edit->converter = conv;
2565 if (cp_id != NULL)
2566 edit->utf8 = str_isutf8 (cp_id);
2569 edit->force = REDRAW_COMPLETELY;
2570 edit_refresh_cmd (edit);
2571 #endif
2574 void
2575 edit_insert_literal_cmd (WEdit *edit)
2577 int char_for_insertion =
2578 editcmd_dialog_raw_key_query (_(" Insert Literal "),
2579 _(" Press any key: "), 0);
2580 edit_execute_key_command (edit, -1,
2581 ascii_alpha_to_cntrl (char_for_insertion));
2584 void
2585 edit_execute_macro_cmd (WEdit *edit)
2587 int command =
2588 CK_Macro (editcmd_dialog_raw_key_query
2589 (_(" Execute Macro "), _(" Press macro hotkey: "),
2590 1));
2591 if (command == CK_Macro (0))
2592 command = CK_Insert_Char;
2594 edit_execute_key_command (edit, command, -1);
2597 void
2598 edit_begin_end_macro_cmd(WEdit *edit)
2600 int command;
2602 /* edit is a pointer to the widget */
2603 if (edit) {
2604 command =
2605 edit->macro_i <
2606 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2607 edit_execute_key_command (edit, command, -1);
2612 edit_load_forward_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 + 1 < MAX_HISTORY_MOVETO ) {
2625 if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
2626 return 1;
2628 edit_stack_iterator++;
2629 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2630 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2631 edit_history_moveto[edit_stack_iterator].line);
2632 return 0;
2633 } else {
2634 return 1;
2636 } else {
2637 return 1;
2642 edit_load_back_cmd (WEdit *edit)
2644 if (edit->modified) {
2645 if (edit_query_dialog2
2646 (_("Warning"),
2647 _(" Current text was modified without a file save. \n"
2648 " Continue discards these changes. "), _("C&ontinue"),
2649 _("&Cancel"))) {
2650 edit->force |= REDRAW_COMPLETELY;
2651 return 0;
2654 if ( edit_stack_iterator > 0 ) {
2655 edit_stack_iterator--;
2656 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2657 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2658 edit_history_moveto[edit_stack_iterator].line);
2659 return 0;
2660 } else {
2661 return 1;
2663 } else {
2664 return 1;
2668 void
2669 edit_get_match_keyword_cmd (WEdit *edit)
2671 gsize word_len = 0, max_len = 0;
2672 int num_def = 0;
2673 int i;
2674 long word_start = 0;
2675 unsigned char *bufpos;
2676 char *match_expr;
2677 char *path = NULL;
2678 char *ptr = NULL;
2679 char *tagfile = NULL;
2681 etags_hash_t def_hash[MAX_DEFINITIONS];
2683 for ( i = 0; i < MAX_DEFINITIONS; i++) {
2684 def_hash[i].filename = NULL;
2687 /* search start of word to be completed */
2688 if (!edit_find_word_start (edit, &word_start, &word_len))
2689 return;
2691 /* prepare match expression */
2692 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2693 [word_start & M_EDIT_BUF_SIZE];
2694 match_expr = g_strdup_printf ("%.*s", word_len, bufpos);
2696 ptr = g_get_current_dir ();
2697 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
2698 g_free (ptr);
2700 /* Recursive search file 'TAGS' in parent dirs */
2701 do {
2702 ptr = g_path_get_dirname (path);
2703 g_free(path); path = ptr;
2704 g_free (tagfile);
2705 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
2706 if ( exist_file (tagfile) )
2707 break;
2708 } while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
2710 if (tagfile){
2711 num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
2712 g_free (tagfile);
2714 g_free (path);
2716 max_len = MAX_WIDTH_DEF_DIALOG;
2717 word_len = 0;
2718 if ( num_def > 0 ) {
2719 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
2720 (etags_hash_t *) &def_hash,
2721 num_def);
2723 g_free (match_expr);
2726 void
2727 edit_move_block_to_right (WEdit * edit)
2729 long start_mark, end_mark;
2730 long cur_bol, start_bol;
2732 if ( eval_marks (edit, &start_mark, &end_mark) )
2733 return;
2735 start_bol = edit_bol (edit, start_mark);
2736 cur_bol = edit_bol (edit, end_mark - 1);
2737 do {
2738 edit_cursor_move (edit, cur_bol - edit->curs1);
2739 if ( option_fill_tabs_with_spaces ) {
2740 if ( option_fake_half_tabs ) {
2741 insert_spaces_tab (edit, 1);
2742 } else {
2743 insert_spaces_tab (edit, 0);
2745 } else {
2746 edit_insert (edit, '\t');
2748 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
2749 if ( cur_bol == 0 ) {
2750 break;
2752 cur_bol = edit_bol (edit, cur_bol - 1);
2753 } while (cur_bol >= start_bol) ;
2754 edit->force |= REDRAW_PAGE;
2757 void
2758 edit_move_block_to_left (WEdit * edit)
2760 long start_mark, end_mark;
2761 long cur_bol, start_bol;
2762 int i, del_tab_width;
2763 int next_char;
2765 if ( eval_marks (edit, &start_mark, &end_mark) )
2766 return;
2768 start_bol = edit_bol (edit, start_mark);
2769 cur_bol = edit_bol (edit, end_mark - 1);
2770 do {
2771 edit_cursor_move (edit, cur_bol - edit->curs1);
2772 if (option_fake_half_tabs) {
2773 del_tab_width = HALF_TAB_SIZE;
2774 } else {
2775 del_tab_width = option_tab_spacing;
2777 next_char = edit_get_byte (edit, edit->curs1);
2778 if ( next_char == '\t' ) {
2779 edit_delete (edit, 1);
2780 } else if ( next_char == ' ' ) {
2781 for (i = 1; i <= del_tab_width; i++) {
2782 if ( next_char == ' ' ) {
2783 edit_delete (edit, 1);
2785 next_char = edit_get_byte (edit, edit->curs1);
2788 if ( cur_bol == 0 ) {
2789 break;
2791 cur_bol = edit_bol (edit, cur_bol - 1);
2792 } while (cur_bol >= start_bol) ;
2793 edit->force |= REDRAW_PAGE;