my homework was late :-)
[midnight-commander.git] / gtkedit / editcmd.c
blob1ec27422faf7592938ed2a61d605323023dc0a31
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 /* globals: */
46 /* search and replace: */
47 int replace_scanf = 0;
48 int replace_regexp = 0;
49 int replace_all = 0;
50 int replace_prompt = 1;
51 int replace_whole = 0;
52 int replace_case = 0;
53 int replace_backwards = 0;
54 int search_create_bookmark = 0;
56 /* queries on a save */
57 #ifdef MIDNIGHT
58 int edit_confirm_save = 1;
59 #else
60 int edit_confirm_save = 0;
61 #endif
63 #define NUM_REPL_ARGS 64
64 #define MAX_REPL_LEN 1024
66 #if defined(MIDNIGHT) || defined(GTK)
68 static inline int my_lower_case (int c)
70 return tolower(c & 0xFF);
73 char *strcasechr (const unsigned char *s, int c)
75 for (c = my_lower_case (c); my_lower_case ((int) *s) != c; ++s)
76 if (*s == '\0')
77 return 0;
78 return (char *) s;
81 #ifdef MIDNIGHT
82 #include "../src/mad.h"
83 #elif !defined (GTK)
84 #include "mad.h"
85 #endif
87 #ifndef HAVE_MEMMOVE
88 /* for Christophe */
89 static void *memmove (void *dest, const void *src, size_t n)
91 char *t, *s;
93 if (dest <= src) {
94 t = (char *) dest;
95 s = (char *) src;
96 while (n--)
97 *t++ = *s++;
98 } else {
99 t = (char *) dest + n;
100 s = (char *) src + n;
101 while (n--)
102 *--t = *--s;
104 return dest;
106 #endif
108 /* #define itoa MY_itoa <---- this line is now in edit.h */
109 char *itoa (int i)
111 static char t[14];
112 char *s = t + 13;
113 int j = i;
114 *s-- = 0;
115 do {
116 *s-- = i % 10 + '0';
117 } while ((i = i / 10));
118 if (j < 0)
119 *s-- = '-';
120 return ++s;
124 This joins strings end on end and allocates memory for the result.
125 The result is later automatically free'd and must not be free'd
126 by the caller.
128 char *catstrs (const char *first,...)
130 static char *stacked[16] =
131 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
132 static int i = 0;
133 va_list ap;
134 int len;
135 char *data;
137 if (!first)
138 return 0;
140 len = strlen (first);
141 va_start (ap, first);
143 while ((data = va_arg (ap, char *)) != 0)
144 len += strlen (data);
146 len++;
148 i = (i + 1) % 16;
149 if (stacked[i])
150 free (stacked[i]);
152 stacked[i] = malloc (len);
153 va_end (ap);
154 va_start (ap, first);
155 strcpy (stacked[i], first);
156 while ((data = va_arg (ap, char *)) != 0)
157 strcat (stacked[i], data);
158 va_end (ap);
160 return stacked[i];
162 #endif
164 #ifdef MIDNIGHT
166 void edit_help_cmd (WEdit * edit)
168 char *hlpdir = concat_dir_and_file (mc_home, _("mc.hlp"));
169 interactive_display (hlpdir, "[Internal File Editor]");
170 free (hlpdir);
171 edit->force |= REDRAW_COMPLETELY;
174 void edit_refresh_cmd (WEdit * edit)
176 #ifndef HAVE_SLANG
177 clr_scr();
178 do_refresh();
179 #else
181 int fg, bg;
182 edit_get_syntax_color (edit, -1, &fg, &bg);
184 touchwin(stdscr);
185 #endif /* !HAVE_SLANG */
186 mc_refresh();
187 doupdate();
190 #else /* MIDNIGHT */
192 void edit_help_cmd (WEdit * edit)
196 void edit_refresh_cmd (WEdit * edit)
198 int fg, bg;
199 edit_get_syntax_color (edit, -1, &fg, &bg);
200 edit->force |= REDRAW_COMPLETELY;
203 void CRefreshEditor (WEdit * edit)
205 edit_refresh_cmd (edit);
208 #endif /* MIDNIGHT */
210 #ifndef MIDNIGHT
211 #ifndef GTK
213 /* three argument open */
214 int my_open (const char *pathname, int flags,...)
216 int file;
217 va_list ap;
219 file = open ((char *) pathname, O_RDONLY);
220 if (file < 0 && (flags & O_CREAT)) { /* must it be created ? */
221 mode_t mode;
222 va_start(ap, flags);
223 mode = va_arg(ap, mode_t);
224 va_end(ap);
225 return creat ((char *) pathname, mode);
227 close (file);
228 return open ((char *) pathname, flags);
231 #define open my_open
233 #endif /* !GTK */
234 #endif /* !MIDNIGHT */
236 /* "Oleg Yu. Repin" <repin@ssd.sscc.ru> added backup filenames
237 ...thanks -paul */
239 /* If 0 (quick save) then a) create/truncate <filename> file,
240 b) save to <filename>;
241 if 1 (safe save) then a) save to <tempnam>,
242 b) rename <tempnam> to <filename>;
243 if 2 (do backups) then a) save to <tempnam>,
244 b) rename <filename> to <filename.backup_ext>,
245 c) rename <tempnam> to <filename>. */
247 /* returns 0 on error */
248 int edit_save_file (WEdit * edit, const char *filename)
250 char *p;
251 long filelen = 0;
252 char *savename = 0;
253 int this_save_mode, fd;
255 if (!filename)
256 return 0;
257 if (!*filename)
258 return 0;
260 savename = (char *) strdup ((char *) filename);
262 if ((fd = open (savename, O_WRONLY)) == -1) {
263 this_save_mode = 0; /* the file does not exists yet, so no safe save or backup necessary */
264 } else {
265 close (fd);
266 this_save_mode = option_save_mode;
269 if (this_save_mode > 0) {
270 char *savedir, *slashpos;
271 savedir = (char *) strdup (".");
272 slashpos = strrchr (filename, '/');
273 if (slashpos) {
274 free (savedir);
275 savedir = (char *) strdup (filename);
276 savedir[slashpos - filename + 1] = '\0';
278 if (savename)
279 free (savename);
280 savename = (char *) tempnam (savedir, "cooledit");
281 free (savedir);
282 if (!savename)
283 return 0;
286 if ((fd = open (savename, O_CREAT | O_WRONLY | O_TRUNC | MY_O_TEXT, edit->stat.st_mode)) == -1)
287 goto error_save;
289 chmod (savename, edit->stat.st_mode);
290 chown (savename, edit->stat.st_uid, edit->stat.st_gid);
292 /* pipe save */
293 if ((p = (char *) edit_get_write_filter (savename, filename))) {
294 FILE *file;
296 close (fd);
297 file = (FILE *) popen (p, "w");
299 if (file) {
300 filelen = edit_write_stream (edit, file);
301 #if 1
302 pclose (file);
303 #else
304 if (pclose (file) != 0) {
305 edit_error_dialog (_ (" Error "), catstrs (_ (" Error writing to pipe: "), p, " ", 0));
306 free (p);
307 goto error_save;
309 #endif
310 } else {
311 edit_error_dialog (_ (" Error "), get_sys_error (catstrs (_ (" Failed trying to open pipe for writing: "), p, " ", 0)));
312 free (p);
313 goto error_save;
315 free (p);
316 #ifdef CR_LF_TRANSLATION
317 } else { /* optimised save */
318 filelen = edit_write_stream (edit, f);
319 if (fclose (file))
320 filelen = -1;
321 #else
322 } else {
323 long buf;
324 buf = 0;
325 filelen = edit->last_byte;
326 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
327 if (write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
328 close (fd);
329 goto error_save;
331 buf++;
333 if (write (fd, (char *) edit->buffers1[buf], edit->curs1 & M_EDIT_BUF_SIZE) != (edit->curs1 & M_EDIT_BUF_SIZE)) {
334 filelen = -1;
335 } else if (edit->curs2) {
336 edit->curs2--;
337 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
338 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)) {
339 filelen = -1;
340 } else {
341 while (--buf >= 0) {
342 if (write (fd, (char *) edit->buffers2[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
343 filelen = -1;
344 break;
348 edit->curs2++;
350 if (close (fd))
351 goto error_save;
352 #endif /* CR_LF_TRANSLATION */
355 if (filelen != edit->last_byte)
356 goto error_save;
357 if (this_save_mode == 2)
358 if (rename (filename, catstrs (filename, option_backup_ext, 0)) == -1)
359 goto error_save;
360 if (this_save_mode > 0)
361 if (rename (savename, filename) == -1)
362 goto error_save;
363 if (savename)
364 free (savename);
365 return 1;
366 error_save:
367 if (savename)
368 free (savename);
369 return 0;
372 #ifdef MIDNIGHT
374 I changed this from Oleg's original routine so
375 that option_backup_ext works with coolwidgets as well. This
376 does mean there is a memory leak - paul.
378 void menu_save_mode_cmd (void)
380 #define DLG_X 38
381 #define DLG_Y 10
382 static char *str_result;
383 static int save_mode_new;
384 static char *str[] =
386 N_("Quick save "),
387 N_("Safe save "),
388 N_("Do backups -->")};
389 static QuickWidget widgets[] =
391 {quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
392 B_CANCEL, 0, 0, "c"},
393 {quick_button, 6, DLG_X, 7, DLG_Y, N_("&Ok"), 0,
394 B_ENTER, 0, 0, "o"},
395 {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
396 0, 0, &str_result, "i"},
397 {quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
398 0, 0, 0, "savemext"},
399 {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
400 0, &save_mode_new, str, "t"},
401 {0}};
402 static QuickDialog dialog =
403 {DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
404 "esm", widgets};
405 static int i18n_flag = 0;
407 if (!i18n_flag) {
408 int i;
410 for (i = 0; i < 3; i++ )
411 str[i] = _(str[i]);
412 i18n_flag = 1;
415 widgets[2].text = option_backup_ext;
416 widgets[4].value = option_save_mode;
417 if (quick_dialog (&dialog) != B_ENTER)
418 return;
419 option_save_mode = save_mode_new;
420 option_backup_ext = str_result; /* this is a memory leak */
421 option_backup_ext_int = 0;
422 str_result[min (strlen (str_result), sizeof (int))] = '\0';
423 memcpy ((char *) &option_backup_ext_int, str_result, strlen (option_backup_ext));
426 void edit_split_filename (WEdit * edit, const char *f)
428 if (edit->filename)
429 free (edit->filename);
430 edit->filename = (char *) strdup (f);
431 if (edit->dir)
432 free (edit->dir);
433 edit->dir = (char *) strdup ("");
436 #else /* MIDNIGHT */
438 #ifdef GTK
440 static char cwd[1040];
442 static char *canonicalize_pathname (const char *p)
444 char *q, *r;
445 char *t = NULL;
447 if (*p != '/') {
448 if (strlen (cwd) == 0) {
449 #ifdef HAVE_GETCWD
450 getcwd (cwd, MAX_PATH_LEN);
451 #else
452 getwd (cwd);
453 #endif
455 t = malloc (strlen (cwd) + strlen (p) + 2);
456 strcpy (t, cwd);
457 strcat (t, "/");
458 strcat (t, p);
459 p = t;
461 r = q = malloc (strlen (p) + 2);
462 while (*p) {
463 if (*p != '/') {
464 *q++ = *p++;
465 } else {
466 while (*p == '/') {
467 *q = '/';
468 if (!strncmp (p, "/./", 3) || !strcmp (p, "/."))
469 p++;
470 else if (!strncmp (p, "/../", 4) || !strcmp (p, "/..")) {
471 p += 2;
472 *q = ' ';
473 q = strrchr (r, '/');
474 if (!q) {
475 q = r;
476 *q = '/';
479 p++;
481 q++;
484 if (t)
485 free (t);
486 *q = '\0';
487 /* get rid of trailing / */
488 if (r[0] && r[1])
489 if (*--q == '/')
490 *q = '\0';
491 return r;
494 #endif /* GTK */
497 void edit_split_filename (WEdit * edit, const char *longname)
499 char *exp, *p;
500 #ifdef GTK
501 exp = canonicalize_pathname (longname);
502 #else
503 exp = pathdup (longname); /* this ensures a full path */
504 #endif
505 if (edit->filename)
506 free (edit->filename);
507 if (edit->dir)
508 free (edit->dir);
509 p = strrchr (exp, '/');
510 edit->filename = (char *) strdup (++p);
511 *p = 0;
512 edit->dir = (char *) strdup (exp);
513 free (exp);
516 #endif /* ! MIDNIGHT */
518 /* here we want to warn the user of overwriting an existing file, but only if they
519 have made a change to the filename */
520 /* returns 1 on success */
521 int edit_save_as_cmd (WEdit * edit)
523 /* This heads the 'Save As' dialog box */
524 char *exp = 0;
525 int different_filename = 0;
527 exp = edit_get_save_file (edit->dir, edit->filename, _(" Save As "));
528 edit_push_action (edit, KEY_PRESS + edit->start_display);
530 if (exp) {
531 if (!*exp) {
532 free (exp);
533 edit->force |= REDRAW_COMPLETELY;
534 return 0;
535 } else {
536 if (strcmp(catstrs (edit->dir, edit->filename, 0), exp)) {
537 int file;
538 different_filename = 1;
539 if ((file = open ((char *) exp, O_RDONLY)) != -1) { /* the file exists */
540 close (file);
541 if (edit_query_dialog2 (_(" Warning "),
542 _(" A file already exists with this name. "),
543 /* Push buttons to over-write the current file, or cancel the operation */
544 _("Overwrite"), _("Cancel"))) {
545 edit->force |= REDRAW_COMPLETELY;
546 return 0;
550 if (edit_save_file (edit, exp)) {
551 edit_split_filename (edit, exp);
552 free (exp);
553 edit->modified = 0;
554 #if defined(MIDNIGHT) || defined(GTK)
555 edit->delete_file = 0;
556 #endif
557 if (different_filename && !edit->explicit_syntax)
558 edit_load_syntax (edit, 0, 0);
559 edit->force |= REDRAW_COMPLETELY;
560 return 1;
561 } else {
562 free (exp);
563 edit_error_dialog (_(" Save as "), get_sys_error (_(" Error trying to save file. ")));
564 edit->force |= REDRAW_COMPLETELY;
565 return 0;
569 edit->force |= REDRAW_COMPLETELY;
570 return 0;
573 /* {{{ Macro stuff starts here */
575 #ifdef MIDNIGHT
576 int raw_callback (struct Dlg_head *h, int key, int Msg)
578 switch (Msg) {
579 case DLG_DRAW:
580 attrset (REVERSE_COLOR);
581 dlg_erase (h);
582 draw_box (h, 1, 1, h->lines - 2, h->cols - 2);
584 attrset (COLOR_HOT_NORMAL);
585 dlg_move (h, 1, 2);
586 printw (h->title);
587 break;
589 case DLG_KEY:
590 h->running = 0;
591 h->ret_value = key;
592 return 1;
594 return 0;
597 /* gets a raw key from the keyboard. Passing cancel = 1 draws
598 a cancel button thus allowing c-c etc.. Alternatively, cancel = 0
599 will return the next key pressed */
600 int edit_raw_key_query (char *heading, char *query, int cancel)
602 int w = strlen (query) + 7;
603 struct Dlg_head *raw_dlg = create_dlg (0, 0, 7, w, dialog_colors,
604 /* NLS ? */
605 raw_callback, "[Raw Key Query]",
606 "raw_key_input",
607 DLG_CENTER | DLG_TRYUP);
608 x_set_dialog_title (raw_dlg, heading);
609 raw_dlg->raw = 1; /* to return even a tab key */
610 if (cancel)
611 add_widget (raw_dlg, button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON, _("Cancel"), 0, 0, 0));
612 add_widget (raw_dlg, label_new (3 - cancel, 2, query, 0));
613 add_widget (raw_dlg, input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0));
614 run_dlg (raw_dlg);
615 w = raw_dlg->ret_value;
616 destroy_dlg (raw_dlg);
617 if (cancel)
618 if (w == XCTRL ('g') || w == XCTRL ('c') || w == ESC_CHAR || w == B_CANCEL)
619 return 0;
620 /* hence ctrl-a (=B_CANCEL), ctrl-g, ctrl-c, and Esc are cannot returned */
621 return w;
624 #else /* MIDNIGHT */
626 int edit_raw_key_query (char *heading, char *query, int cancel)
628 #ifdef GTK
629 /* *** */
630 return 0;
631 #else
632 return CKeySymMod (CRawkeyQuery (0, 0, 0, heading, query));
633 #endif
636 #endif /* MIDNIGHT */
638 /* creates a macro file if it doesn't exist */
639 static FILE *edit_open_macro_file (const char *r)
641 char *filename;
642 int file;
643 filename = catstrs (home_dir, MACRO_FILE, 0);
644 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
645 return 0;
646 close (file);
647 return fopen (filename, r);
650 #define MAX_MACROS 1024
651 static int saved_macro[MAX_MACROS + 1] =
652 {0, 0};
653 static int saved_macros_loaded = 0;
656 This is just to stop the macro file be loaded over and over for keys
657 that aren't defined to anything. On slow systems this could be annoying.
659 int macro_exists (int k)
661 int i;
662 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
663 if (saved_macro[i] == k)
664 return i;
665 return -1;
668 /* returns 1 on error */
669 int edit_delete_macro (WEdit * edit, int k)
671 struct macro macro[MAX_MACRO_LENGTH];
672 FILE *f, *g;
673 int s, i, n, j = 0;
675 if (saved_macros_loaded)
676 if ((j = macro_exists (k)) < 0)
677 return 0;
678 g = fopen (catstrs (home_dir, TEMP_FILE, 0), "w");
679 if (!g) {
680 /* This heads the delete macro error dialog box */
681 edit_error_dialog (_(" Delete macro "),
682 /* 'Open' = load temp file */
683 get_sys_error (_(" Error trying to open temp file ")));
684 return 1;
686 f = edit_open_macro_file ("r");
687 if (!f) {
688 /* This heads the delete macro error dialog box */
689 edit_error_dialog (_(" Delete macro "),
690 /* 'Open' = load temp file */
691 get_sys_error (_(" Error trying to open macro file ")));
692 fclose (g);
693 return 1;
695 for (;;) {
696 n = fscanf (f, ("key '%d 0': "), &s);
697 if (!n || n == EOF)
698 break;
699 n = 0;
700 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
701 n++;
702 fscanf (f, ";\n");
703 if (s != k) {
704 fprintf (g, ("key '%d 0': "), s);
705 for (i = 0; i < n; i++)
706 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
707 fprintf (g, ";\n");
710 fclose (f);
711 fclose (g);
712 if (rename (catstrs (home_dir, TEMP_FILE, 0), catstrs (home_dir, MACRO_FILE, 0)) == -1) {
713 /* This heads the delete macro error dialog box */
714 edit_error_dialog (_(" Delete macro "),
715 get_sys_error (_(" Error trying to overwrite macro file ")));
716 return 1;
718 if (saved_macros_loaded)
719 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
720 return 0;
723 /* returns 0 on error */
724 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
726 FILE *f;
727 int s, i;
729 edit_push_action (edit, KEY_PRESS + edit->start_display);
730 /* This heads the 'Macro' dialog box */
731 s = edit_raw_key_query (_(" Macro "),
732 /* Input line for a single key press follows the ':' */
733 _(" Press the macro's new hotkey: "), 1);
734 edit->force |= REDRAW_COMPLETELY;
735 if (s) {
736 if (edit_delete_macro (edit, s))
737 return 0;
738 f = edit_open_macro_file ("a+");
739 if (f) {
740 fprintf (f, ("key '%d 0': "), s);
741 for (i = 0; i < n; i++)
742 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
743 fprintf (f, ";\n");
744 fclose (f);
745 if (saved_macros_loaded) {
746 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
747 saved_macro[i] = s;
749 return 1;
750 } else
751 /* This heads the 'Save Macro' dialog box */
752 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Error trying to open macro file ")));
754 return 0;
757 void edit_delete_macro_cmd (WEdit * edit)
759 int command;
761 #ifdef MIDNIGHT
762 command = edit_raw_key_query (_ (" Delete Macro "),
763 _ (" Press macro hotkey: "), 1);
764 #else
765 /* This heads the 'Delete Macro' dialog box */
766 #ifdef GTK
767 /* *** */
768 command = 0;
769 #else
770 command = CKeySymMod (CRawkeyQuery (0, 0, 0, _ (" Delete Macro "),
771 /* Input line for a single key press follows the ':' */
772 _ (" Press macro hotkey: ")));
773 #endif
774 #endif
776 if (!command)
777 return;
779 edit_delete_macro (edit, command);
782 /* return 0 on error */
783 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
785 FILE *f;
786 int s, i = 0, found = 0;
788 if (saved_macros_loaded)
789 if (macro_exists (k) < 0)
790 return 0;
792 if ((f = edit_open_macro_file ("r"))) {
793 struct macro dummy;
794 do {
795 int u;
796 u = fscanf (f, ("key '%d 0': "), &s);
797 if (!u || u == EOF)
798 break;
799 if (!saved_macros_loaded)
800 saved_macro[i++] = s;
801 if (!found) {
802 *n = 0;
803 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
804 (*n)++;
805 } else {
806 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
808 fscanf (f, ";\n");
809 if (s == k)
810 found = 1;
811 } while (!found || !saved_macros_loaded);
812 if (!saved_macros_loaded) {
813 saved_macro[i] = 0;
814 saved_macros_loaded = 1;
816 fclose (f);
817 return found;
818 } else
819 /* This heads the 'Load Macro' dialog box */
820 edit_error_dialog (_(" Load macro "),
821 get_sys_error (_(" Error trying to open macro file ")));
822 return 0;
825 /* }}} Macro stuff starts here */
827 /* returns 1 on success */
828 int edit_save_confirm_cmd (WEdit * edit)
830 char *f;
832 if (edit_confirm_save) {
833 #ifdef MIDNIGHT
834 f = catstrs (_(" Confirm save file? : "), edit->filename, " ", 0);
835 #else
836 f = catstrs (_(" Confirm save file? : "), edit->dir, edit->filename, " ", 0);
837 #endif
838 /* Buttons to 'Confirm save file' query */
839 if (edit_query_dialog2 (_(" Save file "), f, _("Save"), _("Cancel")))
840 return 0;
842 return edit_save_cmd (edit);
846 /* returns 1 on success */
847 int edit_save_cmd (WEdit * edit)
849 if (!edit_save_file (edit, catstrs (edit->dir, edit->filename, 0)))
850 return edit_save_as_cmd (edit);
851 edit->force |= REDRAW_COMPLETELY;
852 edit->modified = 0;
853 #if defined(MIDNIGHT) || defined(GTK)
854 edit->delete_file = 0;
855 #endif
857 return 1;
861 /* returns 1 on success */
862 int edit_new_cmd (WEdit * edit)
864 if (edit->modified) {
865 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
866 edit->force |= REDRAW_COMPLETELY;
867 return 0;
870 edit->force |= REDRAW_COMPLETELY;
871 edit->modified = 0;
872 return edit_renew (edit); /* if this gives an error, something has really screwed up */
875 /* returns 1 on error */
876 int edit_load_file_from_filename (WEdit * edit, char *exp)
878 if (!edit_reload (edit, exp, 0, "", 0))
879 return 1;
880 edit_split_filename (edit, exp);
881 edit->modified = 0;
882 return 0;
885 int edit_load_cmd (WEdit * edit)
887 char *exp;
889 if (edit->modified) {
890 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
891 edit->force |= REDRAW_COMPLETELY;
892 return 0;
896 exp = edit_get_load_file (edit->dir, edit->filename, _ (" Load "));
898 if (exp) {
899 if (*exp)
900 edit_load_file_from_filename (edit, exp);
901 free (exp);
903 edit->force |= REDRAW_COMPLETELY;
904 return 0;
908 if mark2 is -1 then marking is from mark1 to the cursor.
909 Otherwise its between the markers. This handles this.
910 Returns 1 if no text is marked.
912 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
914 if (edit->mark1 != edit->mark2) {
915 if (edit->mark2 >= 0) {
916 *start_mark = min (edit->mark1, edit->mark2);
917 *end_mark = max (edit->mark1, edit->mark2);
918 } else {
919 *start_mark = min (edit->mark1, edit->curs1);
920 *end_mark = max (edit->mark1, edit->curs1);
921 edit->column2 = edit->curs_col;
923 return 0;
924 } else {
925 *start_mark = *end_mark = 0;
926 edit->column2 = edit->column1 = 0;
927 return 1;
931 /*Block copy, move and delete commands */
932 extern int column_highlighting;
934 #ifdef MIDNIGHT
935 #define space_width 1
936 #else
937 extern int space_width;
938 #endif
940 void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
942 long cursor;
943 int i, col;
944 cursor = edit->curs1;
945 col = edit_get_col (edit);
946 for (i = 0; i < size; i++) {
947 if (data[i] == '\n') { /* fill in and move to next line */
948 int l;
949 long p;
950 if (edit_get_byte (edit, edit->curs1) != '\n') {
951 l = width - (edit_get_col (edit) - col);
952 while (l > 0) {
953 edit_insert (edit, ' ');
954 l -= space_width;
957 for (p = edit->curs1;; p++) {
958 if (p == edit->last_byte)
959 edit_insert_ahead (edit, '\n');
960 if (edit_get_byte (edit, p) == '\n') {
961 p++;
962 break;
965 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
966 l = col - edit_get_col (edit);
967 while (l >= space_width) {
968 edit_insert (edit, ' ');
969 l -= space_width;
971 continue;
973 edit_insert (edit, data[i]);
975 edit_cursor_move (edit, cursor - edit->curs1);
979 void edit_block_copy_cmd (WEdit * edit)
981 long start_mark, end_mark, current = edit->curs1;
982 int size, x;
983 unsigned char *copy_buf;
985 edit_update_curs_col (edit);
986 x = edit->curs_col;
987 if (eval_marks (edit, &start_mark, &end_mark))
988 return;
989 if (column_highlighting)
990 if ((x >= edit->column1 && x < edit->column2) || (x > edit->column2 && x <= edit->column1))
991 return;
993 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
995 /* all that gets pushed are deletes hence little space is used on the stack */
997 edit_push_markers (edit);
999 if (column_highlighting) {
1000 edit_insert_column_of_text (edit, copy_buf, size, abs (edit->column2 - edit->column1));
1001 } else {
1002 while (size--)
1003 edit_insert_ahead (edit, copy_buf[size]);
1006 free (copy_buf);
1007 edit_scroll_screen_over_cursor (edit);
1009 if (column_highlighting) {
1010 edit_set_markers (edit, 0, 0, 0, 0);
1011 edit_push_action (edit, COLUMN_ON);
1012 column_highlighting = 0;
1013 } else if (start_mark < current && end_mark > current)
1014 edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
1016 edit->force |= REDRAW_PAGE;
1020 void edit_block_move_cmd (WEdit * edit)
1022 long count;
1023 long current;
1024 unsigned char *copy_buf;
1025 long start_mark, end_mark;
1026 int deleted = 0;
1027 int x = 0;
1029 if (eval_marks (edit, &start_mark, &end_mark))
1030 return;
1031 if (column_highlighting) {
1032 edit_update_curs_col (edit);
1033 x = edit->curs_col;
1034 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1035 if ((x > edit->column1 && x < edit->column2) || (x > edit->column2 && x < edit->column1))
1036 return;
1037 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1038 return;
1040 if ((end_mark - start_mark) > option_max_undo / 2)
1041 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ ("Continue"), _ ("Cancel")))
1042 return;
1044 edit_push_markers (edit);
1045 current = edit->curs1;
1046 if (column_highlighting) {
1047 int size, c1, c2, line;
1048 line = edit->curs_line;
1049 if (edit->mark2 < 0)
1050 edit_mark_cmd (edit, 0);
1051 c1 = min (edit->column1, edit->column2);
1052 c2 = max (edit->column1, edit->column2);
1053 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1054 if (x < c2) {
1055 edit_block_delete_cmd (edit);
1056 deleted = 1;
1058 edit_move_to_line (edit, line);
1059 edit_cursor_move (edit, edit_move_forward3 (edit, edit_bol (edit, edit->curs1), x, 0) - edit->curs1);
1060 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1061 if (!deleted) {
1062 line = edit->curs_line;
1063 edit_update_curs_col (edit);
1064 x = edit->curs_col;
1065 edit_block_delete_cmd (edit);
1066 edit_move_to_line (edit, line);
1067 edit_cursor_move (edit, edit_move_forward3 (edit, edit_bol (edit, edit->curs1), x, 0) - edit->curs1);
1069 edit_set_markers (edit, 0, 0, 0, 0);
1070 edit_push_action (edit, COLUMN_ON);
1071 column_highlighting = 0;
1072 } else {
1073 copy_buf = malloc (end_mark - start_mark);
1074 edit_cursor_move (edit, start_mark - edit->curs1);
1075 edit_scroll_screen_over_cursor (edit);
1076 count = start_mark;
1077 while (count < end_mark) {
1078 copy_buf[end_mark - count - 1] = edit_delete (edit);
1079 count++;
1081 edit_scroll_screen_over_cursor (edit);
1082 edit_cursor_move (edit, current - edit->curs1 - (((current - edit->curs1) > 0) ? end_mark - start_mark : 0));
1083 edit_scroll_screen_over_cursor (edit);
1084 while (count-- > start_mark)
1085 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1086 edit_set_markers (edit, edit->curs1, edit->curs1 + end_mark - start_mark, 0, 0);
1088 edit_scroll_screen_over_cursor (edit);
1089 free (copy_buf);
1090 edit->force |= REDRAW_PAGE;
1093 void edit_cursor_to_bol (WEdit * edit);
1095 void edit_delete_column_of_text (WEdit * edit)
1097 long p, q, r, m1, m2;
1098 int b, c, d;
1099 int n;
1101 eval_marks (edit, &m1, &m2);
1102 n = edit_move_forward (edit, m1, 0, m2) + 1;
1103 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1104 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1106 b = min (c, d);
1107 c = max (c, d);
1109 while (n--) {
1110 r = edit_bol (edit, edit->curs1);
1111 p = edit_move_forward3 (edit, r, b, 0);
1112 q = edit_move_forward3 (edit, r, c, 0);
1113 if (p < m1)
1114 p = m1;
1115 if (q > m2)
1116 q = m2;
1117 edit_cursor_move (edit, p - edit->curs1);
1118 while (q > p) { /* delete line between margins */
1119 if (edit_get_byte (edit, edit->curs1) != '\n')
1120 edit_delete (edit);
1121 q--;
1123 if (n) /* move to next line except on the last delete */
1124 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1128 /* if success return 0 */
1129 int edit_block_delete (WEdit * edit)
1131 long count;
1132 long start_mark, end_mark;
1133 if (eval_marks (edit, &start_mark, &end_mark))
1134 return 0;
1135 if (column_highlighting && edit->mark2 < 0)
1136 edit_mark_cmd (edit, 0);
1137 if ((end_mark - start_mark) > option_max_undo / 2)
1138 /* Warning message with a query to continue or cancel the operation */
1139 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ (" Continue "), _ (" Cancel ")))
1140 return 1;
1141 edit_push_markers (edit);
1142 edit_cursor_move (edit, start_mark - edit->curs1);
1143 edit_scroll_screen_over_cursor (edit);
1144 count = start_mark;
1145 if (start_mark < end_mark) {
1146 if (column_highlighting) {
1147 if (edit->mark2 < 0)
1148 edit_mark_cmd (edit, 0);
1149 edit_delete_column_of_text (edit);
1150 } else {
1151 while (count < end_mark) {
1152 edit_delete (edit);
1153 count++;
1157 edit_set_markers (edit, 0, 0, 0, 0);
1158 edit->force |= REDRAW_PAGE;
1159 return 0;
1162 /* returns 1 if canceelled by user */
1163 int edit_block_delete_cmd (WEdit * edit)
1165 long start_mark, end_mark;
1166 if (eval_marks (edit, &start_mark, &end_mark)) {
1167 edit_delete_line (edit);
1168 return 0;
1170 return edit_block_delete (edit);
1174 #ifdef MIDNIGHT
1176 #define INPUT_INDEX 9
1177 #define SEARCH_DLG_WIDTH 58
1178 #define SEARCH_DLG_HEIGHT 10
1179 #define REPLACE_DLG_WIDTH 58
1180 #define REPLACE_DLG_HEIGHT 15
1181 #define CONFIRM_DLG_WIDTH 79
1182 #define CONFIRM_DLG_HEIGTH 6
1183 #define B_REPLACE_ALL B_USER+1
1184 #define B_REPLACE_ONE B_USER+2
1185 #define B_SKIP_REPLACE B_USER+3
1187 int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
1189 QuickWidget quick_widgets[] =
1191 {quick_button, 63, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Cancel"),
1192 0, B_CANCEL, 0, 0, NULL},
1193 {quick_button, 50, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("o&Ne"),
1194 0, B_REPLACE_ONE, 0, 0, NULL},
1195 {quick_button, 37, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("al&L"),
1196 0, B_REPLACE_ALL, 0, 0, NULL},
1197 {quick_button, 21, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Skip"),
1198 0, B_SKIP_REPLACE, 0, 0, NULL},
1199 {quick_button, 4, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Replace"),
1200 0, B_ENTER, 0, 0, NULL},
1201 {quick_label, 2, CONFIRM_DLG_WIDTH, 2, CONFIRM_DLG_HEIGTH, 0,
1202 0, 0, 0, 0, 0},
1203 {0}};
1205 quick_widgets[5].text = catstrs (_ (" Replace with: "), replace_text, 0);
1208 QuickDialog Quick_input =
1209 {CONFIRM_DLG_WIDTH, CONFIRM_DLG_HEIGTH, 0, 0, N_ (" Confirm replace "),
1210 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1212 Quick_input.widgets = quick_widgets;
1214 Quick_input.xpos = xpos;
1216 /* Sometimes menu can hide replaced text. I don't like it */
1218 if ((edit->curs_row >= ypos) && (edit->curs_row <= ypos + CONFIRM_DLG_HEIGTH))
1219 ypos -= CONFIRM_DLG_HEIGTH;
1221 Quick_input.ypos = ypos;
1222 return quick_dialog (&Quick_input);
1226 void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order)
1228 int treplace_scanf = replace_scanf;
1229 int treplace_regexp = replace_regexp;
1230 int treplace_all = replace_all;
1231 int treplace_prompt = replace_prompt;
1232 int treplace_backwards = replace_backwards;
1233 int treplace_whole = replace_whole;
1234 int treplace_case = replace_case;
1236 char *tsearch_text;
1237 char *treplace_text;
1238 char *targ_order;
1239 QuickWidget quick_widgets[] =
1241 {quick_button, 6, 10, 12, REPLACE_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1242 0, NULL},
1243 {quick_button, 2, 10, 12, REPLACE_DLG_HEIGHT, N_("&Ok"), 0, B_ENTER, 0,
1244 0, NULL},
1245 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1246 0, 0, NULL},
1247 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("replace &All"), 0, 0,
1248 0, 0, NULL},
1249 {quick_checkbox, 33, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("pr&Ompt on replace"), 0, 0,
1250 0, 0, NULL},
1251 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1252 0, 0, NULL},
1253 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1254 0, 0, NULL},
1255 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1256 0, 0, NULL},
1257 {quick_checkbox, 4, REPLACE_DLG_WIDTH, 8, REPLACE_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1258 0, 0, NULL},
1259 {quick_input, 3, REPLACE_DLG_WIDTH, 7, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1260 0, "edit-argord"},
1261 {quick_label, 2, REPLACE_DLG_WIDTH, 6, REPLACE_DLG_HEIGHT, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1262 0, 0, 0},
1263 {quick_input, 3, REPLACE_DLG_WIDTH, 5, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1264 0, "edit-replace"},
1265 {quick_label, 2, REPLACE_DLG_WIDTH, 4, REPLACE_DLG_HEIGHT, N_(" Enter replacement string:"), 0, 0, 0,
1266 0, 0},
1267 {quick_input, 3, REPLACE_DLG_WIDTH, 3, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
1268 0, "edit-search"},
1269 {quick_label, 2, REPLACE_DLG_WIDTH, 2, REPLACE_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1270 0, 0},
1271 {0}};
1273 quick_widgets[2].result = &treplace_scanf;
1274 quick_widgets[3].result = &treplace_all;
1275 quick_widgets[4].result = &treplace_prompt;
1276 quick_widgets[5].result = &treplace_backwards;
1277 quick_widgets[6].result = &treplace_regexp;
1278 quick_widgets[7].result = &treplace_whole;
1279 quick_widgets[8].result = &treplace_case;
1280 quick_widgets[9].str_result = &targ_order;
1281 quick_widgets[9].text = *arg_order;
1282 quick_widgets[11].str_result = &treplace_text;
1283 quick_widgets[11].text = *replace_text;
1284 quick_widgets[13].str_result = &tsearch_text;
1285 quick_widgets[13].text = *search_text;
1287 QuickDialog Quick_input =
1288 {REPLACE_DLG_WIDTH, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "),
1289 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1291 Quick_input.widgets = quick_widgets;
1293 if (quick_dialog (&Quick_input) != B_CANCEL) {
1294 *arg_order = *(quick_widgets[INPUT_INDEX].str_result);
1295 *replace_text = *(quick_widgets[INPUT_INDEX + 2].str_result);
1296 *search_text = *(quick_widgets[INPUT_INDEX + 4].str_result);
1297 replace_scanf = treplace_scanf;
1298 replace_backwards = treplace_backwards;
1299 replace_regexp = treplace_regexp;
1300 replace_all = treplace_all;
1301 replace_prompt = treplace_prompt;
1302 replace_whole = treplace_whole;
1303 replace_case = treplace_case;
1304 return;
1305 } else {
1306 *arg_order = NULL;
1307 *replace_text = NULL;
1308 *search_text = NULL;
1309 return;
1315 void edit_search_dialog (WEdit * edit, char **search_text)
1317 int treplace_scanf = replace_scanf;
1318 int treplace_regexp = replace_regexp;
1319 int treplace_whole = replace_whole;
1320 int treplace_case = replace_case;
1321 int treplace_backwards = replace_backwards;
1323 char *tsearch_text;
1324 QuickWidget quick_widgets[] =
1326 {quick_button, 6, 10, 7, SEARCH_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
1327 0, NULL},
1328 {quick_button, 2, 10, 7, SEARCH_DLG_HEIGHT, N_("&Ok"), 0, B_ENTER, 0,
1329 0, NULL},
1330 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
1331 0, 0, NULL },
1332 {quick_checkbox, 33, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Backwards"), 0, 0,
1333 0, 0, NULL},
1334 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
1335 0, 0, NULL},
1336 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
1337 0, 0, NULL},
1338 {quick_checkbox, 4, SEARCH_DLG_WIDTH, 4, SEARCH_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
1339 0, 0, NULL},
1340 {quick_input, 3, SEARCH_DLG_WIDTH, 3, SEARCH_DLG_HEIGHT, "", 52, 0, 0,
1341 0, "edit-search"},
1342 {quick_label, 2, SEARCH_DLG_WIDTH, 2, SEARCH_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
1343 0, 0},
1344 {0}};
1346 quick_widgets[2].result = &treplace_scanf;
1347 quick_widgets[3].result = &treplace_backwards;
1348 quick_widgets[4].result = &treplace_regexp;
1349 quick_widgets[5].result = &treplace_whole;
1350 quick_widgets[6].result = &treplace_case;
1351 quick_widgets[7].str_result = &tsearch_text;
1352 quick_widgets[7].text = *search_text;
1355 QuickDialog Quick_input =
1356 {SEARCH_DLG_WIDTH, SEARCH_DLG_HEIGHT, -1, 0, N_(" Search "),
1357 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1359 Quick_input.widgets = quick_widgets;
1361 if (quick_dialog (&Quick_input) != B_CANCEL) {
1362 *search_text = *(quick_widgets[7].str_result);
1363 replace_scanf = treplace_scanf;
1364 replace_backwards = treplace_backwards;
1365 replace_regexp = treplace_regexp;
1366 replace_whole = treplace_whole;
1367 replace_case = treplace_case;
1368 return;
1369 } else {
1370 *search_text = NULL;
1371 return;
1376 #else
1378 #define B_ENTER 0
1379 #define B_SKIP_REPLACE 1
1380 #define B_REPLACE_ALL 2
1381 #define B_REPLACE_ONE 3
1382 #define B_CANCEL 4
1384 extern CWidget *wedit;
1386 #ifndef GTK
1388 void edit_search_replace_dialog (Window parent, int x, int y, char **search_text, char **replace_text, char **arg_order, char *heading, int option)
1390 Window win;
1391 XEvent xev;
1392 CEvent cev;
1393 CState s;
1394 int xh, yh, h, xb, ys, yc, yb, yr;
1395 CWidget *m;
1396 int text_input_width ;
1398 CBackupState (&s);
1399 CDisable ("*");
1401 win = CDrawHeadedDialog ("replace", parent, x, y, heading);
1402 CGetHintPos (&xh, &h);
1403 #ifdef NEXT_LOOK
1404 xh += NEXT_SPACING ;
1405 #endif
1407 /* NLS hotkey ? */
1408 CIdent ("replace")->position = WINDOW_ALWAYS_RAISED;
1409 /* An input line comes after the ':' */
1410 (CDrawText ("replace.t1", win, xh, h, _(" Enter search text : ")))->hotkey = 'E';
1412 CGetHintPos (0, &yh);
1413 (m = CDrawTextInput ("replace.sinp", win, xh, yh, 10, AUTO_HEIGHT, 8192, *search_text))->hotkey = 'E';
1415 if (replace_text) {
1416 CGetHintPos (0, &yh);
1417 (CDrawText ("replace.t2", win, xh, yh, _(" Enter replace text : ")))->hotkey = 'n';
1418 CGetHintPos (0, &yh);
1419 (CDrawTextInput ("replace.rinp", win, xh, yh, 10, AUTO_HEIGHT, 8192, *replace_text))->hotkey = 'n';
1420 CSetToolHint ("replace.t2", _("You can enter regexp substrings with %s\n(not \\1, \\2 like sed) then use \"Enter...order\""));
1421 CSetToolHint ("replace.rinp", _("You can enter regexp substrings with %s\n(not \\1, \\2 like sed) then use \"Enter...order\""));
1422 CGetHintPos (0, &yh);
1423 (CDrawText ("replace.t3", win, xh, yh, _(" Enter argument (or substring) order : ")))->hotkey = 'o';
1424 CGetHintPos (0, &yh);
1425 (CDrawTextInput ("replace.ainp", win, xh, yh, 10, AUTO_HEIGHT, 256, *arg_order))->hotkey = 'o';
1426 /* Tool hint */
1427 CSetToolHint ("replace.ainp", _("Enter the order of replacement of your scanf\nformat specifiers or regexp substrings, eg 3,1,2"));
1428 CSetToolHint ("replace.t3", _("Enter the order of replacement of your scanf\nformat specifiers or regexp substrings, eg 3,1,2"));
1430 CGetHintPos (0, &yh);
1431 ys = yh;
1432 /* The following are check boxes */
1433 CDrawSwitch ("replace.ww", win, xh, yh, replace_whole, _(" Whole words only "), 0);
1434 CGetHintPos (0, &yh);
1435 CDrawSwitch ("replace.case", win, xh, yh, replace_case, _(" Case sensitive "), 0);
1436 yc = yh;
1437 CGetHintPos (0, &yh);
1438 CDrawSwitch ("replace.reg", win, xh, yh, replace_regexp, _(" Regular expression "), 1);
1439 CSetToolHint ("replace.reg", _("See the regex man page for how\nto compose a regular expression"));
1440 CSetToolHint ("replace.reg.label", _("See the regex man page for how\nto compose a regular expression"));
1441 yb = yh;
1442 CGetHintPos (0, &yh);
1443 CGetHintPos (&xb, 0);
1444 #ifdef NEXT_LOOK
1445 xb += NEXT_SPACING ;
1446 #endif
1447 if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
1448 CDrawSwitch ("replace.bkwd", win, xh, yh, replace_backwards, _(" Backwards "), 0);
1449 /* Tool hint */
1450 CSetToolHint ("replace.bkwd", _("Warning: Searching backward can be slow"));
1451 CSetToolHint ("replace.bkwd.label", _("Warning: Searching backward can be slow"));
1453 if (replace_text) {
1454 yr = ys;
1455 if (option & SEARCH_DIALOG_OPTION_BACKWARDS)
1456 yr = yc;
1457 } else {
1458 if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
1459 if (option & SEARCH_DIALOG_OPTION_BOOKMARK)
1460 yr = yb;
1461 else
1462 yr = yh;
1463 } else {
1464 if (option & SEARCH_DIALOG_OPTION_BOOKMARK)
1465 yr = yc;
1466 else
1467 yr = yb;
1471 if (replace_text) {
1472 CDrawSwitch ("replace.pr", win, xb, yr, replace_prompt, _(" Prompt on replace "), 0);
1473 /* Tool hint */
1474 CSetToolHint ("replace.pr", _("Ask before making each replacement"));
1475 CGetHintPos (0, &yr);
1476 CDrawSwitch ("replace.all", win, xb, yr, replace_all, _(" Replace all "), 0);
1477 /* Tool hint */
1478 CSetToolHint ("replace.all", _("Replace repeatedly"));
1479 CGetHintPos (0, &yr);
1481 if (option & SEARCH_DIALOG_OPTION_BOOKMARK) {
1482 CDrawSwitch ("replace.bkmk", win, xb, yr, search_create_bookmark, _(" Bookmarks "), 0);
1483 /* Tool hint */
1484 CSetToolHint ("replace.bkmk", _("Create bookmarks at all lines found"));
1485 CSetToolHint ("replace.bkmk.label", _("Create bookmarks at all lines found"));
1486 CGetHintPos (0, &yr);
1488 CDrawSwitch ("replace.scanf", win, xb, yr, replace_scanf, _(" Scanf expression "), 1);
1489 /* Tool hint */
1490 CSetToolHint ("replace.scanf", _("Allows entering of a C format string,\nsee the scanf man page"));
1492 get_hint_limits (&x, &y);
1493 #ifdef NEXT_LOOK
1495 int btn_width, x, y ;
1496 CGetHintPos (&x, &y);
1498 y += NEXT_SPACING * 2 ;
1499 x += NEXT_SPACING * 2 ;
1500 CTextSize (&btn_width, 0, " Cancel ");
1501 btn_width += 4 + BUTTON_RELIEF * 2;
1502 x -= (btn_width + NEXT_SPACING) * 2 + NEXT_SPACING;
1504 CDrawButton ("replace.ok", win, x+btn_width + NEXT_SPACING * 2, y, AUTO_WIDTH, AUTO_HEIGHT, " Ok ");
1505 CDrawButton ("replace.cancel", win, x, y, AUTO_WIDTH, AUTO_HEIGHT, " Cancel ");
1506 CGetHintPos (0, &y);
1507 x += (btn_width + NEXT_SPACING) * 2 + NEXT_SPACING;
1508 reset_hint_pos (x, y + NEXT_SPACING*2);
1510 #else
1511 CDrawPixmapButton ("replace.ok", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h, PIXMAP_BUTTON_TICK);
1512 CDrawPixmapButton ("replace.cancel", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h + WIDGET_SPACING + TICK_BUTTON_WIDTH, PIXMAP_BUTTON_CROSS);
1513 #endif
1514 /* Tool hint */
1515 CSetToolHint ("replace.ok", _("Begin search, Enter"));
1516 CSetToolHint ("replace.cancel", _("Abort this dialog, Esc"));
1517 CSetSizeHintPos ("replace");
1518 CMapDialog ("replace");
1520 m = CIdent ("replace");
1521 #ifdef NEXT_LOOK
1522 text_input_width = m->width - WIDGET_SPACING * 3 - 4 - NEXT_SPACING*2 ;
1523 #else
1524 text_input_width = m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH ;
1525 #endif
1526 CSetWidgetSize ("replace.sinp", text_input_width, (CIdent ("replace.sinp"))->height);
1527 if (replace_text) {
1528 CSetWidgetSize ("replace.rinp", text_input_width, (CIdent ("replace.rinp"))->height);
1529 CSetWidgetSize ("replace.ainp", text_input_width, (CIdent ("replace.ainp"))->height);
1531 CFocus (CIdent ("replace.sinp"));
1533 for (;;) {
1534 CNextEvent (&xev, &cev);
1535 if (!CIdent ("replace")) {
1536 *search_text = 0;
1537 break;
1539 if (!strcmp (cev.ident, "replace.cancel") || cev.command == CK_Cancel) {
1540 *search_text = 0;
1541 break;
1543 if (!strcmp (cev.ident, "replace.reg") || !strcmp (cev.ident, "replace.scanf")) {
1544 if (CIdent ("replace.reg")->keypressed || CIdent ("replace.scanf")->keypressed) {
1545 if (!(CIdent ("replace.case")->keypressed)) {
1546 CIdent ("replace.case")->keypressed = 1;
1547 CExpose ("replace.case");
1551 if (!strcmp (cev.ident, "replace.ok") || cev.command == CK_Enter) {
1552 if (replace_text) {
1553 replace_all = CIdent ("replace.all")->keypressed;
1554 replace_prompt = CIdent ("replace.pr")->keypressed;
1555 *replace_text = (char *) strdup (CIdent ("replace.rinp")->text);
1556 *arg_order = (char *) strdup (CIdent ("replace.ainp")->text);
1558 *search_text = (char *) strdup (CIdent ("replace.sinp")->text);
1559 replace_whole = CIdent ("replace.ww")->keypressed;
1560 replace_case = CIdent ("replace.case")->keypressed;
1561 replace_scanf = CIdent ("replace.scanf")->keypressed;
1562 replace_regexp = CIdent ("replace.reg")->keypressed;
1564 if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
1565 replace_backwards = CIdent ("replace.bkwd")->keypressed;
1566 } else {
1567 replace_backwards = 0;
1570 if (option & SEARCH_DIALOG_OPTION_BOOKMARK) {
1571 search_create_bookmark = CIdent ("replace.bkmk")->keypressed;
1572 } else {
1573 search_create_bookmark = 0;
1576 break;
1579 CDestroyWidget ("replace");
1580 CRestoreState (&s);
1583 void edit_search_dialog (WEdit * edit, char **search_text)
1585 /* Heads the 'Search' dialog box */
1586 edit_search_replace_dialog (WIN_MESSAGES, search_text, 0, 0, _(" Search "), SEARCH_DIALOG_OPTION_BACKWARDS | SEARCH_DIALOG_OPTION_BOOKMARK);
1589 void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order)
1591 /* Heads the 'Replace' dialog box */
1592 edit_search_replace_dialog (WIN_MESSAGES, search_text, replace_text, arg_order, _(" Replace "), SEARCH_DIALOG_OPTION_BACKWARDS);
1595 #else
1597 #include <libgnomeui/gtkcauldron.h>
1598 #include <libgnomeui/gnome-stock.h>
1600 void edit_search_dialog (WEdit * edit, char **search_text)
1602 char *s;
1603 s = gtk_dialog_cauldron (
1604 "Search", GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB,
1605 " ( (Enter search text)d | %Eogxf )xf / ( ( %Cd // %Cd // %Cd ) || ( %Cd // %Cd )xf )xf / ( %Bxfgrq || %Bxfgq )f",
1606 search_text, "search",
1607 "&Whole word", &replace_whole,
1608 "Case &sensitive", &replace_case,
1609 "&Regular expression", &replace_regexp,
1610 "&Backwards", &replace_backwards,
1611 "Scanf &expression", &replace_scanf,
1612 GNOME_STOCK_BUTTON_OK,
1613 GNOME_STOCK_BUTTON_CANCEL
1615 if (s == GTK_CAULDRON_ESCAPE || !s || s == GNOME_STOCK_BUTTON_CANCEL)
1616 *search_text = 0;
1617 return;
1620 void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order)
1622 char *s;
1623 s = gtk_dialog_cauldron (
1624 "Search", GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB,
1625 " ( (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",
1626 search_text, "search",
1627 replace_text, "replace",
1628 arg_order, "arg_order",
1629 "&Whole word", &replace_whole,
1630 "Case &sensitive", &replace_case,
1631 "&Regular expression", &replace_regexp,
1632 "&Backwards", &replace_backwards,
1633 "Pr&ompt on replace", &replace_prompt,
1634 "Replace &all", &replace_all,
1635 "Scanf &expression", &replace_scanf,
1636 GNOME_STOCK_BUTTON_OK,
1637 GNOME_STOCK_BUTTON_CANCEL
1639 if (s == GTK_CAULDRON_ESCAPE || !s || s == GNOME_STOCK_BUTTON_CANCEL)
1640 *search_text = 0;
1641 return;
1644 #endif
1646 #ifdef GTK
1648 int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
1650 char *s;
1651 s = gtk_dialog_cauldron (
1652 "Replace", GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB,
1653 " ( (Replace with:)d %Ld )xf / ( %Bxfrq || %Bxfq || %Bxfq || %Bxfq || %Bxfgq )f",
1654 replace_text,
1655 "Replace", "Skip", "Replace all", "Replace one",
1656 GNOME_STOCK_BUTTON_CANCEL
1658 if (s == GTK_CAULDRON_ESCAPE || !s || s == GNOME_STOCK_BUTTON_CANCEL)
1659 return B_CANCEL;
1660 if (!strcmp (s, "Replace all"))
1661 return B_REPLACE_ALL;
1662 if (!strcmp (s, "Replace one"))
1663 return B_REPLACE_ONE;
1664 if (!strcmp (s, "Skip"))
1665 return B_SKIP_REPLACE;
1666 if (!strcmp (s, "Replace"))
1667 return B_ENTER;
1668 /* Shouldn't ever reach this point */
1669 return B_CANCEL;
1672 #else
1674 int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
1676 int q, x[] =
1678 B_CANCEL, B_ENTER, B_SKIP_REPLACE, B_REPLACE_ALL, B_REPLACE_ONE, B_CANCEL
1680 q = CQueryDialog (WIN_MESSAGES + (edit->curs_line < 8 ? edit->num_widget_lines / 2 * FONT_PIX_PER_LINE + CYof (edit->widget) : 0),
1681 _ (" Replace "), catstrs (_ (" Replace with: "), replace_text, 0), _ ("Replace"), _ ("Skip"), _ ("Replace all"), _ ("Replace one"), _ ("Cancel"), 0);
1682 edit->force |= REDRAW_COMPLETELY;
1683 return x[q + 1];
1686 #endif
1688 #endif
1690 long sargs[NUM_REPL_ARGS][256 / sizeof (long)];
1692 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1693 sargs[4], sargs[5], sargs[6], sargs[7], \
1694 sargs[8], sargs[9], sargs[10], sargs[11], \
1695 sargs[12], sargs[13], sargs[14], sargs[15]
1697 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1698 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1699 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1700 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1703 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1704 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1705 int string_regexp_search (char *pattern, char *string, int len, int match_type, int match_bol, int icase, int *found_len, void *d)
1707 static regex_t r;
1708 static char *old_pattern = NULL;
1709 static int old_type, old_icase;
1710 regmatch_t *pmatch;
1711 static regmatch_t s[1];
1713 pmatch = (regmatch_t *) d;
1714 if (!pmatch)
1715 pmatch = s;
1717 if (!old_pattern || strcmp (old_pattern, pattern) || old_type != match_type || old_icase != icase) {
1718 if (old_pattern) {
1719 regfree (&r);
1720 free (old_pattern);
1721 old_pattern = 0;
1723 if (regcomp (&r, pattern, REG_EXTENDED | (icase ? REG_ICASE : 0))) {
1724 *found_len = 0;
1725 return -3;
1727 old_pattern = (char *) strdup (pattern);
1728 old_type = match_type;
1729 old_icase = icase;
1731 if (regexec (&r, string, d ? NUM_REPL_ARGS : 1, pmatch, ((match_bol || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) {
1732 *found_len = 0;
1733 return -1;
1735 *found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
1736 return (pmatch[0].rm_so);
1739 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1740 (and the above) routines to work properly - paul */
1742 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)
1744 long p, q = 0;
1745 long l = strlen ((char *) exp), f = 0;
1746 int n = 0;
1748 for (p = 0; p < l; p++) /* count conversions... */
1749 if (exp[p] == '%')
1750 if (exp[++p] != '%') /* ...except for "%%" */
1751 n++;
1753 if (replace_scanf || replace_regexp) {
1754 int c;
1755 unsigned char *buf;
1756 unsigned char mbuf[MAX_REPL_LEN * 2 + 3];
1758 replace_scanf = (!replace_regexp); /* can't have both */
1760 buf = mbuf;
1762 if (replace_scanf) {
1763 unsigned char e[MAX_REPL_LEN];
1764 if (n >= NUM_REPL_ARGS)
1765 return -3;
1767 if (replace_case) {
1768 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++)
1769 buf[p - start] = (*get_byte) (data, p);
1770 } else {
1771 for (p = 0; exp[p] != 0; p++)
1772 exp[p] = my_lower_case (exp[p]);
1773 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) {
1774 c = (*get_byte) (data, p);
1775 buf[p - start] = my_lower_case (c);
1779 buf[(q = p - start)] = 0;
1780 strcpy ((char *) e, (char *) exp);
1781 strcat ((char *) e, "%n");
1782 exp = e;
1784 while (q) {
1785 *((int *) sargs[n]) = 0; /* --> here was the problem - now fixed: good */
1786 if (n == sscanf ((char *) buf, (char *) exp, SCANF_ARGS)) {
1787 if (*((int *) sargs[n])) {
1788 *len = *((int *) sargs[n]);
1789 return start;
1792 if (once_only)
1793 return -2;
1794 if (q + start < last_byte) {
1795 if (replace_case) {
1796 buf[q] = (*get_byte) (data, q + start);
1797 } else {
1798 c = (*get_byte) (data, q + start);
1799 buf[q] = my_lower_case (c);
1801 q++;
1803 buf[q] = 0;
1804 start++;
1805 buf++; /* move the window along */
1806 if (buf == mbuf + MAX_REPL_LEN) { /* the window is about to go past the end of array, so... */
1807 memmove (mbuf, buf, strlen ((char *) buf) + 1); /* reset it */
1808 buf = mbuf;
1810 q--;
1812 } else { /* regexp matching */
1813 long offset = 0;
1814 int found_start, match_bol, move_win = 0;
1816 while (start + offset < last_byte) {
1817 match_bol = (offset == 0 || (*get_byte) (data, start + offset - 1) == '\n');
1818 if (!move_win) {
1819 p = start + offset;
1820 q = 0;
1822 for (; p < last_byte && q < MAX_REPL_LEN; p++, q++) {
1823 mbuf[q] = (*get_byte) (data, p);
1824 if (mbuf[q] == '\n')
1825 break;
1827 q++;
1828 offset += q;
1829 mbuf[q] = 0;
1831 buf = mbuf;
1832 while (q) {
1833 found_start = string_regexp_search ((char *) exp, (char *) buf, q, match_normal, match_bol, !replace_case, len, d);
1835 if (found_start <= -2) { /* regcomp/regexec error */
1836 *len = 0;
1837 return -3;
1839 else if (found_start == -1) /* not found: try next line */
1840 break;
1841 else if (*len == 0) { /* null pattern: try again at next character */
1842 q--;
1843 buf++;
1844 match_bol = 0;
1845 continue;
1847 else /* found */
1848 return (start + offset - q + found_start);
1850 if (once_only)
1851 return -2;
1853 if (buf[q - 1] != '\n') { /* incomplete line: try to recover */
1854 buf = mbuf + MAX_REPL_LEN / 2;
1855 q = strlen ((char *) buf);
1856 memmove (mbuf, buf, q);
1857 p = start + q;
1858 move_win = 1;
1860 else
1861 move_win = 0;
1864 } else {
1865 *len = strlen ((char *) exp);
1866 if (replace_case) {
1867 for (p = start; p <= last_byte - l; p++) {
1868 if ((*get_byte) (data, p) == (unsigned char)exp[0]) { /* check if first char matches */
1869 for (f = 0, q = 0; q < l && f < 1; q++)
1870 if ((*get_byte) (data, q + p) != (unsigned char)exp[q])
1871 f = 1;
1872 if (f == 0)
1873 return p;
1875 if (once_only)
1876 return -2;
1878 } else {
1879 for (p = 0; exp[p] != 0; p++)
1880 exp[p] = my_lower_case (exp[p]);
1882 for (p = start; p <= last_byte - l; p++) {
1883 if (my_lower_case ((*get_byte) (data, p)) == (unsigned char)exp[0]) {
1884 for (f = 0, q = 0; q < l && f < 1; q++)
1885 if (my_lower_case ((*get_byte) (data, q + p)) != (unsigned char)exp[q])
1886 f = 1;
1887 if (f == 0)
1888 return p;
1890 if (once_only)
1891 return -2;
1895 return -2;
1899 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)
1900 { /*front end to find_string to check for
1901 whole words */
1902 long p;
1903 p = search_start;
1905 while ((p = edit_find_string (p, exp, len, last_byte, get_byte, data, once_only, d)) >= 0) {
1906 if (replace_whole) {
1907 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1908 if (!strcasechr (option_whole_chars_search, (*get_byte) (data, p - 1))
1909 && !strcasechr (option_whole_chars_search, (*get_byte) (data, p + *len)))
1910 return p;
1911 if (once_only)
1912 return -2;
1913 } else
1914 return p;
1915 if (once_only)
1916 break;
1917 p++; /*not a whole word so continue search. */
1919 return p;
1922 long edit_find (long search_start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, void *d)
1924 long p;
1925 if (replace_backwards) {
1926 while (search_start >= 0) {
1927 p = edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 1, d);
1928 if (p == search_start)
1929 return p;
1930 search_start--;
1932 } else {
1933 return edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 0, d);
1935 return -2;
1938 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1940 #define snprintf(v) { \
1941 *p1++ = *p++; \
1942 *p1++ = '%'; \
1943 *p1++ = 'n'; \
1944 *p1 = '\0'; \
1945 sprintf(s,q1,v,&n); \
1946 s += n; \
1949 /* this function uses the sprintf command to do a vprintf */
1950 /* it takes pointers to arguments instead of the arguments themselves */
1951 int sprintf_p (char *str, const char *fmt,...)
1953 va_list ap;
1954 int n;
1955 char *q, *p, *s = str;
1956 char q1[32];
1957 char *p1;
1959 va_start (ap, fmt);
1960 p = q = (char *) fmt;
1962 while ((p = strchr (p, '%'))) {
1963 n = (int) ((unsigned long) p - (unsigned long) q);
1964 strncpy (s, q, n); /* copy stuff between format specifiers */
1965 s += n;
1966 *s = 0;
1967 q = p;
1968 p1 = q1;
1969 *p1++ = *p++;
1970 if (*p == '%') {
1971 p++;
1972 *s++ = '%';
1973 q = p;
1974 continue;
1976 if (*p == 'n') {
1977 p++;
1978 /* do nothing */
1979 q = p;
1980 continue;
1982 if (*p == '#')
1983 *p1++ = *p++;
1984 if (*p == '0')
1985 *p1++ = *p++;
1986 if (*p == '-')
1987 *p1++ = *p++;
1988 if (*p == '+')
1989 *p1++ = *p++;
1990 if (*p == '*') {
1991 p++;
1992 strcpy (p1, itoa (*va_arg (ap, int *))); /* replace field width with a number */
1993 p1 += strlen (p1);
1994 } else {
1995 while (is_digit (*p))
1996 *p1++ = *p++;
1998 if (*p == '.')
1999 *p1++ = *p++;
2000 if (*p == '*') {
2001 p++;
2002 strcpy (p1, itoa (*va_arg (ap, int *))); /* replace precision with a number */
2003 p1 += strlen (p1);
2004 } else {
2005 while (is_digit (*p))
2006 *p1++ = *p++;
2008 /* flags done, now get argument */
2009 if (*p == 's') {
2010 snprintf (va_arg (ap, char *));
2011 } else if (*p == 'h') {
2012 if (strchr ("diouxX", *p))
2013 snprintf (*va_arg (ap, short *));
2014 } else if (*p == 'l') {
2015 *p1++ = *p++;
2016 if (strchr ("diouxX", *p))
2017 snprintf (*va_arg (ap, long *));
2018 } else if (strchr ("cdiouxX", *p)) {
2019 snprintf (*va_arg (ap, int *));
2020 } else if (*p == 'L') {
2021 *p1++ = *p++;
2022 if (strchr ("EefgG", *p))
2023 snprintf (*va_arg (ap, double *)); /* should be long double */
2024 } else if (strchr ("EefgG", *p)) {
2025 snprintf (*va_arg (ap, double *));
2026 } else if (strchr ("DOU", *p)) {
2027 snprintf (*va_arg (ap, long *));
2028 } else if (*p == 'p') {
2029 snprintf (*va_arg (ap, void **));
2031 q = p;
2033 va_end (ap);
2034 sprintf (s, q); /* print trailing leftover */
2035 return (unsigned long) s - (unsigned long) str + strlen (s);
2038 static void regexp_error (WEdit *edit)
2040 /* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */
2041 edit_error_dialog (_(" Error "), _(" Invalid regular expression, or scanf expression with to many conversions "));
2044 /* call with edit = 0 before shutdown to close memory leaks */
2045 void edit_replace_cmd (WEdit * edit, int again)
2047 static regmatch_t pmatch[NUM_REPL_ARGS];
2048 static char *old1 = NULL;
2049 static char *old2 = NULL;
2050 static char *old3 = NULL;
2051 char *exp1 = "";
2052 char *exp2 = "";
2053 char *exp3 = "";
2054 int replace_yes;
2055 int replace_continue;
2056 int treplace_prompt = 0;
2057 int i = 0;
2058 long times_replaced = 0, last_search;
2059 char fin_string[64];
2060 int argord[NUM_REPL_ARGS];
2062 if (!edit) {
2063 if (old1) {
2064 free (old1);
2065 old1 = 0;
2067 if (old2) {
2068 free (old2);
2069 old2 = 0;
2071 if (old3) {
2072 free (old3);
2073 old3 = 0;
2075 return;
2077 last_search = edit->last_byte;
2079 edit->force |= REDRAW_COMPLETELY;
2081 exp1 = old1 ? old1 : exp1;
2082 exp2 = old2 ? old2 : exp2;
2083 exp3 = old3 ? old3 : exp3;
2085 if (again) {
2086 if (!old1 || !old2)
2087 return;
2088 exp1 = (char *) strdup (old1);
2089 exp2 = (char *) strdup (old2);
2090 exp3 = (char *) strdup (old3);
2091 } else {
2092 edit_push_action (edit, KEY_PRESS + edit->start_display);
2093 edit_replace_dialog (edit, &exp1, &exp2, &exp3);
2094 treplace_prompt = replace_prompt;
2097 if (!exp1 || !*exp1) {
2098 edit->force = REDRAW_COMPLETELY;
2099 if (exp1) {
2100 free (exp1);
2101 free (exp2);
2102 free (exp3);
2104 return;
2106 if (old1)
2107 free (old1);
2108 if (old2)
2109 free (old2);
2110 if (old3)
2111 free (old3);
2112 old1 = (char *) strdup (exp1);
2113 old2 = (char *) strdup (exp2);
2114 old3 = (char *) strdup (exp3);
2117 char *s;
2118 int ord;
2119 while ((s = strchr (exp3, ' ')))
2120 memmove (s, s + 1, strlen (s));
2121 s = exp3;
2122 for (i = 0; i < NUM_REPL_ARGS; i++) {
2123 if ((unsigned long) s != 1 && s < exp3 + strlen (exp3)) {
2124 if ((ord = atoi (s)))
2125 argord[i] = ord - 1;
2126 else
2127 argord[i] = i;
2128 s = strchr (s, ',') + 1;
2129 } else
2130 argord[i] = i;
2134 replace_continue = replace_all;
2136 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
2137 edit->search_start--;
2139 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
2140 edit->search_start++;
2142 do {
2143 int len = 0;
2144 long new_start;
2145 new_start = edit_find (edit->search_start, (unsigned char *) exp1, &len, last_search,
2146 (int (*)(void *, long)) edit_get_byte, (void *) edit, pmatch);
2147 if (new_start == -3) {
2148 regexp_error (edit);
2149 break;
2151 edit->search_start = new_start;
2152 /*returns negative on not found or error in pattern */
2154 if (edit->search_start >= 0) {
2155 edit->found_start = edit->search_start;
2156 i = edit->found_len = len;
2158 edit_cursor_move (edit, edit->search_start - edit->curs1);
2159 edit_scroll_screen_over_cursor (edit);
2161 replace_yes = 1;
2163 if (treplace_prompt) {
2164 int l;
2165 l = edit->curs_row - edit->num_widget_lines / 3;
2166 if (l > 0)
2167 edit_scroll_downward (edit, l);
2168 if (l < 0)
2169 edit_scroll_upward (edit, -l);
2171 edit_scroll_screen_over_cursor (edit);
2172 edit->force |= REDRAW_PAGE;
2173 edit_render_keypress (edit);
2175 /*so that undo stops at each query */
2176 edit_push_key_press (edit);
2178 switch (edit_replace_prompt (edit, exp2, /*and prompt 2/3 down */
2179 #ifdef MIDNIGHT
2180 (edit->num_widget_columns - CONFIRM_DLG_WIDTH)/2, edit->num_widget_lines * 2 / 3)) {
2181 #else
2182 edit->num_widget_columns / 2 - 33, edit->num_widget_lines * 2 / 3)) {
2183 #endif
2184 case B_ENTER:
2185 break;
2186 case B_SKIP_REPLACE:
2187 replace_yes = 0;
2188 break;
2189 case B_REPLACE_ALL:
2190 treplace_prompt = 0;
2191 replace_continue = 1;
2192 break;
2193 case B_REPLACE_ONE:
2194 replace_continue = 0;
2195 break;
2196 case B_CANCEL:
2197 replace_yes = 0;
2198 replace_continue = 0;
2199 break;
2202 if (replace_yes) { /* delete then insert new */
2203 if (replace_scanf || replace_regexp) {
2204 char repl_str[MAX_REPL_LEN + 2];
2205 if (replace_regexp) { /* we need to fill in sargs just like with scanf */
2206 int k, j;
2207 for (k = 1; k < NUM_REPL_ARGS && pmatch[k].rm_eo >= 0; k++) {
2208 unsigned char *t;
2209 t = (unsigned char *) &sargs[k - 1][0];
2210 for (j = 0; j < pmatch[k].rm_eo - pmatch[k].rm_so && j < 255; j++, t++)
2211 *t = (unsigned char) edit_get_byte (edit, edit->search_start - pmatch[0].rm_so + pmatch[k].rm_so + j);
2212 *t = '\0';
2214 for (; k <= NUM_REPL_ARGS; k++)
2215 sargs[k - 1][0] = 0;
2217 if (sprintf_p (repl_str, exp2, PRINTF_ARGS) >= 0) {
2218 times_replaced++;
2219 while (i--)
2220 edit_delete (edit);
2221 while (repl_str[++i])
2222 edit_insert (edit, repl_str[i]);
2223 } else {
2224 edit_error_dialog (_ (" Replace "),
2225 /* "Invalid regexp string or scanf string" */
2226 _ (" Error in replacement format string. "));
2227 replace_continue = 0;
2229 } else {
2230 times_replaced++;
2231 while (i--)
2232 edit_delete (edit);
2233 while (exp2[++i])
2234 edit_insert (edit, exp2[i]);
2236 edit->found_len = i;
2238 /* so that we don't find the same string again */
2239 if (replace_backwards) {
2240 last_search = edit->search_start;
2241 edit->search_start--;
2242 } else {
2243 edit->search_start += i;
2244 last_search = edit->last_byte;
2246 edit_scroll_screen_over_cursor (edit);
2247 } else {
2248 edit->search_start = edit->curs1; /* try and find from right here for next search */
2249 edit_update_curs_col (edit);
2251 edit->force |= REDRAW_PAGE;
2252 edit_render_keypress (edit);
2253 if (times_replaced) {
2254 sprintf (fin_string, _ (" %ld replacements made. "), times_replaced);
2255 edit_message_dialog (_ (" Replace "), fin_string);
2256 } else
2257 edit_message_dialog (_ (" Replace "), _ (" Search string not found. "));
2258 replace_continue = 0;
2260 } while (replace_continue);
2262 free (exp1);
2263 free (exp2);
2264 free (exp3);
2265 edit->force = REDRAW_COMPLETELY;
2266 edit_scroll_screen_over_cursor (edit);
2272 void edit_search_cmd (WEdit * edit, int again)
2274 static char *old = NULL;
2275 char *exp = "";
2277 if (!edit) {
2278 if (old) {
2279 free (old);
2280 old = 0;
2282 return;
2284 exp = old ? old : exp;
2285 if (again) { /*ctrl-hotkey for search again. */
2286 if (!old)
2287 return;
2288 exp = (char *) strdup (old);
2289 } else {
2290 edit_search_dialog (edit, &exp);
2291 edit_push_action (edit, KEY_PRESS + edit->start_display);
2294 if (exp) {
2295 if (*exp) {
2296 int len = 0;
2297 if (old)
2298 free (old);
2299 old = (char *) strdup (exp);
2301 if (search_create_bookmark) {
2302 int found = 0, books = 0;
2303 int l = 0, l_last = -1;
2304 long p, q = 0;
2305 for (;;) {
2306 p = edit_find (q, (unsigned char *) exp, &len, edit->last_byte,
2307 (int (*)(void *, long)) edit_get_byte, (void *) edit, 0);
2308 if (p < 0)
2309 break;
2310 found++;
2311 l += edit_count_lines (edit, q, p);
2312 if (l != l_last) {
2313 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
2314 books++;
2316 l_last = l;
2317 q = p + 1;
2319 if (found) {
2320 char fin_string[64];
2321 /* in response to number of bookmarks added because of string being found %d times */
2322 sprintf (fin_string, _ (" %d finds made, %d bookmarks added "), found, books);
2323 edit_message_dialog (_ (" Search "), fin_string);
2324 } else {
2325 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
2327 } else {
2329 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
2330 edit->search_start--;
2332 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
2333 edit->search_start++;
2335 edit->search_start = edit_find (edit->search_start, (unsigned char *) exp, &len, edit->last_byte,
2336 (int (*)(void *, long)) edit_get_byte, (void *) edit, 0);
2338 if (edit->search_start >= 0) {
2339 edit->found_start = edit->search_start;
2340 edit->found_len = len;
2342 edit_cursor_move (edit, edit->search_start - edit->curs1);
2343 edit_scroll_screen_over_cursor (edit);
2344 if (replace_backwards)
2345 edit->search_start--;
2346 else
2347 edit->search_start++;
2348 } else if (edit->search_start == -3) {
2349 edit->search_start = edit->curs1;
2350 regexp_error (edit);
2351 } else {
2352 edit->search_start = edit->curs1;
2353 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
2357 free (exp);
2359 edit->force |= REDRAW_COMPLETELY;
2360 edit_scroll_screen_over_cursor (edit);
2364 /* Real edit only */
2365 void edit_quit_cmd (WEdit * edit)
2367 edit_push_action (edit, KEY_PRESS + edit->start_display);
2369 #ifndef MIDNIGHT
2370 if (edit->stopped)
2371 return;
2372 #endif
2374 edit->force |= REDRAW_COMPLETELY;
2375 if (edit->modified) {
2376 #ifdef GTK
2377 char *r;
2378 r = gtk_dialog_cauldron (_ (" Quit "), GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB, " [ ( %Lxf )xf ]xf / ( %Bgxfq || %Bgxfq || %Bgxfq ) ",
2379 _ (" Current text was modified without a file save. \n Save with exit? "), GNOME_STOCK_BUTTON_CANCEL, GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO);
2380 if (!strcmp (r, GNOME_STOCK_BUTTON_YES)) {
2381 edit_push_markers (edit);
2382 edit_set_markers (edit, 0, 0, 0, 0);
2383 if (!edit_save_cmd (edit))
2384 return;
2385 } else if (!strcmp (r, GNOME_STOCK_BUTTON_NO)) {
2386 if (edit->delete_file)
2387 unlink (catstrs (edit->dir, edit->filename, 0));
2388 } else {
2389 return;
2391 #else
2392 #ifdef MIDNIGHT
2393 switch (edit_query_dialog3 (_ (" Quit "), _ (" File was modified, Save with exit? "), _ ("Cancel quit"), _ ("&Yes"), _ ("&No"))) {
2394 #else
2395 /* Confirm 'Quit' dialog box */
2396 switch (edit_query_dialog3 (_ (" Quit "),
2397 _ (" Current text was modified without a file save. \n Save with exit? "), _ (" &Cancel quit "), _ (" &Yes "), _ (" &No "))) {
2398 #endif
2399 case 1:
2400 edit_push_markers (edit);
2401 edit_set_markers (edit, 0, 0, 0, 0);
2402 if (!edit_save_cmd (edit))
2403 return;
2404 break;
2405 case 2:
2406 #ifdef MIDNIGHT
2407 if (edit->delete_file)
2408 unlink (catstrs (edit->dir, edit->filename, 0));
2409 #endif
2410 break;
2411 case 0:
2412 case -1:
2413 return;
2415 #endif
2417 #if defined(MIDNIGHT) || defined(GTK)
2418 else if (edit->delete_file)
2419 unlink (catstrs (edit->dir, edit->filename, 0));
2420 #endif
2421 #ifdef MIDNIGHT
2422 dlg_stop (edit->widget.parent);
2423 #else
2424 #ifdef GTK
2426 extern char *edit_one_file;
2428 if (edit_one_file)
2429 gtk_main_quit ();
2431 #endif
2432 edit->stopped = 1;
2433 #endif
2436 #define TEMP_BUF_LEN 1024
2438 /* returns a null terminated length of text. Result must be free'd */
2439 unsigned char *edit_get_block (WEdit * edit, long start, long finish, int *l)
2441 unsigned char *s, *r;
2442 r = s = malloc (finish - start + 1);
2443 if (column_highlighting) {
2444 *l = 0;
2445 while (start < finish) { /* copy from buffer, excluding chars that are out of the column 'margins' */
2446 int c, x;
2447 x = edit_move_forward3 (edit, edit_bol (edit, start), 0, start);
2448 c = edit_get_byte (edit, start);
2449 if ((x >= edit->column1 && x < edit->column2)
2450 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
2451 *s++ = c;
2452 (*l)++;
2454 start++;
2456 } else {
2457 *l = finish - start;
2458 while (start < finish)
2459 *s++ = edit_get_byte (edit, start++);
2461 *s = 0;
2462 return r;
2465 /* save block, returns 1 on success */
2466 int edit_save_block (WEdit * edit, const char *filename, long start, long finish)
2468 int len, file;
2470 if ((file = open ((char *) filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
2471 return 0;
2473 if (column_highlighting) {
2474 unsigned char *block, *p;
2475 int r;
2476 p = block = edit_get_block (edit, start, finish, &len);
2477 while (len) {
2478 r = write (file, p, len);
2479 if (r < 0)
2480 break;
2481 p += r;
2482 len -= r;
2484 free (block);
2485 } else {
2486 unsigned char *buf;
2487 int i = start, end;
2488 len = finish - start;
2489 buf = malloc (TEMP_BUF_LEN);
2490 while (start != finish) {
2491 end = min (finish, start + TEMP_BUF_LEN);
2492 for (; i < end; i++)
2493 buf[i - start] = edit_get_byte (edit, i);
2494 len -= write (file, (char *) buf, end - start);
2495 start = end;
2497 free (buf);
2499 close (file);
2500 if (len)
2501 return 0;
2502 return 1;
2505 /* copies a block to clipboard file */
2506 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
2508 return edit_save_block (edit, catstrs (home_dir, CLIP_FILE, 0), start, finish);
2511 #ifndef MIDNIGHT
2513 void paste_text (WEdit * edit, unsigned char *data, unsigned int nitems)
2515 if (data) {
2516 data += nitems - 1;
2517 while (nitems--)
2518 edit_insert_ahead (edit, *data--);
2520 edit->force |= REDRAW_COMPLETELY;
2523 char *selection_get_line (void *data, int line)
2525 static unsigned char t[1024];
2526 struct selection *s;
2527 int i = 0;
2528 s = (struct selection *) data;
2529 line = (current_selection + line + 1) % NUM_SELECTION_HISTORY;
2530 if (s[line].text) {
2531 unsigned char *p = s[line].text;
2532 int c, j;
2533 for (j = 0; j < s[line].len; j++) {
2534 c = *p++;
2535 if (!isprint (c)) {
2536 t[i++] = '_';
2537 t[i++] = '\b';
2538 t[i++] = '\\';
2539 t[i++] = '_';
2540 t[i++] = '\b';
2541 switch (c) {
2542 case '\a':
2543 t[i++] = 'a';
2544 break;
2545 case '\b':
2546 t[i++] = 'b';
2547 break;
2548 case '\t':
2549 t[i++] = 't';
2550 break;
2551 case '\n':
2552 t[i++] = 'n';
2553 break;
2554 case '\v':
2555 t[i++] = 'v';
2556 break;
2557 case '\f':
2558 t[i++] = 'f';
2559 break;
2560 case '\r':
2561 t[i++] = 'r';
2562 break;
2563 default:
2564 i -= 3;
2565 t[i++] = '.';
2566 break;
2568 } else
2569 t[i++] = c;
2570 if (i > 1000)
2571 break;
2574 t[i] = 0;
2575 return (char *) t;
2578 void edit_paste_from_history (WEdit * edit)
2580 int i, c;
2582 edit_update_curs_col (edit);
2583 edit_update_curs_row (edit);
2585 c = max (20, edit->num_widget_columns - 5);
2587 #ifdef GTK
2588 #if 0
2589 /* *** */
2590 i = gtk_edit_list_box_dialog (c, 10,
2591 0, NUM_SELECTION_HISTORY - 10, NUM_SELECTION_HISTORY - 1, NUM_SELECTION_HISTORY,
2592 selection_get_line, (void *) selection_history);
2593 #else
2594 i = -1;
2595 #endif
2596 #else
2597 i = CListboxDialog (WIN_MESSAGES, c, 10,
2598 0, NUM_SELECTION_HISTORY - 10, NUM_SELECTION_HISTORY - 1, NUM_SELECTION_HISTORY,
2599 selection_get_line, (void *) selection_history);
2600 #endif
2602 if (i < 0)
2603 return;
2605 i = (current_selection + i + 1) % NUM_SELECTION_HISTORY;
2607 paste_text (edit, selection_history[i].text, selection_history[i].len);
2608 edit->force |= REDRAW_COMPLETELY;
2611 /* copies a block to the XWindows buffer */
2612 static int edit_XStore_block (WEdit * edit, long start, long finish)
2614 edit_get_selection (edit);
2615 if (selection.len <= 512 * 1024) { /* we don't want to fill up the server */
2616 XStoreBytes (CDisplay, (char *) selection.text, (int) selection.len);
2617 return 0;
2618 } else
2619 return 1;
2622 int edit_copy_to_X_buf_cmd (WEdit * edit)
2624 long start_mark, end_mark;
2625 if (eval_marks (edit, &start_mark, &end_mark))
2626 return 0;
2627 edit_XStore_block (edit, start_mark, end_mark);
2628 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2629 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2630 return 1;
2632 #ifdef GTK
2633 gtk_selection_owner_set (GTK_WIDGET (edit->widget), GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
2634 edit->widget->editable.selection_start_pos = start_mark;
2635 edit->widget->editable.selection_end_pos = end_mark;
2636 edit->widget->editable.has_selection = TRUE;
2637 #else
2638 XSetSelectionOwner (CDisplay, XA_PRIMARY, CWindowOf (edit->widget), CurrentTime);
2639 #endif
2640 edit_mark_cmd (edit, 1);
2641 return 0;
2644 int edit_cut_to_X_buf_cmd (WEdit * edit)
2646 long start_mark, end_mark;
2647 if (eval_marks (edit, &start_mark, &end_mark))
2648 return 0;
2649 edit_XStore_block (edit, start_mark, end_mark);
2650 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2651 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2652 return 1;
2654 edit_block_delete_cmd (edit);
2655 #ifdef GTK
2656 gtk_selection_owner_set (GTK_WIDGET (edit->widget), GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
2657 edit->widget->editable.selection_start_pos = start_mark;
2658 edit->widget->editable.selection_end_pos = end_mark;
2659 edit->widget->editable.has_selection = TRUE;
2660 #else
2661 XSetSelectionOwner (CDisplay, XA_PRIMARY, CWindowOf (edit->widget), CurrentTime);
2662 #endif
2663 edit_mark_cmd (edit, 1);
2664 return 0;
2667 void selection_paste (WEdit * edit, Window win, unsigned prop, int delete);
2669 void edit_paste_from_X_buf_cmd (WEdit * edit)
2671 if (selection.text)
2672 paste_text (edit, selection.text, selection.len);
2673 else if (!XGetSelectionOwner (CDisplay, XA_PRIMARY))
2674 #ifdef GTK
2675 /* *** */
2677 #else
2678 selection_paste (edit, CRoot, XA_CUT_BUFFER0, False);
2679 #endif
2680 else
2681 #ifdef GTK
2682 gtk_selection_convert (GTK_WIDGET (edit->widget), GDK_SELECTION_PRIMARY,
2683 gdk_atom_intern ("COMPOUND_TEXT", FALSE), GDK_CURRENT_TIME);
2684 #else
2685 XConvertSelection (CDisplay, XA_PRIMARY, XA_STRING,
2686 XInternAtom (CDisplay, "VT_SELECTION", False),
2687 CWindowOf (edit->widget), CurrentTime);
2688 #endif
2689 edit->force |= REDRAW_PAGE;
2692 #else /* MIDNIGHT */
2694 void edit_paste_from_history (WEdit *edit)
2698 int edit_copy_to_X_buf_cmd (WEdit * edit)
2700 long start_mark, end_mark;
2701 if (eval_marks (edit, &start_mark, &end_mark))
2702 return 0;
2703 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2704 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2705 return 1;
2707 edit_mark_cmd (edit, 1);
2708 return 0;
2711 int edit_cut_to_X_buf_cmd (WEdit * edit)
2713 long start_mark, end_mark;
2714 if (eval_marks (edit, &start_mark, &end_mark))
2715 return 0;
2716 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2717 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2718 return 1;
2720 edit_block_delete_cmd (edit);
2721 edit_mark_cmd (edit, 1);
2722 return 0;
2725 void edit_paste_from_X_buf_cmd (WEdit * edit)
2727 edit_insert_file (edit, catstrs (home_dir, CLIP_FILE, 0));
2730 #endif /* MIDMIGHT */
2732 void edit_goto_cmd (WEdit *edit)
2734 char *f;
2735 static int l = 0;
2736 #ifdef MIDNIGHT
2737 char s[12];
2738 sprintf (s, "%d", l);
2739 f = input_dialog (_(" Goto line "), _(" Enter line: "), l ? s : "");
2740 #else
2741 #ifdef GTK
2742 #if 0
2743 f = gtk_edit_dialog_input ("goto", 150, l ? itoa (l) : "", _(" Goto line "), _(" Enter line: "));
2744 #else
2745 char s [12];
2747 sprintf (s, "%d", l);
2748 f = (char *) input_dialog (_(" Goto line "), _(" Enter line: "), l ? s : "");
2749 #endif
2750 #else
2751 f = CInputDialog ("goto", WIN_MESSAGES, 150, l ? itoa (l) : "", _(" Goto line "), _(" Enter line: "));
2752 #endif
2753 #endif
2754 if (f) {
2755 if (*f) {
2756 l = atoi (f);
2757 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2758 edit_move_to_line (edit, l - 1);
2759 edit->force |= REDRAW_COMPLETELY;
2761 free (f);
2765 /*returns 1 on success */
2766 int edit_save_block_cmd (WEdit * edit)
2768 long start_mark, end_mark;
2769 char *exp;
2770 if (eval_marks (edit, &start_mark, &end_mark))
2771 return 1;
2772 exp = edit_get_save_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _ (" Save Block "));
2773 edit_push_action (edit, KEY_PRESS + edit->start_display);
2774 if (exp) {
2775 if (!*exp) {
2776 free (exp);
2777 return 0;
2778 } else {
2779 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2780 free (exp);
2781 edit->force |= REDRAW_COMPLETELY;
2782 return 1;
2783 } else {
2784 free (exp);
2785 edit_error_dialog (_ (" Save Block "), get_sys_error (_ (" Error trying to save file. ")));
2789 edit->force |= REDRAW_COMPLETELY;
2790 return 0;
2794 /* returns 1 on success */
2795 int edit_insert_file_cmd (WEdit * edit)
2797 char *exp = edit_get_load_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _ (" Insert File "));
2798 edit_push_action (edit, KEY_PRESS + edit->start_display);
2799 if (exp) {
2800 if (!*exp) {
2801 free (exp);
2802 return 0;
2803 } else {
2804 if (edit_insert_file (edit, exp)) {
2805 free (exp);
2806 edit->force |= REDRAW_COMPLETELY;
2807 return 1;
2808 } else {
2809 free (exp);
2810 edit_error_dialog (_ (" Insert file "), get_sys_error (_ (" Error trying to insert file. ")));
2814 edit->force |= REDRAW_COMPLETELY;
2815 return 0;
2818 #ifdef MIDNIGHT
2820 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2821 int edit_sort_cmd (WEdit * edit)
2823 static char *old = 0;
2824 char *exp;
2825 long start_mark, end_mark;
2826 int e;
2828 if (eval_marks (edit, &start_mark, &end_mark)) {
2829 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2830 return 0;
2832 edit_save_block (edit, catstrs (home_dir, BLOCK_FILE, 0), start_mark, end_mark);
2834 exp = old ? old : "";
2836 exp = input_dialog (_(" Run Sort "),
2837 _(" Enter sort options (see manpage) separated by whitespace: "), exp);
2839 if (!exp)
2840 return 1;
2841 if (old)
2842 free (old);
2843 old = exp;
2845 e = system (catstrs (" sort ", exp, " ", home_dir, BLOCK_FILE, " > ", home_dir, TEMP_FILE, 0));
2846 if (e) {
2847 if (e == -1 || e == 127) {
2848 edit_error_dialog (_(" Sort "),
2849 get_sys_error (_(" Error trying to execute sort command ")));
2850 } else {
2851 char q[8];
2852 sprintf (q, "%d ", e);
2853 edit_error_dialog (_(" Sort "),
2854 catstrs (_(" Sort returned non-zero: "), q, 0));
2856 return -1;
2859 edit->force |= REDRAW_COMPLETELY;
2861 if (edit_block_delete_cmd (edit))
2862 return 1;
2863 edit_insert_file (edit, catstrs (home_dir, TEMP_FILE, 0));
2864 return 0;
2867 /* if block is 1, a block must be highlighted and the shell command
2868 processes it. If block is 0 the shell command is a straight system
2869 command, that just produces some output which is to be inserted */
2870 void edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block)
2872 long start_mark, end_mark;
2873 struct stat s;
2874 char buf[BUFSIZ];
2875 FILE *script_home = NULL;
2876 FILE *script_src = NULL;
2877 FILE *block_file = NULL;
2879 char *o = catstrs (mc_home, shell_cmd, 0); /* original source script */
2880 char *h = catstrs (home_dir, EDIT_DIR, shell_cmd, 0); /* home script */
2881 char *b = catstrs (home_dir, BLOCK_FILE, 0); /* block file */
2882 char *e = catstrs (home_dir, ERROR_FILE, 0); /* error file */
2884 if (! (script_home = fopen (h, "r"))) {
2885 if (! (script_home = fopen (h, "w"))) {
2886 edit_error_dialog ("",
2887 get_sys_error (catstrs (_ ("Error create script:"), h, 0)));
2888 return;
2889 } else {
2890 if (! (script_src = fopen (o, "r"))) {
2891 fclose (script_home); unlink (h);
2892 edit_error_dialog ("",
2893 get_sys_error (catstrs (_ ("Error read script:"), o, 0)));
2894 return;
2895 } else {
2896 while (fgets(buf, sizeof(buf), script_src))
2897 fputs (buf, script_home);
2898 if (fclose(script_home)) {
2899 edit_error_dialog ("",
2900 get_sys_error (catstrs (_ ("Error close script:"), h, 0)));
2901 return;
2902 } else {
2903 chmod (h, 0700);
2904 edit_error_dialog ("",
2905 get_sys_error (catstrs (_ ("Script created:"), h, 0)));
2910 if (block) { /* for marked block run indent formatter */
2911 if (eval_marks (edit, &start_mark, &end_mark)) {
2912 edit_error_dialog (_("Process block"),
2913 _(" You must first highlight a block of text. "));
2914 return;
2916 edit_save_block (edit, b, start_mark, end_mark);
2918 /* run your script */
2919 my_system (EXECUTE_AS_SHELL, shell,
2920 catstrs (home_dir, EDIT_DIR, shell_cmd, " ",
2921 edit->filename, " ", home_dir, BLOCK_FILE, " ",
2922 home_dir, ERROR_FILE, 0));
2924 } else { /* for missing marked block run ... */
2925 my_system (0, shell, catstrs (EDIT_DIR, shell_cmd));
2928 edit_refresh_cmd (edit);
2929 edit->force |= REDRAW_COMPLETELY;
2931 /* insert result block */
2932 if (block) {
2933 if (stat (e, &s) == 0) {
2934 if (!s.st_size) { /* no error messages */
2935 if (edit_block_delete_cmd (edit))
2936 return;
2937 edit_insert_file (edit, b);
2938 } else {
2939 edit_insert_file (edit, e);
2941 } else {
2942 edit_error_dialog ("",
2943 get_sys_error (catstrs (_ ("Error trying to stat file:"), e, 0)));
2944 edit->force |= REDRAW_COMPLETELY;
2946 if ((block_file = fopen (b, "w")))
2947 fclose (block_file);
2948 return;
2950 return;
2953 #endif /* MIDNIGHT */
2955 int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion);
2957 /* prints at the cursor */
2958 /* returns the number of chars printed */
2959 int edit_print_string (WEdit * e, const char *s)
2961 int i = 0;
2962 while (s[i])
2963 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2964 e->force |= REDRAW_COMPLETELY;
2965 edit_update_screen (e);
2966 return i;
2969 int edit_printf (WEdit * e, const char *fmt,...)
2971 int i;
2972 va_list pa;
2973 char s[1024];
2974 va_start (pa, fmt);
2975 sprintf (s, fmt, pa);
2976 i = edit_print_string (e, s);
2977 va_end (pa);
2978 return i;
2981 #ifdef MIDNIGHT
2983 /* FIXME: does this function break NT_OS2 ? */
2985 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2987 FILE *p = 0;
2988 char *s;
2990 s = g_strdup_printf ("mail -s \"%s\" -c \"%s\" \"%s\"", subject, cc, to);
2992 if (s) {
2993 p = popen (s, "w");
2994 g_free (s);
2997 if (p) {
2998 long i;
2999 for (i = 0; i < edit->last_byte; i++)
3000 fputc (edit_get_byte (edit, i), p);
3001 pclose (p);
3005 #define MAIL_DLG_HEIGHT 12
3007 void edit_mail_dialog (WEdit * edit)
3009 char *tmail_to;
3010 char *tmail_subject;
3011 char *tmail_cc;
3013 static char *mail_cc_last = 0;
3014 static char *mail_subject_last = 0;
3015 static char *mail_to_last = 0;
3017 QuickDialog Quick_input =
3018 {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
3019 "[Input Line Keys]", "quick_input", 0};
3021 QuickWidget quick_widgets[] =
3023 {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
3024 0, NULL},
3025 {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&Ok"), 0, B_ENTER, 0,
3026 0, NULL},
3027 {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
3028 0, "mail-dlg-input"},
3029 {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
3030 0, 0},
3031 {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
3032 0, "mail-dlg-input-2"},
3033 {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
3034 0, 0},
3035 {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
3036 0, "mail-dlg-input-3"},
3037 {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
3038 0, 0},
3039 {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
3040 0, 0},
3041 {0}};
3043 quick_widgets[2].str_result = &tmail_cc;
3044 quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
3045 quick_widgets[4].str_result = &tmail_subject;
3046 quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
3047 quick_widgets[6].str_result = &tmail_to;
3048 quick_widgets[6].text = mail_to_last ? mail_to_last : "";
3050 Quick_input.widgets = quick_widgets;
3052 if (quick_dialog (&Quick_input) != B_CANCEL) {
3053 if (mail_cc_last)
3054 free (mail_cc_last);
3055 if (mail_subject_last)
3056 free (mail_subject_last);
3057 if (mail_to_last)
3058 free (mail_to_last);
3059 mail_cc_last = *(quick_widgets[2].str_result);
3060 mail_subject_last = *(quick_widgets[4].str_result);
3061 mail_to_last = *(quick_widgets[6].str_result);
3062 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
3066 #endif /* MIDNIGHT */