* editcmd.c (edit_save_file): Use g_free() on the result of
[midnight-commander.git] / edit / editcmd.c
blob240f356da9c1beea1c730a029735ef9e15f1d333
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 savedir = (char *) strdup (".");
205 slashpos = strrchr (filename, '/');
206 if (slashpos) {
207 free (savedir);
208 savedir = (char *) strdup (filename);
209 savedir[slashpos - filename + 1] = '\0';
211 saveprefix = concat_dir_and_file (savedir, "cooledit");
212 free (savedir);
213 fd = mc_mkstemps(&savename, saveprefix, NULL);
214 g_free (saveprefix);
215 if (!savename)
216 return 0;
217 close (fd);
218 } else
219 savename = g_strdup (filename);
221 if ((fd = open (savename, O_CREAT | O_WRONLY | O_TRUNC | MY_O_TEXT,
222 edit->stat1.st_mode)) == -1)
223 goto error_save;
225 chmod (savename, edit->stat1.st_mode);
226 chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
228 /* pipe save */
229 if ((p = (char *) edit_get_write_filter (savename, filename))) {
230 FILE *file;
232 close (fd);
233 file = (FILE *) popen (p, "w");
235 if (file) {
236 filelen = edit_write_stream (edit, file);
237 #if 1
238 pclose (file);
239 #else
240 if (pclose (file) != 0) {
241 edit_error_dialog (_ (" Error "), catstrs (_ (" Error writing to pipe: "), p, " ", 0));
242 free (p);
243 goto error_save;
245 #endif
246 } else {
247 edit_error_dialog (_ (" Error "), get_sys_error (catstrs (_ (" Failed trying to open pipe for writing: "), p, " ", 0)));
248 free (p);
249 goto error_save;
251 free (p);
252 #ifdef CR_LF_TRANSLATION
253 } else { /* optimised save */
254 filelen = edit_write_stream (edit, f);
255 if (fclose (file))
256 filelen = -1;
257 #else
258 } else {
259 long buf;
260 buf = 0;
261 filelen = edit->last_byte;
262 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
263 if (write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
264 close (fd);
265 goto error_save;
267 buf++;
269 if (write (fd, (char *) edit->buffers1[buf], edit->curs1 & M_EDIT_BUF_SIZE) != (edit->curs1 & M_EDIT_BUF_SIZE)) {
270 filelen = -1;
271 } else if (edit->curs2) {
272 edit->curs2--;
273 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
274 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)) {
275 filelen = -1;
276 } else {
277 while (--buf >= 0) {
278 if (write (fd, (char *) edit->buffers2[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
279 filelen = -1;
280 break;
284 edit->curs2++;
286 if (close (fd))
287 goto error_save;
288 #endif /* !CR_LF_TRANSLATION */
291 if (filelen != edit->last_byte)
292 goto error_save;
293 if (this_save_mode == 2)
294 if (rename (filename, catstrs (filename, option_backup_ext, 0)) == -1)
295 goto error_save;
296 if (this_save_mode > 0)
297 if (rename (savename, filename) == -1)
298 goto error_save;
299 if (savename)
300 g_free (savename);
301 return 1;
302 error_save:
303 if (savename)
304 g_free (savename);
305 return 0;
309 I changed this from Oleg's original routine so
310 that option_backup_ext works with coolwidgets as well. This
311 does mean there is a memory leak - paul.
313 void menu_save_mode_cmd (void)
315 #define DLG_X 38
316 #define DLG_Y 10
317 static char *str_result;
318 static int save_mode_new;
319 static char *str[] =
321 N_("Quick save "),
322 N_("Safe save "),
323 N_("Do backups -->")};
324 static QuickWidget widgets[] =
326 {quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
327 B_CANCEL, 0, 0, "c"},
328 {quick_button, 6, DLG_X, 7, DLG_Y, N_("&Ok"), 0,
329 B_ENTER, 0, 0, "o"},
330 {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
331 0, 0, &str_result, "edit-backup-ext"},
332 {quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
333 0, 0, 0, "savemext"},
334 {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
335 0, &save_mode_new, str, "t"},
336 {0}};
337 static QuickDialog dialog =
338 {DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
339 "esm", widgets};
340 static int i18n_flag = 0;
342 if (!i18n_flag) {
343 int i;
344 int maxlen = 0;
345 int dlg_x;
346 int l1;
348 /* Ok/Cancel buttons */
349 l1 = strlen (_(widgets[0].text)) + strlen (_(widgets[1].text)) + 5;
350 maxlen = max (maxlen, l1);
352 for (i = 0; i < 3; i++ ) {
353 str[i] = _(str[i]);
354 maxlen = max (maxlen, strlen (str[i]) + 7);
356 i18n_flag = 1;
358 dlg_x = maxlen + strlen (_(widgets[3].text)) + 5 + 1;
359 widgets[2].hotkey_pos = strlen (_(widgets[3].text)); /* input field length */
360 dlg_x = min (COLS, dlg_x);
361 dialog.xlen = dlg_x;
363 i = (dlg_x - l1)/3;
364 widgets[1].relative_x = i;
365 widgets[0].relative_x = i + strlen (_(widgets[1].text)) + i + 4;
367 widgets[2].relative_x = widgets[3].relative_x = maxlen + 2;
369 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
370 widgets[i].x_divisions = dlg_x;
373 widgets[2].text = option_backup_ext;
374 widgets[4].value = option_save_mode;
375 if (quick_dialog (&dialog) != B_ENTER)
376 return;
377 option_save_mode = save_mode_new;
378 option_backup_ext = str_result; /* this is a memory leak */
379 option_backup_ext_int = 0;
380 str_result[min (strlen (str_result), sizeof (int))] = '\0';
381 memcpy ((char *) &option_backup_ext_int, str_result, strlen (option_backup_ext));
384 void edit_split_filename (WEdit * edit, const char *f)
386 if (edit->filename)
387 free (edit->filename);
388 edit->filename = (char *) strdup (f);
389 if (edit->dir)
390 free (edit->dir);
391 edit->dir = (char *) strdup ("");
394 /* here we want to warn the user of overwriting an existing file, but only if they
395 have made a change to the filename */
396 /* returns 1 on success */
397 int edit_save_as_cmd (WEdit * edit)
399 /* This heads the 'Save As' dialog box */
400 char *exp = 0;
401 int different_filename = 0;
403 exp = edit_get_save_file (edit->dir, edit->filename, _(" Save As "));
404 edit_push_action (edit, KEY_PRESS + edit->start_display);
406 if (exp) {
407 if (!*exp) {
408 g_free (exp);
409 edit->force |= REDRAW_COMPLETELY;
410 return 0;
411 } else {
412 if (strcmp(catstrs (edit->dir, edit->filename, 0), exp)) {
413 int file;
414 different_filename = 1;
415 if ((file = open ((char *) exp, O_RDONLY)) != -1) { /* the file exists */
416 close (file);
417 if (edit_query_dialog2 (_(" Warning "),
418 _(" A file already exists with this name. "),
419 /* Push buttons to over-write the current file, or cancel the operation */
420 _("Overwrite"), _("Cancel"))) {
421 edit->force |= REDRAW_COMPLETELY;
422 g_free (exp);
423 return 0;
427 if (edit_save_file (edit, exp)) {
428 edit_split_filename (edit, exp);
429 g_free (exp);
430 edit->modified = 0;
431 edit->delete_file = 0;
432 if (different_filename && !edit->explicit_syntax)
433 edit_load_syntax (edit, 0, 0);
434 edit->force |= REDRAW_COMPLETELY;
435 return 1;
436 } else {
437 g_free (exp);
438 edit_error_dialog (_(" Save as "), get_sys_error (_(" Error trying to save file. ")));
439 edit->force |= REDRAW_COMPLETELY;
440 return 0;
444 edit->force |= REDRAW_COMPLETELY;
445 return 0;
448 /* {{{ Macro stuff starts here */
450 int raw_callback (struct Dlg_head *h, int key, int Msg)
452 switch (Msg) {
453 case DLG_DRAW:
454 attrset (REVERSE_COLOR);
455 dlg_erase (h);
456 draw_box (h, 1, 1, h->lines - 2, h->cols - 2);
458 attrset (COLOR_HOT_NORMAL);
459 dlg_move (h, 1, 2);
460 printw (h->title);
461 break;
463 case DLG_KEY:
464 h->running = 0;
465 h->ret_value = key;
466 return 1;
468 return 0;
471 /* gets a raw key from the keyboard. Passing cancel = 1 draws
472 a cancel button thus allowing c-c etc.. Alternatively, cancel = 0
473 will return the next key pressed */
474 int edit_raw_key_query (char *heading, char *query, int cancel)
476 int w = strlen (query) + 7;
477 struct Dlg_head *raw_dlg = create_dlg (0, 0, 7, w, dialog_colors,
478 /* NLS ? */
479 raw_callback, "[Raw Key Query]",
480 "raw_key_input",
481 DLG_CENTER | DLG_TRYUP);
482 x_set_dialog_title (raw_dlg, heading);
483 raw_dlg->raw = 1; /* to return even a tab key */
484 if (cancel)
485 add_widget (raw_dlg, button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON, _("Cancel"), 0, 0, 0));
486 add_widget (raw_dlg, label_new (3 - cancel, 2, query, 0));
487 add_widget (raw_dlg, input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0));
488 run_dlg (raw_dlg);
489 w = raw_dlg->ret_value;
490 destroy_dlg (raw_dlg);
491 if (cancel)
492 if (w == XCTRL ('g') || w == XCTRL ('c') || w == ESC_CHAR || w == B_CANCEL)
493 return 0;
494 /* hence ctrl-a (=B_CANCEL), ctrl-g, ctrl-c, and Esc are cannot returned */
495 return w;
498 /* creates a macro file if it doesn't exist */
499 static FILE *edit_open_macro_file (const char *r)
501 char *filename;
502 int file;
503 filename = catstrs (home_dir, MACRO_FILE, 0);
504 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
505 return 0;
506 close (file);
507 return fopen (filename, r);
510 #define MAX_MACROS 1024
511 static int saved_macro[MAX_MACROS + 1];
512 static int saved_macros_loaded = 0;
515 This is just to stop the macro file be loaded over and over for keys
516 that aren't defined to anything. On slow systems this could be annoying.
518 int macro_exists (int k)
520 int i;
521 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
522 if (saved_macro[i] == k)
523 return i;
524 return -1;
527 /* returns 1 on error */
528 int edit_delete_macro (WEdit * edit, int k)
530 struct macro macro[MAX_MACRO_LENGTH];
531 FILE *f, *g;
532 int s, i, n, j = 0;
534 if (saved_macros_loaded)
535 if ((j = macro_exists (k)) < 0)
536 return 0;
537 g = fopen (catstrs (home_dir, TEMP_FILE, 0), "w");
538 if (!g) {
539 /* This heads the delete macro error dialog box */
540 edit_error_dialog (_(" Delete macro "),
541 /* 'Open' = load temp file */
542 get_sys_error (_(" Error trying to open temp file ")));
543 return 1;
545 f = edit_open_macro_file ("r");
546 if (!f) {
547 /* This heads the delete macro error dialog box */
548 edit_error_dialog (_(" Delete macro "),
549 /* 'Open' = load temp file */
550 get_sys_error (_(" Error trying to open macro file ")));
551 fclose (g);
552 return 1;
554 for (;;) {
555 n = fscanf (f, ("key '%d 0': "), &s);
556 if (!n || n == EOF)
557 break;
558 n = 0;
559 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
560 n++;
561 fscanf (f, ";\n");
562 if (s != k) {
563 fprintf (g, ("key '%d 0': "), s);
564 for (i = 0; i < n; i++)
565 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
566 fprintf (g, ";\n");
569 fclose (f);
570 fclose (g);
571 if (rename (catstrs (home_dir, TEMP_FILE, 0), catstrs (home_dir, MACRO_FILE, 0)) == -1) {
572 /* This heads the delete macro error dialog box */
573 edit_error_dialog (_(" Delete macro "),
574 get_sys_error (_(" Error trying to overwrite macro file ")));
575 return 1;
577 if (saved_macros_loaded)
578 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
579 return 0;
582 /* returns 0 on error */
583 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
585 FILE *f;
586 int s, i;
588 edit_push_action (edit, KEY_PRESS + edit->start_display);
589 /* This heads the 'Macro' dialog box */
590 s = edit_raw_key_query (_(" Macro "),
591 /* Input line for a single key press follows the ':' */
592 _(" Press the macro's new hotkey: "), 1);
593 edit->force |= REDRAW_COMPLETELY;
594 if (s) {
595 if (edit_delete_macro (edit, s))
596 return 0;
597 f = edit_open_macro_file ("a+");
598 if (f) {
599 fprintf (f, ("key '%d 0': "), s);
600 for (i = 0; i < n; i++)
601 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
602 fprintf (f, ";\n");
603 fclose (f);
604 if (saved_macros_loaded) {
605 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
606 saved_macro[i] = s;
608 return 1;
609 } else
610 /* This heads the 'Save Macro' dialog box */
611 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Error trying to open macro file ")));
613 return 0;
616 void edit_delete_macro_cmd (WEdit * edit)
618 int command;
620 command = edit_raw_key_query (_ (" Delete Macro "),
621 _ (" Press macro hotkey: "), 1);
623 if (!command)
624 return;
626 edit_delete_macro (edit, command);
629 /* return 0 on error */
630 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
632 FILE *f;
633 int s, i = 0, found = 0;
635 if (saved_macros_loaded)
636 if (macro_exists (k) < 0)
637 return 0;
639 if ((f = edit_open_macro_file ("r"))) {
640 struct macro dummy;
641 do {
642 int u;
643 u = fscanf (f, ("key '%d 0': "), &s);
644 if (!u || u == EOF)
645 break;
646 if (!saved_macros_loaded)
647 saved_macro[i++] = s;
648 if (!found) {
649 *n = 0;
650 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
651 (*n)++;
652 } else {
653 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
655 fscanf (f, ";\n");
656 if (s == k)
657 found = 1;
658 } while (!found || !saved_macros_loaded);
659 if (!saved_macros_loaded) {
660 saved_macro[i] = 0;
661 saved_macros_loaded = 1;
663 fclose (f);
664 return found;
665 } else
666 /* This heads the 'Load Macro' dialog box */
667 edit_error_dialog (_(" Load macro "),
668 get_sys_error (_(" Error trying to open macro file ")));
669 return 0;
672 /* }}} Macro stuff starts here */
674 /* returns 1 on success */
675 int edit_save_confirm_cmd (WEdit * edit)
677 char *f;
679 if (edit_confirm_save) {
680 f = catstrs (_(" Confirm save file? : "), edit->filename, " ", 0);
681 /* Buttons to 'Confirm save file' query */
682 if (edit_query_dialog2 (_(" Save file "), f, _("Save"), _("Cancel")))
683 return 0;
685 return edit_save_cmd (edit);
689 /* returns 1 on success */
690 int edit_save_cmd (WEdit * edit)
692 if (!edit_save_file (edit, catstrs (edit->dir, edit->filename, 0)))
693 return edit_save_as_cmd (edit);
694 edit->force |= REDRAW_COMPLETELY;
695 edit->modified = 0;
696 edit->delete_file = 0;
698 return 1;
702 /* returns 1 on success */
703 int edit_new_cmd (WEdit * edit)
705 if (edit->modified) {
706 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
707 edit->force |= REDRAW_COMPLETELY;
708 return 0;
711 edit->force |= REDRAW_COMPLETELY;
712 edit->modified = 0;
713 return edit_renew (edit); /* if this gives an error, something has really screwed up */
716 /* returns 1 on error */
717 int edit_load_file_from_filename (WEdit * edit, char *exp)
719 if (!edit_reload (edit, exp, 0, "", 0))
720 return 1;
721 edit_split_filename (edit, exp);
722 edit->modified = 0;
723 return 0;
726 int edit_load_cmd (WEdit * edit)
728 char *exp;
730 if (edit->modified) {
731 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
732 edit->force |= REDRAW_COMPLETELY;
733 return 0;
737 exp = edit_get_load_file (edit->dir, edit->filename, _ (" Load "));
739 if (exp) {
740 if (*exp)
741 edit_load_file_from_filename (edit, exp);
742 g_free (exp);
744 edit->force |= REDRAW_COMPLETELY;
745 return 0;
749 if mark2 is -1 then marking is from mark1 to the cursor.
750 Otherwise its between the markers. This handles this.
751 Returns 1 if no text is marked.
753 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
755 if (edit->mark1 != edit->mark2) {
756 if (edit->mark2 >= 0) {
757 *start_mark = min (edit->mark1, edit->mark2);
758 *end_mark = max (edit->mark1, edit->mark2);
759 } else {
760 *start_mark = min (edit->mark1, edit->curs1);
761 *end_mark = max (edit->mark1, edit->curs1);
762 edit->column2 = edit->curs_col;
764 return 0;
765 } else {
766 *start_mark = *end_mark = 0;
767 edit->column2 = edit->column1 = 0;
768 return 1;
772 /*Block copy, move and delete commands */
773 extern int column_highlighting;
775 #define space_width 1
777 void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
779 long cursor;
780 int i, col;
781 cursor = edit->curs1;
782 col = edit_get_col (edit);
783 for (i = 0; i < size; i++) {
784 if (data[i] == '\n') { /* fill in and move to next line */
785 int l;
786 long p;
787 if (edit_get_byte (edit, edit->curs1) != '\n') {
788 l = width - (edit_get_col (edit) - col);
789 while (l > 0) {
790 edit_insert (edit, ' ');
791 l -= space_width;
794 for (p = edit->curs1;; p++) {
795 if (p == edit->last_byte)
796 edit_insert_ahead (edit, '\n');
797 if (edit_get_byte (edit, p) == '\n') {
798 p++;
799 break;
802 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
803 l = col - edit_get_col (edit);
804 while (l >= space_width) {
805 edit_insert (edit, ' ');
806 l -= space_width;
808 continue;
810 edit_insert (edit, data[i]);
812 edit_cursor_move (edit, cursor - edit->curs1);
816 void edit_block_copy_cmd (WEdit * edit)
818 long start_mark, end_mark, current = edit->curs1;
819 int size, x;
820 unsigned char *copy_buf;
822 edit_update_curs_col (edit);
823 x = edit->curs_col;
824 if (eval_marks (edit, &start_mark, &end_mark))
825 return;
826 if (column_highlighting)
827 if ((x >= edit->column1 && x < edit->column2) || (x > edit->column2 && x <= edit->column1))
828 return;
830 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
832 /* all that gets pushed are deletes hence little space is used on the stack */
834 edit_push_markers (edit);
836 if (column_highlighting) {
837 edit_insert_column_of_text (edit, copy_buf, size, abs (edit->column2 - edit->column1));
838 } else {
839 while (size--)
840 edit_insert_ahead (edit, copy_buf[size]);
843 free (copy_buf);
844 edit_scroll_screen_over_cursor (edit);
846 if (column_highlighting) {
847 edit_set_markers (edit, 0, 0, 0, 0);
848 edit_push_action (edit, COLUMN_ON);
849 column_highlighting = 0;
850 } else if (start_mark < current && end_mark > current)
851 edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
853 edit->force |= REDRAW_PAGE;
857 void edit_block_move_cmd (WEdit * edit)
859 long count;
860 long current;
861 unsigned char *copy_buf;
862 long start_mark, end_mark;
863 int deleted = 0;
864 int x = 0;
866 if (eval_marks (edit, &start_mark, &end_mark))
867 return;
868 if (column_highlighting) {
869 edit_update_curs_col (edit);
870 x = edit->curs_col;
871 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
872 if ((x > edit->column1 && x < edit->column2) || (x > edit->column2 && x < edit->column1))
873 return;
874 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
875 return;
877 if ((end_mark - start_mark) > option_max_undo / 2)
878 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ ("Continue"), _ ("Cancel")))
879 return;
881 edit_push_markers (edit);
882 current = edit->curs1;
883 if (column_highlighting) {
884 int size, c1, c2, line;
885 line = edit->curs_line;
886 if (edit->mark2 < 0)
887 edit_mark_cmd (edit, 0);
888 c1 = min (edit->column1, edit->column2);
889 c2 = max (edit->column1, edit->column2);
890 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
891 if (x < c2) {
892 edit_block_delete_cmd (edit);
893 deleted = 1;
895 edit_move_to_line (edit, line);
896 edit_cursor_move (edit, edit_move_forward3 (edit, edit_bol (edit, edit->curs1), x, 0) - edit->curs1);
897 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
898 if (!deleted) {
899 line = edit->curs_line;
900 edit_update_curs_col (edit);
901 x = edit->curs_col;
902 edit_block_delete_cmd (edit);
903 edit_move_to_line (edit, line);
904 edit_cursor_move (edit, edit_move_forward3 (edit, edit_bol (edit, edit->curs1), x, 0) - edit->curs1);
906 edit_set_markers (edit, 0, 0, 0, 0);
907 edit_push_action (edit, COLUMN_ON);
908 column_highlighting = 0;
909 } else {
910 copy_buf = malloc (end_mark - start_mark);
911 edit_cursor_move (edit, start_mark - edit->curs1);
912 edit_scroll_screen_over_cursor (edit);
913 count = start_mark;
914 while (count < end_mark) {
915 copy_buf[end_mark - count - 1] = edit_delete (edit);
916 count++;
918 edit_scroll_screen_over_cursor (edit);
919 edit_cursor_move (edit, current - edit->curs1 - (((current - edit->curs1) > 0) ? end_mark - start_mark : 0));
920 edit_scroll_screen_over_cursor (edit);
921 while (count-- > start_mark)
922 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
923 edit_set_markers (edit, edit->curs1, edit->curs1 + end_mark - start_mark, 0, 0);
925 edit_scroll_screen_over_cursor (edit);
926 free (copy_buf);
927 edit->force |= REDRAW_PAGE;
930 void edit_cursor_to_bol (WEdit * edit);
932 void edit_delete_column_of_text (WEdit * edit)
934 long p, q, r, m1, m2;
935 int b, c, d;
936 int n;
938 eval_marks (edit, &m1, &m2);
939 n = edit_move_forward (edit, m1, 0, m2) + 1;
940 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
941 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
943 b = min (c, d);
944 c = max (c, d);
946 while (n--) {
947 r = edit_bol (edit, edit->curs1);
948 p = edit_move_forward3 (edit, r, b, 0);
949 q = edit_move_forward3 (edit, r, c, 0);
950 if (p < m1)
951 p = m1;
952 if (q > m2)
953 q = m2;
954 edit_cursor_move (edit, p - edit->curs1);
955 while (q > p) { /* delete line between margins */
956 if (edit_get_byte (edit, edit->curs1) != '\n')
957 edit_delete (edit);
958 q--;
960 if (n) /* move to next line except on the last delete */
961 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
965 /* if success return 0 */
966 int edit_block_delete (WEdit * edit)
968 long count;
969 long start_mark, end_mark;
970 if (eval_marks (edit, &start_mark, &end_mark))
971 return 0;
972 if (column_highlighting && edit->mark2 < 0)
973 edit_mark_cmd (edit, 0);
974 if ((end_mark - start_mark) > option_max_undo / 2)
975 /* Warning message with a query to continue or cancel the operation */
976 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ (" Continue "), _ (" Cancel ")))
977 return 1;
978 edit_push_markers (edit);
979 edit_cursor_move (edit, start_mark - edit->curs1);
980 edit_scroll_screen_over_cursor (edit);
981 count = start_mark;
982 if (start_mark < end_mark) {
983 if (column_highlighting) {
984 if (edit->mark2 < 0)
985 edit_mark_cmd (edit, 0);
986 edit_delete_column_of_text (edit);
987 } else {
988 while (count < end_mark) {
989 edit_delete (edit);
990 count++;
994 edit_set_markers (edit, 0, 0, 0, 0);
995 edit->force |= REDRAW_PAGE;
996 return 0;
999 /* returns 1 if canceelled by user */
1000 int edit_block_delete_cmd (WEdit * edit)
1002 long start_mark, end_mark;
1003 if (eval_marks (edit, &start_mark, &end_mark)) {
1004 edit_delete_line (edit);
1005 return 0;
1007 return edit_block_delete (edit);
1011 #define INPUT_INDEX 9
1012 #define SEARCH_DLG_WIDTH 58
1013 #define SEARCH_DLG_HEIGHT 10
1014 #define REPLACE_DLG_WIDTH 58
1015 #define REPLACE_DLG_HEIGHT 15
1016 #define CONFIRM_DLG_WIDTH 79
1017 #define CONFIRM_DLG_HEIGTH 6
1018 #define B_REPLACE_ALL B_USER+1
1019 #define B_REPLACE_ONE B_USER+2
1020 #define B_SKIP_REPLACE B_USER+3
1022 int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
1024 QuickWidget quick_widgets[] =
1026 {quick_button, 63, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Cancel"),
1027 0, B_CANCEL, 0, 0, NULL},
1028 {quick_button, 50, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("o&Ne"),
1029 0, B_REPLACE_ONE, 0, 0, NULL},
1030 {quick_button, 37, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("al&L"),
1031 0, B_REPLACE_ALL, 0, 0, NULL},
1032 {quick_button, 21, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Skip"),
1033 0, B_SKIP_REPLACE, 0, 0, NULL},
1034 {quick_button, 4, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Replace"),
1035 0, B_ENTER, 0, 0, NULL},
1036 {quick_label, 2, CONFIRM_DLG_WIDTH, 2, CONFIRM_DLG_HEIGTH, 0,
1037 0, 0, 0, 0, 0},
1038 {0}};
1040 #ifdef HAVE_CHARSET
1041 char *msg = _(" Replace with: ");
1043 quick_widgets[5].text = catstrs (msg, replace_text, 0);
1045 if (*replace_text)
1046 convert_to_display (quick_widgets[5].text + strlen (msg));
1047 #else
1048 quick_widgets[5].text = catstrs (_ (" Replace with: "), replace_text, 0);
1049 #endif /* !HAVE_CHARSET */
1052 QuickDialog Quick_input =
1053 {CONFIRM_DLG_WIDTH, CONFIRM_DLG_HEIGTH, 0, 0, N_ (" Confirm replace "),
1054 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1056 Quick_input.widgets = quick_widgets;
1058 Quick_input.xpos = xpos;
1060 /* Sometimes menu can hide replaced text. I don't like it */
1062 if ((edit->curs_row >= ypos - 1) && (edit->curs_row <= ypos + CONFIRM_DLG_HEIGTH - 1))
1063 ypos -= CONFIRM_DLG_HEIGTH;
1065 Quick_input.ypos = ypos;
1066 return quick_dialog (&Quick_input);
1070 void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order)
1072 int treplace_scanf = replace_scanf;
1073 int treplace_regexp = replace_regexp;
1074 int treplace_all = replace_all;
1075 int treplace_prompt = replace_prompt;
1076 int treplace_backwards = replace_backwards;
1077 int treplace_whole = replace_whole;
1078 int treplace_case = replace_case;
1080 QuickWidget quick_widgets[] =
1082 {quick_button, 6, 10, 12, REPLACE_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1083 0, NULL},
1084 {quick_button, 2, 10, 12, REPLACE_DLG_HEIGHT, N_("&Ok"), 0, B_ENTER, 0,
1085 0, NULL},
1086 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1087 0, 0, NULL},
1088 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("replace &All"), 0, 0,
1089 0, 0, NULL},
1090 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("pr&Ompt on replace"), 0, 0,
1091 0, 0, NULL},
1092 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1093 0, 0, NULL},
1094 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1095 0, 0, NULL},
1096 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1097 0, 0, NULL},
1098 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 8, REPLACE_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1099 0, 0, NULL},
1100 {quick_input, 3, REPLACE_DLG_WIDTH, 7, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1101 0, "edit-argord"},
1102 {quick_label, 2, REPLACE_DLG_WIDTH, 6, REPLACE_DLG_HEIGHT, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1103 0, 0, 0},
1104 {quick_input, 3, REPLACE_DLG_WIDTH, 5, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1105 0, "edit-replace"},
1106 {quick_label, 2, REPLACE_DLG_WIDTH, 4, REPLACE_DLG_HEIGHT, N_(" Enter replacement string:"), 0, 0, 0,
1107 0, 0},
1108 {quick_input, 3, REPLACE_DLG_WIDTH, 3, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1109 0, "edit-search"},
1110 {quick_label, 2, REPLACE_DLG_WIDTH, 2, REPLACE_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1111 0, 0},
1112 {0}};
1114 quick_widgets[2].result = &treplace_scanf;
1115 quick_widgets[3].result = &treplace_all;
1116 quick_widgets[4].result = &treplace_prompt;
1117 quick_widgets[5].result = &treplace_backwards;
1118 quick_widgets[6].result = &treplace_regexp;
1119 quick_widgets[7].result = &treplace_whole;
1120 quick_widgets[8].result = &treplace_case;
1121 quick_widgets[9].str_result = arg_order;
1122 quick_widgets[9].text = *arg_order;
1123 quick_widgets[11].str_result = replace_text;
1124 quick_widgets[11].text = *replace_text;
1125 quick_widgets[13].str_result = search_text;
1126 quick_widgets[13].text = *search_text;
1128 QuickDialog Quick_input =
1129 {REPLACE_DLG_WIDTH, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "),
1130 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1132 Quick_input.widgets = quick_widgets;
1134 if (quick_dialog (&Quick_input) != B_CANCEL) {
1135 replace_scanf = treplace_scanf;
1136 replace_backwards = treplace_backwards;
1137 replace_regexp = treplace_regexp;
1138 replace_all = treplace_all;
1139 replace_prompt = treplace_prompt;
1140 replace_whole = treplace_whole;
1141 replace_case = treplace_case;
1142 return;
1143 } else {
1144 *arg_order = NULL;
1145 *replace_text = NULL;
1146 *search_text = NULL;
1147 return;
1153 void edit_search_dialog (WEdit * edit, char **search_text)
1155 int treplace_scanf = replace_scanf;
1156 int treplace_regexp = replace_regexp;
1157 int treplace_whole = replace_whole;
1158 int treplace_case = replace_case;
1159 int treplace_backwards = replace_backwards;
1161 QuickWidget quick_widgets[] =
1163 {quick_button, 6, 10, 7, SEARCH_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1164 0, NULL},
1165 {quick_button, 2, 10, 7, SEARCH_DLG_HEIGHT, N_("&Ok"), 0, B_ENTER, 0,
1166 0, NULL},
1167 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1168 0, 0, NULL },
1169 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1170 0, 0, NULL},
1171 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1172 0, 0, NULL},
1173 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1174 0, 0, NULL},
1175 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 4, SEARCH_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1176 0, 0, NULL},
1177 {quick_input, 3, SEARCH_DLG_WIDTH, 3, SEARCH_DLG_HEIGHT, "", 52, 0, 0,
1178 0, "edit-search"},
1179 {quick_label, 2, SEARCH_DLG_WIDTH, 2, SEARCH_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1180 0, 0},
1181 {0}};
1183 quick_widgets[2].result = &treplace_scanf;
1184 quick_widgets[3].result = &treplace_backwards;
1185 quick_widgets[4].result = &treplace_regexp;
1186 quick_widgets[5].result = &treplace_whole;
1187 quick_widgets[6].result = &treplace_case;
1188 quick_widgets[7].str_result = search_text;
1189 quick_widgets[7].text = *search_text;
1192 QuickDialog Quick_input =
1193 {SEARCH_DLG_WIDTH, SEARCH_DLG_HEIGHT, -1, 0, N_(" Search "),
1194 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1196 Quick_input.widgets = quick_widgets;
1198 if (quick_dialog (&Quick_input) != B_CANCEL) {
1199 replace_scanf = treplace_scanf;
1200 replace_backwards = treplace_backwards;
1201 replace_regexp = treplace_regexp;
1202 replace_whole = treplace_whole;
1203 replace_case = treplace_case;
1204 } else {
1205 *search_text = NULL;
1211 static long sargs[NUM_REPL_ARGS][256 / sizeof (long)];
1213 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1214 sargs[4], sargs[5], sargs[6], sargs[7], \
1215 sargs[8], sargs[9], sargs[10], sargs[11], \
1216 sargs[12], sargs[13], sargs[14], sargs[15]
1218 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1219 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1220 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1221 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1224 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1225 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1226 int string_regexp_search (char *pattern, char *string, int len, int match_type, int match_bol, int icase, int *found_len, void *d)
1228 static regex_t r;
1229 static char *old_pattern = NULL;
1230 static int old_type, old_icase;
1231 regmatch_t *pmatch;
1232 static regmatch_t s[1];
1234 pmatch = (regmatch_t *) d;
1235 if (!pmatch)
1236 pmatch = s;
1238 if (!old_pattern || strcmp (old_pattern, pattern) || old_type != match_type || old_icase != icase) {
1239 if (old_pattern) {
1240 regfree (&r);
1241 free (old_pattern);
1242 old_pattern = 0;
1244 if (regcomp (&r, pattern, REG_EXTENDED | (icase ? REG_ICASE : 0))) {
1245 *found_len = 0;
1246 return -3;
1248 old_pattern = (char *) strdup (pattern);
1249 old_type = match_type;
1250 old_icase = icase;
1252 if (regexec (&r, string, d ? NUM_REPL_ARGS : 1, pmatch, ((match_bol || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) {
1253 *found_len = 0;
1254 return -1;
1256 *found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
1257 return (pmatch[0].rm_so);
1260 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1261 (and the above) routines to work properly - paul */
1263 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)
1265 long p, q = 0;
1266 long l = strlen ((char *) exp), f = 0;
1267 int n = 0;
1269 for (p = 0; p < l; p++) /* count conversions... */
1270 if (exp[p] == '%')
1271 if (exp[++p] != '%') /* ...except for "%%" */
1272 n++;
1274 if (replace_scanf || replace_regexp) {
1275 int c;
1276 unsigned char *buf;
1277 unsigned char mbuf[MAX_REPL_LEN * 2 + 3];
1279 replace_scanf = (!replace_regexp); /* can't have both */
1281 buf = mbuf;
1283 if (replace_scanf) {
1284 unsigned char e[MAX_REPL_LEN];
1285 if (n >= NUM_REPL_ARGS)
1286 return -3;
1288 if (replace_case) {
1289 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++)
1290 buf[p - start] = (*get_byte) (data, p);
1291 } else {
1292 for (p = 0; exp[p] != 0; p++)
1293 exp[p] = my_lower_case (exp[p]);
1294 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) {
1295 c = (*get_byte) (data, p);
1296 buf[p - start] = my_lower_case (c);
1300 buf[(q = p - start)] = 0;
1301 strcpy ((char *) e, (char *) exp);
1302 strcat ((char *) e, "%n");
1303 exp = e;
1305 while (q) {
1306 *((int *) sargs[n]) = 0; /* --> here was the problem - now fixed: good */
1307 if (n == sscanf ((char *) buf, (char *) exp, SCANF_ARGS)) {
1308 if (*((int *) sargs[n])) {
1309 *len = *((int *) sargs[n]);
1310 return start;
1313 if (once_only)
1314 return -2;
1315 if (q + start < last_byte) {
1316 if (replace_case) {
1317 buf[q] = (*get_byte) (data, q + start);
1318 } else {
1319 c = (*get_byte) (data, q + start);
1320 buf[q] = my_lower_case (c);
1322 q++;
1324 buf[q] = 0;
1325 start++;
1326 buf++; /* move the window along */
1327 if (buf == mbuf + MAX_REPL_LEN) { /* the window is about to go past the end of array, so... */
1328 memmove (mbuf, buf, strlen ((char *) buf) + 1); /* reset it */
1329 buf = mbuf;
1331 q--;
1333 } else { /* regexp matching */
1334 long offset = 0;
1335 int found_start, match_bol, move_win = 0;
1337 while (start + offset < last_byte) {
1338 match_bol = (offset == 0 || (*get_byte) (data, start + offset - 1) == '\n');
1339 if (!move_win) {
1340 p = start + offset;
1341 q = 0;
1343 for (; p < last_byte && q < MAX_REPL_LEN; p++, q++) {
1344 mbuf[q] = (*get_byte) (data, p);
1345 if (mbuf[q] == '\n')
1346 break;
1348 q++;
1349 offset += q;
1350 mbuf[q] = 0;
1352 buf = mbuf;
1353 while (q) {
1354 found_start = string_regexp_search ((char *) exp, (char *) buf, q, match_normal, match_bol, !replace_case, len, d);
1356 if (found_start <= -2) { /* regcomp/regexec error */
1357 *len = 0;
1358 return -3;
1360 else if (found_start == -1) /* not found: try next line */
1361 break;
1362 else if (*len == 0) { /* null pattern: try again at next character */
1363 q--;
1364 buf++;
1365 match_bol = 0;
1366 continue;
1368 else /* found */
1369 return (start + offset - q + found_start);
1371 if (once_only)
1372 return -2;
1374 if (buf[q - 1] != '\n') { /* incomplete line: try to recover */
1375 buf = mbuf + MAX_REPL_LEN / 2;
1376 q = strlen ((char *) buf);
1377 memmove (mbuf, buf, q);
1378 p = start + q;
1379 move_win = 1;
1381 else
1382 move_win = 0;
1385 } else {
1386 *len = strlen ((char *) exp);
1387 if (replace_case) {
1388 for (p = start; p <= last_byte - l; p++) {
1389 if ((*get_byte) (data, p) == (unsigned char)exp[0]) { /* check if first char matches */
1390 for (f = 0, q = 0; q < l && f < 1; q++)
1391 if ((*get_byte) (data, q + p) != (unsigned char)exp[q])
1392 f = 1;
1393 if (f == 0)
1394 return p;
1396 if (once_only)
1397 return -2;
1399 } else {
1400 for (p = 0; exp[p] != 0; p++)
1401 exp[p] = my_lower_case (exp[p]);
1403 for (p = start; p <= last_byte - l; p++) {
1404 if (my_lower_case ((*get_byte) (data, p)) == (unsigned char)exp[0]) {
1405 for (f = 0, q = 0; q < l && f < 1; q++)
1406 if (my_lower_case ((*get_byte) (data, q + p)) != (unsigned char)exp[q])
1407 f = 1;
1408 if (f == 0)
1409 return p;
1411 if (once_only)
1412 return -2;
1416 return -2;
1420 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)
1421 { /*front end to find_string to check for
1422 whole words */
1423 long p;
1424 p = search_start;
1426 while ((p = edit_find_string (p, exp, len, last_byte, get_byte, data, once_only, d)) >= 0) {
1427 if (replace_whole) {
1428 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1429 if (!strcasechr (option_whole_chars_search, (*get_byte) (data, p - 1))
1430 && !strcasechr (option_whole_chars_search, (*get_byte) (data, p + *len)))
1431 return p;
1432 if (once_only)
1433 return -2;
1434 } else
1435 return p;
1436 if (once_only)
1437 break;
1438 p++; /*not a whole word so continue search. */
1440 return p;
1443 long edit_find (long search_start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, void *d)
1445 long p;
1446 if (replace_backwards) {
1447 while (search_start >= 0) {
1448 p = edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 1, d);
1449 if (p == search_start)
1450 return p;
1451 search_start--;
1453 } else {
1454 return edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 0, d);
1456 return -2;
1459 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1461 #define snprintf(v) { \
1462 *p1++ = *p++; \
1463 *p1++ = '%'; \
1464 *p1++ = 'n'; \
1465 *p1 = '\0'; \
1466 sprintf(s,q1,v,&n); \
1467 s += n; \
1470 /* this function uses the sprintf command to do a vprintf */
1471 /* it takes pointers to arguments instead of the arguments themselves */
1472 static int sprintf_p (char *str, const char *fmt,...)
1473 __attribute__ ((format (printf, 2, 3)));
1475 static int sprintf_p (char *str, const char *fmt,...)
1477 va_list ap;
1478 int n;
1479 char *q, *p, *s = str;
1480 char q1[32];
1481 char *p1;
1483 va_start (ap, fmt);
1484 p = q = (char *) fmt;
1486 while ((p = strchr (p, '%'))) {
1487 n = (int) ((unsigned long) p - (unsigned long) q);
1488 strncpy (s, q, n); /* copy stuff between format specifiers */
1489 s += n;
1490 *s = 0;
1491 q = p;
1492 p1 = q1;
1493 *p1++ = *p++;
1494 if (*p == '%') {
1495 p++;
1496 *s++ = '%';
1497 q = p;
1498 continue;
1500 if (*p == 'n') {
1501 p++;
1502 /* do nothing */
1503 q = p;
1504 continue;
1506 if (*p == '#')
1507 *p1++ = *p++;
1508 if (*p == '0')
1509 *p1++ = *p++;
1510 if (*p == '-')
1511 *p1++ = *p++;
1512 if (*p == '+')
1513 *p1++ = *p++;
1514 if (*p == '*') {
1515 p++;
1516 strcpy (p1, itoa (*va_arg (ap, int *))); /* replace field width with a number */
1517 p1 += strlen (p1);
1518 } else {
1519 while (is_digit (*p))
1520 *p1++ = *p++;
1522 if (*p == '.')
1523 *p1++ = *p++;
1524 if (*p == '*') {
1525 p++;
1526 strcpy (p1, itoa (*va_arg (ap, int *))); /* replace precision with a number */
1527 p1 += strlen (p1);
1528 } else {
1529 while (is_digit (*p))
1530 *p1++ = *p++;
1532 /* flags done, now get argument */
1533 if (*p == 's') {
1534 snprintf (va_arg (ap, char *));
1535 } else if (*p == 'h') {
1536 if (strchr ("diouxX", *p))
1537 snprintf (*va_arg (ap, short *));
1538 } else if (*p == 'l') {
1539 *p1++ = *p++;
1540 if (strchr ("diouxX", *p))
1541 snprintf (*va_arg (ap, long *));
1542 } else if (strchr ("cdiouxX", *p)) {
1543 snprintf (*va_arg (ap, int *));
1544 } else if (*p == 'L') {
1545 *p1++ = *p++;
1546 if (strchr ("EefgG", *p))
1547 snprintf (*va_arg (ap, double *)); /* should be long double */
1548 } else if (strchr ("EefgG", *p)) {
1549 snprintf (*va_arg (ap, double *));
1550 } else if (strchr ("DOU", *p)) {
1551 snprintf (*va_arg (ap, long *));
1552 } else if (*p == 'p') {
1553 snprintf (*va_arg (ap, void **));
1555 q = p;
1557 va_end (ap);
1558 sprintf (s, q); /* print trailing leftover */
1559 return (unsigned long) s - (unsigned long) str + strlen (s);
1562 static void regexp_error (WEdit *edit)
1564 /* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */
1565 edit_error_dialog (_(" Error "), _(" Invalid regular expression, or scanf expression with to many conversions "));
1568 /* call with edit = 0 before shutdown to close memory leaks */
1569 void edit_replace_cmd (WEdit * edit, int again)
1571 static regmatch_t pmatch[NUM_REPL_ARGS];
1572 static char *old1 = NULL;
1573 static char *old2 = NULL;
1574 static char *old3 = NULL;
1575 char *exp1 = "";
1576 char *exp2 = "";
1577 char *exp3 = "";
1578 int replace_yes;
1579 int replace_continue;
1580 int treplace_prompt = 0;
1581 int i = 0;
1582 long times_replaced = 0, last_search;
1583 char fin_string[64];
1584 int argord[NUM_REPL_ARGS];
1586 if (!edit) {
1587 if (old1) {
1588 g_free (old1);
1589 old1 = 0;
1591 if (old2) {
1592 g_free (old2);
1593 old2 = 0;
1595 if (old3) {
1596 g_free (old3);
1597 old3 = 0;
1599 return;
1601 last_search = edit->last_byte;
1603 edit->force |= REDRAW_COMPLETELY;
1605 exp1 = old1 ? old1 : exp1;
1606 exp2 = old2 ? old2 : exp2;
1607 exp3 = old3 ? old3 : exp3;
1609 if (again) {
1610 if (!old1 || !old2)
1611 return;
1612 exp1 = g_strdup (old1);
1613 exp2 = g_strdup (old2);
1614 exp3 = g_strdup (old3);
1615 } else {
1616 edit_push_action (edit, KEY_PRESS + edit->start_display);
1618 #ifdef HAVE_CHARSET
1619 if (exp1 && *exp1)
1620 convert_to_display (exp1);
1621 if (exp2 && *exp2)
1622 convert_to_display (exp2);
1623 #endif /* HAVE_CHARSET */
1625 edit_replace_dialog (edit, &exp1, &exp2, &exp3);
1627 #ifdef HAVE_CHARSET
1628 if (exp1 && *exp1)
1629 convert_from_input (exp1);
1630 if (exp2 && *exp2)
1631 convert_from_input (exp2);
1632 #endif /* HAVE_CHARSET */
1634 treplace_prompt = replace_prompt;
1637 if (!exp1 || !*exp1) {
1638 edit->force = REDRAW_COMPLETELY;
1639 if (exp1)
1640 g_free (exp1);
1641 if (exp2)
1642 g_free (exp2);
1643 if (exp3)
1644 g_free (exp3);
1645 return;
1647 if (old1)
1648 g_free (old1);
1649 if (old2)
1650 g_free (old2);
1651 if (old3)
1652 g_free (old3);
1653 old1 = g_strdup (exp1);
1654 old2 = g_strdup (exp2);
1655 old3 = g_strdup (exp3);
1658 char *s;
1659 int ord;
1660 while ((s = strchr (exp3, ' ')))
1661 memmove (s, s + 1, strlen (s));
1662 s = exp3;
1663 for (i = 0; i < NUM_REPL_ARGS; i++) {
1664 if (s != (char *)1 && *s) {
1665 ord = atoi (s);
1666 if ((ord > 0) && (ord < NUM_REPL_ARGS))
1667 argord[i] = ord - 1;
1668 else
1669 argord[i] = i;
1670 s = strchr (s, ',') + 1;
1671 } else
1672 argord[i] = i;
1676 replace_continue = replace_all;
1678 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
1679 edit->search_start--;
1681 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
1682 edit->search_start++;
1684 do {
1685 int len = 0;
1686 long new_start;
1687 new_start = edit_find (edit->search_start, (unsigned char *) exp1, &len, last_search,
1688 (int (*)(void *, long)) edit_get_byte, (void *) edit, pmatch);
1689 if (new_start == -3) {
1690 regexp_error (edit);
1691 break;
1693 edit->search_start = new_start;
1694 /*returns negative on not found or error in pattern */
1696 if (edit->search_start >= 0) {
1697 edit->found_start = edit->search_start;
1698 i = edit->found_len = len;
1700 edit_cursor_move (edit, edit->search_start - edit->curs1);
1701 edit_scroll_screen_over_cursor (edit);
1703 replace_yes = 1;
1705 if (treplace_prompt) {
1706 int l;
1707 l = edit->curs_row - edit->num_widget_lines / 3;
1708 if (l > 0)
1709 edit_scroll_downward (edit, l);
1710 if (l < 0)
1711 edit_scroll_upward (edit, -l);
1713 edit_scroll_screen_over_cursor (edit);
1714 edit->force |= REDRAW_PAGE;
1715 edit_render_keypress (edit);
1717 /*so that undo stops at each query */
1718 edit_push_key_press (edit);
1720 switch (edit_replace_prompt (edit, exp2, /* and prompt 2/3 down */
1721 (edit->num_widget_columns - CONFIRM_DLG_WIDTH)/2,
1722 edit->num_widget_lines * 2 / 3)) {
1723 case B_ENTER:
1724 break;
1725 case B_SKIP_REPLACE:
1726 replace_yes = 0;
1727 break;
1728 case B_REPLACE_ALL:
1729 treplace_prompt = 0;
1730 replace_continue = 1;
1731 break;
1732 case B_REPLACE_ONE:
1733 replace_continue = 0;
1734 break;
1735 case B_CANCEL:
1736 replace_yes = 0;
1737 replace_continue = 0;
1738 break;
1741 if (replace_yes) { /* delete then insert new */
1742 if (replace_scanf || replace_regexp) {
1743 char repl_str[MAX_REPL_LEN + 2];
1744 if (replace_regexp) { /* we need to fill in sargs just like with scanf */
1745 int k, j;
1746 for (k = 1; k < NUM_REPL_ARGS && pmatch[k].rm_eo >= 0; k++) {
1747 unsigned char *t;
1748 t = (unsigned char *) &sargs[k - 1][0];
1749 for (j = 0; j < pmatch[k].rm_eo - pmatch[k].rm_so && j < 255; j++, t++)
1750 *t = (unsigned char) edit_get_byte (edit, edit->search_start - pmatch[0].rm_so + pmatch[k].rm_so + j);
1751 *t = '\0';
1753 for (; k <= NUM_REPL_ARGS; k++)
1754 sargs[k - 1][0] = 0;
1756 if (sprintf_p (repl_str, exp2, PRINTF_ARGS) >= 0) {
1757 times_replaced++;
1758 while (i--)
1759 edit_delete (edit);
1760 while (repl_str[++i])
1761 edit_insert (edit, repl_str[i]);
1762 } else {
1763 edit_error_dialog (_ (" Replace "),
1764 /* "Invalid regexp string or scanf string" */
1765 _ (" Error in replacement format string. "));
1766 replace_continue = 0;
1768 } else {
1769 times_replaced++;
1770 while (i--)
1771 edit_delete (edit);
1772 while (exp2[++i])
1773 edit_insert (edit, exp2[i]);
1775 edit->found_len = i;
1777 /* so that we don't find the same string again */
1778 if (replace_backwards) {
1779 last_search = edit->search_start;
1780 edit->search_start--;
1781 } else {
1782 edit->search_start += i;
1783 last_search = edit->last_byte;
1785 edit_scroll_screen_over_cursor (edit);
1786 } else {
1787 edit->search_start = edit->curs1; /* try and find from right here for next search */
1788 edit_update_curs_col (edit);
1790 edit->force |= REDRAW_PAGE;
1791 edit_render_keypress (edit);
1792 if (times_replaced) {
1793 sprintf (fin_string, _ (" %ld replacements made. "), times_replaced);
1794 edit_message_dialog (_ (" Replace "), fin_string);
1795 } else
1796 edit_message_dialog (_ (" Replace "), _ (" Search string not found. "));
1797 replace_continue = 0;
1799 } while (replace_continue);
1801 g_free (exp1);
1802 g_free (exp2);
1803 g_free (exp3);
1804 edit->force = REDRAW_COMPLETELY;
1805 edit_scroll_screen_over_cursor (edit);
1811 void edit_search_cmd (WEdit * edit, int again)
1813 static char *old = NULL;
1814 char *exp = "";
1816 if (!edit) {
1817 if (old) {
1818 g_free (old);
1819 old = 0;
1821 return;
1823 exp = old ? old : exp;
1824 if (again) { /*ctrl-hotkey for search again. */
1825 if (!old)
1826 return;
1827 exp = (char *) g_strdup (old);
1828 } else {
1830 #ifdef HAVE_CHARSET
1831 if (exp && *exp)
1832 convert_to_display (exp);
1833 #endif /* HAVE_CHARSET */
1835 edit_search_dialog (edit, &exp);
1837 #ifdef HAVE_CHARSET
1838 if (exp && *exp)
1839 convert_from_input (exp);
1840 #endif /* HAVE_CHARSET */
1842 edit_push_action (edit, KEY_PRESS + edit->start_display);
1845 if (exp) {
1846 if (*exp) {
1847 int len = 0;
1848 if (old)
1849 g_free (old);
1850 old = (char *) g_strdup (exp);
1852 if (search_create_bookmark) {
1853 int found = 0, books = 0;
1854 int l = 0, l_last = -1;
1855 long p, q = 0;
1856 for (;;) {
1857 p = edit_find (q, (unsigned char *) exp, &len, edit->last_byte,
1858 (int (*)(void *, long)) edit_get_byte, (void *) edit, 0);
1859 if (p < 0)
1860 break;
1861 found++;
1862 l += edit_count_lines (edit, q, p);
1863 if (l != l_last) {
1864 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
1865 books++;
1867 l_last = l;
1868 q = p + 1;
1870 if (found) {
1871 char fin_string[64];
1872 /* in response to number of bookmarks added because of string being found %d times */
1873 sprintf (fin_string, _ (" %d finds made, %d bookmarks added "), found, books);
1874 edit_message_dialog (_ (" Search "), fin_string);
1875 } else {
1876 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
1878 } else {
1880 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
1881 edit->search_start--;
1883 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
1884 edit->search_start++;
1886 edit->search_start = edit_find (edit->search_start, (unsigned char *) exp, &len, edit->last_byte,
1887 (int (*)(void *, long)) edit_get_byte, (void *) edit, 0);
1889 if (edit->search_start >= 0) {
1890 edit->found_start = edit->search_start;
1891 edit->found_len = len;
1893 edit_cursor_move (edit, edit->search_start - edit->curs1);
1894 edit_scroll_screen_over_cursor (edit);
1895 if (replace_backwards)
1896 edit->search_start--;
1897 else
1898 edit->search_start++;
1899 } else if (edit->search_start == -3) {
1900 edit->search_start = edit->curs1;
1901 regexp_error (edit);
1902 } else {
1903 edit->search_start = edit->curs1;
1904 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
1908 g_free (exp);
1910 edit->force |= REDRAW_COMPLETELY;
1911 edit_scroll_screen_over_cursor (edit);
1915 /* Real edit only */
1916 void edit_quit_cmd (WEdit * edit)
1918 edit_push_action (edit, KEY_PRESS + edit->start_display);
1920 edit->force |= REDRAW_COMPLETELY;
1921 if (edit->modified) {
1922 switch (edit_query_dialog3 (_ (" Quit "), _ (" File was modified, Save with exit? "), _ ("Cancel quit"), _ ("&Yes"), _ ("&No"))) {
1923 case 1:
1924 edit_push_markers (edit);
1925 edit_set_markers (edit, 0, 0, 0, 0);
1926 if (!edit_save_cmd (edit))
1927 return;
1928 break;
1929 case 2:
1930 if (edit->delete_file)
1931 unlink (catstrs (edit->dir, edit->filename, 0));
1932 break;
1933 case 0:
1934 case -1:
1935 return;
1938 else if (edit->delete_file)
1939 unlink (catstrs (edit->dir, edit->filename, 0));
1940 dlg_stop (edit->widget.parent);
1943 #define TEMP_BUF_LEN 1024
1945 /* returns a null terminated length of text. Result must be free'd */
1946 unsigned char *edit_get_block (WEdit * edit, long start, long finish, int *l)
1948 unsigned char *s, *r;
1949 r = s = malloc (finish - start + 1);
1950 if (column_highlighting) {
1951 *l = 0;
1952 while (start < finish) { /* copy from buffer, excluding chars that are out of the column 'margins' */
1953 int c, x;
1954 x = edit_move_forward3 (edit, edit_bol (edit, start), 0, start);
1955 c = edit_get_byte (edit, start);
1956 if ((x >= edit->column1 && x < edit->column2)
1957 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1958 *s++ = c;
1959 (*l)++;
1961 start++;
1963 } else {
1964 *l = finish - start;
1965 while (start < finish)
1966 *s++ = edit_get_byte (edit, start++);
1968 *s = 0;
1969 return r;
1972 /* save block, returns 1 on success */
1973 int edit_save_block (WEdit * edit, const char *filename, long start, long finish)
1975 int len, file;
1977 if ((file = open ((char *) filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
1978 return 0;
1980 if (column_highlighting) {
1981 unsigned char *block, *p;
1982 int r;
1983 p = block = edit_get_block (edit, start, finish, &len);
1984 while (len) {
1985 r = write (file, p, len);
1986 if (r < 0)
1987 break;
1988 p += r;
1989 len -= r;
1991 free (block);
1992 } else {
1993 unsigned char *buf;
1994 int i = start, end;
1995 len = finish - start;
1996 buf = malloc (TEMP_BUF_LEN);
1997 while (start != finish) {
1998 end = min (finish, start + TEMP_BUF_LEN);
1999 for (; i < end; i++)
2000 buf[i - start] = edit_get_byte (edit, i);
2001 len -= write (file, (char *) buf, end - start);
2002 start = end;
2004 free (buf);
2006 close (file);
2007 if (len)
2008 return 0;
2009 return 1;
2012 /* copies a block to clipboard file */
2013 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
2015 return edit_save_block (edit, catstrs (home_dir, CLIP_FILE, 0), start, finish);
2019 void edit_paste_from_history (WEdit *edit)
2023 int edit_copy_to_X_buf_cmd (WEdit * edit)
2025 long start_mark, end_mark;
2026 if (eval_marks (edit, &start_mark, &end_mark))
2027 return 0;
2028 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2029 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2030 return 1;
2032 edit_mark_cmd (edit, 1);
2033 return 0;
2036 int edit_cut_to_X_buf_cmd (WEdit * edit)
2038 long start_mark, end_mark;
2039 if (eval_marks (edit, &start_mark, &end_mark))
2040 return 0;
2041 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2042 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2043 return 1;
2045 edit_block_delete_cmd (edit);
2046 edit_mark_cmd (edit, 1);
2047 return 0;
2050 void edit_paste_from_X_buf_cmd (WEdit * edit)
2052 edit_insert_file (edit, catstrs (home_dir, CLIP_FILE, 0));
2056 void edit_goto_cmd (WEdit *edit)
2058 char *f;
2059 static int l = 0;
2060 char s[12];
2061 sprintf (s, "%d", l);
2062 f = input_dialog (_(" Goto line "), _(" Enter line: "), l ? s : "");
2063 if (f) {
2064 if (*f) {
2065 l = atoi (f);
2066 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2067 edit_move_to_line (edit, l - 1);
2068 edit->force |= REDRAW_COMPLETELY;
2070 free (f);
2074 /*returns 1 on success */
2075 int edit_save_block_cmd (WEdit * edit)
2077 long start_mark, end_mark;
2078 char *exp;
2079 if (eval_marks (edit, &start_mark, &end_mark))
2080 return 1;
2081 exp = edit_get_save_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _ (" Save Block "));
2082 edit_push_action (edit, KEY_PRESS + edit->start_display);
2083 if (exp) {
2084 if (!*exp) {
2085 g_free (exp);
2086 return 0;
2087 } else {
2088 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2089 g_free (exp);
2090 edit->force |= REDRAW_COMPLETELY;
2091 return 1;
2092 } else {
2093 g_free (exp);
2094 edit_error_dialog (_ (" Save Block "), get_sys_error (_ (" Error trying to save file. ")));
2098 edit->force |= REDRAW_COMPLETELY;
2099 return 0;
2103 /* returns 1 on success */
2104 int edit_insert_file_cmd (WEdit * edit)
2106 char *exp = edit_get_load_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _ (" Insert File "));
2107 edit_push_action (edit, KEY_PRESS + edit->start_display);
2108 if (exp) {
2109 if (!*exp) {
2110 g_free (exp);
2111 return 0;
2112 } else {
2113 if (edit_insert_file (edit, exp)) {
2114 g_free (exp);
2115 edit->force |= REDRAW_COMPLETELY;
2116 return 1;
2117 } else {
2118 g_free (exp);
2119 edit_error_dialog (_ (" Insert file "), get_sys_error (_ (" Error trying to insert file. ")));
2123 edit->force |= REDRAW_COMPLETELY;
2124 return 0;
2127 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2128 int edit_sort_cmd (WEdit * edit)
2130 static char *old = 0;
2131 char *exp;
2132 long start_mark, end_mark;
2133 int e;
2135 if (eval_marks (edit, &start_mark, &end_mark)) {
2136 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2137 return 0;
2139 edit_save_block (edit, catstrs (home_dir, BLOCK_FILE, 0), start_mark, end_mark);
2141 exp = old ? old : "";
2143 exp = input_dialog (_(" Run Sort "),
2144 _(" Enter sort options (see manpage) separated by whitespace: "), exp);
2146 if (!exp)
2147 return 1;
2148 if (old)
2149 g_free (old);
2150 old = exp;
2152 e = system (catstrs (" sort ", exp, " ", home_dir, BLOCK_FILE, " > ", home_dir, TEMP_FILE, 0));
2153 if (e) {
2154 if (e == -1 || e == 127) {
2155 edit_error_dialog (_(" Sort "),
2156 get_sys_error (_(" Error trying to execute sort command ")));
2157 } else {
2158 char q[8];
2159 sprintf (q, "%d ", e);
2160 edit_error_dialog (_(" Sort "),
2161 catstrs (_(" Sort returned non-zero: "), q, 0));
2163 return -1;
2166 edit->force |= REDRAW_COMPLETELY;
2168 if (edit_block_delete_cmd (edit))
2169 return 1;
2170 edit_insert_file (edit, catstrs (home_dir, TEMP_FILE, 0));
2171 return 0;
2174 /* if block is 1, a block must be highlighted and the shell command
2175 processes it. If block is 0 the shell command is a straight system
2176 command, that just produces some output which is to be inserted */
2177 void edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block)
2179 long start_mark, end_mark;
2180 struct stat s;
2181 char buf[BUFSIZ];
2182 FILE *script_home = NULL;
2183 FILE *script_src = NULL;
2184 FILE *block_file = NULL;
2186 char *o = catstrs (mc_home, shell_cmd, 0); /* original source script */
2187 char *h = catstrs (home_dir, EDIT_DIR, shell_cmd, 0); /* home script */
2188 char *b = catstrs (home_dir, BLOCK_FILE, 0); /* block file */
2189 char *e = catstrs (home_dir, ERROR_FILE, 0); /* error file */
2191 if (! (script_home = fopen (h, "r"))) {
2192 if (! (script_home = fopen (h, "w"))) {
2193 edit_error_dialog ("",
2194 get_sys_error (catstrs (_ ("Error create script:"), h, 0)));
2195 return;
2196 } else {
2197 if (! (script_src = fopen (o, "r"))) {
2198 fclose (script_home); unlink (h);
2199 edit_error_dialog ("",
2200 get_sys_error (catstrs (_ ("Error read script:"), o, 0)));
2201 return;
2202 } else {
2203 while (fgets(buf, sizeof(buf), script_src))
2204 fputs (buf, script_home);
2205 if (fclose(script_home)) {
2206 edit_error_dialog ("",
2207 get_sys_error (catstrs (_ ("Error close script:"), h, 0)));
2208 return;
2209 } else {
2210 chmod (h, 0700);
2211 edit_error_dialog ("",
2212 get_sys_error (catstrs (_ ("Script created:"), h, 0)));
2217 if (block) { /* for marked block run indent formatter */
2218 if (eval_marks (edit, &start_mark, &end_mark)) {
2219 edit_error_dialog (_("Process block"),
2220 _(" You must first highlight a block of text. "));
2221 return;
2223 edit_save_block (edit, b, start_mark, end_mark);
2226 * Run script.
2227 * Initial space is to avoid polluting bash history.
2228 * Arguments:
2229 * $1 - name of the edited file (to check its extention etc).
2230 * $2 - file containing the current block.
2231 * $3 - file where error messages should be put.
2233 execute (catstrs (" ", home_dir, EDIT_DIR, shell_cmd, " ",
2234 edit->filename, " ", home_dir, BLOCK_FILE, " ",
2235 home_dir, ERROR_FILE, NULL));
2237 } else {
2239 * No block selected, just execute the command for the file.
2240 * Arguments:
2241 * $1 - name of the edited file.
2243 execute (catstrs (" ", home_dir, EDIT_DIR, shell_cmd, " ",
2244 edit->filename, NULL));
2247 edit_refresh_cmd (edit);
2248 edit->force |= REDRAW_COMPLETELY;
2250 /* insert result block */
2251 if (block) {
2252 if (mc_stat (e, &s) == 0) {
2253 if (!s.st_size) { /* no error messages */
2254 if (edit_block_delete_cmd (edit))
2255 return;
2256 edit_insert_file (edit, b);
2257 } else {
2258 edit_insert_file (edit, e);
2260 } else {
2261 edit_error_dialog ("",
2262 get_sys_error (catstrs (_ ("Error trying to stat file:"), e, 0)));
2263 edit->force |= REDRAW_COMPLETELY;
2265 if ((block_file = fopen (b, "w")))
2266 fclose (block_file);
2267 return;
2269 return;
2272 /* prints at the cursor */
2273 /* returns the number of chars printed */
2274 int edit_print_string (WEdit * e, const char *s)
2276 int i = 0;
2277 while (s[i])
2278 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2279 e->force |= REDRAW_COMPLETELY;
2280 edit_update_screen (e);
2281 return i;
2284 int edit_printf (WEdit * e, const char *fmt,...)
2286 int i;
2287 va_list pa;
2288 char s[1024];
2289 va_start (pa, fmt);
2290 sprintf (s, fmt, pa);
2291 i = edit_print_string (e, s);
2292 va_end (pa);
2293 return i;
2296 /* FIXME: does this function break NT_OS2 ? */
2298 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2300 FILE *p = 0;
2301 char *s;
2303 s = g_strdup_printf ("mail -s \"%s\" -c \"%s\" \"%s\"", subject, cc, to);
2305 if (s) {
2306 p = popen (s, "w");
2307 g_free (s);
2310 if (p) {
2311 long i;
2312 for (i = 0; i < edit->last_byte; i++)
2313 fputc (edit_get_byte (edit, i), p);
2314 pclose (p);
2318 #define MAIL_DLG_HEIGHT 12
2320 void edit_mail_dialog (WEdit * edit)
2322 char *tmail_to;
2323 char *tmail_subject;
2324 char *tmail_cc;
2326 static char *mail_cc_last = 0;
2327 static char *mail_subject_last = 0;
2328 static char *mail_to_last = 0;
2330 QuickDialog Quick_input =
2331 {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
2332 "[Input Line Keys]", "quick_input", 0};
2334 QuickWidget quick_widgets[] =
2336 {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
2337 0, NULL},
2338 {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&Ok"), 0, B_ENTER, 0,
2339 0, NULL},
2340 {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2341 0, "mail-dlg-input"},
2342 {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
2343 0, 0},
2344 {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2345 0, "mail-dlg-input-2"},
2346 {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
2347 0, 0},
2348 {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2349 0, "mail-dlg-input-3"},
2350 {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
2351 0, 0},
2352 {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2353 0, 0},
2354 {0}};
2356 quick_widgets[2].str_result = &tmail_cc;
2357 quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
2358 quick_widgets[4].str_result = &tmail_subject;
2359 quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
2360 quick_widgets[6].str_result = &tmail_to;
2361 quick_widgets[6].text = mail_to_last ? mail_to_last : "";
2363 Quick_input.widgets = quick_widgets;
2365 if (quick_dialog (&Quick_input) != B_CANCEL) {
2366 if (mail_cc_last)
2367 g_free (mail_cc_last);
2368 if (mail_subject_last)
2369 g_free (mail_subject_last);
2370 if (mail_to_last)
2371 g_free (mail_to_last);
2372 mail_cc_last = *(quick_widgets[2].str_result);
2373 mail_subject_last = *(quick_widgets[4].str_result);
2374 mail_to_last = *(quick_widgets[6].str_result);
2375 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);