*** empty log message ***
[midnight-commander.git] / edit / editcmd.c
blobcde830977e43e221a9752548b823dbb8cc243e37
1 /* editor high level editing commands.
3 Copyright (C) 1996, 1997 the Free Software Foundation
5 Authors: 1996, 1997 Paul Sheer
7 $Id$
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22 02111-1307, USA.
26 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
28 #include <config.h>
29 #include <ctype.h>
31 #include "edit.h"
32 #include "editcmddef.h"
34 #ifdef HAVE_CHARSET
35 #include "src/charsets.h"
36 #endif
38 /* globals: */
40 /* search and replace: */
41 int replace_scanf = 0;
42 int replace_regexp = 0;
43 int replace_all = 0;
44 int replace_prompt = 1;
45 int replace_whole = 0;
46 int replace_case = 0;
47 int replace_backwards = 0;
48 int search_create_bookmark = 0;
50 /* queries on a save */
51 int edit_confirm_save = 1;
53 #define NUM_REPL_ARGS 64
54 #define MAX_REPL_LEN 1024
56 static inline int my_lower_case (int c)
58 return tolower(c & 0xFF);
61 char *strcasechr (const unsigned char *s, int c)
63 for (c = my_lower_case (c); my_lower_case ((int) *s) != c; ++s)
64 if (*s == '\0')
65 return 0;
66 return (char *) s;
69 #ifndef HAVE_MEMMOVE
70 /* for Christophe */
71 static void *memmove (void *dest, const void *src, size_t n)
73 char *t, *s;
75 if (dest <= src) {
76 t = (char *) dest;
77 s = (char *) src;
78 while (n--)
79 *t++ = *s++;
80 } else {
81 t = (char *) dest + n;
82 s = (char *) src + n;
83 while (n--)
84 *--t = *--s;
86 return dest;
88 #endif /* !HAVE_MEMMOVE */
90 /* #define itoa MY_itoa <---- this line is now in edit.h */
91 char *itoa (int i)
93 static char t[14];
94 char *s = t + 13;
95 int j = i;
96 *s-- = 0;
97 do {
98 *s-- = i % 10 + '0';
99 } while ((i = i / 10));
100 if (j < 0)
101 *s-- = '-';
102 return ++s;
106 This joins strings end on end and allocates memory for the result.
107 The result is later automatically free'd and must not be free'd
108 by the caller.
110 char *catstrs (const char *first,...)
112 static char *stacked[16] =
113 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
114 static int i = 0;
115 va_list ap;
116 int len;
117 char *data;
119 if (!first)
120 return 0;
122 len = strlen (first);
123 va_start (ap, first);
125 while ((data = va_arg (ap, char *)) != 0)
126 len += strlen (data);
128 len++;
130 i = (i + 1) % 16;
131 if (stacked[i])
132 free (stacked[i]);
134 stacked[i] = malloc (len);
135 va_end (ap);
136 va_start (ap, first);
137 strcpy (stacked[i], first);
138 while ((data = va_arg (ap, char *)) != 0)
139 strcat (stacked[i], data);
140 va_end (ap);
142 return stacked[i];
145 void edit_help_cmd (WEdit * edit)
147 interactive_display (NULL, "[Internal File Editor]");
148 edit->force |= REDRAW_COMPLETELY;
151 void edit_refresh_cmd (WEdit * edit)
153 #ifndef HAVE_SLANG
154 clr_scr();
155 do_refresh();
156 #else
158 int fg, bg;
159 edit_get_syntax_color (edit, -1, &fg, &bg);
161 touchwin(stdscr);
162 #endif /* !HAVE_SLANG */
163 mc_refresh();
164 doupdate();
167 /* "Oleg Yu. Repin" <repin@ssd.sscc.ru> added backup filenames
168 ...thanks -paul */
170 /* If 0 (quick save) then a) create/truncate <filename> file,
171 b) save to <filename>;
172 if 1 (safe save) then a) save to <tempnam>,
173 b) rename <tempnam> to <filename>;
174 if 2 (do backups) then a) save to <tempnam>,
175 b) rename <filename> to <filename.backup_ext>,
176 c) rename <tempnam> to <filename>. */
178 /* returns 0 on error */
179 int edit_save_file (WEdit * edit, const char *filename)
181 char *p;
182 long filelen = 0;
183 char *savename = 0;
184 int this_save_mode, fd;
186 if (!filename)
187 return 0;
188 if (!*filename)
189 return 0;
191 if ((fd = open (filename, O_WRONLY)) == -1) {
193 * The file does not exists yet, so no safe save or
194 * backup are necessary.
196 this_save_mode = 0;
197 } else {
198 close (fd);
199 this_save_mode = option_save_mode;
202 if (this_save_mode > 0) {
203 char *savedir, *slashpos, *saveprefix;
204 slashpos = strrchr (filename, PATH_SEP);
205 if (slashpos) {
206 savedir = (char *) strdup (filename);
207 savedir[slashpos - filename + 1] = '\0';
208 } else
209 savedir = (char *) strdup (".");
210 saveprefix = concat_dir_and_file (savedir, "cooledit");
211 free (savedir);
212 fd = mc_mkstemps(&savename, saveprefix, NULL);
213 g_free (saveprefix);
214 if (!savename)
215 return 0;
217 * FIXME: mc_mkstemps use pure open system call to create temporary file...
218 * This file handle must be close()d, but there is next line in edit.h:
219 * #define close mc_close
220 * So this hack needed.
222 #undef close
223 close (fd);
224 #define close mc_close
225 } else
226 savename = g_strdup (filename);
228 if ((fd = open (savename, O_CREAT | O_WRONLY | O_TRUNC | MY_O_TEXT,
229 edit->stat1.st_mode)) == -1)
230 goto error_save;
232 chmod (savename, edit->stat1.st_mode);
233 chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
235 /* pipe save */
236 if ((p = (char *) edit_get_write_filter (savename, filename))) {
237 FILE *file;
239 close (fd);
240 file = (FILE *) popen (p, "w");
242 if (file) {
243 filelen = edit_write_stream (edit, file);
244 #if 1
245 pclose (file);
246 #else
247 if (pclose (file) != 0) {
248 edit_error_dialog (_ (" Error "), catstrs (_ (" Error writing to pipe: "), p, " ", 0));
249 free (p);
250 goto error_save;
252 #endif
253 } else {
254 edit_error_dialog (_ (" Error "), get_sys_error (catstrs (_ (" Failed trying to open pipe for writing: "), p, " ", 0)));
255 free (p);
256 goto error_save;
258 free (p);
259 #ifdef CR_LF_TRANSLATION
260 } else { /* optimised save */
261 filelen = edit_write_stream (edit, f);
262 if (fclose (file))
263 filelen = -1;
264 #else
265 } else {
266 long buf;
267 buf = 0;
268 filelen = edit->last_byte;
269 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
270 if (write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
271 close (fd);
272 goto error_save;
274 buf++;
276 if (write (fd, (char *) edit->buffers1[buf], edit->curs1 & M_EDIT_BUF_SIZE) != (edit->curs1 & M_EDIT_BUF_SIZE)) {
277 filelen = -1;
278 } else if (edit->curs2) {
279 edit->curs2--;
280 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
281 if (write (fd, (char *) edit->buffers2[buf] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1, 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) != 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
282 filelen = -1;
283 } else {
284 while (--buf >= 0) {
285 if (write (fd, (char *) edit->buffers2[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
286 filelen = -1;
287 break;
291 edit->curs2++;
293 if (close (fd))
294 goto error_save;
295 #endif /* !CR_LF_TRANSLATION */
298 if (filelen != edit->last_byte)
299 goto error_save;
300 if (this_save_mode == 2)
301 if (rename (filename, catstrs (filename, option_backup_ext, 0)) == -1)
302 goto error_save;
303 if (this_save_mode > 0)
304 if (rename (savename, filename) == -1)
305 goto error_save;
306 if (savename)
307 g_free (savename);
308 return 1;
309 error_save:
310 if (savename)
311 g_free (savename);
312 return 0;
316 I changed this from Oleg's original routine so
317 that option_backup_ext works with coolwidgets as well. This
318 does mean there is a memory leak - paul.
320 void menu_save_mode_cmd (void)
322 #define DLG_X 38
323 #define DLG_Y 10
324 static char *str_result;
325 static int save_mode_new;
326 static char *str[] =
328 N_("Quick save "),
329 N_("Safe save "),
330 N_("Do backups -->")};
331 static QuickWidget widgets[] =
333 {quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
334 B_CANCEL, 0, 0, "c"},
335 {quick_button, 6, DLG_X, 7, DLG_Y, N_("&Ok"), 0,
336 B_ENTER, 0, 0, "o"},
337 {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
338 0, 0, &str_result, "edit-backup-ext"},
339 {quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
340 0, 0, 0, "savemext"},
341 {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
342 0, &save_mode_new, str, "t"},
343 {0}};
344 static QuickDialog dialog =
345 {DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
346 "esm", widgets};
347 static int i18n_flag = 0;
349 if (!i18n_flag) {
350 int i;
351 int maxlen = 0;
352 int dlg_x;
353 int l1;
355 /* Ok/Cancel buttons */
356 l1 = strlen (_(widgets[0].text)) + strlen (_(widgets[1].text)) + 5;
357 maxlen = max (maxlen, l1);
359 for (i = 0; i < 3; i++ ) {
360 str[i] = _(str[i]);
361 maxlen = max (maxlen, strlen (str[i]) + 7);
363 i18n_flag = 1;
365 dlg_x = maxlen + strlen (_(widgets[3].text)) + 5 + 1;
366 widgets[2].hotkey_pos = strlen (_(widgets[3].text)); /* input field length */
367 dlg_x = min (COLS, dlg_x);
368 dialog.xlen = dlg_x;
370 i = (dlg_x - l1)/3;
371 widgets[1].relative_x = i;
372 widgets[0].relative_x = i + strlen (_(widgets[1].text)) + i + 4;
374 widgets[2].relative_x = widgets[3].relative_x = maxlen + 2;
376 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
377 widgets[i].x_divisions = dlg_x;
380 widgets[2].text = option_backup_ext;
381 widgets[4].value = option_save_mode;
382 if (quick_dialog (&dialog) != B_ENTER)
383 return;
384 option_save_mode = save_mode_new;
385 option_backup_ext = str_result; /* this is a memory leak */
386 option_backup_ext_int = 0;
387 str_result[min (strlen (str_result), sizeof (int))] = '\0';
388 memcpy ((char *) &option_backup_ext_int, str_result, strlen (option_backup_ext));
391 void edit_split_filename (WEdit * edit, const char *f)
393 if (edit->filename)
394 free (edit->filename);
395 edit->filename = (char *) strdup (f);
396 if (edit->dir)
397 free (edit->dir);
398 edit->dir = (char *) strdup ("");
401 /* Here we want to warn the users of overwriting an existing file,
402 but only if they have made a change to the filename */
403 /* returns 1 on success */
404 int edit_save_as_cmd (WEdit * edit)
406 /* This heads the 'Save As' dialog box */
407 char *exp = 0;
408 int different_filename = 0;
410 exp = edit_get_save_file (edit->dir, edit->filename, _(" Save As "));
411 edit_push_action (edit, KEY_PRESS + edit->start_display);
413 if (exp) {
414 if (!*exp) {
415 g_free (exp);
416 edit->force |= REDRAW_COMPLETELY;
417 return 0;
418 } else {
419 if (strcmp(catstrs (edit->dir, edit->filename, 0), exp)) {
420 int file;
421 different_filename = 1;
422 if ((file = open ((char *) exp, O_RDONLY)) != -1) { /* the file exists */
423 close (file);
424 if (edit_query_dialog2 (_(" Warning "),
425 _(" A file already exists with this name. "),
426 /* Push buttons to over-write the current file, or cancel the operation */
427 _("Overwrite"), _("Cancel"))) {
428 edit->force |= REDRAW_COMPLETELY;
429 g_free (exp);
430 return 0;
434 if (edit_save_file (edit, exp)) {
435 edit_split_filename (edit, exp);
436 g_free (exp);
437 edit->modified = 0;
438 edit->delete_file = 0;
439 if (different_filename && !edit->explicit_syntax)
440 edit_load_syntax (edit, 0, 0);
441 edit->force |= REDRAW_COMPLETELY;
442 return 1;
443 } else {
444 g_free (exp);
445 edit_error_dialog (_(" Save as "), get_sys_error (_(" Error trying to save file. ")));
446 edit->force |= REDRAW_COMPLETELY;
447 return 0;
451 edit->force |= REDRAW_COMPLETELY;
452 return 0;
455 /* {{{ Macro stuff starts here */
457 int raw_callback (struct Dlg_head *h, int key, int Msg)
459 switch (Msg) {
460 case DLG_DRAW:
461 attrset (REVERSE_COLOR);
462 dlg_erase (h);
463 draw_box (h, 1, 1, h->lines - 2, h->cols - 2);
465 attrset (COLOR_HOT_NORMAL);
466 dlg_move (h, 1, 2);
467 printw (h->title);
468 break;
470 case DLG_KEY:
471 h->running = 0;
472 h->ret_value = key;
473 return 1;
475 return 0;
478 /* gets a raw key from the keyboard. Passing cancel = 1 draws
479 a cancel button thus allowing c-c etc.. Alternatively, cancel = 0
480 will return the next key pressed */
481 int edit_raw_key_query (char *heading, char *query, int cancel)
483 int w = strlen (query) + 7;
484 struct Dlg_head *raw_dlg = create_dlg (0, 0, 7, w, dialog_colors,
485 /* NLS ? */
486 raw_callback, "[Raw Key Query]",
487 "raw_key_input",
488 DLG_CENTER | DLG_TRYUP);
489 x_set_dialog_title (raw_dlg, heading);
490 raw_dlg->raw = 1; /* to return even a tab key */
491 if (cancel)
492 add_widget (raw_dlg, button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON, _("Cancel"), 0, 0, 0));
493 add_widget (raw_dlg, label_new (3 - cancel, 2, query, 0));
494 add_widget (raw_dlg, input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0));
495 run_dlg (raw_dlg);
496 w = raw_dlg->ret_value;
497 destroy_dlg (raw_dlg);
498 if (cancel)
499 if (w == XCTRL ('g') || w == XCTRL ('c') || w == ESC_CHAR || w == B_CANCEL)
500 return 0;
501 /* hence ctrl-a (=B_CANCEL), ctrl-g, ctrl-c, and Esc are cannot returned */
502 return w;
505 /* creates a macro file if it doesn't exist */
506 static FILE *edit_open_macro_file (const char *r)
508 char *filename;
509 int file;
510 filename = catstrs (home_dir, MACRO_FILE, 0);
511 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
512 return 0;
513 close (file);
514 return fopen (filename, r);
517 #define MAX_MACROS 1024
518 static int saved_macro[MAX_MACROS + 1];
519 static int saved_macros_loaded = 0;
522 This is just to stop the macro file be loaded over and over for keys
523 that aren't defined to anything. On slow systems this could be annoying.
525 int macro_exists (int k)
527 int i;
528 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
529 if (saved_macro[i] == k)
530 return i;
531 return -1;
534 /* returns 1 on error */
535 int edit_delete_macro (WEdit * edit, int k)
537 struct macro macro[MAX_MACRO_LENGTH];
538 FILE *f, *g;
539 int s, i, n, j = 0;
541 if (saved_macros_loaded)
542 if ((j = macro_exists (k)) < 0)
543 return 0;
544 g = fopen (catstrs (home_dir, TEMP_FILE, 0), "w");
545 if (!g) {
546 /* This heads the delete macro error dialog box */
547 edit_error_dialog (_(" Delete macro "),
548 /* 'Open' = load temp file */
549 get_sys_error (_(" Error trying to open temp file ")));
550 return 1;
552 f = edit_open_macro_file ("r");
553 if (!f) {
554 /* This heads the delete macro error dialog box */
555 edit_error_dialog (_(" Delete macro "),
556 /* 'Open' = load temp file */
557 get_sys_error (_(" Error trying to open macro file ")));
558 fclose (g);
559 return 1;
561 for (;;) {
562 n = fscanf (f, ("key '%d 0': "), &s);
563 if (!n || n == EOF)
564 break;
565 n = 0;
566 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
567 n++;
568 fscanf (f, ";\n");
569 if (s != k) {
570 fprintf (g, ("key '%d 0': "), s);
571 for (i = 0; i < n; i++)
572 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
573 fprintf (g, ";\n");
576 fclose (f);
577 fclose (g);
578 if (rename (catstrs (home_dir, TEMP_FILE, 0), catstrs (home_dir, MACRO_FILE, 0)) == -1) {
579 /* This heads the delete macro error dialog box */
580 edit_error_dialog (_(" Delete macro "),
581 get_sys_error (_(" Error trying to overwrite macro file ")));
582 return 1;
584 if (saved_macros_loaded)
585 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
586 return 0;
589 /* returns 0 on error */
590 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
592 FILE *f;
593 int s, i;
595 edit_push_action (edit, KEY_PRESS + edit->start_display);
596 /* This heads the 'Macro' dialog box */
597 s = edit_raw_key_query (_(" Macro "),
598 /* Input line for a single key press follows the ':' */
599 _(" Press the macro's new hotkey: "), 1);
600 edit->force |= REDRAW_COMPLETELY;
601 if (s) {
602 if (edit_delete_macro (edit, s))
603 return 0;
604 f = edit_open_macro_file ("a+");
605 if (f) {
606 fprintf (f, ("key '%d 0': "), s);
607 for (i = 0; i < n; i++)
608 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
609 fprintf (f, ";\n");
610 fclose (f);
611 if (saved_macros_loaded) {
612 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
613 saved_macro[i] = s;
615 return 1;
616 } else
617 /* This heads the 'Save Macro' dialog box */
618 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Error trying to open macro file ")));
620 return 0;
623 void edit_delete_macro_cmd (WEdit * edit)
625 int command;
627 command = edit_raw_key_query (_ (" Delete Macro "),
628 _ (" Press macro hotkey: "), 1);
630 if (!command)
631 return;
633 edit_delete_macro (edit, command);
636 /* return 0 on error */
637 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
639 FILE *f;
640 int s, i = 0, found = 0;
642 if (saved_macros_loaded)
643 if (macro_exists (k) < 0)
644 return 0;
646 if ((f = edit_open_macro_file ("r"))) {
647 struct macro dummy;
648 do {
649 int u;
650 u = fscanf (f, ("key '%d 0': "), &s);
651 if (!u || u == EOF)
652 break;
653 if (!saved_macros_loaded)
654 saved_macro[i++] = s;
655 if (!found) {
656 *n = 0;
657 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
658 (*n)++;
659 } else {
660 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
662 fscanf (f, ";\n");
663 if (s == k)
664 found = 1;
665 } while (!found || !saved_macros_loaded);
666 if (!saved_macros_loaded) {
667 saved_macro[i] = 0;
668 saved_macros_loaded = 1;
670 fclose (f);
671 return found;
672 } else
673 /* This heads the 'Load Macro' dialog box */
674 edit_error_dialog (_(" Load macro "),
675 get_sys_error (_(" Error trying to open macro file ")));
676 return 0;
679 /* }}} Macro stuff starts here */
681 /* returns 1 on success */
682 int edit_save_confirm_cmd (WEdit * edit)
684 char *f;
686 if (edit_confirm_save) {
687 f = catstrs (_(" Confirm save file? : "), edit->filename, " ", 0);
688 /* Buttons to 'Confirm save file' query */
689 if (edit_query_dialog2 (_(" Save file "), f, _("Save"), _("Cancel")))
690 return 0;
692 return edit_save_cmd (edit);
696 /* returns 1 on success */
697 int edit_save_cmd (WEdit * edit)
699 if (!edit_save_file (edit, catstrs (edit->dir, edit->filename, 0)))
700 return edit_save_as_cmd (edit);
701 edit->force |= REDRAW_COMPLETELY;
702 edit->modified = 0;
703 edit->delete_file = 0;
705 return 1;
709 /* returns 1 on success */
710 int edit_new_cmd (WEdit * edit)
712 if (edit->modified) {
713 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
714 edit->force |= REDRAW_COMPLETELY;
715 return 0;
718 edit->force |= REDRAW_COMPLETELY;
719 edit->modified = 0;
720 return edit_renew (edit); /* if this gives an error, something has really screwed up */
723 /* returns 1 on error */
724 int edit_load_file_from_filename (WEdit * edit, char *exp)
726 if (!edit_reload (edit, exp, 0, "", 0))
727 return 1;
728 edit_split_filename (edit, exp);
729 edit->modified = 0;
730 return 0;
733 int edit_load_cmd (WEdit * edit)
735 char *exp;
737 if (edit->modified) {
738 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
739 edit->force |= REDRAW_COMPLETELY;
740 return 0;
744 exp = edit_get_load_file (edit->dir, edit->filename, _ (" Load "));
746 if (exp) {
747 if (*exp)
748 edit_load_file_from_filename (edit, exp);
749 g_free (exp);
751 edit->force |= REDRAW_COMPLETELY;
752 return 0;
756 if mark2 is -1 then marking is from mark1 to the cursor.
757 Otherwise its between the markers. This handles this.
758 Returns 1 if no text is marked.
760 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
762 if (edit->mark1 != edit->mark2) {
763 if (edit->mark2 >= 0) {
764 *start_mark = min (edit->mark1, edit->mark2);
765 *end_mark = max (edit->mark1, edit->mark2);
766 } else {
767 *start_mark = min (edit->mark1, edit->curs1);
768 *end_mark = max (edit->mark1, edit->curs1);
769 edit->column2 = edit->curs_col;
771 return 0;
772 } else {
773 *start_mark = *end_mark = 0;
774 edit->column2 = edit->column1 = 0;
775 return 1;
779 /*Block copy, move and delete commands */
780 extern int column_highlighting;
782 #define space_width 1
784 void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
786 long cursor;
787 int i, col;
788 cursor = edit->curs1;
789 col = edit_get_col (edit);
790 for (i = 0; i < size; i++) {
791 if (data[i] == '\n') { /* fill in and move to next line */
792 int l;
793 long p;
794 if (edit_get_byte (edit, edit->curs1) != '\n') {
795 l = width - (edit_get_col (edit) - col);
796 while (l > 0) {
797 edit_insert (edit, ' ');
798 l -= space_width;
801 for (p = edit->curs1;; p++) {
802 if (p == edit->last_byte)
803 edit_insert_ahead (edit, '\n');
804 if (edit_get_byte (edit, p) == '\n') {
805 p++;
806 break;
809 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
810 l = col - edit_get_col (edit);
811 while (l >= space_width) {
812 edit_insert (edit, ' ');
813 l -= space_width;
815 continue;
817 edit_insert (edit, data[i]);
819 edit_cursor_move (edit, cursor - edit->curs1);
823 void edit_block_copy_cmd (WEdit * edit)
825 long start_mark, end_mark, current = edit->curs1;
826 int size, x;
827 unsigned char *copy_buf;
829 edit_update_curs_col (edit);
830 x = edit->curs_col;
831 if (eval_marks (edit, &start_mark, &end_mark))
832 return;
833 if (column_highlighting)
834 if ((x >= edit->column1 && x < edit->column2) || (x > edit->column2 && x <= edit->column1))
835 return;
837 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
839 /* all that gets pushed are deletes hence little space is used on the stack */
841 edit_push_markers (edit);
843 if (column_highlighting) {
844 edit_insert_column_of_text (edit, copy_buf, size, abs (edit->column2 - edit->column1));
845 } else {
846 while (size--)
847 edit_insert_ahead (edit, copy_buf[size]);
850 free (copy_buf);
851 edit_scroll_screen_over_cursor (edit);
853 if (column_highlighting) {
854 edit_set_markers (edit, 0, 0, 0, 0);
855 edit_push_action (edit, COLUMN_ON);
856 column_highlighting = 0;
857 } else if (start_mark < current && end_mark > current)
858 edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
860 edit->force |= REDRAW_PAGE;
864 void edit_block_move_cmd (WEdit * edit)
866 long count;
867 long current;
868 unsigned char *copy_buf;
869 long start_mark, end_mark;
870 int deleted = 0;
871 int x = 0;
873 if (eval_marks (edit, &start_mark, &end_mark))
874 return;
875 if (column_highlighting) {
876 edit_update_curs_col (edit);
877 x = edit->curs_col;
878 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
879 if ((x > edit->column1 && x < edit->column2) || (x > edit->column2 && x < edit->column1))
880 return;
881 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
882 return;
884 if ((end_mark - start_mark) > option_max_undo / 2)
885 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ ("Continue"), _ ("Cancel")))
886 return;
888 edit_push_markers (edit);
889 current = edit->curs1;
890 if (column_highlighting) {
891 int size, c1, c2, line;
892 line = edit->curs_line;
893 if (edit->mark2 < 0)
894 edit_mark_cmd (edit, 0);
895 c1 = min (edit->column1, edit->column2);
896 c2 = max (edit->column1, edit->column2);
897 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
898 if (x < c2) {
899 edit_block_delete_cmd (edit);
900 deleted = 1;
902 edit_move_to_line (edit, line);
903 edit_cursor_move (edit, edit_move_forward3 (edit, edit_bol (edit, edit->curs1), x, 0) - edit->curs1);
904 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
905 if (!deleted) {
906 line = edit->curs_line;
907 edit_update_curs_col (edit);
908 x = edit->curs_col;
909 edit_block_delete_cmd (edit);
910 edit_move_to_line (edit, line);
911 edit_cursor_move (edit, edit_move_forward3 (edit, edit_bol (edit, edit->curs1), x, 0) - edit->curs1);
913 edit_set_markers (edit, 0, 0, 0, 0);
914 edit_push_action (edit, COLUMN_ON);
915 column_highlighting = 0;
916 } else {
917 copy_buf = malloc (end_mark - start_mark);
918 edit_cursor_move (edit, start_mark - edit->curs1);
919 edit_scroll_screen_over_cursor (edit);
920 count = start_mark;
921 while (count < end_mark) {
922 copy_buf[end_mark - count - 1] = edit_delete (edit);
923 count++;
925 edit_scroll_screen_over_cursor (edit);
926 edit_cursor_move (edit, current - edit->curs1 - (((current - edit->curs1) > 0) ? end_mark - start_mark : 0));
927 edit_scroll_screen_over_cursor (edit);
928 while (count-- > start_mark)
929 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
930 edit_set_markers (edit, edit->curs1, edit->curs1 + end_mark - start_mark, 0, 0);
932 edit_scroll_screen_over_cursor (edit);
933 free (copy_buf);
934 edit->force |= REDRAW_PAGE;
937 void edit_cursor_to_bol (WEdit * edit);
939 void edit_delete_column_of_text (WEdit * edit)
941 long p, q, r, m1, m2;
942 int b, c, d;
943 int n;
945 eval_marks (edit, &m1, &m2);
946 n = edit_move_forward (edit, m1, 0, m2) + 1;
947 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
948 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
950 b = min (c, d);
951 c = max (c, d);
953 while (n--) {
954 r = edit_bol (edit, edit->curs1);
955 p = edit_move_forward3 (edit, r, b, 0);
956 q = edit_move_forward3 (edit, r, c, 0);
957 if (p < m1)
958 p = m1;
959 if (q > m2)
960 q = m2;
961 edit_cursor_move (edit, p - edit->curs1);
962 while (q > p) { /* delete line between margins */
963 if (edit_get_byte (edit, edit->curs1) != '\n')
964 edit_delete (edit);
965 q--;
967 if (n) /* move to next line except on the last delete */
968 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
972 /* if success return 0 */
973 int edit_block_delete (WEdit * edit)
975 long count;
976 long start_mark, end_mark;
977 if (eval_marks (edit, &start_mark, &end_mark))
978 return 0;
979 if (column_highlighting && edit->mark2 < 0)
980 edit_mark_cmd (edit, 0);
981 if ((end_mark - start_mark) > option_max_undo / 2)
982 /* Warning message with a query to continue or cancel the operation */
983 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ (" Continue "), _ (" Cancel ")))
984 return 1;
985 edit_push_markers (edit);
986 edit_cursor_move (edit, start_mark - edit->curs1);
987 edit_scroll_screen_over_cursor (edit);
988 count = start_mark;
989 if (start_mark < end_mark) {
990 if (column_highlighting) {
991 if (edit->mark2 < 0)
992 edit_mark_cmd (edit, 0);
993 edit_delete_column_of_text (edit);
994 } else {
995 while (count < end_mark) {
996 edit_delete (edit);
997 count++;
1001 edit_set_markers (edit, 0, 0, 0, 0);
1002 edit->force |= REDRAW_PAGE;
1003 return 0;
1006 /* returns 1 if canceelled by user */
1007 int edit_block_delete_cmd (WEdit * edit)
1009 long start_mark, end_mark;
1010 if (eval_marks (edit, &start_mark, &end_mark)) {
1011 edit_delete_line (edit);
1012 return 0;
1014 return edit_block_delete (edit);
1018 #define INPUT_INDEX 9
1019 #define SEARCH_DLG_WIDTH 58
1020 #define SEARCH_DLG_HEIGHT 10
1021 #define REPLACE_DLG_WIDTH 58
1022 #define REPLACE_DLG_HEIGHT 15
1023 #define CONFIRM_DLG_WIDTH 79
1024 #define CONFIRM_DLG_HEIGTH 6
1025 #define B_REPLACE_ALL B_USER+1
1026 #define B_REPLACE_ONE B_USER+2
1027 #define B_SKIP_REPLACE B_USER+3
1029 int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
1031 QuickWidget quick_widgets[] =
1033 {quick_button, 63, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Cancel"),
1034 0, B_CANCEL, 0, 0, NULL},
1035 {quick_button, 50, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("o&Ne"),
1036 0, B_REPLACE_ONE, 0, 0, NULL},
1037 {quick_button, 37, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("al&L"),
1038 0, B_REPLACE_ALL, 0, 0, NULL},
1039 {quick_button, 21, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Skip"),
1040 0, B_SKIP_REPLACE, 0, 0, NULL},
1041 {quick_button, 4, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Replace"),
1042 0, B_ENTER, 0, 0, NULL},
1043 {quick_label, 2, CONFIRM_DLG_WIDTH, 2, CONFIRM_DLG_HEIGTH, 0,
1044 0, 0, 0, 0, 0},
1045 {0}};
1047 #ifdef HAVE_CHARSET
1048 char *msg = _(" Replace with: ");
1050 quick_widgets[5].text = catstrs (msg, replace_text, 0);
1052 if (*replace_text)
1053 convert_to_display (quick_widgets[5].text + strlen (msg));
1054 #else
1055 quick_widgets[5].text = catstrs (_ (" Replace with: "), replace_text, 0);
1056 #endif /* !HAVE_CHARSET */
1059 QuickDialog Quick_input =
1060 {CONFIRM_DLG_WIDTH, CONFIRM_DLG_HEIGTH, 0, 0, N_ (" Confirm replace "),
1061 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1063 Quick_input.widgets = quick_widgets;
1065 Quick_input.xpos = xpos;
1067 /* Sometimes menu can hide replaced text. I don't like it */
1069 if ((edit->curs_row >= ypos - 1) && (edit->curs_row <= ypos + CONFIRM_DLG_HEIGTH - 1))
1070 ypos -= CONFIRM_DLG_HEIGTH;
1072 Quick_input.ypos = ypos;
1073 return quick_dialog (&Quick_input);
1077 void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order)
1079 int treplace_scanf = replace_scanf;
1080 int treplace_regexp = replace_regexp;
1081 int treplace_all = replace_all;
1082 int treplace_prompt = replace_prompt;
1083 int treplace_backwards = replace_backwards;
1084 int treplace_whole = replace_whole;
1085 int treplace_case = replace_case;
1087 QuickWidget quick_widgets[] =
1089 {quick_button, 6, 10, 12, REPLACE_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1090 0, NULL},
1091 {quick_button, 2, 10, 12, REPLACE_DLG_HEIGHT, N_("&Ok"), 0, B_ENTER, 0,
1092 0, NULL},
1093 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1094 0, 0, NULL},
1095 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("replace &All"), 0, 0,
1096 0, 0, NULL},
1097 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("pr&Ompt on replace"), 0, 0,
1098 0, 0, NULL},
1099 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1100 0, 0, NULL},
1101 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1102 0, 0, NULL},
1103 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1104 0, 0, NULL},
1105 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 8, REPLACE_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1106 0, 0, NULL},
1107 {quick_input, 3, REPLACE_DLG_WIDTH, 7, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1108 0, "edit-argord"},
1109 {quick_label, 2, REPLACE_DLG_WIDTH, 6, REPLACE_DLG_HEIGHT, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1110 0, 0, 0},
1111 {quick_input, 3, REPLACE_DLG_WIDTH, 5, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1112 0, "edit-replace"},
1113 {quick_label, 2, REPLACE_DLG_WIDTH, 4, REPLACE_DLG_HEIGHT, N_(" Enter replacement string:"), 0, 0, 0,
1114 0, 0},
1115 {quick_input, 3, REPLACE_DLG_WIDTH, 3, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1116 0, "edit-search"},
1117 {quick_label, 2, REPLACE_DLG_WIDTH, 2, REPLACE_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1118 0, 0},
1119 {0}};
1121 quick_widgets[2].result = &treplace_scanf;
1122 quick_widgets[3].result = &treplace_all;
1123 quick_widgets[4].result = &treplace_prompt;
1124 quick_widgets[5].result = &treplace_backwards;
1125 quick_widgets[6].result = &treplace_regexp;
1126 quick_widgets[7].result = &treplace_whole;
1127 quick_widgets[8].result = &treplace_case;
1128 quick_widgets[9].str_result = arg_order;
1129 quick_widgets[9].text = *arg_order;
1130 quick_widgets[11].str_result = replace_text;
1131 quick_widgets[11].text = *replace_text;
1132 quick_widgets[13].str_result = search_text;
1133 quick_widgets[13].text = *search_text;
1135 QuickDialog Quick_input =
1136 {REPLACE_DLG_WIDTH, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "),
1137 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1139 Quick_input.widgets = quick_widgets;
1141 if (quick_dialog (&Quick_input) != B_CANCEL) {
1142 replace_scanf = treplace_scanf;
1143 replace_backwards = treplace_backwards;
1144 replace_regexp = treplace_regexp;
1145 replace_all = treplace_all;
1146 replace_prompt = treplace_prompt;
1147 replace_whole = treplace_whole;
1148 replace_case = treplace_case;
1149 return;
1150 } else {
1151 *arg_order = NULL;
1152 *replace_text = NULL;
1153 *search_text = NULL;
1154 return;
1160 void edit_search_dialog (WEdit * edit, char **search_text)
1162 int treplace_scanf = replace_scanf;
1163 int treplace_regexp = replace_regexp;
1164 int treplace_whole = replace_whole;
1165 int treplace_case = replace_case;
1166 int treplace_backwards = replace_backwards;
1168 QuickWidget quick_widgets[] =
1170 {quick_button, 6, 10, 7, SEARCH_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1171 0, NULL},
1172 {quick_button, 2, 10, 7, SEARCH_DLG_HEIGHT, N_("&Ok"), 0, B_ENTER, 0,
1173 0, NULL},
1174 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1175 0, 0, NULL },
1176 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1177 0, 0, NULL},
1178 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1179 0, 0, NULL},
1180 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1181 0, 0, NULL},
1182 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 4, SEARCH_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1183 0, 0, NULL},
1184 {quick_input, 3, SEARCH_DLG_WIDTH, 3, SEARCH_DLG_HEIGHT, "", 52, 0, 0,
1185 0, "edit-search"},
1186 {quick_label, 2, SEARCH_DLG_WIDTH, 2, SEARCH_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1187 0, 0},
1188 {0}};
1190 quick_widgets[2].result = &treplace_scanf;
1191 quick_widgets[3].result = &treplace_backwards;
1192 quick_widgets[4].result = &treplace_regexp;
1193 quick_widgets[5].result = &treplace_whole;
1194 quick_widgets[6].result = &treplace_case;
1195 quick_widgets[7].str_result = search_text;
1196 quick_widgets[7].text = *search_text;
1199 QuickDialog Quick_input =
1200 {SEARCH_DLG_WIDTH, SEARCH_DLG_HEIGHT, -1, 0, N_(" Search "),
1201 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1203 Quick_input.widgets = quick_widgets;
1205 if (quick_dialog (&Quick_input) != B_CANCEL) {
1206 replace_scanf = treplace_scanf;
1207 replace_backwards = treplace_backwards;
1208 replace_regexp = treplace_regexp;
1209 replace_whole = treplace_whole;
1210 replace_case = treplace_case;
1211 } else {
1212 *search_text = NULL;
1218 static long sargs[NUM_REPL_ARGS][256 / sizeof (long)];
1220 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1221 sargs[4], sargs[5], sargs[6], sargs[7], \
1222 sargs[8], sargs[9], sargs[10], sargs[11], \
1223 sargs[12], sargs[13], sargs[14], sargs[15]
1225 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1226 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1227 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1228 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1231 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1232 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1233 int string_regexp_search (char *pattern, char *string, int len, int match_type, int match_bol, int icase, int *found_len, void *d)
1235 static regex_t r;
1236 static char *old_pattern = NULL;
1237 static int old_type, old_icase;
1238 regmatch_t *pmatch;
1239 static regmatch_t s[1];
1241 pmatch = (regmatch_t *) d;
1242 if (!pmatch)
1243 pmatch = s;
1245 if (!old_pattern || strcmp (old_pattern, pattern) || old_type != match_type || old_icase != icase) {
1246 if (old_pattern) {
1247 regfree (&r);
1248 free (old_pattern);
1249 old_pattern = 0;
1251 if (regcomp (&r, pattern, REG_EXTENDED | (icase ? REG_ICASE : 0))) {
1252 *found_len = 0;
1253 return -3;
1255 old_pattern = (char *) strdup (pattern);
1256 old_type = match_type;
1257 old_icase = icase;
1259 if (regexec (&r, string, d ? NUM_REPL_ARGS : 1, pmatch, ((match_bol || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) {
1260 *found_len = 0;
1261 return -1;
1263 *found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
1264 return (pmatch[0].rm_so);
1267 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1268 (and the above) routines to work properly - paul */
1270 long edit_find_string (long start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, int once_only, void *d)
1272 long p, q = 0;
1273 long l = strlen ((char *) exp), f = 0;
1274 int n = 0;
1276 for (p = 0; p < l; p++) /* count conversions... */
1277 if (exp[p] == '%')
1278 if (exp[++p] != '%') /* ...except for "%%" */
1279 n++;
1281 if (replace_scanf || replace_regexp) {
1282 int c;
1283 unsigned char *buf;
1284 unsigned char mbuf[MAX_REPL_LEN * 2 + 3];
1286 replace_scanf = (!replace_regexp); /* can't have both */
1288 buf = mbuf;
1290 if (replace_scanf) {
1291 unsigned char e[MAX_REPL_LEN];
1292 if (n >= NUM_REPL_ARGS)
1293 return -3;
1295 if (replace_case) {
1296 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++)
1297 buf[p - start] = (*get_byte) (data, p);
1298 } else {
1299 for (p = 0; exp[p] != 0; p++)
1300 exp[p] = my_lower_case (exp[p]);
1301 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) {
1302 c = (*get_byte) (data, p);
1303 buf[p - start] = my_lower_case (c);
1307 buf[(q = p - start)] = 0;
1308 strcpy ((char *) e, (char *) exp);
1309 strcat ((char *) e, "%n");
1310 exp = e;
1312 while (q) {
1313 *((int *) sargs[n]) = 0; /* --> here was the problem - now fixed: good */
1314 if (n == sscanf ((char *) buf, (char *) exp, SCANF_ARGS)) {
1315 if (*((int *) sargs[n])) {
1316 *len = *((int *) sargs[n]);
1317 return start;
1320 if (once_only)
1321 return -2;
1322 if (q + start < last_byte) {
1323 if (replace_case) {
1324 buf[q] = (*get_byte) (data, q + start);
1325 } else {
1326 c = (*get_byte) (data, q + start);
1327 buf[q] = my_lower_case (c);
1329 q++;
1331 buf[q] = 0;
1332 start++;
1333 buf++; /* move the window along */
1334 if (buf == mbuf + MAX_REPL_LEN) { /* the window is about to go past the end of array, so... */
1335 memmove (mbuf, buf, strlen ((char *) buf) + 1); /* reset it */
1336 buf = mbuf;
1338 q--;
1340 } else { /* regexp matching */
1341 long offset = 0;
1342 int found_start, match_bol, move_win = 0;
1344 while (start + offset < last_byte) {
1345 match_bol = (offset == 0 || (*get_byte) (data, start + offset - 1) == '\n');
1346 if (!move_win) {
1347 p = start + offset;
1348 q = 0;
1350 for (; p < last_byte && q < MAX_REPL_LEN; p++, q++) {
1351 mbuf[q] = (*get_byte) (data, p);
1352 if (mbuf[q] == '\n')
1353 break;
1355 q++;
1356 offset += q;
1357 mbuf[q] = 0;
1359 buf = mbuf;
1360 while (q) {
1361 found_start = string_regexp_search ((char *) exp, (char *) buf, q, match_normal, match_bol, !replace_case, len, d);
1363 if (found_start <= -2) { /* regcomp/regexec error */
1364 *len = 0;
1365 return -3;
1367 else if (found_start == -1) /* not found: try next line */
1368 break;
1369 else if (*len == 0) { /* null pattern: try again at next character */
1370 q--;
1371 buf++;
1372 match_bol = 0;
1373 continue;
1375 else /* found */
1376 return (start + offset - q + found_start);
1378 if (once_only)
1379 return -2;
1381 if (buf[q - 1] != '\n') { /* incomplete line: try to recover */
1382 buf = mbuf + MAX_REPL_LEN / 2;
1383 q = strlen ((char *) buf);
1384 memmove (mbuf, buf, q);
1385 p = start + q;
1386 move_win = 1;
1388 else
1389 move_win = 0;
1392 } else {
1393 *len = strlen ((char *) exp);
1394 if (replace_case) {
1395 for (p = start; p <= last_byte - l; p++) {
1396 if ((*get_byte) (data, p) == (unsigned char)exp[0]) { /* check if first char matches */
1397 for (f = 0, q = 0; q < l && f < 1; q++)
1398 if ((*get_byte) (data, q + p) != (unsigned char)exp[q])
1399 f = 1;
1400 if (f == 0)
1401 return p;
1403 if (once_only)
1404 return -2;
1406 } else {
1407 for (p = 0; exp[p] != 0; p++)
1408 exp[p] = my_lower_case (exp[p]);
1410 for (p = start; p <= last_byte - l; p++) {
1411 if (my_lower_case ((*get_byte) (data, p)) == (unsigned char)exp[0]) {
1412 for (f = 0, q = 0; q < l && f < 1; q++)
1413 if (my_lower_case ((*get_byte) (data, q + p)) != (unsigned char)exp[q])
1414 f = 1;
1415 if (f == 0)
1416 return p;
1418 if (once_only)
1419 return -2;
1423 return -2;
1427 long edit_find_forwards (long search_start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, int once_only, void *d)
1428 { /*front end to find_string to check for
1429 whole words */
1430 long p;
1431 p = search_start;
1433 while ((p = edit_find_string (p, exp, len, last_byte, get_byte, data, once_only, d)) >= 0) {
1434 if (replace_whole) {
1435 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1436 if (!strcasechr (option_whole_chars_search, (*get_byte) (data, p - 1))
1437 && !strcasechr (option_whole_chars_search, (*get_byte) (data, p + *len)))
1438 return p;
1439 if (once_only)
1440 return -2;
1441 } else
1442 return p;
1443 if (once_only)
1444 break;
1445 p++; /*not a whole word so continue search. */
1447 return p;
1450 long edit_find (long search_start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, void *d)
1452 long p;
1453 if (replace_backwards) {
1454 while (search_start >= 0) {
1455 p = edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 1, d);
1456 if (p == search_start)
1457 return p;
1458 search_start--;
1460 } else {
1461 return edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 0, d);
1463 return -2;
1466 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1468 #define snprintf(v) { \
1469 *p1++ = *p++; \
1470 *p1++ = '%'; \
1471 *p1++ = 'n'; \
1472 *p1 = '\0'; \
1473 sprintf(s,q1,v,&n); \
1474 s += n; \
1477 /* this function uses the sprintf command to do a vprintf */
1478 /* it takes pointers to arguments instead of the arguments themselves */
1479 static int sprintf_p (char *str, const char *fmt,...)
1480 __attribute__ ((format (printf, 2, 3)));
1482 static int sprintf_p (char *str, const char *fmt,...)
1484 va_list ap;
1485 int n;
1486 char *q, *p, *s = str;
1487 char q1[32];
1488 char *p1;
1490 va_start (ap, fmt);
1491 p = q = (char *) fmt;
1493 while ((p = strchr (p, '%'))) {
1494 n = p - q;
1495 strncpy (s, q, n); /* copy stuff between format specifiers */
1496 s += n;
1497 *s = 0;
1498 q = p;
1499 p1 = q1;
1500 *p1++ = *p++;
1501 if (*p == '%') {
1502 p++;
1503 *s++ = '%';
1504 q = p;
1505 continue;
1507 if (*p == 'n') {
1508 p++;
1509 /* do nothing */
1510 q = p;
1511 continue;
1513 if (*p == '#')
1514 *p1++ = *p++;
1515 if (*p == '0')
1516 *p1++ = *p++;
1517 if (*p == '-')
1518 *p1++ = *p++;
1519 if (*p == '+')
1520 *p1++ = *p++;
1521 if (*p == '*') {
1522 p++;
1523 strcpy (p1, itoa (*va_arg (ap, int *))); /* replace field width with a number */
1524 p1 += strlen (p1);
1525 } else {
1526 while (is_digit (*p))
1527 *p1++ = *p++;
1529 if (*p == '.')
1530 *p1++ = *p++;
1531 if (*p == '*') {
1532 p++;
1533 strcpy (p1, itoa (*va_arg (ap, int *))); /* replace precision with a number */
1534 p1 += strlen (p1);
1535 } else {
1536 while (is_digit (*p))
1537 *p1++ = *p++;
1539 /* flags done, now get argument */
1540 if (*p == 's') {
1541 snprintf (va_arg (ap, char *));
1542 } else if (*p == 'h') {
1543 if (strchr ("diouxX", *p))
1544 snprintf (*va_arg (ap, short *));
1545 } else if (*p == 'l') {
1546 *p1++ = *p++;
1547 if (strchr ("diouxX", *p))
1548 snprintf (*va_arg (ap, long *));
1549 } else if (strchr ("cdiouxX", *p)) {
1550 snprintf (*va_arg (ap, int *));
1551 } else if (*p == 'L') {
1552 *p1++ = *p++;
1553 if (strchr ("EefgG", *p))
1554 snprintf (*va_arg (ap, double *)); /* should be long double */
1555 } else if (strchr ("EefgG", *p)) {
1556 snprintf (*va_arg (ap, double *));
1557 } else if (strchr ("DOU", *p)) {
1558 snprintf (*va_arg (ap, long *));
1559 } else if (*p == 'p') {
1560 snprintf (*va_arg (ap, void **));
1562 q = p;
1564 va_end (ap);
1565 sprintf (s, q); /* print trailing leftover */
1566 return s - str + strlen (s);
1569 static void regexp_error (WEdit *edit)
1571 /* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */
1572 edit_error_dialog (_(" Error "), _(" Invalid regular expression, or scanf expression with to many conversions "));
1575 /* call with edit = 0 before shutdown to close memory leaks */
1576 void edit_replace_cmd (WEdit * edit, int again)
1578 static regmatch_t pmatch[NUM_REPL_ARGS];
1579 static char *old1 = NULL;
1580 static char *old2 = NULL;
1581 static char *old3 = NULL;
1582 char *exp1 = "";
1583 char *exp2 = "";
1584 char *exp3 = "";
1585 int replace_yes;
1586 int replace_continue;
1587 int treplace_prompt = 0;
1588 int i = 0;
1589 long times_replaced = 0, last_search;
1590 char fin_string[64];
1591 int argord[NUM_REPL_ARGS];
1593 if (!edit) {
1594 if (old1) {
1595 g_free (old1);
1596 old1 = 0;
1598 if (old2) {
1599 g_free (old2);
1600 old2 = 0;
1602 if (old3) {
1603 g_free (old3);
1604 old3 = 0;
1606 return;
1608 last_search = edit->last_byte;
1610 edit->force |= REDRAW_COMPLETELY;
1612 exp1 = old1 ? old1 : exp1;
1613 exp2 = old2 ? old2 : exp2;
1614 exp3 = old3 ? old3 : exp3;
1616 if (again) {
1617 if (!old1 || !old2)
1618 return;
1619 exp1 = g_strdup (old1);
1620 exp2 = g_strdup (old2);
1621 exp3 = g_strdup (old3);
1622 } else {
1623 edit_push_action (edit, KEY_PRESS + edit->start_display);
1625 #ifdef HAVE_CHARSET
1626 if (exp1 && *exp1)
1627 convert_to_display (exp1);
1628 if (exp2 && *exp2)
1629 convert_to_display (exp2);
1630 #endif /* HAVE_CHARSET */
1632 edit_replace_dialog (edit, &exp1, &exp2, &exp3);
1634 #ifdef HAVE_CHARSET
1635 if (exp1 && *exp1)
1636 convert_from_input (exp1);
1637 if (exp2 && *exp2)
1638 convert_from_input (exp2);
1639 #endif /* HAVE_CHARSET */
1641 treplace_prompt = replace_prompt;
1644 if (!exp1 || !*exp1) {
1645 edit->force = REDRAW_COMPLETELY;
1646 if (exp1)
1647 g_free (exp1);
1648 if (exp2)
1649 g_free (exp2);
1650 if (exp3)
1651 g_free (exp3);
1652 return;
1654 if (old1)
1655 g_free (old1);
1656 if (old2)
1657 g_free (old2);
1658 if (old3)
1659 g_free (old3);
1660 old1 = g_strdup (exp1);
1661 old2 = g_strdup (exp2);
1662 old3 = g_strdup (exp3);
1665 char *s;
1666 int ord;
1667 while ((s = strchr (exp3, ' ')))
1668 memmove (s, s + 1, strlen (s));
1669 s = exp3;
1670 for (i = 0; i < NUM_REPL_ARGS; i++) {
1671 if (s != (char *)1 && *s) {
1672 ord = atoi (s);
1673 if ((ord > 0) && (ord < NUM_REPL_ARGS))
1674 argord[i] = ord - 1;
1675 else
1676 argord[i] = i;
1677 s = strchr (s, ',') + 1;
1678 } else
1679 argord[i] = i;
1683 replace_continue = replace_all;
1685 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
1686 edit->search_start--;
1688 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
1689 edit->search_start++;
1691 do {
1692 int len = 0;
1693 long new_start;
1694 new_start = edit_find (edit->search_start, (unsigned char *) exp1, &len, last_search,
1695 (int (*)(void *, long)) edit_get_byte, (void *) edit, pmatch);
1696 if (new_start == -3) {
1697 regexp_error (edit);
1698 break;
1700 edit->search_start = new_start;
1701 /*returns negative on not found or error in pattern */
1703 if (edit->search_start >= 0) {
1704 edit->found_start = edit->search_start;
1705 i = edit->found_len = len;
1707 edit_cursor_move (edit, edit->search_start - edit->curs1);
1708 edit_scroll_screen_over_cursor (edit);
1710 replace_yes = 1;
1712 if (treplace_prompt) {
1713 int l;
1714 l = edit->curs_row - edit->num_widget_lines / 3;
1715 if (l > 0)
1716 edit_scroll_downward (edit, l);
1717 if (l < 0)
1718 edit_scroll_upward (edit, -l);
1720 edit_scroll_screen_over_cursor (edit);
1721 edit->force |= REDRAW_PAGE;
1722 edit_render_keypress (edit);
1724 /*so that undo stops at each query */
1725 edit_push_key_press (edit);
1727 switch (edit_replace_prompt (edit, exp2, /* and prompt 2/3 down */
1728 (edit->num_widget_columns - CONFIRM_DLG_WIDTH)/2,
1729 edit->num_widget_lines * 2 / 3)) {
1730 case B_ENTER:
1731 break;
1732 case B_SKIP_REPLACE:
1733 replace_yes = 0;
1734 break;
1735 case B_REPLACE_ALL:
1736 treplace_prompt = 0;
1737 replace_continue = 1;
1738 break;
1739 case B_REPLACE_ONE:
1740 replace_continue = 0;
1741 break;
1742 case B_CANCEL:
1743 replace_yes = 0;
1744 replace_continue = 0;
1745 break;
1748 if (replace_yes) { /* delete then insert new */
1749 if (replace_scanf || replace_regexp) {
1750 char repl_str[MAX_REPL_LEN + 2];
1751 if (replace_regexp) { /* we need to fill in sargs just like with scanf */
1752 int k, j;
1753 for (k = 1; k < NUM_REPL_ARGS && pmatch[k].rm_eo >= 0; k++) {
1754 unsigned char *t;
1755 t = (unsigned char *) &sargs[k - 1][0];
1756 for (j = 0; j < pmatch[k].rm_eo - pmatch[k].rm_so && j < 255; j++, t++)
1757 *t = (unsigned char) edit_get_byte (edit, edit->search_start - pmatch[0].rm_so + pmatch[k].rm_so + j);
1758 *t = '\0';
1760 for (; k <= NUM_REPL_ARGS; k++)
1761 sargs[k - 1][0] = 0;
1763 if (sprintf_p (repl_str, exp2, PRINTF_ARGS) >= 0) {
1764 times_replaced++;
1765 while (i--)
1766 edit_delete (edit);
1767 while (repl_str[++i])
1768 edit_insert (edit, repl_str[i]);
1769 } else {
1770 edit_error_dialog (_ (" Replace "),
1771 /* "Invalid regexp string or scanf string" */
1772 _ (" Error in replacement format string. "));
1773 replace_continue = 0;
1775 } else {
1776 times_replaced++;
1777 while (i--)
1778 edit_delete (edit);
1779 while (exp2[++i])
1780 edit_insert (edit, exp2[i]);
1782 edit->found_len = i;
1784 /* so that we don't find the same string again */
1785 if (replace_backwards) {
1786 last_search = edit->search_start;
1787 edit->search_start--;
1788 } else {
1789 edit->search_start += i;
1790 last_search = edit->last_byte;
1792 edit_scroll_screen_over_cursor (edit);
1793 } else {
1794 edit->search_start = edit->curs1; /* try and find from right here for next search */
1795 edit_update_curs_col (edit);
1797 edit->force |= REDRAW_PAGE;
1798 edit_render_keypress (edit);
1799 if (times_replaced) {
1800 sprintf (fin_string, _ (" %ld replacements made. "), times_replaced);
1801 edit_message_dialog (_ (" Replace "), fin_string);
1802 } else
1803 edit_message_dialog (_ (" Replace "), _ (" Search string not found. "));
1804 replace_continue = 0;
1806 } while (replace_continue);
1808 g_free (exp1);
1809 g_free (exp2);
1810 g_free (exp3);
1811 edit->force = REDRAW_COMPLETELY;
1812 edit_scroll_screen_over_cursor (edit);
1818 void edit_search_cmd (WEdit * edit, int again)
1820 static char *old = NULL;
1821 char *exp = "";
1823 if (!edit) {
1824 if (old) {
1825 g_free (old);
1826 old = 0;
1828 return;
1830 exp = old ? old : exp;
1831 if (again) { /*ctrl-hotkey for search again. */
1832 if (!old)
1833 return;
1834 exp = (char *) g_strdup (old);
1835 } else {
1837 #ifdef HAVE_CHARSET
1838 if (exp && *exp)
1839 convert_to_display (exp);
1840 #endif /* HAVE_CHARSET */
1842 edit_search_dialog (edit, &exp);
1844 #ifdef HAVE_CHARSET
1845 if (exp && *exp)
1846 convert_from_input (exp);
1847 #endif /* HAVE_CHARSET */
1849 edit_push_action (edit, KEY_PRESS + edit->start_display);
1852 if (exp) {
1853 if (*exp) {
1854 int len = 0;
1855 if (old)
1856 g_free (old);
1857 old = (char *) g_strdup (exp);
1859 if (search_create_bookmark) {
1860 int found = 0, books = 0;
1861 int l = 0, l_last = -1;
1862 long p, q = 0;
1863 for (;;) {
1864 p = edit_find (q, (unsigned char *) exp, &len, edit->last_byte,
1865 (int (*)(void *, long)) edit_get_byte, (void *) edit, 0);
1866 if (p < 0)
1867 break;
1868 found++;
1869 l += edit_count_lines (edit, q, p);
1870 if (l != l_last) {
1871 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
1872 books++;
1874 l_last = l;
1875 q = p + 1;
1877 if (found) {
1878 char fin_string[64];
1879 /* in response to number of bookmarks added because of string being found %d times */
1880 sprintf (fin_string, _ (" %d finds made, %d bookmarks added "), found, books);
1881 edit_message_dialog (_ (" Search "), fin_string);
1882 } else {
1883 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
1885 } else {
1887 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
1888 edit->search_start--;
1890 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
1891 edit->search_start++;
1893 edit->search_start = edit_find (edit->search_start, (unsigned char *) exp, &len, edit->last_byte,
1894 (int (*)(void *, long)) edit_get_byte, (void *) edit, 0);
1896 if (edit->search_start >= 0) {
1897 edit->found_start = edit->search_start;
1898 edit->found_len = len;
1900 edit_cursor_move (edit, edit->search_start - edit->curs1);
1901 edit_scroll_screen_over_cursor (edit);
1902 if (replace_backwards)
1903 edit->search_start--;
1904 else
1905 edit->search_start++;
1906 } else if (edit->search_start == -3) {
1907 edit->search_start = edit->curs1;
1908 regexp_error (edit);
1909 } else {
1910 edit->search_start = edit->curs1;
1911 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
1915 g_free (exp);
1917 edit->force |= REDRAW_COMPLETELY;
1918 edit_scroll_screen_over_cursor (edit);
1922 /* Real edit only */
1923 void edit_quit_cmd (WEdit * edit)
1925 edit_push_action (edit, KEY_PRESS + edit->start_display);
1927 edit->force |= REDRAW_COMPLETELY;
1928 if (edit->modified) {
1929 switch (edit_query_dialog3 (_ (" Quit "), _ (" File was modified, Save with exit? "), _ ("Cancel quit"), _ ("&Yes"), _ ("&No"))) {
1930 case 1:
1931 edit_push_markers (edit);
1932 edit_set_markers (edit, 0, 0, 0, 0);
1933 if (!edit_save_cmd (edit))
1934 return;
1935 break;
1936 case 2:
1937 if (edit->delete_file)
1938 unlink (catstrs (edit->dir, edit->filename, 0));
1939 break;
1940 case 0:
1941 case -1:
1942 return;
1945 else if (edit->delete_file)
1946 unlink (catstrs (edit->dir, edit->filename, 0));
1947 dlg_stop (edit->widget.parent);
1950 #define TEMP_BUF_LEN 1024
1952 /* returns a null terminated length of text. Result must be free'd */
1953 unsigned char *edit_get_block (WEdit * edit, long start, long finish, int *l)
1955 unsigned char *s, *r;
1956 r = s = malloc (finish - start + 1);
1957 if (column_highlighting) {
1958 *l = 0;
1959 while (start < finish) { /* copy from buffer, excluding chars that are out of the column 'margins' */
1960 int c, x;
1961 x = edit_move_forward3 (edit, edit_bol (edit, start), 0, start);
1962 c = edit_get_byte (edit, start);
1963 if ((x >= edit->column1 && x < edit->column2)
1964 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1965 *s++ = c;
1966 (*l)++;
1968 start++;
1970 } else {
1971 *l = finish - start;
1972 while (start < finish)
1973 *s++ = edit_get_byte (edit, start++);
1975 *s = 0;
1976 return r;
1979 /* save block, returns 1 on success */
1980 int edit_save_block (WEdit * edit, const char *filename, long start, long finish)
1982 int len, file;
1984 if ((file = open ((char *) filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
1985 return 0;
1987 if (column_highlighting) {
1988 unsigned char *block, *p;
1989 int r;
1990 p = block = edit_get_block (edit, start, finish, &len);
1991 while (len) {
1992 r = write (file, p, len);
1993 if (r < 0)
1994 break;
1995 p += r;
1996 len -= r;
1998 free (block);
1999 } else {
2000 unsigned char *buf;
2001 int i = start, end;
2002 len = finish - start;
2003 buf = malloc (TEMP_BUF_LEN);
2004 while (start != finish) {
2005 end = min (finish, start + TEMP_BUF_LEN);
2006 for (; i < end; i++)
2007 buf[i - start] = edit_get_byte (edit, i);
2008 len -= write (file, (char *) buf, end - start);
2009 start = end;
2011 free (buf);
2013 close (file);
2014 if (len)
2015 return 0;
2016 return 1;
2019 /* copies a block to clipboard file */
2020 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
2022 return edit_save_block (edit, catstrs (home_dir, CLIP_FILE, 0), start, finish);
2026 void edit_paste_from_history (WEdit *edit)
2030 int edit_copy_to_X_buf_cmd (WEdit * edit)
2032 long start_mark, end_mark;
2033 if (eval_marks (edit, &start_mark, &end_mark))
2034 return 0;
2035 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2036 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2037 return 1;
2039 edit_mark_cmd (edit, 1);
2040 return 0;
2043 int edit_cut_to_X_buf_cmd (WEdit * edit)
2045 long start_mark, end_mark;
2046 if (eval_marks (edit, &start_mark, &end_mark))
2047 return 0;
2048 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2049 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2050 return 1;
2052 edit_block_delete_cmd (edit);
2053 edit_mark_cmd (edit, 1);
2054 return 0;
2057 void edit_paste_from_X_buf_cmd (WEdit * edit)
2059 edit_insert_file (edit, catstrs (home_dir, CLIP_FILE, 0));
2063 void edit_goto_cmd (WEdit *edit)
2065 char *f;
2066 static int l = 0;
2067 char s[12];
2068 sprintf (s, "%d", l);
2069 f = input_dialog (_(" Goto line "), _(" Enter line: "), l ? s : "");
2070 if (f) {
2071 if (*f) {
2072 l = atoi (f);
2073 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2074 edit_move_to_line (edit, l - 1);
2075 edit->force |= REDRAW_COMPLETELY;
2077 g_free (f);
2081 /*returns 1 on success */
2082 int edit_save_block_cmd (WEdit * edit)
2084 long start_mark, end_mark;
2085 char *exp;
2086 if (eval_marks (edit, &start_mark, &end_mark))
2087 return 1;
2088 exp = edit_get_save_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _ (" Save Block "));
2089 edit_push_action (edit, KEY_PRESS + edit->start_display);
2090 if (exp) {
2091 if (!*exp) {
2092 g_free (exp);
2093 return 0;
2094 } else {
2095 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2096 g_free (exp);
2097 edit->force |= REDRAW_COMPLETELY;
2098 return 1;
2099 } else {
2100 g_free (exp);
2101 edit_error_dialog (_ (" Save Block "), get_sys_error (_ (" Error trying to save file. ")));
2105 edit->force |= REDRAW_COMPLETELY;
2106 return 0;
2110 /* returns 1 on success */
2111 int edit_insert_file_cmd (WEdit * edit)
2113 char *exp = edit_get_load_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _ (" Insert File "));
2114 edit_push_action (edit, KEY_PRESS + edit->start_display);
2115 if (exp) {
2116 if (!*exp) {
2117 g_free (exp);
2118 return 0;
2119 } else {
2120 if (edit_insert_file (edit, exp)) {
2121 g_free (exp);
2122 edit->force |= REDRAW_COMPLETELY;
2123 return 1;
2124 } else {
2125 g_free (exp);
2126 edit_error_dialog (_ (" Insert file "), get_sys_error (_ (" Error trying to insert file. ")));
2130 edit->force |= REDRAW_COMPLETELY;
2131 return 0;
2134 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2135 int edit_sort_cmd (WEdit * edit)
2137 static char *old = 0;
2138 char *exp;
2139 long start_mark, end_mark;
2140 int e;
2142 if (eval_marks (edit, &start_mark, &end_mark)) {
2143 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2144 return 0;
2146 edit_save_block (edit, catstrs (home_dir, BLOCK_FILE, 0), start_mark, end_mark);
2148 exp = old ? old : "";
2150 exp = input_dialog (_(" Run Sort "),
2151 _(" Enter sort options (see manpage) separated by whitespace: "), exp);
2153 if (!exp)
2154 return 1;
2155 if (old)
2156 g_free (old);
2157 old = exp;
2159 e = system (catstrs (" sort ", exp, " ", home_dir, BLOCK_FILE, " > ", home_dir, TEMP_FILE, 0));
2160 if (e) {
2161 if (e == -1 || e == 127) {
2162 edit_error_dialog (_(" Sort "),
2163 get_sys_error (_(" Error trying to execute sort command ")));
2164 } else {
2165 char q[8];
2166 sprintf (q, "%d ", e);
2167 edit_error_dialog (_(" Sort "),
2168 catstrs (_(" Sort returned non-zero: "), q, 0));
2170 return -1;
2173 edit->force |= REDRAW_COMPLETELY;
2175 if (edit_block_delete_cmd (edit))
2176 return 1;
2177 edit_insert_file (edit, catstrs (home_dir, TEMP_FILE, 0));
2178 return 0;
2181 /* if block is 1, a block must be highlighted and the shell command
2182 processes it. If block is 0 the shell command is a straight system
2183 command, that just produces some output which is to be inserted */
2184 void edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block)
2186 long start_mark, end_mark;
2187 struct stat s;
2188 char buf[BUFSIZ];
2189 FILE *script_home = NULL;
2190 FILE *script_src = NULL;
2191 FILE *block_file = NULL;
2193 char *o = catstrs (mc_home, shell_cmd, 0); /* original source script */
2194 char *h = catstrs (home_dir, EDIT_DIR, shell_cmd, 0); /* home script */
2195 char *b = catstrs (home_dir, BLOCK_FILE, 0); /* block file */
2196 char *e = catstrs (home_dir, ERROR_FILE, 0); /* error file */
2198 if (! (script_home = fopen (h, "r"))) {
2199 if (! (script_home = fopen (h, "w"))) {
2200 edit_error_dialog ("",
2201 get_sys_error (catstrs (_ ("Error create script:"), h, 0)));
2202 return;
2203 } else {
2204 if (! (script_src = fopen (o, "r"))) {
2205 fclose (script_home); unlink (h);
2206 edit_error_dialog ("",
2207 get_sys_error (catstrs (_ ("Error read script:"), o, 0)));
2208 return;
2209 } else {
2210 while (fgets(buf, sizeof(buf), script_src))
2211 fputs (buf, script_home);
2212 if (fclose(script_home)) {
2213 edit_error_dialog ("",
2214 get_sys_error (catstrs (_ ("Error close script:"), h, 0)));
2215 return;
2216 } else {
2217 chmod (h, 0700);
2218 edit_error_dialog ("",
2219 get_sys_error (catstrs (_ ("Script created:"), h, 0)));
2224 if (block) { /* for marked block run indent formatter */
2225 if (eval_marks (edit, &start_mark, &end_mark)) {
2226 edit_error_dialog (_("Process block"),
2227 _(" You must first highlight a block of text. "));
2228 return;
2230 edit_save_block (edit, b, start_mark, end_mark);
2233 * Run script.
2234 * Initial space is to avoid polluting bash history.
2235 * Arguments:
2236 * $1 - name of the edited file (to check its extention etc).
2237 * $2 - file containing the current block.
2238 * $3 - file where error messages should be put.
2240 execute (catstrs (" ", home_dir, EDIT_DIR, shell_cmd, " ",
2241 edit->filename, " ", home_dir, BLOCK_FILE, " ",
2242 home_dir, ERROR_FILE, NULL));
2244 } else {
2246 * No block selected, just execute the command for the file.
2247 * Arguments:
2248 * $1 - name of the edited file.
2250 execute (catstrs (" ", home_dir, EDIT_DIR, shell_cmd, " ",
2251 edit->filename, NULL));
2254 edit_refresh_cmd (edit);
2255 edit->force |= REDRAW_COMPLETELY;
2257 /* insert result block */
2258 if (block) {
2259 if (mc_stat (e, &s) == 0) {
2260 if (!s.st_size) { /* no error messages */
2261 if (edit_block_delete_cmd (edit))
2262 return;
2263 edit_insert_file (edit, b);
2264 } else {
2265 edit_insert_file (edit, e);
2267 } else {
2268 edit_error_dialog ("",
2269 get_sys_error (catstrs (_ ("Error trying to stat file:"), e, 0)));
2270 edit->force |= REDRAW_COMPLETELY;
2272 if ((block_file = fopen (b, "w")))
2273 fclose (block_file);
2274 return;
2276 return;
2279 /* prints at the cursor */
2280 /* returns the number of chars printed */
2281 int edit_print_string (WEdit * e, const char *s)
2283 int i = 0;
2284 while (s[i])
2285 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2286 e->force |= REDRAW_COMPLETELY;
2287 edit_update_screen (e);
2288 return i;
2291 int edit_printf (WEdit * e, const char *fmt,...)
2293 int i;
2294 va_list pa;
2295 char s[1024];
2296 va_start (pa, fmt);
2297 sprintf (s, fmt, pa);
2298 i = edit_print_string (e, s);
2299 va_end (pa);
2300 return i;
2303 /* FIXME: does this function break NT_OS2 ? */
2305 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2307 FILE *p = 0;
2308 char *s;
2310 s = g_strdup_printf ("mail -s \"%s\" -c \"%s\" \"%s\"", subject, cc, to);
2312 if (s) {
2313 p = popen (s, "w");
2314 g_free (s);
2317 if (p) {
2318 long i;
2319 for (i = 0; i < edit->last_byte; i++)
2320 fputc (edit_get_byte (edit, i), p);
2321 pclose (p);
2325 #define MAIL_DLG_HEIGHT 12
2327 void edit_mail_dialog (WEdit * edit)
2329 char *tmail_to;
2330 char *tmail_subject;
2331 char *tmail_cc;
2333 static char *mail_cc_last = 0;
2334 static char *mail_subject_last = 0;
2335 static char *mail_to_last = 0;
2337 QuickDialog Quick_input =
2338 {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
2339 "[Input Line Keys]", "quick_input", 0};
2341 QuickWidget quick_widgets[] =
2343 {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
2344 0, NULL},
2345 {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&Ok"), 0, B_ENTER, 0,
2346 0, NULL},
2347 {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2348 0, "mail-dlg-input"},
2349 {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
2350 0, 0},
2351 {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2352 0, "mail-dlg-input-2"},
2353 {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
2354 0, 0},
2355 {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2356 0, "mail-dlg-input-3"},
2357 {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
2358 0, 0},
2359 {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2360 0, 0},
2361 {0}};
2363 quick_widgets[2].str_result = &tmail_cc;
2364 quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
2365 quick_widgets[4].str_result = &tmail_subject;
2366 quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
2367 quick_widgets[6].str_result = &tmail_to;
2368 quick_widgets[6].text = mail_to_last ? mail_to_last : "";
2370 Quick_input.widgets = quick_widgets;
2372 if (quick_dialog (&Quick_input) != B_CANCEL) {
2373 if (mail_cc_last)
2374 g_free (mail_cc_last);
2375 if (mail_subject_last)
2376 g_free (mail_subject_last);
2377 if (mail_to_last)
2378 g_free (mail_to_last);
2379 mail_cc_last = *(quick_widgets[2].str_result);
2380 mail_subject_last = *(quick_widgets[4].str_result);
2381 mail_to_last = *(quick_widgets[6].str_result);
2382 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);