* Make-mc.in: Include necessary parts of Make.common to
[midnight-commander.git] / gtkedit / editcmd.c
blob7731132effdec0b089da07b553a510b2167734fb
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 #ifdef NEEDS_IO_H
30 #include <io.h>
31 #include <fcntl.h>
32 #endif
33 #include <ctype.h>
34 #include "edit.h"
35 #include "editcmddef.h"
37 #ifndef MIDNIGHT
38 #include <X11/Xatom.h>
39 #ifndef GTK
40 #include "loadfile.h"
41 #endif
42 #endif
44 #ifdef HAVE_CHARSET
45 #include "../src/charsets.h"
46 #endif
48 /* globals: */
50 /* search and replace: */
51 int replace_scanf = 0;
52 int replace_regexp = 0;
53 int replace_all = 0;
54 int replace_prompt = 1;
55 int replace_whole = 0;
56 int replace_case = 0;
57 int replace_backwards = 0;
58 int search_create_bookmark = 0;
60 /* queries on a save */
61 #ifdef MIDNIGHT
62 int edit_confirm_save = 1;
63 #else
64 int edit_confirm_save = 0;
65 #endif
67 #define NUM_REPL_ARGS 64
68 #define MAX_REPL_LEN 1024
70 #if defined(MIDNIGHT) || defined(GTK)
72 static inline int my_lower_case (int c)
74 return tolower(c & 0xFF);
77 char *strcasechr (const unsigned char *s, int c)
79 for (c = my_lower_case (c); my_lower_case ((int) *s) != c; ++s)
80 if (*s == '\0')
81 return 0;
82 return (char *) s;
85 #ifdef MIDNIGHT
86 #include "../src/mad.h"
87 #elif !defined (GTK)
88 #include "mad.h"
89 #endif
91 #ifndef HAVE_MEMMOVE
92 /* for Christophe */
93 static void *memmove (void *dest, const void *src, size_t n)
95 char *t, *s;
97 if (dest <= src) {
98 t = (char *) dest;
99 s = (char *) src;
100 while (n--)
101 *t++ = *s++;
102 } else {
103 t = (char *) dest + n;
104 s = (char *) src + n;
105 while (n--)
106 *--t = *--s;
108 return dest;
110 #endif
112 /* #define itoa MY_itoa <---- this line is now in edit.h */
113 char *itoa (int i)
115 static char t[14];
116 char *s = t + 13;
117 int j = i;
118 *s-- = 0;
119 do {
120 *s-- = i % 10 + '0';
121 } while ((i = i / 10));
122 if (j < 0)
123 *s-- = '-';
124 return ++s;
128 This joins strings end on end and allocates memory for the result.
129 The result is later automatically free'd and must not be free'd
130 by the caller.
132 char *catstrs (const char *first,...)
134 static char *stacked[16] =
135 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
136 static int i = 0;
137 va_list ap;
138 int len;
139 char *data;
141 if (!first)
142 return 0;
144 len = strlen (first);
145 va_start (ap, first);
147 while ((data = va_arg (ap, char *)) != 0)
148 len += strlen (data);
150 len++;
152 i = (i + 1) % 16;
153 if (stacked[i])
154 free (stacked[i]);
156 stacked[i] = malloc (len);
157 va_end (ap);
158 va_start (ap, first);
159 strcpy (stacked[i], first);
160 while ((data = va_arg (ap, char *)) != 0)
161 strcat (stacked[i], data);
162 va_end (ap);
164 return stacked[i];
166 #endif
168 #ifdef MIDNIGHT
170 void edit_help_cmd (WEdit * edit)
172 interactive_display (NULL, "[Internal File Editor]");
173 edit->force |= REDRAW_COMPLETELY;
176 void edit_refresh_cmd (WEdit * edit)
178 #ifndef HAVE_SLANG
179 clr_scr();
180 do_refresh();
181 #else
183 int fg, bg;
184 edit_get_syntax_color (edit, -1, &fg, &bg);
186 touchwin(stdscr);
187 #endif /* !HAVE_SLANG */
188 mc_refresh();
189 doupdate();
192 #else /* MIDNIGHT */
194 void edit_help_cmd (WEdit * edit)
198 void edit_refresh_cmd (WEdit * edit)
200 int fg, bg;
201 edit_get_syntax_color (edit, -1, &fg, &bg);
202 edit->force |= REDRAW_COMPLETELY;
205 void CRefreshEditor (WEdit * edit)
207 edit_refresh_cmd (edit);
210 #endif /* MIDNIGHT */
212 #ifndef MIDNIGHT
213 #ifndef GTK
215 /* three argument open */
216 int my_open (const char *pathname, int flags,...)
218 int file;
219 va_list ap;
221 file = open ((char *) pathname, O_RDONLY);
222 if (file < 0 && (flags & O_CREAT)) { /* must it be created ? */
223 mode_t mode;
224 va_start(ap, flags);
225 mode = va_arg(ap, mode_t);
226 va_end(ap);
227 return creat ((char *) pathname, mode);
229 close (file);
230 return open ((char *) pathname, flags);
233 #define open my_open
235 #endif /* !GTK */
236 #endif /* !MIDNIGHT */
238 /* "Oleg Yu. Repin" <repin@ssd.sscc.ru> added backup filenames
239 ...thanks -paul */
241 /* If 0 (quick save) then a) create/truncate <filename> file,
242 b) save to <filename>;
243 if 1 (safe save) then a) save to <tempnam>,
244 b) rename <tempnam> to <filename>;
245 if 2 (do backups) then a) save to <tempnam>,
246 b) rename <filename> to <filename.backup_ext>,
247 c) rename <tempnam> to <filename>. */
249 /* returns 0 on error */
250 int edit_save_file (WEdit * edit, const char *filename)
252 char *p;
253 long filelen = 0;
254 char *savename = 0;
255 int this_save_mode, fd;
257 if (!filename)
258 return 0;
259 if (!*filename)
260 return 0;
262 savename = (char *) strdup ((char *) filename);
264 if (vfs_file_is_local (filename)) {
265 if ((fd = open (savename, O_WRONLY)) == -1) {
267 * The file does not exists yet, so no safe save or
268 * backup are necessary.
270 this_save_mode = 0;
271 } else {
272 close (fd);
273 this_save_mode = option_save_mode;
275 } else {
277 * FIXME - rename is not impemented in VFS, so only
278 * quick save is possible.
280 this_save_mode = 0;
283 if (this_save_mode > 0) {
284 char *savedir, *slashpos, *saveprefix;
285 savedir = (char *) strdup (".");
286 slashpos = strrchr (filename, '/');
287 if (slashpos) {
288 free (savedir);
289 savedir = (char *) strdup (filename);
290 savedir[slashpos - filename + 1] = '\0';
292 if (savename)
293 free (savename);
294 saveprefix = concat_dir_and_file (savedir, "cooledit");
295 fd = mc_mkstemps(&savename, saveprefix, NULL);
296 g_free (saveprefix);
297 free (savedir);
298 if (!savename)
299 return 0;
301 * Close for now because it needs to be reopened by
302 * VFS-aware mc_open() and MY_O_TEXT should be used.
304 close (fd);
307 if ((fd = open (savename, O_CREAT | O_WRONLY | O_TRUNC | MY_O_TEXT,
308 edit->stat1.st_mode)) == -1)
309 goto error_save;
311 chmod (savename, edit->stat1.st_mode);
312 chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
314 /* pipe save */
315 if ((p = (char *) edit_get_write_filter (savename, filename))) {
316 FILE *file;
318 close (fd);
319 file = (FILE *) popen (p, "w");
321 if (file) {
322 filelen = edit_write_stream (edit, file);
323 #if 1
324 pclose (file);
325 #else
326 if (pclose (file) != 0) {
327 edit_error_dialog (_ (" Error "), catstrs (_ (" Error writing to pipe: "), p, " ", 0));
328 free (p);
329 goto error_save;
331 #endif
332 } else {
333 edit_error_dialog (_ (" Error "), get_sys_error (catstrs (_ (" Failed trying to open pipe for writing: "), p, " ", 0)));
334 free (p);
335 goto error_save;
337 free (p);
338 #ifdef CR_LF_TRANSLATION
339 } else { /* optimised save */
340 filelen = edit_write_stream (edit, f);
341 if (fclose (file))
342 filelen = -1;
343 #else
344 } else {
345 long buf;
346 buf = 0;
347 filelen = edit->last_byte;
348 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
349 if (write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
350 close (fd);
351 goto error_save;
353 buf++;
355 if (write (fd, (char *) edit->buffers1[buf], edit->curs1 & M_EDIT_BUF_SIZE) != (edit->curs1 & M_EDIT_BUF_SIZE)) {
356 filelen = -1;
357 } else if (edit->curs2) {
358 edit->curs2--;
359 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
360 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)) {
361 filelen = -1;
362 } else {
363 while (--buf >= 0) {
364 if (write (fd, (char *) edit->buffers2[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
365 filelen = -1;
366 break;
370 edit->curs2++;
372 if (close (fd))
373 goto error_save;
374 #endif /* CR_LF_TRANSLATION */
377 if (filelen != edit->last_byte)
378 goto error_save;
379 if (this_save_mode == 2)
380 if (rename (filename, catstrs (filename, option_backup_ext, 0)) == -1)
381 goto error_save;
382 if (this_save_mode > 0)
383 if (rename (savename, filename) == -1)
384 goto error_save;
385 if (savename)
386 free (savename);
387 return 1;
388 error_save:
389 if (savename)
390 free (savename);
391 return 0;
394 #ifdef MIDNIGHT
396 I changed this from Oleg's original routine so
397 that option_backup_ext works with coolwidgets as well. This
398 does mean there is a memory leak - paul.
400 void menu_save_mode_cmd (void)
402 #define DLG_X 38
403 #define DLG_Y 10
404 static char *str_result;
405 static int save_mode_new;
406 static char *str[] =
408 N_("Quick save "),
409 N_("Safe save "),
410 N_("Do backups -->")};
411 static QuickWidget widgets[] =
413 {quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
414 B_CANCEL, 0, 0, "c"},
415 {quick_button, 6, DLG_X, 7, DLG_Y, N_("&Ok"), 0,
416 B_ENTER, 0, 0, "o"},
417 {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
418 0, 0, &str_result, "edit-backup-ext"},
419 {quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
420 0, 0, 0, "savemext"},
421 {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
422 0, &save_mode_new, str, "t"},
423 {0}};
424 static QuickDialog dialog =
425 {DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
426 "esm", widgets};
427 static int i18n_flag = 0;
429 if (!i18n_flag) {
430 int i;
431 int maxlen = 0;
432 int dlg_x;
433 int l1;
435 /* Ok/Cancel buttons */
436 l1 = strlen (_(widgets[0].text)) + strlen (_(widgets[1].text)) + 5;
437 maxlen = max (maxlen, l1);
439 for (i = 0; i < 3; i++ ) {
440 str[i] = _(str[i]);
441 maxlen = max (maxlen, strlen (str[i]) + 7);
443 i18n_flag = 1;
445 dlg_x = maxlen + strlen (_(widgets[3].text)) + 5 + 1;
446 widgets[2].hotkey_pos = strlen (_(widgets[3].text)); /* input field length */
447 dlg_x = min (COLS, dlg_x);
448 dialog.xlen = dlg_x;
450 i = (dlg_x - l1)/3;
451 widgets[1].relative_x = i;
452 widgets[0].relative_x = i + strlen (_(widgets[1].text)) + i + 4;
454 widgets[2].relative_x = widgets[3].relative_x = maxlen + 2;
456 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
457 widgets[i].x_divisions = dlg_x;
460 widgets[2].text = option_backup_ext;
461 widgets[4].value = option_save_mode;
462 if (quick_dialog (&dialog) != B_ENTER)
463 return;
464 option_save_mode = save_mode_new;
465 option_backup_ext = str_result; /* this is a memory leak */
466 option_backup_ext_int = 0;
467 str_result[min (strlen (str_result), sizeof (int))] = '\0';
468 memcpy ((char *) &option_backup_ext_int, str_result, strlen (option_backup_ext));
471 void edit_split_filename (WEdit * edit, const char *f)
473 if (edit->filename)
474 free (edit->filename);
475 edit->filename = (char *) strdup (f);
476 if (edit->dir)
477 free (edit->dir);
478 edit->dir = (char *) strdup ("");
481 #else /* MIDNIGHT */
483 #ifdef GTK
486 static char *edit_canonicalize_pathname (const char *p)
488 char *q, *r;
489 char *t = NULL;
490 char *cwd;
492 if (*p != '/') {
493 cwd = g_get_current_dir ();
494 t = g_malloc (strlen (cwd) + strlen (p) + 2);
495 strcpy (t, cwd);
496 strcat (t, "/");
497 strcat (t, p);
498 g_free (cwd);
499 p = t;
502 r = q = malloc (strlen (p) + 2);
503 while (*p) {
504 if (*p != '/') {
505 *q++ = *p++;
506 } else {
507 while (*p == '/') {
508 *q = '/';
509 if (!strncmp (p, "/./", 3) || !strcmp (p, "/."))
510 p++;
511 else if (!strncmp (p, "/../", 4) || !strcmp (p, "/..")) {
512 p += 2;
513 *q = ' ';
514 q = strrchr (r, '/');
515 if (!q) {
516 q = r;
517 *q = '/';
520 p++;
522 q++;
525 g_free (t);
526 *q = '\0';
527 /* get rid of trailing / */
528 if (r[0] && r[1])
529 if (*--q == '/')
530 *q = '\0';
531 return r;
534 #endif /* GTK */
537 void edit_split_filename (WEdit * edit, const char *longname)
539 char *exp, *p;
540 #ifdef GTK
541 exp = edit_canonicalize_pathname (longname);
542 #else
543 exp = pathdup (longname); /* this ensures a full path */
544 #endif
545 if (edit->filename)
546 free (edit->filename);
547 if (edit->dir)
548 free (edit->dir);
549 p = strrchr (exp, '/');
550 edit->filename = (char *) strdup (++p);
551 *p = 0;
552 edit->dir = (char *) strdup (exp);
553 free (exp);
556 #endif /* ! MIDNIGHT */
558 /* here we want to warn the user of overwriting an existing file, but only if they
559 have made a change to the filename */
560 /* returns 1 on success */
561 int edit_save_as_cmd (WEdit * edit)
563 /* This heads the 'Save As' dialog box */
564 char *exp = 0;
565 int different_filename = 0;
567 exp = edit_get_save_file (edit->dir, edit->filename, _(" Save As "));
568 edit_push_action (edit, KEY_PRESS + edit->start_display);
570 if (exp) {
571 if (!*exp) {
572 free (exp);
573 edit->force |= REDRAW_COMPLETELY;
574 return 0;
575 } else {
576 if (strcmp(catstrs (edit->dir, edit->filename, 0), exp)) {
577 int file;
578 different_filename = 1;
579 if ((file = open ((char *) exp, O_RDONLY)) != -1) { /* the file exists */
580 close (file);
581 if (edit_query_dialog2 (_(" Warning "),
582 _(" A file already exists with this name. "),
583 /* Push buttons to over-write the current file, or cancel the operation */
584 _("Overwrite"), _("Cancel"))) {
585 edit->force |= REDRAW_COMPLETELY;
586 return 0;
590 if (edit_save_file (edit, exp)) {
591 edit_split_filename (edit, exp);
592 free (exp);
593 edit->modified = 0;
594 #if defined(MIDNIGHT) || defined(GTK)
595 edit->delete_file = 0;
596 #endif
597 if (different_filename && !edit->explicit_syntax)
598 edit_load_syntax (edit, 0, 0);
599 edit->force |= REDRAW_COMPLETELY;
600 return 1;
601 } else {
602 free (exp);
603 edit_error_dialog (_(" Save as "), get_sys_error (_(" Error trying to save file. ")));
604 edit->force |= REDRAW_COMPLETELY;
605 return 0;
609 edit->force |= REDRAW_COMPLETELY;
610 return 0;
613 /* {{{ Macro stuff starts here */
615 #ifdef MIDNIGHT
616 int raw_callback (struct Dlg_head *h, int key, int Msg)
618 switch (Msg) {
619 case DLG_DRAW:
620 attrset (REVERSE_COLOR);
621 dlg_erase (h);
622 draw_box (h, 1, 1, h->lines - 2, h->cols - 2);
624 attrset (COLOR_HOT_NORMAL);
625 dlg_move (h, 1, 2);
626 printw (h->title);
627 break;
629 case DLG_KEY:
630 h->running = 0;
631 h->ret_value = key;
632 return 1;
634 return 0;
637 /* gets a raw key from the keyboard. Passing cancel = 1 draws
638 a cancel button thus allowing c-c etc.. Alternatively, cancel = 0
639 will return the next key pressed */
640 int edit_raw_key_query (char *heading, char *query, int cancel)
642 int w = strlen (query) + 7;
643 struct Dlg_head *raw_dlg = create_dlg (0, 0, 7, w, dialog_colors,
644 /* NLS ? */
645 raw_callback, "[Raw Key Query]",
646 "raw_key_input",
647 DLG_CENTER | DLG_TRYUP);
648 x_set_dialog_title (raw_dlg, heading);
649 raw_dlg->raw = 1; /* to return even a tab key */
650 if (cancel)
651 add_widget (raw_dlg, button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON, _("Cancel"), 0, 0, 0));
652 add_widget (raw_dlg, label_new (3 - cancel, 2, query, 0));
653 add_widget (raw_dlg, input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0));
654 run_dlg (raw_dlg);
655 w = raw_dlg->ret_value;
656 destroy_dlg (raw_dlg);
657 if (cancel)
658 if (w == XCTRL ('g') || w == XCTRL ('c') || w == ESC_CHAR || w == B_CANCEL)
659 return 0;
660 /* hence ctrl-a (=B_CANCEL), ctrl-g, ctrl-c, and Esc are cannot returned */
661 return w;
664 #else /* MIDNIGHT */
666 int edit_raw_key_query (char *heading, char *query, int cancel)
668 #ifdef GTK
669 /* *** */
670 return 0;
671 #else
672 return CKeySymMod (CRawkeyQuery (0, 0, 0, heading, query));
673 #endif
676 #endif /* MIDNIGHT */
678 /* creates a macro file if it doesn't exist */
679 static FILE *edit_open_macro_file (const char *r)
681 char *filename;
682 int file;
683 filename = catstrs (home_dir, MACRO_FILE, 0);
684 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
685 return 0;
686 close (file);
687 return fopen (filename, r);
690 #define MAX_MACROS 1024
691 static int saved_macro[MAX_MACROS + 1] =
692 {0, 0};
693 static int saved_macros_loaded = 0;
696 This is just to stop the macro file be loaded over and over for keys
697 that aren't defined to anything. On slow systems this could be annoying.
699 int macro_exists (int k)
701 int i;
702 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
703 if (saved_macro[i] == k)
704 return i;
705 return -1;
708 /* returns 1 on error */
709 int edit_delete_macro (WEdit * edit, int k)
711 struct macro macro[MAX_MACRO_LENGTH];
712 FILE *f, *g;
713 int s, i, n, j = 0;
715 if (saved_macros_loaded)
716 if ((j = macro_exists (k)) < 0)
717 return 0;
718 g = fopen (catstrs (home_dir, TEMP_FILE, 0), "w");
719 if (!g) {
720 /* This heads the delete macro error dialog box */
721 edit_error_dialog (_(" Delete macro "),
722 /* 'Open' = load temp file */
723 get_sys_error (_(" Error trying to open temp file ")));
724 return 1;
726 f = edit_open_macro_file ("r");
727 if (!f) {
728 /* This heads the delete macro error dialog box */
729 edit_error_dialog (_(" Delete macro "),
730 /* 'Open' = load temp file */
731 get_sys_error (_(" Error trying to open macro file ")));
732 fclose (g);
733 return 1;
735 for (;;) {
736 n = fscanf (f, ("key '%d 0': "), &s);
737 if (!n || n == EOF)
738 break;
739 n = 0;
740 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
741 n++;
742 fscanf (f, ";\n");
743 if (s != k) {
744 fprintf (g, ("key '%d 0': "), s);
745 for (i = 0; i < n; i++)
746 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
747 fprintf (g, ";\n");
750 fclose (f);
751 fclose (g);
752 if (rename (catstrs (home_dir, TEMP_FILE, 0), catstrs (home_dir, MACRO_FILE, 0)) == -1) {
753 /* This heads the delete macro error dialog box */
754 edit_error_dialog (_(" Delete macro "),
755 get_sys_error (_(" Error trying to overwrite macro file ")));
756 return 1;
758 if (saved_macros_loaded)
759 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
760 return 0;
763 /* returns 0 on error */
764 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
766 FILE *f;
767 int s, i;
769 edit_push_action (edit, KEY_PRESS + edit->start_display);
770 /* This heads the 'Macro' dialog box */
771 s = edit_raw_key_query (_(" Macro "),
772 /* Input line for a single key press follows the ':' */
773 _(" Press the macro's new hotkey: "), 1);
774 edit->force |= REDRAW_COMPLETELY;
775 if (s) {
776 if (edit_delete_macro (edit, s))
777 return 0;
778 f = edit_open_macro_file ("a+");
779 if (f) {
780 fprintf (f, ("key '%d 0': "), s);
781 for (i = 0; i < n; i++)
782 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
783 fprintf (f, ";\n");
784 fclose (f);
785 if (saved_macros_loaded) {
786 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
787 saved_macro[i] = s;
789 return 1;
790 } else
791 /* This heads the 'Save Macro' dialog box */
792 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Error trying to open macro file ")));
794 return 0;
797 void edit_delete_macro_cmd (WEdit * edit)
799 int command;
801 #ifdef MIDNIGHT
802 command = edit_raw_key_query (_ (" Delete Macro "),
803 _ (" Press macro hotkey: "), 1);
804 #else
805 /* This heads the 'Delete Macro' dialog box */
806 #ifdef GTK
807 /* *** */
808 command = 0;
809 #else
810 command = CKeySymMod (CRawkeyQuery (0, 0, 0, _ (" Delete Macro "),
811 /* Input line for a single key press follows the ':' */
812 _ (" Press macro hotkey: ")));
813 #endif
814 #endif
816 if (!command)
817 return;
819 edit_delete_macro (edit, command);
822 /* return 0 on error */
823 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
825 FILE *f;
826 int s, i = 0, found = 0;
828 if (saved_macros_loaded)
829 if (macro_exists (k) < 0)
830 return 0;
832 if ((f = edit_open_macro_file ("r"))) {
833 struct macro dummy;
834 do {
835 int u;
836 u = fscanf (f, ("key '%d 0': "), &s);
837 if (!u || u == EOF)
838 break;
839 if (!saved_macros_loaded)
840 saved_macro[i++] = s;
841 if (!found) {
842 *n = 0;
843 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
844 (*n)++;
845 } else {
846 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
848 fscanf (f, ";\n");
849 if (s == k)
850 found = 1;
851 } while (!found || !saved_macros_loaded);
852 if (!saved_macros_loaded) {
853 saved_macro[i] = 0;
854 saved_macros_loaded = 1;
856 fclose (f);
857 return found;
858 } else
859 /* This heads the 'Load Macro' dialog box */
860 edit_error_dialog (_(" Load macro "),
861 get_sys_error (_(" Error trying to open macro file ")));
862 return 0;
865 /* }}} Macro stuff starts here */
867 /* returns 1 on success */
868 int edit_save_confirm_cmd (WEdit * edit)
870 char *f;
872 if (edit_confirm_save) {
873 #ifdef MIDNIGHT
874 f = catstrs (_(" Confirm save file? : "), edit->filename, " ", 0);
875 #else
876 f = catstrs (_(" Confirm save file? : "), edit->dir, edit->filename, " ", 0);
877 #endif
878 /* Buttons to 'Confirm save file' query */
879 if (edit_query_dialog2 (_(" Save file "), f, _("Save"), _("Cancel")))
880 return 0;
882 return edit_save_cmd (edit);
886 /* returns 1 on success */
887 int edit_save_cmd (WEdit * edit)
889 if (!edit_save_file (edit, catstrs (edit->dir, edit->filename, 0)))
890 return edit_save_as_cmd (edit);
891 edit->force |= REDRAW_COMPLETELY;
892 edit->modified = 0;
893 #if defined(MIDNIGHT) || defined(GTK)
894 edit->delete_file = 0;
895 #endif
897 return 1;
901 /* returns 1 on success */
902 int edit_new_cmd (WEdit * edit)
904 if (edit->modified) {
905 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
906 edit->force |= REDRAW_COMPLETELY;
907 return 0;
910 edit->force |= REDRAW_COMPLETELY;
911 edit->modified = 0;
912 return edit_renew (edit); /* if this gives an error, something has really screwed up */
915 /* returns 1 on error */
916 int edit_load_file_from_filename (WEdit * edit, char *exp)
918 if (!edit_reload (edit, exp, 0, "", 0))
919 return 1;
920 edit_split_filename (edit, exp);
921 edit->modified = 0;
922 return 0;
925 int edit_load_cmd (WEdit * edit)
927 char *exp;
929 if (edit->modified) {
930 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
931 edit->force |= REDRAW_COMPLETELY;
932 return 0;
936 exp = edit_get_load_file (edit->dir, edit->filename, _ (" Load "));
938 if (exp) {
939 if (*exp)
940 edit_load_file_from_filename (edit, exp);
941 free (exp);
943 edit->force |= REDRAW_COMPLETELY;
944 return 0;
948 if mark2 is -1 then marking is from mark1 to the cursor.
949 Otherwise its between the markers. This handles this.
950 Returns 1 if no text is marked.
952 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
954 if (edit->mark1 != edit->mark2) {
955 if (edit->mark2 >= 0) {
956 *start_mark = min (edit->mark1, edit->mark2);
957 *end_mark = max (edit->mark1, edit->mark2);
958 } else {
959 *start_mark = min (edit->mark1, edit->curs1);
960 *end_mark = max (edit->mark1, edit->curs1);
961 edit->column2 = edit->curs_col;
963 return 0;
964 } else {
965 *start_mark = *end_mark = 0;
966 edit->column2 = edit->column1 = 0;
967 return 1;
971 /*Block copy, move and delete commands */
972 extern int column_highlighting;
974 #ifdef MIDNIGHT
975 #define space_width 1
976 #else
977 extern int space_width;
978 #endif
980 void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
982 long cursor;
983 int i, col;
984 cursor = edit->curs1;
985 col = edit_get_col (edit);
986 for (i = 0; i < size; i++) {
987 if (data[i] == '\n') { /* fill in and move to next line */
988 int l;
989 long p;
990 if (edit_get_byte (edit, edit->curs1) != '\n') {
991 l = width - (edit_get_col (edit) - col);
992 while (l > 0) {
993 edit_insert (edit, ' ');
994 l -= space_width;
997 for (p = edit->curs1;; p++) {
998 if (p == edit->last_byte)
999 edit_insert_ahead (edit, '\n');
1000 if (edit_get_byte (edit, p) == '\n') {
1001 p++;
1002 break;
1005 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1006 l = col - edit_get_col (edit);
1007 while (l >= space_width) {
1008 edit_insert (edit, ' ');
1009 l -= space_width;
1011 continue;
1013 edit_insert (edit, data[i]);
1015 edit_cursor_move (edit, cursor - edit->curs1);
1019 void edit_block_copy_cmd (WEdit * edit)
1021 long start_mark, end_mark, current = edit->curs1;
1022 int size, x;
1023 unsigned char *copy_buf;
1025 edit_update_curs_col (edit);
1026 x = edit->curs_col;
1027 if (eval_marks (edit, &start_mark, &end_mark))
1028 return;
1029 if (column_highlighting)
1030 if ((x >= edit->column1 && x < edit->column2) || (x > edit->column2 && x <= edit->column1))
1031 return;
1033 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1035 /* all that gets pushed are deletes hence little space is used on the stack */
1037 edit_push_markers (edit);
1039 if (column_highlighting) {
1040 edit_insert_column_of_text (edit, copy_buf, size, abs (edit->column2 - edit->column1));
1041 } else {
1042 while (size--)
1043 edit_insert_ahead (edit, copy_buf[size]);
1046 free (copy_buf);
1047 edit_scroll_screen_over_cursor (edit);
1049 if (column_highlighting) {
1050 edit_set_markers (edit, 0, 0, 0, 0);
1051 edit_push_action (edit, COLUMN_ON);
1052 column_highlighting = 0;
1053 } else if (start_mark < current && end_mark > current)
1054 edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
1056 edit->force |= REDRAW_PAGE;
1060 void edit_block_move_cmd (WEdit * edit)
1062 long count;
1063 long current;
1064 unsigned char *copy_buf;
1065 long start_mark, end_mark;
1066 int deleted = 0;
1067 int x = 0;
1069 if (eval_marks (edit, &start_mark, &end_mark))
1070 return;
1071 if (column_highlighting) {
1072 edit_update_curs_col (edit);
1073 x = edit->curs_col;
1074 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1075 if ((x > edit->column1 && x < edit->column2) || (x > edit->column2 && x < edit->column1))
1076 return;
1077 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1078 return;
1080 if ((end_mark - start_mark) > option_max_undo / 2)
1081 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ ("Continue"), _ ("Cancel")))
1082 return;
1084 edit_push_markers (edit);
1085 current = edit->curs1;
1086 if (column_highlighting) {
1087 int size, c1, c2, line;
1088 line = edit->curs_line;
1089 if (edit->mark2 < 0)
1090 edit_mark_cmd (edit, 0);
1091 c1 = min (edit->column1, edit->column2);
1092 c2 = max (edit->column1, edit->column2);
1093 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1094 if (x < c2) {
1095 edit_block_delete_cmd (edit);
1096 deleted = 1;
1098 edit_move_to_line (edit, line);
1099 edit_cursor_move (edit, edit_move_forward3 (edit, edit_bol (edit, edit->curs1), x, 0) - edit->curs1);
1100 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1101 if (!deleted) {
1102 line = edit->curs_line;
1103 edit_update_curs_col (edit);
1104 x = edit->curs_col;
1105 edit_block_delete_cmd (edit);
1106 edit_move_to_line (edit, line);
1107 edit_cursor_move (edit, edit_move_forward3 (edit, edit_bol (edit, edit->curs1), x, 0) - edit->curs1);
1109 edit_set_markers (edit, 0, 0, 0, 0);
1110 edit_push_action (edit, COLUMN_ON);
1111 column_highlighting = 0;
1112 } else {
1113 copy_buf = malloc (end_mark - start_mark);
1114 edit_cursor_move (edit, start_mark - edit->curs1);
1115 edit_scroll_screen_over_cursor (edit);
1116 count = start_mark;
1117 while (count < end_mark) {
1118 copy_buf[end_mark - count - 1] = edit_delete (edit);
1119 count++;
1121 edit_scroll_screen_over_cursor (edit);
1122 edit_cursor_move (edit, current - edit->curs1 - (((current - edit->curs1) > 0) ? end_mark - start_mark : 0));
1123 edit_scroll_screen_over_cursor (edit);
1124 while (count-- > start_mark)
1125 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1126 edit_set_markers (edit, edit->curs1, edit->curs1 + end_mark - start_mark, 0, 0);
1128 edit_scroll_screen_over_cursor (edit);
1129 free (copy_buf);
1130 edit->force |= REDRAW_PAGE;
1133 void edit_cursor_to_bol (WEdit * edit);
1135 void edit_delete_column_of_text (WEdit * edit)
1137 long p, q, r, m1, m2;
1138 int b, c, d;
1139 int n;
1141 eval_marks (edit, &m1, &m2);
1142 n = edit_move_forward (edit, m1, 0, m2) + 1;
1143 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1144 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1146 b = min (c, d);
1147 c = max (c, d);
1149 while (n--) {
1150 r = edit_bol (edit, edit->curs1);
1151 p = edit_move_forward3 (edit, r, b, 0);
1152 q = edit_move_forward3 (edit, r, c, 0);
1153 if (p < m1)
1154 p = m1;
1155 if (q > m2)
1156 q = m2;
1157 edit_cursor_move (edit, p - edit->curs1);
1158 while (q > p) { /* delete line between margins */
1159 if (edit_get_byte (edit, edit->curs1) != '\n')
1160 edit_delete (edit);
1161 q--;
1163 if (n) /* move to next line except on the last delete */
1164 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1168 /* if success return 0 */
1169 int edit_block_delete (WEdit * edit)
1171 long count;
1172 long start_mark, end_mark;
1173 if (eval_marks (edit, &start_mark, &end_mark))
1174 return 0;
1175 if (column_highlighting && edit->mark2 < 0)
1176 edit_mark_cmd (edit, 0);
1177 if ((end_mark - start_mark) > option_max_undo / 2)
1178 /* Warning message with a query to continue or cancel the operation */
1179 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ (" Continue "), _ (" Cancel ")))
1180 return 1;
1181 edit_push_markers (edit);
1182 edit_cursor_move (edit, start_mark - edit->curs1);
1183 edit_scroll_screen_over_cursor (edit);
1184 count = start_mark;
1185 if (start_mark < end_mark) {
1186 if (column_highlighting) {
1187 if (edit->mark2 < 0)
1188 edit_mark_cmd (edit, 0);
1189 edit_delete_column_of_text (edit);
1190 } else {
1191 while (count < end_mark) {
1192 edit_delete (edit);
1193 count++;
1197 edit_set_markers (edit, 0, 0, 0, 0);
1198 edit->force |= REDRAW_PAGE;
1199 return 0;
1202 /* returns 1 if canceelled by user */
1203 int edit_block_delete_cmd (WEdit * edit)
1205 long start_mark, end_mark;
1206 if (eval_marks (edit, &start_mark, &end_mark)) {
1207 edit_delete_line (edit);
1208 return 0;
1210 return edit_block_delete (edit);
1214 #ifdef MIDNIGHT
1216 #define INPUT_INDEX 9
1217 #define SEARCH_DLG_WIDTH 58
1218 #define SEARCH_DLG_HEIGHT 10
1219 #define REPLACE_DLG_WIDTH 58
1220 #define REPLACE_DLG_HEIGHT 15
1221 #define CONFIRM_DLG_WIDTH 79
1222 #define CONFIRM_DLG_HEIGTH 6
1223 #define B_REPLACE_ALL B_USER+1
1224 #define B_REPLACE_ONE B_USER+2
1225 #define B_SKIP_REPLACE B_USER+3
1227 int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
1229 QuickWidget quick_widgets[] =
1231 {quick_button, 63, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Cancel"),
1232 0, B_CANCEL, 0, 0, NULL},
1233 {quick_button, 50, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("o&Ne"),
1234 0, B_REPLACE_ONE, 0, 0, NULL},
1235 {quick_button, 37, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("al&L"),
1236 0, B_REPLACE_ALL, 0, 0, NULL},
1237 {quick_button, 21, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Skip"),
1238 0, B_SKIP_REPLACE, 0, 0, NULL},
1239 {quick_button, 4, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Replace"),
1240 0, B_ENTER, 0, 0, NULL},
1241 {quick_label, 2, CONFIRM_DLG_WIDTH, 2, CONFIRM_DLG_HEIGTH, 0,
1242 0, 0, 0, 0, 0},
1243 {0}};
1245 #ifndef HAVE_CHARSET
1246 quick_widgets[5].text = catstrs (_ (" Replace with: "), replace_text, 0);
1247 #else
1248 char *msg;
1250 quick_widgets[5].text = catstrs (msg = _(" Replace with: "), replace_text, 0);
1252 if (*replace_text)
1253 convert_to_display (quick_widgets[5].text + strlen (msg));
1254 #endif
1257 QuickDialog Quick_input =
1258 {CONFIRM_DLG_WIDTH, CONFIRM_DLG_HEIGTH, 0, 0, N_ (" Confirm replace "),
1259 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1261 Quick_input.widgets = quick_widgets;
1263 Quick_input.xpos = xpos;
1265 /* Sometimes menu can hide replaced text. I don't like it */
1267 if ((edit->curs_row >= ypos - 1) && (edit->curs_row <= ypos + CONFIRM_DLG_HEIGTH - 1))
1268 ypos -= CONFIRM_DLG_HEIGTH;
1270 Quick_input.ypos = ypos;
1271 return quick_dialog (&Quick_input);
1275 void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order)
1277 int treplace_scanf = replace_scanf;
1278 int treplace_regexp = replace_regexp;
1279 int treplace_all = replace_all;
1280 int treplace_prompt = replace_prompt;
1281 int treplace_backwards = replace_backwards;
1282 int treplace_whole = replace_whole;
1283 int treplace_case = replace_case;
1285 char *tsearch_text;
1286 char *treplace_text;
1287 char *targ_order;
1288 QuickWidget quick_widgets[] =
1290 {quick_button, 6, 10, 12, REPLACE_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1291 0, NULL},
1292 {quick_button, 2, 10, 12, REPLACE_DLG_HEIGHT, N_("&Ok"), 0, B_ENTER, 0,
1293 0, NULL},
1294 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1295 0, 0, NULL},
1296 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("replace &All"), 0, 0,
1297 0, 0, NULL},
1298 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("pr&Ompt on replace"), 0, 0,
1299 0, 0, NULL},
1300 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1301 0, 0, NULL},
1302 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1303 0, 0, NULL},
1304 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1305 0, 0, NULL},
1306 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 8, REPLACE_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1307 0, 0, NULL},
1308 {quick_input, 3, REPLACE_DLG_WIDTH, 7, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1309 0, "edit-argord"},
1310 {quick_label, 2, REPLACE_DLG_WIDTH, 6, REPLACE_DLG_HEIGHT, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1311 0, 0, 0},
1312 {quick_input, 3, REPLACE_DLG_WIDTH, 5, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1313 0, "edit-replace"},
1314 {quick_label, 2, REPLACE_DLG_WIDTH, 4, REPLACE_DLG_HEIGHT, N_(" Enter replacement string:"), 0, 0, 0,
1315 0, 0},
1316 {quick_input, 3, REPLACE_DLG_WIDTH, 3, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1317 0, "edit-search"},
1318 {quick_label, 2, REPLACE_DLG_WIDTH, 2, REPLACE_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1319 0, 0},
1320 {0}};
1322 quick_widgets[2].result = &treplace_scanf;
1323 quick_widgets[3].result = &treplace_all;
1324 quick_widgets[4].result = &treplace_prompt;
1325 quick_widgets[5].result = &treplace_backwards;
1326 quick_widgets[6].result = &treplace_regexp;
1327 quick_widgets[7].result = &treplace_whole;
1328 quick_widgets[8].result = &treplace_case;
1329 quick_widgets[9].str_result = &targ_order;
1330 quick_widgets[9].text = *arg_order;
1331 quick_widgets[11].str_result = &treplace_text;
1332 quick_widgets[11].text = *replace_text;
1333 quick_widgets[13].str_result = &tsearch_text;
1334 quick_widgets[13].text = *search_text;
1336 QuickDialog Quick_input =
1337 {REPLACE_DLG_WIDTH, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "),
1338 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1340 Quick_input.widgets = quick_widgets;
1342 if (quick_dialog (&Quick_input) != B_CANCEL) {
1343 *arg_order = *(quick_widgets[INPUT_INDEX].str_result);
1344 *replace_text = *(quick_widgets[INPUT_INDEX + 2].str_result);
1345 *search_text = *(quick_widgets[INPUT_INDEX + 4].str_result);
1346 replace_scanf = treplace_scanf;
1347 replace_backwards = treplace_backwards;
1348 replace_regexp = treplace_regexp;
1349 replace_all = treplace_all;
1350 replace_prompt = treplace_prompt;
1351 replace_whole = treplace_whole;
1352 replace_case = treplace_case;
1353 return;
1354 } else {
1355 *arg_order = NULL;
1356 *replace_text = NULL;
1357 *search_text = NULL;
1358 return;
1364 void edit_search_dialog (WEdit * edit, char **search_text)
1366 int treplace_scanf = replace_scanf;
1367 int treplace_regexp = replace_regexp;
1368 int treplace_whole = replace_whole;
1369 int treplace_case = replace_case;
1370 int treplace_backwards = replace_backwards;
1372 char *tsearch_text;
1373 QuickWidget quick_widgets[] =
1375 {quick_button, 6, 10, 7, SEARCH_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1376 0, NULL},
1377 {quick_button, 2, 10, 7, SEARCH_DLG_HEIGHT, N_("&Ok"), 0, B_ENTER, 0,
1378 0, NULL},
1379 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1380 0, 0, NULL },
1381 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1382 0, 0, NULL},
1383 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1384 0, 0, NULL},
1385 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1386 0, 0, NULL},
1387 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 4, SEARCH_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1388 0, 0, NULL},
1389 {quick_input, 3, SEARCH_DLG_WIDTH, 3, SEARCH_DLG_HEIGHT, "", 52, 0, 0,
1390 0, "edit-search"},
1391 {quick_label, 2, SEARCH_DLG_WIDTH, 2, SEARCH_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1392 0, 0},
1393 {0}};
1395 quick_widgets[2].result = &treplace_scanf;
1396 quick_widgets[3].result = &treplace_backwards;
1397 quick_widgets[4].result = &treplace_regexp;
1398 quick_widgets[5].result = &treplace_whole;
1399 quick_widgets[6].result = &treplace_case;
1400 quick_widgets[7].str_result = &tsearch_text;
1401 quick_widgets[7].text = *search_text;
1404 QuickDialog Quick_input =
1405 {SEARCH_DLG_WIDTH, SEARCH_DLG_HEIGHT, -1, 0, N_(" Search "),
1406 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1408 Quick_input.widgets = quick_widgets;
1410 if (quick_dialog (&Quick_input) != B_CANCEL) {
1411 *search_text = *(quick_widgets[7].str_result);
1412 replace_scanf = treplace_scanf;
1413 replace_backwards = treplace_backwards;
1414 replace_regexp = treplace_regexp;
1415 replace_whole = treplace_whole;
1416 replace_case = treplace_case;
1417 return;
1418 } else {
1419 *search_text = NULL;
1420 return;
1425 #else
1427 #undef B_ENTER
1428 #undef B_CANCEL
1430 #define B_ENTER 0
1431 #define B_SKIP_REPLACE 1
1432 #define B_REPLACE_ALL 2
1433 #define B_REPLACE_ONE 3
1434 #define B_CANCEL 4
1436 extern CWidget *wedit;
1438 #ifndef GTK
1440 void edit_search_replace_dialog (Window parent, int x, int y, char **search_text, char **replace_text, char **arg_order, char *heading, int option)
1442 Window win;
1443 XEvent xev;
1444 CEvent cev;
1445 CState s;
1446 int xh, yh, h, xb, ys, yc, yb, yr;
1447 CWidget *m;
1448 int text_input_width ;
1450 CBackupState (&s);
1451 CDisable ("*");
1453 win = CDrawHeadedDialog ("replace", parent, x, y, heading);
1454 CGetHintPos (&xh, &h);
1455 #ifdef NEXT_LOOK
1456 xh += NEXT_SPACING ;
1457 #endif
1459 /* NLS hotkey ? */
1460 CIdent ("replace")->position = WINDOW_ALWAYS_RAISED;
1461 /* An input line comes after the ':' */
1462 (CDrawText ("replace.t1", win, xh, h, _(" Enter search text : ")))->hotkey = 'E';
1464 CGetHintPos (0, &yh);
1465 (m = CDrawTextInput ("replace.sinp", win, xh, yh, 10, AUTO_HEIGHT, 8192, *search_text))->hotkey = 'E';
1467 if (replace_text) {
1468 CGetHintPos (0, &yh);
1469 (CDrawText ("replace.t2", win, xh, yh, _(" Enter replace text : ")))->hotkey = 'n';
1470 CGetHintPos (0, &yh);
1471 (CDrawTextInput ("replace.rinp", win, xh, yh, 10, AUTO_HEIGHT, 8192, *replace_text))->hotkey = 'n';
1472 CSetToolHint ("replace.t2", _("You can enter regexp substrings with %s\n(not \\1, \\2 like sed) then use \"Enter...order\""));
1473 CSetToolHint ("replace.rinp", _("You can enter regexp substrings with %s\n(not \\1, \\2 like sed) then use \"Enter...order\""));
1474 CGetHintPos (0, &yh);
1475 (CDrawText ("replace.t3", win, xh, yh, _(" Enter argument (or substring) order : ")))->hotkey = 'o';
1476 CGetHintPos (0, &yh);
1477 (CDrawTextInput ("replace.ainp", win, xh, yh, 10, AUTO_HEIGHT, 256, *arg_order))->hotkey = 'o';
1478 /* Tool hint */
1479 CSetToolHint ("replace.ainp", _("Enter the order of replacement of your scanf\nformat specifiers or regexp substrings, eg 3,1,2"));
1480 CSetToolHint ("replace.t3", _("Enter the order of replacement of your scanf\nformat specifiers or regexp substrings, eg 3,1,2"));
1482 CGetHintPos (0, &yh);
1483 ys = yh;
1484 /* The following are check boxes */
1485 CDrawSwitch ("replace.ww", win, xh, yh, replace_whole, _(" Whole words only "), 0);
1486 CGetHintPos (0, &yh);
1487 CDrawSwitch ("replace.case", win, xh, yh, replace_case, _(" Case sensitive "), 0);
1488 yc = yh;
1489 CGetHintPos (0, &yh);
1490 CDrawSwitch ("replace.reg", win, xh, yh, replace_regexp, _(" Regular expression "), 1);
1491 CSetToolHint ("replace.reg", _("See the regex man page for how\nto compose a regular expression"));
1492 CSetToolHint ("replace.reg.label", _("See the regex man page for how\nto compose a regular expression"));
1493 yb = yh;
1494 CGetHintPos (0, &yh);
1495 CGetHintPos (&xb, 0);
1496 #ifdef NEXT_LOOK
1497 xb += NEXT_SPACING ;
1498 #endif
1499 if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
1500 CDrawSwitch ("replace.bkwd", win, xh, yh, replace_backwards, _(" Backwards "), 0);
1501 /* Tool hint */
1502 CSetToolHint ("replace.bkwd", _("Warning: Searching backward can be slow"));
1503 CSetToolHint ("replace.bkwd.label", _("Warning: Searching backward can be slow"));
1505 if (replace_text) {
1506 yr = ys;
1507 if (option & SEARCH_DIALOG_OPTION_BACKWARDS)
1508 yr = yc;
1509 } else {
1510 if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
1511 if (option & SEARCH_DIALOG_OPTION_BOOKMARK)
1512 yr = yb;
1513 else
1514 yr = yh;
1515 } else {
1516 if (option & SEARCH_DIALOG_OPTION_BOOKMARK)
1517 yr = yc;
1518 else
1519 yr = yb;
1523 if (replace_text) {
1524 CDrawSwitch ("replace.pr", win, xb, yr, replace_prompt, _(" Prompt on replace "), 0);
1525 /* Tool hint */
1526 CSetToolHint ("replace.pr", _("Ask before making each replacement"));
1527 CGetHintPos (0, &yr);
1528 CDrawSwitch ("replace.all", win, xb, yr, replace_all, _(" Replace all "), 0);
1529 /* Tool hint */
1530 CSetToolHint ("replace.all", _("Replace repeatedly"));
1531 CGetHintPos (0, &yr);
1533 if (option & SEARCH_DIALOG_OPTION_BOOKMARK) {
1534 CDrawSwitch ("replace.bkmk", win, xb, yr, search_create_bookmark, _(" Bookmarks "), 0);
1535 /* Tool hint */
1536 CSetToolHint ("replace.bkmk", _("Create bookmarks at all lines found"));
1537 CSetToolHint ("replace.bkmk.label", _("Create bookmarks at all lines found"));
1538 CGetHintPos (0, &yr);
1540 CDrawSwitch ("replace.scanf", win, xb, yr, replace_scanf, _(" Scanf expression "), 1);
1541 /* Tool hint */
1542 CSetToolHint ("replace.scanf", _("Allows entering of a C format string,\nsee the scanf man page"));
1544 get_hint_limits (&x, &y);
1545 #ifdef NEXT_LOOK
1547 int btn_width, x, y ;
1548 CGetHintPos (&x, &y);
1550 y += NEXT_SPACING * 2 ;
1551 x += NEXT_SPACING * 2 ;
1552 CTextSize (&btn_width, 0, " Cancel ");
1553 btn_width += 4 + BUTTON_RELIEF * 2;
1554 x -= (btn_width + NEXT_SPACING) * 2 + NEXT_SPACING;
1556 CDrawButton ("replace.ok", win, x+btn_width + NEXT_SPACING * 2, y, AUTO_WIDTH, AUTO_HEIGHT, " Ok ");
1557 CDrawButton ("replace.cancel", win, x, y, AUTO_WIDTH, AUTO_HEIGHT, " Cancel ");
1558 CGetHintPos (0, &y);
1559 x += (btn_width + NEXT_SPACING) * 2 + NEXT_SPACING;
1560 reset_hint_pos (x, y + NEXT_SPACING*2);
1562 #else
1563 CDrawPixmapButton ("replace.ok", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h, PIXMAP_BUTTON_TICK);
1564 CDrawPixmapButton ("replace.cancel", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h + WIDGET_SPACING + TICK_BUTTON_WIDTH, PIXMAP_BUTTON_CROSS);
1565 #endif
1566 /* Tool hint */
1567 CSetToolHint ("replace.ok", _("Begin search, Enter"));
1568 CSetToolHint ("replace.cancel", _("Abort this dialog, Esc"));
1569 CSetSizeHintPos ("replace");
1570 CMapDialog ("replace");
1572 m = CIdent ("replace");
1573 #ifdef NEXT_LOOK
1574 text_input_width = m->width - WIDGET_SPACING * 3 - 4 - NEXT_SPACING*2 ;
1575 #else
1576 text_input_width = m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH ;
1577 #endif
1578 CSetWidgetSize ("replace.sinp", text_input_width, (CIdent ("replace.sinp"))->height);
1579 if (replace_text) {
1580 CSetWidgetSize ("replace.rinp", text_input_width, (CIdent ("replace.rinp"))->height);
1581 CSetWidgetSize ("replace.ainp", text_input_width, (CIdent ("replace.ainp"))->height);
1583 CFocus (CIdent ("replace.sinp"));
1585 for (;;) {
1586 CNextEvent (&xev, &cev);
1587 if (!CIdent ("replace")) {
1588 *search_text = 0;
1589 break;
1591 if (!strcmp (cev.ident, "replace.cancel") || cev.command == CK_Cancel) {
1592 *search_text = 0;
1593 break;
1595 if (!strcmp (cev.ident, "replace.reg") || !strcmp (cev.ident, "replace.scanf")) {
1596 if (CIdent ("replace.reg")->keypressed || CIdent ("replace.scanf")->keypressed) {
1597 if (!(CIdent ("replace.case")->keypressed)) {
1598 CIdent ("replace.case")->keypressed = 1;
1599 CExpose ("replace.case");
1603 if (!strcmp (cev.ident, "replace.ok") || cev.command == CK_Enter) {
1604 if (replace_text) {
1605 replace_all = CIdent ("replace.all")->keypressed;
1606 replace_prompt = CIdent ("replace.pr")->keypressed;
1607 *replace_text = (char *) strdup (CIdent ("replace.rinp")->text);
1608 *arg_order = (char *) strdup (CIdent ("replace.ainp")->text);
1610 *search_text = (char *) strdup (CIdent ("replace.sinp")->text);
1611 replace_whole = CIdent ("replace.ww")->keypressed;
1612 replace_case = CIdent ("replace.case")->keypressed;
1613 replace_scanf = CIdent ("replace.scanf")->keypressed;
1614 replace_regexp = CIdent ("replace.reg")->keypressed;
1616 if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
1617 replace_backwards = CIdent ("replace.bkwd")->keypressed;
1618 } else {
1619 replace_backwards = 0;
1622 if (option & SEARCH_DIALOG_OPTION_BOOKMARK) {
1623 search_create_bookmark = CIdent ("replace.bkmk")->keypressed;
1624 } else {
1625 search_create_bookmark = 0;
1628 break;
1631 CDestroyWidget ("replace");
1632 CRestoreState (&s);
1635 void edit_search_dialog (WEdit * edit, char **search_text)
1637 /* Heads the 'Search' dialog box */
1638 edit_search_replace_dialog (WIN_MESSAGES, search_text, 0, 0, _(" Search "), SEARCH_DIALOG_OPTION_BACKWARDS | SEARCH_DIALOG_OPTION_BOOKMARK);
1641 void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order)
1643 /* Heads the 'Replace' dialog box */
1644 edit_search_replace_dialog (WIN_MESSAGES, search_text, replace_text, arg_order, _(" Replace "), SEARCH_DIALOG_OPTION_BACKWARDS);
1647 #else
1649 #include <libgnomeui/gtkcauldron.h>
1650 #include <libgnomeui/gnome-stock.h>
1652 void edit_search_dialog (WEdit * edit, char **search_text)
1654 char *s;
1655 s = gtk_dialog_cauldron (
1656 "Search", GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB,
1657 " ( (Enter search text)d | %Eogxf )xf / ( ( %Cd // %Cd // %Cd ) || ( %Cd // %Cd )xf )xf / ( %Bxfgrq || %Bxfgq )f",
1658 search_text, "search",
1659 "&Whole word", &replace_whole,
1660 "Case &sensitive", &replace_case,
1661 "&Regular expression", &replace_regexp,
1662 "&Backwards", &replace_backwards,
1663 "Scanf &expression", &replace_scanf,
1664 GNOME_STOCK_BUTTON_OK,
1665 GNOME_STOCK_BUTTON_CANCEL
1667 if (s == GTK_CAULDRON_ESCAPE || !s || s == GNOME_STOCK_BUTTON_CANCEL)
1668 *search_text = 0;
1669 return;
1672 void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order)
1674 char *s;
1675 s = gtk_dialog_cauldron (
1676 "Search", GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB,
1677 " ( (Enter search text)d | %Eogxf )xf / ( (Enter replace text)d | %Egxf )xf / ( (Enter argument order)d | %Egxf )xf / ( ( %Cd // %Cd // %Cd // %Cd ) || ( %Cd // %Cd // %Cd )xf )xf / ( %Bxfgrq || %Bxfgq )f",
1678 search_text, "search",
1679 replace_text, "replace",
1680 arg_order, "arg_order",
1681 "&Whole word", &replace_whole,
1682 "Case &sensitive", &replace_case,
1683 "&Regular expression", &replace_regexp,
1684 "&Backwards", &replace_backwards,
1685 "Pr&ompt on replace", &replace_prompt,
1686 "Replace &all", &replace_all,
1687 "Scanf &expression", &replace_scanf,
1688 GNOME_STOCK_BUTTON_OK,
1689 GNOME_STOCK_BUTTON_CANCEL
1691 if (s == GTK_CAULDRON_ESCAPE || !s || s == GNOME_STOCK_BUTTON_CANCEL)
1692 *search_text = 0;
1693 return;
1696 #endif
1698 #ifdef GTK
1700 int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
1702 char *s;
1703 s = gtk_dialog_cauldron (
1704 "Replace", GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB,
1705 " ( (Replace with:)d %Ld )xf / ( %Bxfrq || %Bxfq || %Bxfq || %Bxfq || %Bxfgq )f",
1706 replace_text,
1707 "Replace", "Skip", "Replace all", "Replace one",
1708 GNOME_STOCK_BUTTON_CANCEL
1710 if (s == GTK_CAULDRON_ESCAPE || !s || s == GNOME_STOCK_BUTTON_CANCEL)
1711 return B_CANCEL;
1712 if (!strcmp (s, "Replace all"))
1713 return B_REPLACE_ALL;
1714 if (!strcmp (s, "Replace one"))
1715 return B_REPLACE_ONE;
1716 if (!strcmp (s, "Skip"))
1717 return B_SKIP_REPLACE;
1718 if (!strcmp (s, "Replace"))
1719 return B_ENTER;
1720 /* Shouldn't ever reach this point */
1721 return B_CANCEL;
1724 #else
1726 int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
1728 int q, x[] =
1730 B_CANCEL, B_ENTER, B_SKIP_REPLACE, B_REPLACE_ALL, B_REPLACE_ONE, B_CANCEL
1732 q = CQueryDialog (WIN_MESSAGES + (edit->curs_line < 8 ? edit->num_widget_lines / 2 * FONT_PIX_PER_LINE + CYof (edit->widget) : 0),
1733 _ (" Replace "), catstrs (_ (" Replace with: "), replace_text, 0), _ ("Replace"), _ ("Skip"), _ ("Replace all"), _ ("Replace one"), _ ("Cancel"), 0);
1734 edit->force |= REDRAW_COMPLETELY;
1735 return x[q + 1];
1738 #endif
1740 #endif
1742 long sargs[NUM_REPL_ARGS][256 / sizeof (long)];
1744 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1745 sargs[4], sargs[5], sargs[6], sargs[7], \
1746 sargs[8], sargs[9], sargs[10], sargs[11], \
1747 sargs[12], sargs[13], sargs[14], sargs[15]
1749 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1750 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1751 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1752 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1755 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1756 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1757 int string_regexp_search (char *pattern, char *string, int len, int match_type, int match_bol, int icase, int *found_len, void *d)
1759 static regex_t r;
1760 static char *old_pattern = NULL;
1761 static int old_type, old_icase;
1762 regmatch_t *pmatch;
1763 static regmatch_t s[1];
1765 pmatch = (regmatch_t *) d;
1766 if (!pmatch)
1767 pmatch = s;
1769 if (!old_pattern || strcmp (old_pattern, pattern) || old_type != match_type || old_icase != icase) {
1770 if (old_pattern) {
1771 regfree (&r);
1772 free (old_pattern);
1773 old_pattern = 0;
1775 if (regcomp (&r, pattern, REG_EXTENDED | (icase ? REG_ICASE : 0))) {
1776 *found_len = 0;
1777 return -3;
1779 old_pattern = (char *) strdup (pattern);
1780 old_type = match_type;
1781 old_icase = icase;
1783 if (regexec (&r, string, d ? NUM_REPL_ARGS : 1, pmatch, ((match_bol || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) {
1784 *found_len = 0;
1785 return -1;
1787 *found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
1788 return (pmatch[0].rm_so);
1791 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1792 (and the above) routines to work properly - paul */
1794 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)
1796 long p, q = 0;
1797 long l = strlen ((char *) exp), f = 0;
1798 int n = 0;
1800 for (p = 0; p < l; p++) /* count conversions... */
1801 if (exp[p] == '%')
1802 if (exp[++p] != '%') /* ...except for "%%" */
1803 n++;
1805 if (replace_scanf || replace_regexp) {
1806 int c;
1807 unsigned char *buf;
1808 unsigned char mbuf[MAX_REPL_LEN * 2 + 3];
1810 replace_scanf = (!replace_regexp); /* can't have both */
1812 buf = mbuf;
1814 if (replace_scanf) {
1815 unsigned char e[MAX_REPL_LEN];
1816 if (n >= NUM_REPL_ARGS)
1817 return -3;
1819 if (replace_case) {
1820 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++)
1821 buf[p - start] = (*get_byte) (data, p);
1822 } else {
1823 for (p = 0; exp[p] != 0; p++)
1824 exp[p] = my_lower_case (exp[p]);
1825 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) {
1826 c = (*get_byte) (data, p);
1827 buf[p - start] = my_lower_case (c);
1831 buf[(q = p - start)] = 0;
1832 strcpy ((char *) e, (char *) exp);
1833 strcat ((char *) e, "%n");
1834 exp = e;
1836 while (q) {
1837 *((int *) sargs[n]) = 0; /* --> here was the problem - now fixed: good */
1838 if (n == sscanf ((char *) buf, (char *) exp, SCANF_ARGS)) {
1839 if (*((int *) sargs[n])) {
1840 *len = *((int *) sargs[n]);
1841 return start;
1844 if (once_only)
1845 return -2;
1846 if (q + start < last_byte) {
1847 if (replace_case) {
1848 buf[q] = (*get_byte) (data, q + start);
1849 } else {
1850 c = (*get_byte) (data, q + start);
1851 buf[q] = my_lower_case (c);
1853 q++;
1855 buf[q] = 0;
1856 start++;
1857 buf++; /* move the window along */
1858 if (buf == mbuf + MAX_REPL_LEN) { /* the window is about to go past the end of array, so... */
1859 memmove (mbuf, buf, strlen ((char *) buf) + 1); /* reset it */
1860 buf = mbuf;
1862 q--;
1864 } else { /* regexp matching */
1865 long offset = 0;
1866 int found_start, match_bol, move_win = 0;
1868 while (start + offset < last_byte) {
1869 match_bol = (offset == 0 || (*get_byte) (data, start + offset - 1) == '\n');
1870 if (!move_win) {
1871 p = start + offset;
1872 q = 0;
1874 for (; p < last_byte && q < MAX_REPL_LEN; p++, q++) {
1875 mbuf[q] = (*get_byte) (data, p);
1876 if (mbuf[q] == '\n')
1877 break;
1879 q++;
1880 offset += q;
1881 mbuf[q] = 0;
1883 buf = mbuf;
1884 while (q) {
1885 found_start = string_regexp_search ((char *) exp, (char *) buf, q, match_normal, match_bol, !replace_case, len, d);
1887 if (found_start <= -2) { /* regcomp/regexec error */
1888 *len = 0;
1889 return -3;
1891 else if (found_start == -1) /* not found: try next line */
1892 break;
1893 else if (*len == 0) { /* null pattern: try again at next character */
1894 q--;
1895 buf++;
1896 match_bol = 0;
1897 continue;
1899 else /* found */
1900 return (start + offset - q + found_start);
1902 if (once_only)
1903 return -2;
1905 if (buf[q - 1] != '\n') { /* incomplete line: try to recover */
1906 buf = mbuf + MAX_REPL_LEN / 2;
1907 q = strlen ((char *) buf);
1908 memmove (mbuf, buf, q);
1909 p = start + q;
1910 move_win = 1;
1912 else
1913 move_win = 0;
1916 } else {
1917 *len = strlen ((char *) exp);
1918 if (replace_case) {
1919 for (p = start; p <= last_byte - l; p++) {
1920 if ((*get_byte) (data, p) == (unsigned char)exp[0]) { /* check if first char matches */
1921 for (f = 0, q = 0; q < l && f < 1; q++)
1922 if ((*get_byte) (data, q + p) != (unsigned char)exp[q])
1923 f = 1;
1924 if (f == 0)
1925 return p;
1927 if (once_only)
1928 return -2;
1930 } else {
1931 for (p = 0; exp[p] != 0; p++)
1932 exp[p] = my_lower_case (exp[p]);
1934 for (p = start; p <= last_byte - l; p++) {
1935 if (my_lower_case ((*get_byte) (data, p)) == (unsigned char)exp[0]) {
1936 for (f = 0, q = 0; q < l && f < 1; q++)
1937 if (my_lower_case ((*get_byte) (data, q + p)) != (unsigned char)exp[q])
1938 f = 1;
1939 if (f == 0)
1940 return p;
1942 if (once_only)
1943 return -2;
1947 return -2;
1951 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)
1952 { /*front end to find_string to check for
1953 whole words */
1954 long p;
1955 p = search_start;
1957 while ((p = edit_find_string (p, exp, len, last_byte, get_byte, data, once_only, d)) >= 0) {
1958 if (replace_whole) {
1959 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1960 if (!strcasechr (option_whole_chars_search, (*get_byte) (data, p - 1))
1961 && !strcasechr (option_whole_chars_search, (*get_byte) (data, p + *len)))
1962 return p;
1963 if (once_only)
1964 return -2;
1965 } else
1966 return p;
1967 if (once_only)
1968 break;
1969 p++; /*not a whole word so continue search. */
1971 return p;
1974 long edit_find (long search_start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, void *d)
1976 long p;
1977 if (replace_backwards) {
1978 while (search_start >= 0) {
1979 p = edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 1, d);
1980 if (p == search_start)
1981 return p;
1982 search_start--;
1984 } else {
1985 return edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 0, d);
1987 return -2;
1990 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1992 #define snprintf(v) { \
1993 *p1++ = *p++; \
1994 *p1++ = '%'; \
1995 *p1++ = 'n'; \
1996 *p1 = '\0'; \
1997 sprintf(s,q1,v,&n); \
1998 s += n; \
2001 /* this function uses the sprintf command to do a vprintf */
2002 /* it takes pointers to arguments instead of the arguments themselves */
2003 int sprintf_p (char *str, const char *fmt,...)
2005 va_list ap;
2006 int n;
2007 char *q, *p, *s = str;
2008 char q1[32];
2009 char *p1;
2011 va_start (ap, fmt);
2012 p = q = (char *) fmt;
2014 while ((p = strchr (p, '%'))) {
2015 n = (int) ((unsigned long) p - (unsigned long) q);
2016 strncpy (s, q, n); /* copy stuff between format specifiers */
2017 s += n;
2018 *s = 0;
2019 q = p;
2020 p1 = q1;
2021 *p1++ = *p++;
2022 if (*p == '%') {
2023 p++;
2024 *s++ = '%';
2025 q = p;
2026 continue;
2028 if (*p == 'n') {
2029 p++;
2030 /* do nothing */
2031 q = p;
2032 continue;
2034 if (*p == '#')
2035 *p1++ = *p++;
2036 if (*p == '0')
2037 *p1++ = *p++;
2038 if (*p == '-')
2039 *p1++ = *p++;
2040 if (*p == '+')
2041 *p1++ = *p++;
2042 if (*p == '*') {
2043 p++;
2044 strcpy (p1, itoa (*va_arg (ap, int *))); /* replace field width with a number */
2045 p1 += strlen (p1);
2046 } else {
2047 while (is_digit (*p))
2048 *p1++ = *p++;
2050 if (*p == '.')
2051 *p1++ = *p++;
2052 if (*p == '*') {
2053 p++;
2054 strcpy (p1, itoa (*va_arg (ap, int *))); /* replace precision with a number */
2055 p1 += strlen (p1);
2056 } else {
2057 while (is_digit (*p))
2058 *p1++ = *p++;
2060 /* flags done, now get argument */
2061 if (*p == 's') {
2062 snprintf (va_arg (ap, char *));
2063 } else if (*p == 'h') {
2064 if (strchr ("diouxX", *p))
2065 snprintf (*va_arg (ap, short *));
2066 } else if (*p == 'l') {
2067 *p1++ = *p++;
2068 if (strchr ("diouxX", *p))
2069 snprintf (*va_arg (ap, long *));
2070 } else if (strchr ("cdiouxX", *p)) {
2071 snprintf (*va_arg (ap, int *));
2072 } else if (*p == 'L') {
2073 *p1++ = *p++;
2074 if (strchr ("EefgG", *p))
2075 snprintf (*va_arg (ap, double *)); /* should be long double */
2076 } else if (strchr ("EefgG", *p)) {
2077 snprintf (*va_arg (ap, double *));
2078 } else if (strchr ("DOU", *p)) {
2079 snprintf (*va_arg (ap, long *));
2080 } else if (*p == 'p') {
2081 snprintf (*va_arg (ap, void **));
2083 q = p;
2085 va_end (ap);
2086 sprintf (s, q); /* print trailing leftover */
2087 return (unsigned long) s - (unsigned long) str + strlen (s);
2090 static void regexp_error (WEdit *edit)
2092 /* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */
2093 edit_error_dialog (_(" Error "), _(" Invalid regular expression, or scanf expression with to many conversions "));
2096 /* call with edit = 0 before shutdown to close memory leaks */
2097 void edit_replace_cmd (WEdit * edit, int again)
2099 static regmatch_t pmatch[NUM_REPL_ARGS];
2100 static char *old1 = NULL;
2101 static char *old2 = NULL;
2102 static char *old3 = NULL;
2103 char *exp1 = "";
2104 char *exp2 = "";
2105 char *exp3 = "";
2106 int replace_yes;
2107 int replace_continue;
2108 int treplace_prompt = 0;
2109 int i = 0;
2110 long times_replaced = 0, last_search;
2111 char fin_string[64];
2112 int argord[NUM_REPL_ARGS];
2114 if (!edit) {
2115 if (old1) {
2116 free (old1);
2117 old1 = 0;
2119 if (old2) {
2120 free (old2);
2121 old2 = 0;
2123 if (old3) {
2124 free (old3);
2125 old3 = 0;
2127 return;
2129 last_search = edit->last_byte;
2131 edit->force |= REDRAW_COMPLETELY;
2133 exp1 = old1 ? old1 : exp1;
2134 exp2 = old2 ? old2 : exp2;
2135 exp3 = old3 ? old3 : exp3;
2137 if (again) {
2138 if (!old1 || !old2)
2139 return;
2140 exp1 = (char *) strdup (old1);
2141 exp2 = (char *) strdup (old2);
2142 exp3 = (char *) strdup (old3);
2143 } else {
2144 edit_push_action (edit, KEY_PRESS + edit->start_display);
2146 #ifdef HAVE_CHARSET
2147 if (exp1 && *exp1)
2148 convert_to_display (exp1);
2149 if (exp2 && *exp2)
2150 convert_to_display (exp2);
2151 #endif
2153 edit_replace_dialog (edit, &exp1, &exp2, &exp3);
2155 #ifdef HAVE_CHARSET
2156 if (exp1 && *exp1)
2157 convert_from_input (exp1);
2158 if (exp2 && *exp2)
2159 convert_from_input (exp2);
2160 #endif
2162 treplace_prompt = replace_prompt;
2165 if (!exp1 || !*exp1) {
2166 edit->force = REDRAW_COMPLETELY;
2167 if (exp1) {
2168 free (exp1);
2169 free (exp2);
2170 free (exp3);
2172 return;
2174 if (old1)
2175 free (old1);
2176 if (old2)
2177 free (old2);
2178 if (old3)
2179 free (old3);
2180 old1 = (char *) strdup (exp1);
2181 old2 = (char *) strdup (exp2);
2182 old3 = (char *) strdup (exp3);
2185 char *s;
2186 int ord;
2187 while ((s = strchr (exp3, ' ')))
2188 memmove (s, s + 1, strlen (s));
2189 s = exp3;
2190 for (i = 0; i < NUM_REPL_ARGS; i++) {
2191 if ((unsigned long) s != 1 && s < exp3 + strlen (exp3)) {
2192 if ((ord = atoi (s)))
2193 argord[i] = ord - 1;
2194 else
2195 argord[i] = i;
2196 s = strchr (s, ',') + 1;
2197 } else
2198 argord[i] = i;
2202 replace_continue = replace_all;
2204 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
2205 edit->search_start--;
2207 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
2208 edit->search_start++;
2210 do {
2211 int len = 0;
2212 long new_start;
2213 new_start = edit_find (edit->search_start, (unsigned char *) exp1, &len, last_search,
2214 (int (*)(void *, long)) edit_get_byte, (void *) edit, pmatch);
2215 if (new_start == -3) {
2216 regexp_error (edit);
2217 break;
2219 edit->search_start = new_start;
2220 /*returns negative on not found or error in pattern */
2222 if (edit->search_start >= 0) {
2223 edit->found_start = edit->search_start;
2224 i = edit->found_len = len;
2226 edit_cursor_move (edit, edit->search_start - edit->curs1);
2227 edit_scroll_screen_over_cursor (edit);
2229 replace_yes = 1;
2231 if (treplace_prompt) {
2232 int l;
2233 l = edit->curs_row - edit->num_widget_lines / 3;
2234 if (l > 0)
2235 edit_scroll_downward (edit, l);
2236 if (l < 0)
2237 edit_scroll_upward (edit, -l);
2239 edit_scroll_screen_over_cursor (edit);
2240 edit->force |= REDRAW_PAGE;
2241 edit_render_keypress (edit);
2243 /*so that undo stops at each query */
2244 edit_push_key_press (edit);
2246 switch (edit_replace_prompt (edit, exp2, /*and prompt 2/3 down */
2247 #ifdef MIDNIGHT
2248 (edit->num_widget_columns - CONFIRM_DLG_WIDTH)/2, edit->num_widget_lines * 2 / 3)) {
2249 #else
2250 edit->num_widget_columns / 2 - 33, edit->num_widget_lines * 2 / 3)) {
2251 #endif
2252 case B_ENTER:
2253 break;
2254 case B_SKIP_REPLACE:
2255 replace_yes = 0;
2256 break;
2257 case B_REPLACE_ALL:
2258 treplace_prompt = 0;
2259 replace_continue = 1;
2260 break;
2261 case B_REPLACE_ONE:
2262 replace_continue = 0;
2263 break;
2264 case B_CANCEL:
2265 replace_yes = 0;
2266 replace_continue = 0;
2267 break;
2270 if (replace_yes) { /* delete then insert new */
2271 if (replace_scanf || replace_regexp) {
2272 char repl_str[MAX_REPL_LEN + 2];
2273 if (replace_regexp) { /* we need to fill in sargs just like with scanf */
2274 int k, j;
2275 for (k = 1; k < NUM_REPL_ARGS && pmatch[k].rm_eo >= 0; k++) {
2276 unsigned char *t;
2277 t = (unsigned char *) &sargs[k - 1][0];
2278 for (j = 0; j < pmatch[k].rm_eo - pmatch[k].rm_so && j < 255; j++, t++)
2279 *t = (unsigned char) edit_get_byte (edit, edit->search_start - pmatch[0].rm_so + pmatch[k].rm_so + j);
2280 *t = '\0';
2282 for (; k <= NUM_REPL_ARGS; k++)
2283 sargs[k - 1][0] = 0;
2285 if (sprintf_p (repl_str, exp2, PRINTF_ARGS) >= 0) {
2286 times_replaced++;
2287 while (i--)
2288 edit_delete (edit);
2289 while (repl_str[++i])
2290 edit_insert (edit, repl_str[i]);
2291 } else {
2292 edit_error_dialog (_ (" Replace "),
2293 /* "Invalid regexp string or scanf string" */
2294 _ (" Error in replacement format string. "));
2295 replace_continue = 0;
2297 } else {
2298 times_replaced++;
2299 while (i--)
2300 edit_delete (edit);
2301 while (exp2[++i])
2302 edit_insert (edit, exp2[i]);
2304 edit->found_len = i;
2306 /* so that we don't find the same string again */
2307 if (replace_backwards) {
2308 last_search = edit->search_start;
2309 edit->search_start--;
2310 } else {
2311 edit->search_start += i;
2312 last_search = edit->last_byte;
2314 edit_scroll_screen_over_cursor (edit);
2315 } else {
2316 edit->search_start = edit->curs1; /* try and find from right here for next search */
2317 edit_update_curs_col (edit);
2319 edit->force |= REDRAW_PAGE;
2320 edit_render_keypress (edit);
2321 if (times_replaced) {
2322 sprintf (fin_string, _ (" %ld replacements made. "), times_replaced);
2323 edit_message_dialog (_ (" Replace "), fin_string);
2324 } else
2325 edit_message_dialog (_ (" Replace "), _ (" Search string not found. "));
2326 replace_continue = 0;
2328 } while (replace_continue);
2330 free (exp1);
2331 free (exp2);
2332 free (exp3);
2333 edit->force = REDRAW_COMPLETELY;
2334 edit_scroll_screen_over_cursor (edit);
2340 void edit_search_cmd (WEdit * edit, int again)
2342 static char *old = NULL;
2343 char *exp = "";
2345 if (!edit) {
2346 if (old) {
2347 free (old);
2348 old = 0;
2350 return;
2352 exp = old ? old : exp;
2353 if (again) { /*ctrl-hotkey for search again. */
2354 if (!old)
2355 return;
2356 exp = (char *) strdup (old);
2357 } else {
2359 #ifdef HAVE_CHARSET
2360 if (exp && *exp)
2361 convert_to_display (exp);
2362 #endif
2364 edit_search_dialog (edit, &exp);
2366 #ifdef HAVE_CHARSET
2367 if (exp && *exp)
2368 convert_from_input (exp);
2369 #endif
2371 edit_push_action (edit, KEY_PRESS + edit->start_display);
2374 if (exp) {
2375 if (*exp) {
2376 int len = 0;
2377 if (old)
2378 free (old);
2379 old = (char *) strdup (exp);
2381 if (search_create_bookmark) {
2382 int found = 0, books = 0;
2383 int l = 0, l_last = -1;
2384 long p, q = 0;
2385 for (;;) {
2386 p = edit_find (q, (unsigned char *) exp, &len, edit->last_byte,
2387 (int (*)(void *, long)) edit_get_byte, (void *) edit, 0);
2388 if (p < 0)
2389 break;
2390 found++;
2391 l += edit_count_lines (edit, q, p);
2392 if (l != l_last) {
2393 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
2394 books++;
2396 l_last = l;
2397 q = p + 1;
2399 if (found) {
2400 char fin_string[64];
2401 /* in response to number of bookmarks added because of string being found %d times */
2402 sprintf (fin_string, _ (" %d finds made, %d bookmarks added "), found, books);
2403 edit_message_dialog (_ (" Search "), fin_string);
2404 } else {
2405 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
2407 } else {
2409 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
2410 edit->search_start--;
2412 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
2413 edit->search_start++;
2415 edit->search_start = edit_find (edit->search_start, (unsigned char *) exp, &len, edit->last_byte,
2416 (int (*)(void *, long)) edit_get_byte, (void *) edit, 0);
2418 if (edit->search_start >= 0) {
2419 edit->found_start = edit->search_start;
2420 edit->found_len = len;
2422 edit_cursor_move (edit, edit->search_start - edit->curs1);
2423 edit_scroll_screen_over_cursor (edit);
2424 if (replace_backwards)
2425 edit->search_start--;
2426 else
2427 edit->search_start++;
2428 } else if (edit->search_start == -3) {
2429 edit->search_start = edit->curs1;
2430 regexp_error (edit);
2431 } else {
2432 edit->search_start = edit->curs1;
2433 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
2437 free (exp);
2439 edit->force |= REDRAW_COMPLETELY;
2440 edit_scroll_screen_over_cursor (edit);
2444 /* Real edit only */
2445 void edit_quit_cmd (WEdit * edit)
2447 edit_push_action (edit, KEY_PRESS + edit->start_display);
2449 #ifndef MIDNIGHT
2450 if (edit->stopped)
2451 return;
2452 #endif
2454 edit->force |= REDRAW_COMPLETELY;
2455 if (edit->modified) {
2456 #ifdef GTK
2457 char *r;
2458 r = gtk_dialog_cauldron (_ (" Quit "), GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB, " [ ( %Lxf )xf ]xf / ( %Bgxfq || %Bgxfq || %Bgxfq ) ",
2459 _ (" Current text was modified without a file save. \n Save with exit? "), GNOME_STOCK_BUTTON_CANCEL, GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO);
2460 if (r == GNOME_STOCK_BUTTON_YES) {
2461 edit_push_markers (edit);
2462 edit_set_markers (edit, 0, 0, 0, 0);
2463 if (!edit_save_cmd (edit))
2464 return;
2465 } else if (r == GNOME_STOCK_BUTTON_NO) {
2466 if (edit->delete_file)
2467 unlink (catstrs (edit->dir, edit->filename, 0));
2468 } else {
2469 return;
2471 #else
2472 #ifdef MIDNIGHT
2473 switch (edit_query_dialog3 (_ (" Quit "), _ (" File was modified, Save with exit? "), _ ("Cancel quit"), _ ("&Yes"), _ ("&No"))) {
2474 #else
2475 /* Confirm 'Quit' dialog box */
2476 switch (edit_query_dialog3 (_ (" Quit "),
2477 _ (" Current text was modified without a file save. \n Save with exit? "), _ (" &Cancel quit "), _ (" &Yes "), _ (" &No "))) {
2478 #endif
2479 case 1:
2480 edit_push_markers (edit);
2481 edit_set_markers (edit, 0, 0, 0, 0);
2482 if (!edit_save_cmd (edit))
2483 return;
2484 break;
2485 case 2:
2486 #ifdef MIDNIGHT
2487 if (edit->delete_file)
2488 unlink (catstrs (edit->dir, edit->filename, 0));
2489 #endif
2490 break;
2491 case 0:
2492 case -1:
2493 return;
2495 #endif
2497 #if defined(MIDNIGHT) || defined(GTK)
2498 else if (edit->delete_file)
2499 unlink (catstrs (edit->dir, edit->filename, 0));
2500 #endif
2501 #ifdef MIDNIGHT
2502 dlg_stop (edit->widget.parent);
2503 #else
2504 #ifdef GTK
2506 extern char *edit_one_file;
2508 if (edit_one_file)
2509 gtk_main_quit ();
2511 #endif
2512 edit->stopped = 1;
2513 #endif
2516 #define TEMP_BUF_LEN 1024
2518 /* returns a null terminated length of text. Result must be free'd */
2519 unsigned char *edit_get_block (WEdit * edit, long start, long finish, int *l)
2521 unsigned char *s, *r;
2522 r = s = malloc (finish - start + 1);
2523 if (column_highlighting) {
2524 *l = 0;
2525 while (start < finish) { /* copy from buffer, excluding chars that are out of the column 'margins' */
2526 int c, x;
2527 x = edit_move_forward3 (edit, edit_bol (edit, start), 0, start);
2528 c = edit_get_byte (edit, start);
2529 if ((x >= edit->column1 && x < edit->column2)
2530 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
2531 *s++ = c;
2532 (*l)++;
2534 start++;
2536 } else {
2537 *l = finish - start;
2538 while (start < finish)
2539 *s++ = edit_get_byte (edit, start++);
2541 *s = 0;
2542 return r;
2545 /* save block, returns 1 on success */
2546 int edit_save_block (WEdit * edit, const char *filename, long start, long finish)
2548 int len, file;
2550 if ((file = open ((char *) filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
2551 return 0;
2553 if (column_highlighting) {
2554 unsigned char *block, *p;
2555 int r;
2556 p = block = edit_get_block (edit, start, finish, &len);
2557 while (len) {
2558 r = write (file, p, len);
2559 if (r < 0)
2560 break;
2561 p += r;
2562 len -= r;
2564 free (block);
2565 } else {
2566 unsigned char *buf;
2567 int i = start, end;
2568 len = finish - start;
2569 buf = malloc (TEMP_BUF_LEN);
2570 while (start != finish) {
2571 end = min (finish, start + TEMP_BUF_LEN);
2572 for (; i < end; i++)
2573 buf[i - start] = edit_get_byte (edit, i);
2574 len -= write (file, (char *) buf, end - start);
2575 start = end;
2577 free (buf);
2579 close (file);
2580 if (len)
2581 return 0;
2582 return 1;
2585 /* copies a block to clipboard file */
2586 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
2588 return edit_save_block (edit, catstrs (home_dir, CLIP_FILE, 0), start, finish);
2591 #ifndef MIDNIGHT
2593 void paste_text (WEdit * edit, unsigned char *data, unsigned int nitems)
2595 if (data) {
2596 data += nitems - 1;
2597 while (nitems--)
2598 edit_insert_ahead (edit, *data--);
2600 edit->force |= REDRAW_COMPLETELY;
2603 char *selection_get_line (void *data, int line)
2605 static unsigned char t[1024];
2606 struct selection *s;
2607 int i = 0;
2608 s = (struct selection *) data;
2609 line = (current_selection + line + 1) % NUM_SELECTION_HISTORY;
2610 if (s[line].text) {
2611 unsigned char *p = s[line].text;
2612 int c, j;
2613 for (j = 0; j < s[line].len; j++) {
2614 c = *p++;
2615 if (!isprint (c)) {
2616 t[i++] = '_';
2617 t[i++] = '\b';
2618 t[i++] = '\\';
2619 t[i++] = '_';
2620 t[i++] = '\b';
2621 switch (c) {
2622 case '\a':
2623 t[i++] = 'a';
2624 break;
2625 case '\b':
2626 t[i++] = 'b';
2627 break;
2628 case '\t':
2629 t[i++] = 't';
2630 break;
2631 case '\n':
2632 t[i++] = 'n';
2633 break;
2634 case '\v':
2635 t[i++] = 'v';
2636 break;
2637 case '\f':
2638 t[i++] = 'f';
2639 break;
2640 case '\r':
2641 t[i++] = 'r';
2642 break;
2643 default:
2644 i -= 3;
2645 t[i++] = '.';
2646 break;
2648 } else
2649 t[i++] = c;
2650 if (i > 1000)
2651 break;
2654 t[i] = 0;
2655 return (char *) t;
2658 void edit_paste_from_history (WEdit * edit)
2660 int i, c;
2662 edit_update_curs_col (edit);
2663 edit_update_curs_row (edit);
2665 c = max (20, edit->num_widget_columns - 5);
2667 #ifdef GTK
2668 #if 0
2669 /* *** */
2670 i = gtk_edit_list_box_dialog (c, 10,
2671 0, NUM_SELECTION_HISTORY - 10, NUM_SELECTION_HISTORY - 1, NUM_SELECTION_HISTORY,
2672 selection_get_line, (void *) selection_history);
2673 #else
2674 i = -1;
2675 #endif
2676 #else
2677 i = CListboxDialog (WIN_MESSAGES, c, 10,
2678 0, NUM_SELECTION_HISTORY - 10, NUM_SELECTION_HISTORY - 1, NUM_SELECTION_HISTORY,
2679 selection_get_line, (void *) selection_history);
2680 #endif
2682 if (i < 0)
2683 return;
2685 i = (current_selection + i + 1) % NUM_SELECTION_HISTORY;
2687 paste_text (edit, selection_history[i].text, selection_history[i].len);
2688 edit->force |= REDRAW_COMPLETELY;
2691 /* copies a block to the XWindows buffer */
2692 static int edit_XStore_block (WEdit * edit, long start, long finish)
2694 edit_get_selection (edit);
2695 if (selection.len <= 512 * 1024) { /* we don't want to fill up the server */
2696 XStoreBytes (CDisplay, (char *) selection.text, (int) selection.len);
2697 return 0;
2698 } else
2699 return 1;
2702 int edit_copy_to_X_buf_cmd (WEdit * edit)
2704 long start_mark, end_mark;
2705 if (eval_marks (edit, &start_mark, &end_mark))
2706 return 0;
2707 edit_XStore_block (edit, start_mark, end_mark);
2708 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2709 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2710 return 1;
2712 #ifdef GTK
2713 gtk_selection_owner_set (GTK_WIDGET (edit->widget), GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
2714 edit->widget->editable.selection_start_pos = start_mark;
2715 edit->widget->editable.selection_end_pos = end_mark;
2716 edit->widget->editable.has_selection = TRUE;
2717 #else
2718 XSetSelectionOwner (CDisplay, XA_PRIMARY, CWindowOf (edit->widget), CurrentTime);
2719 #endif
2720 edit_mark_cmd (edit, 1);
2721 return 0;
2724 int edit_cut_to_X_buf_cmd (WEdit * edit)
2726 long start_mark, end_mark;
2727 if (eval_marks (edit, &start_mark, &end_mark))
2728 return 0;
2729 edit_XStore_block (edit, start_mark, end_mark);
2730 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2731 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2732 return 1;
2734 edit_block_delete_cmd (edit);
2735 #ifdef GTK
2736 gtk_selection_owner_set (GTK_WIDGET (edit->widget), GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
2737 edit->widget->editable.selection_start_pos = start_mark;
2738 edit->widget->editable.selection_end_pos = end_mark;
2739 edit->widget->editable.has_selection = TRUE;
2740 #else
2741 XSetSelectionOwner (CDisplay, XA_PRIMARY, CWindowOf (edit->widget), CurrentTime);
2742 #endif
2743 edit_mark_cmd (edit, 1);
2744 return 0;
2747 void selection_paste (WEdit * edit, Window win, unsigned prop, int delete);
2749 void edit_paste_from_X_buf_cmd (WEdit * edit)
2751 if (selection.text)
2752 paste_text (edit, selection.text, selection.len);
2753 else if (!XGetSelectionOwner (CDisplay, XA_PRIMARY))
2754 #ifdef GTK
2755 /* *** */
2757 #else
2758 selection_paste (edit, CRoot, XA_CUT_BUFFER0, False);
2759 #endif
2760 else
2761 #ifdef GTK
2762 gtk_selection_convert (GTK_WIDGET (edit->widget), GDK_SELECTION_PRIMARY,
2763 gdk_atom_intern ("COMPOUND_TEXT", FALSE), GDK_CURRENT_TIME);
2764 #else
2765 XConvertSelection (CDisplay, XA_PRIMARY, XA_STRING,
2766 XInternAtom (CDisplay, "VT_SELECTION", False),
2767 CWindowOf (edit->widget), CurrentTime);
2768 #endif
2769 edit->force |= REDRAW_PAGE;
2772 #else /* MIDNIGHT */
2774 void edit_paste_from_history (WEdit *edit)
2778 int edit_copy_to_X_buf_cmd (WEdit * edit)
2780 long start_mark, end_mark;
2781 if (eval_marks (edit, &start_mark, &end_mark))
2782 return 0;
2783 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2784 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2785 return 1;
2787 edit_mark_cmd (edit, 1);
2788 return 0;
2791 int edit_cut_to_X_buf_cmd (WEdit * edit)
2793 long start_mark, end_mark;
2794 if (eval_marks (edit, &start_mark, &end_mark))
2795 return 0;
2796 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2797 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2798 return 1;
2800 edit_block_delete_cmd (edit);
2801 edit_mark_cmd (edit, 1);
2802 return 0;
2805 void edit_paste_from_X_buf_cmd (WEdit * edit)
2807 edit_insert_file (edit, catstrs (home_dir, CLIP_FILE, 0));
2810 #endif /* MIDNIGHT */
2812 void edit_goto_cmd (WEdit *edit)
2814 char *f;
2815 static int l = 0;
2816 #ifdef MIDNIGHT
2817 char s[12];
2818 sprintf (s, "%d", l);
2819 f = input_dialog (_(" Goto line "), _(" Enter line: "), l ? s : "");
2820 #else
2821 #ifdef GTK
2822 #if 0
2823 f = gtk_edit_dialog_input ("goto", 150, l ? itoa (l) : "", _(" Goto line "), _(" Enter line: "));
2824 #else
2825 char s [12];
2827 sprintf (s, "%d", l);
2828 f = (char *) input_dialog (_(" Goto line "), _(" Enter line: "), l ? s : "");
2829 #endif
2830 #else
2831 f = CInputDialog ("goto", WIN_MESSAGES, 150, l ? itoa (l) : "", _(" Goto line "), _(" Enter line: "));
2832 #endif
2833 #endif
2834 if (f) {
2835 if (*f) {
2836 l = atoi (f);
2837 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2838 edit_move_to_line (edit, l - 1);
2839 edit->force |= REDRAW_COMPLETELY;
2841 free (f);
2845 /*returns 1 on success */
2846 int edit_save_block_cmd (WEdit * edit)
2848 long start_mark, end_mark;
2849 char *exp;
2850 if (eval_marks (edit, &start_mark, &end_mark))
2851 return 1;
2852 exp = edit_get_save_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _ (" Save Block "));
2853 edit_push_action (edit, KEY_PRESS + edit->start_display);
2854 if (exp) {
2855 if (!*exp) {
2856 free (exp);
2857 return 0;
2858 } else {
2859 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2860 free (exp);
2861 edit->force |= REDRAW_COMPLETELY;
2862 return 1;
2863 } else {
2864 free (exp);
2865 edit_error_dialog (_ (" Save Block "), get_sys_error (_ (" Error trying to save file. ")));
2869 edit->force |= REDRAW_COMPLETELY;
2870 return 0;
2874 /* returns 1 on success */
2875 int edit_insert_file_cmd (WEdit * edit)
2877 char *exp = edit_get_load_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _ (" Insert File "));
2878 edit_push_action (edit, KEY_PRESS + edit->start_display);
2879 if (exp) {
2880 if (!*exp) {
2881 free (exp);
2882 return 0;
2883 } else {
2884 if (edit_insert_file (edit, exp)) {
2885 free (exp);
2886 edit->force |= REDRAW_COMPLETELY;
2887 return 1;
2888 } else {
2889 free (exp);
2890 edit_error_dialog (_ (" Insert file "), get_sys_error (_ (" Error trying to insert file. ")));
2894 edit->force |= REDRAW_COMPLETELY;
2895 return 0;
2898 #ifdef MIDNIGHT
2900 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2901 int edit_sort_cmd (WEdit * edit)
2903 static char *old = 0;
2904 char *exp;
2905 long start_mark, end_mark;
2906 int e;
2908 if (eval_marks (edit, &start_mark, &end_mark)) {
2909 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2910 return 0;
2912 edit_save_block (edit, catstrs (home_dir, BLOCK_FILE, 0), start_mark, end_mark);
2914 exp = old ? old : "";
2916 exp = input_dialog (_(" Run Sort "),
2917 _(" Enter sort options (see manpage) separated by whitespace: "), exp);
2919 if (!exp)
2920 return 1;
2921 if (old)
2922 free (old);
2923 old = exp;
2925 e = system (catstrs (" sort ", exp, " ", home_dir, BLOCK_FILE, " > ", home_dir, TEMP_FILE, 0));
2926 if (e) {
2927 if (e == -1 || e == 127) {
2928 edit_error_dialog (_(" Sort "),
2929 get_sys_error (_(" Error trying to execute sort command ")));
2930 } else {
2931 char q[8];
2932 sprintf (q, "%d ", e);
2933 edit_error_dialog (_(" Sort "),
2934 catstrs (_(" Sort returned non-zero: "), q, 0));
2936 return -1;
2939 edit->force |= REDRAW_COMPLETELY;
2941 if (edit_block_delete_cmd (edit))
2942 return 1;
2943 edit_insert_file (edit, catstrs (home_dir, TEMP_FILE, 0));
2944 return 0;
2947 /* if block is 1, a block must be highlighted and the shell command
2948 processes it. If block is 0 the shell command is a straight system
2949 command, that just produces some output which is to be inserted */
2950 void edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block)
2952 long start_mark, end_mark;
2953 struct stat s;
2954 char buf[BUFSIZ];
2955 FILE *script_home = NULL;
2956 FILE *script_src = NULL;
2957 FILE *block_file = NULL;
2959 char *o = catstrs (mc_home, shell_cmd, 0); /* original source script */
2960 char *h = catstrs (home_dir, EDIT_DIR, shell_cmd, 0); /* home script */
2961 char *b = catstrs (home_dir, BLOCK_FILE, 0); /* block file */
2962 char *e = catstrs (home_dir, ERROR_FILE, 0); /* error file */
2964 if (! (script_home = fopen (h, "r"))) {
2965 if (! (script_home = fopen (h, "w"))) {
2966 edit_error_dialog ("",
2967 get_sys_error (catstrs (_ ("Error create script:"), h, 0)));
2968 return;
2969 } else {
2970 if (! (script_src = fopen (o, "r"))) {
2971 fclose (script_home); unlink (h);
2972 edit_error_dialog ("",
2973 get_sys_error (catstrs (_ ("Error read script:"), o, 0)));
2974 return;
2975 } else {
2976 while (fgets(buf, sizeof(buf), script_src))
2977 fputs (buf, script_home);
2978 if (fclose(script_home)) {
2979 edit_error_dialog ("",
2980 get_sys_error (catstrs (_ ("Error close script:"), h, 0)));
2981 return;
2982 } else {
2983 chmod (h, 0700);
2984 edit_error_dialog ("",
2985 get_sys_error (catstrs (_ ("Script created:"), h, 0)));
2990 if (block) { /* for marked block run indent formatter */
2991 if (eval_marks (edit, &start_mark, &end_mark)) {
2992 edit_error_dialog (_("Process block"),
2993 _(" You must first highlight a block of text. "));
2994 return;
2996 edit_save_block (edit, b, start_mark, end_mark);
2998 /* run your script */
2999 execute (catstrs (home_dir, EDIT_DIR, shell_cmd, " ",
3000 edit->filename, " ", home_dir, BLOCK_FILE, " ",
3001 home_dir, ERROR_FILE, 0));
3003 } else { /* for missing marked block run ... */
3004 execute (catstrs (EDIT_DIR, shell_cmd));
3007 edit_refresh_cmd (edit);
3008 edit->force |= REDRAW_COMPLETELY;
3010 /* insert result block */
3011 if (block) {
3012 if (stat (e, &s) == 0) {
3013 if (!s.st_size) { /* no error messages */
3014 if (edit_block_delete_cmd (edit))
3015 return;
3016 edit_insert_file (edit, b);
3017 } else {
3018 edit_insert_file (edit, e);
3020 } else {
3021 edit_error_dialog ("",
3022 get_sys_error (catstrs (_ ("Error trying to stat file:"), e, 0)));
3023 edit->force |= REDRAW_COMPLETELY;
3025 if ((block_file = fopen (b, "w")))
3026 fclose (block_file);
3027 return;
3029 return;
3032 #endif /* MIDNIGHT */
3034 int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion);
3036 /* prints at the cursor */
3037 /* returns the number of chars printed */
3038 int edit_print_string (WEdit * e, const char *s)
3040 int i = 0;
3041 while (s[i])
3042 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
3043 e->force |= REDRAW_COMPLETELY;
3044 edit_update_screen (e);
3045 return i;
3048 int edit_printf (WEdit * e, const char *fmt,...)
3050 int i;
3051 va_list pa;
3052 char s[1024];
3053 va_start (pa, fmt);
3054 sprintf (s, fmt, pa);
3055 i = edit_print_string (e, s);
3056 va_end (pa);
3057 return i;
3060 #ifdef MIDNIGHT
3062 /* FIXME: does this function break NT_OS2 ? */
3064 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
3066 FILE *p = 0;
3067 char *s;
3069 s = g_strdup_printf ("mail -s \"%s\" -c \"%s\" \"%s\"", subject, cc, to);
3071 if (s) {
3072 p = popen (s, "w");
3073 g_free (s);
3076 if (p) {
3077 long i;
3078 for (i = 0; i < edit->last_byte; i++)
3079 fputc (edit_get_byte (edit, i), p);
3080 pclose (p);
3084 #define MAIL_DLG_HEIGHT 12
3086 void edit_mail_dialog (WEdit * edit)
3088 char *tmail_to;
3089 char *tmail_subject;
3090 char *tmail_cc;
3092 static char *mail_cc_last = 0;
3093 static char *mail_subject_last = 0;
3094 static char *mail_to_last = 0;
3096 QuickDialog Quick_input =
3097 {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
3098 "[Input Line Keys]", "quick_input", 0};
3100 QuickWidget quick_widgets[] =
3102 {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
3103 0, NULL},
3104 {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&Ok"), 0, B_ENTER, 0,
3105 0, NULL},
3106 {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
3107 0, "mail-dlg-input"},
3108 {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
3109 0, 0},
3110 {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
3111 0, "mail-dlg-input-2"},
3112 {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
3113 0, 0},
3114 {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
3115 0, "mail-dlg-input-3"},
3116 {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
3117 0, 0},
3118 {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
3119 0, 0},
3120 {0}};
3122 quick_widgets[2].str_result = &tmail_cc;
3123 quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
3124 quick_widgets[4].str_result = &tmail_subject;
3125 quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
3126 quick_widgets[6].str_result = &tmail_to;
3127 quick_widgets[6].text = mail_to_last ? mail_to_last : "";
3129 Quick_input.widgets = quick_widgets;
3131 if (quick_dialog (&Quick_input) != B_CANCEL) {
3132 if (mail_cc_last)
3133 free (mail_cc_last);
3134 if (mail_subject_last)
3135 free (mail_subject_last);
3136 if (mail_to_last)
3137 free (mail_to_last);
3138 mail_cc_last = *(quick_widgets[2].str_result);
3139 mail_subject_last = *(quick_widgets[4].str_result);
3140 mail_to_last = *(quick_widgets[6].str_result);
3141 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
3145 #endif /* MIDNIGHT */