- Fix KiDispatchException to unmask KI_EXCEPTION_INTERNAL when setting the exception...
[reactos.git] / rosapps / mc / edit / editcmd.c
1 /* editor high level editing commands.
2
3 Copyright (C) 1996, 1997 the Free Software Foundation
4
5 Authors: 1996, 1997 Paul Sheer
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
22
23 #include <config.h>
24 #ifdef OS2_NT
25 #include <io.h>
26 #include <fcntl.h>
27 #endif
28 #include <ctype.h>
29 #include "edit.h"
30 #include "editcmddef.h"
31
32 #ifndef MIDNIGHT
33 #include <X11/Xatom.h>
34 #include "loadfile.h"
35 #endif
36
37 /* globals: */
38
39 /* search and replace: */
40 int replace_scanf = 0;
41 int replace_regexp = 0;
42 int replace_all = 0;
43 int replace_prompt = 1;
44 int replace_whole = 0;
45 int replace_case = 0;
46 int replace_backwards = 0;
47
48 /* queries on a save */
49 #ifdef MIDNIGHT
50 int edit_confirm_save = 1;
51 #else
52 int edit_confirm_save = 0;
53 #endif
54
55 #define NUM_REPL_ARGS 16
56 #define MAX_REPL_LEN 1024
57
58 #ifdef MIDNIGHT
59
60 static inline int my_lower_case (int c)
61 {
62 return tolower(c);
63 }
64
65 char *strcasechr (const char *s, int c)
66 {
67 for (; my_lower_case ((int) *s) != my_lower_case (c); ++s)
68 if (*s == '\0')
69 return 0;
70 return (char *)s;
71 }
72
73
74 #include "../src/mad.h"
75
76 #ifndef HAVE_MEMMOVE
77 /* for Christophe */
78 static void *memmove (void *dest, const void *src, size_t n)
79 {
80 char *t, *s;
81
82 if (dest <= src) {
83 t = (char *) dest;
84 s = (char *) src;
85 while (n--)
86 *t++ = *s++;
87 } else {
88 t = (char *) dest + n;
89 s = (char *) src + n;
90 while (n--)
91 *--t = *--s;
92 }
93 return dest;
94 }
95 #endif
96
97 /* #define itoa MY_itoa <---- this line is now in edit.h */
98 char *itoa (int i)
99 {
100 static char t[14];
101 char *s = t + 13;
102 int j = i;
103 *s-- = 0;
104 do {
105 *s-- = i % 10 + '0';
106 } while ((i = i / 10));
107 if (j < 0)
108 *s-- = '-';
109 return ++s;
110 }
111
112 /*
113 This joins strings end on end and allocates memory for the result.
114 The result is later automatically free'd and must not be free'd
115 by the caller.
116 */
117 char *catstrs (const char *first,...)
118 {
119 static char *stacked[16] =
120 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
121 static int i = 0;
122 va_list ap;
123 int len;
124 char *data;
125
126 if (!first)
127 return 0;
128
129 len = strlen (first);
130 va_start (ap, first);
131
132 while ((data = va_arg (ap, char *)) != 0)
133 len += strlen (data);
134
135 len++;
136
137 i = (i + 1) % 16;
138 if (stacked[i])
139 free (stacked[i]);
140
141 stacked[i] = malloc (len);
142 va_end (ap);
143 va_start (ap, first);
144 strcpy (stacked[i], first);
145 while ((data = va_arg (ap, char *)) != 0)
146 strcat (stacked[i], data);
147 va_end (ap);
148
149 return stacked[i];
150 }
151 #endif
152
153 #ifdef MIDNIGHT
154
155 void edit_help_cmd (WEdit * edit)
156 {
157 char *hlpdir = concat_dir_and_file (mc_home, "mc.hlp");
158 interactive_display (hlpdir, "[Internal File Editor]");
159 free (hlpdir);
160 edit->force |= REDRAW_COMPLETELY;
161 }
162
163 void edit_refresh_cmd (WEdit * edit)
164 {
165 #ifndef HAVE_SLANG
166 clr_scr();
167 do_refresh();
168 #else
169 {
170 int fg, bg;
171 edit_get_syntax_color (edit, -1, &fg, &bg);
172 }
173 touchwin(stdscr);
174 #endif
175 mc_refresh();
176 doupdate();
177 }
178
179 #else
180
181 void edit_help_cmd (WEdit * edit)
182 {
183 }
184
185 void edit_refresh_cmd (WEdit * edit)
186 {
187 }
188
189 void CRefreshEditor (WEdit * edit)
190 {
191 edit_refresh_cmd (edit);
192 }
193
194 #endif
195
196 #ifndef MIDNIGHT
197
198 /* three argument open */
199 int my_open (const char *pathname, int flags,...)
200 {
201 int file;
202 va_list ap;
203
204 file = open ((char *) pathname, O_RDONLY);
205 if (file < 0 && (flags & O_CREAT)) { /* must it be created ? */
206 mode_t mode;
207 va_start(ap, flags);
208 mode = va_arg(ap, mode_t);
209 va_end(ap);
210 return creat ((char *) pathname, mode);
211 }
212 close (file);
213 return open ((char *) pathname, flags);
214 }
215
216 #define open my_open
217
218 #endif
219
220 /* "Oleg Yu. Repin" <repin@ssd.sscc.ru> added backup filenames
221 ...thanks -paul */
222
223 /* If 0 (quick save) then a) create/truncate <filename> file,
224 b) save to <filename>;
225 if 1 (safe save) then a) save to <tempnam>,
226 b) rename <tempnam> to <filename>;
227 if 2 (do backups) then a) save to <tempnam>,
228 b) rename <filename> to <filename.backup_ext>,
229 c) rename <tempnam> to <filename>. */
230
231 /* returns 0 on error */
232 int edit_save_file (WEdit * edit, const char *filename)
233 {
234 long buf;
235 long filelen = 0;
236 int file;
237 char *savename = (char *) filename;
238 int this_save_mode;
239
240 if ((file = open (savename, O_WRONLY)) == -1) {
241 this_save_mode = 0; /* the file does not exists yet, so no safe save or backup necessary */
242 } else {
243 close (file);
244 this_save_mode = option_save_mode;
245 }
246
247 if (this_save_mode > 0) {
248 char *savedir = ".", *slashpos = strrchr (filename, '/');
249 if (slashpos != 0) {
250 savedir = strdup (filename);
251 if (savedir == 0)
252 return 0;
253 savedir[slashpos - filename + 1] = '\0';
254 }
255 #ifdef HAVE_MAD
256 savename = strdup (tempnam (savedir, "cooledit"));
257 #else
258 savename = tempnam (savedir, "cooledit");
259 #endif
260 if (slashpos)
261 free (savedir);
262 if (!savename)
263 return 0;
264 }
265 if ((file = open (savename, O_CREAT | O_WRONLY | O_TRUNC | MY_O_TEXT, edit->stat.st_mode)) == -1) {
266 if (this_save_mode > 0)
267 free (savename);
268 return 0;
269 }
270 chown (savename, edit->stat.st_uid, edit->stat.st_gid);
271 buf = 0;
272 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
273 filelen += write (file, (char *) edit->buffers1[buf], EDIT_BUF_SIZE);
274 buf++;
275 }
276 filelen += write (file, (char *) edit->buffers1[buf], edit->curs1 & M_EDIT_BUF_SIZE);
277
278 if (edit->curs2) {
279 edit->curs2--;
280 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
281 filelen += write (file, (char *) edit->buffers2[buf] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1, 1 + (edit->curs2 & M_EDIT_BUF_SIZE));
282 buf--;
283 while (buf >= 0) {
284 filelen += write (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE);
285 buf--;
286 }
287 edit->curs2++;
288 }
289 close (file);
290
291 if (filelen == edit->last_byte) {
292 if (this_save_mode == 2) {
293 if (rename (filename, catstrs (filename, option_backup_ext, 0)) == -1) { /* catstrs free's automatically */
294 free (savename);
295 return 0;
296 }
297 }
298 if (this_save_mode > 0) {
299 if (rename (savename, filename) == -1) {
300 free (savename);
301 return 0;
302 }
303 free (savename);
304 }
305 return 1;
306 } else {
307 if (this_save_mode > 0)
308 free (savename);
309 return 0;
310 }
311 }
312
313 #ifdef MIDNIGHT
314 /*
315 I changed this from Oleg's original routine so
316 that option_backup_ext works with coolwidgets as well. This
317 does mean there is a memory leak - paul.
318 */
319 void menu_save_mode_cmd (void)
320 {
321 #define DLG_X 36
322 #define DLG_Y 10
323 static char *str_result;
324 static int save_mode_new;
325 static char *str[] =
326 {
327 "Quick save ",
328 "Safe save ",
329 "Do backups -->"};
330 static QuickWidget widgets[] =
331 {
332 {quick_button, 18, DLG_X, 7, DLG_Y, "&Cancel", 0,
333 B_CANCEL, 0, 0, XV_WLAY_DONTCARE, "c"},
334 {quick_button, 6, DLG_X, 7, DLG_Y, "&Ok", 0,
335 B_ENTER, 0, 0, XV_WLAY_DONTCARE, "o"},
336 {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
337 0, 0, &str_result, XV_WLAY_DONTCARE, "i"},
338 {quick_label, 22, DLG_X, 4, DLG_Y, "Extension:", 0,
339 0, 0, 0, XV_WLAY_DONTCARE, "savemext"},
340 {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
341 0, &save_mode_new, str, XV_WLAY_DONTCARE, "t"},
342 {0}};
343 static QuickDialog dialog =
344 /* NLS ? */
345 {DLG_X, DLG_Y, -1, -1, " Edit Save Mode ", "[Edit Save Mode]",
346 "esm", widgets};
347
348 widgets[2].text = option_backup_ext;
349 widgets[4].value = option_save_mode;
350 if (quick_dialog (&dialog) != B_ENTER)
351 return;
352 option_save_mode = save_mode_new;
353 option_backup_ext = str_result; /* this is a memory leak */
354 option_backup_ext_int = 0;
355 str_result[min (strlen (str_result), sizeof (int))] = '\0';
356 memcpy ((char *) &option_backup_ext_int, str_result, strlen (option_backup_ext));
357 }
358
359 #endif
360
361 #ifdef MIDNIGHT
362
363 void edit_split_filename (WEdit * edit, char *f)
364 {
365 if (edit->filename)
366 free (edit->filename);
367 edit->filename = strdup (f);
368 if (edit->dir)
369 free (edit->dir);
370 edit->dir = strdup ("");
371 }
372
373 #else
374
375 void edit_split_filename (WEdit * edit, char *longname)
376 {
377 char *exp, *p;
378 exp = canonicalize_pathname (longname); /* this ensures a full path */
379 if (edit->filename)
380 free (edit->filename);
381 if (edit->dir)
382 free (edit->dir);
383 p = strrchr (exp, '/');
384 edit->filename = strdup (++p);
385 *p = 0;
386 edit->dir = strdup (exp);
387 free (exp);
388 }
389
390 #endif
391
392 /* here we want to warn the user of overwriting an existing file, but only if they
393 have made a change to the filename */
394 /* returns 1 on success */
395 int edit_save_as_cmd (WEdit * edit)
396 {
397 /* This heads the 'Save As' dialog box */
398 char *exp = edit_get_save_file (edit->dir, edit->filename, _(" Save As "));
399 int different_filename = 0;
400 edit_push_action (edit, KEY_PRESS + edit->start_display);
401 edit->force |= REDRAW_COMPLETELY;
402
403 if (exp) {
404 if (!*exp) {
405 free (exp);
406 return 0;
407 } else {
408 if (strcmp(catstrs (edit->dir, edit->filename, 0), exp)) {
409 int file;
410 different_filename = 1;
411 if ((file = open ((char *) exp, O_RDONLY)) != -1) { /* the file exists */
412 close (file);
413 if (edit_query_dialog2 (_(" Warning "),
414 _(" A file already exists with this name. "),
415 /* Push buttons to over-write the current file, or cancel the operation */
416 _("Overwrite"), _("Cancel")))
417 return 0;
418 }
419 }
420 if (edit_save_file (edit, exp)) {
421 edit_split_filename (edit, exp);
422 free (exp);
423 edit->modified = 0;
424 #ifdef MIDNIGHT
425 edit->delete_file = 0;
426 #endif
427 if (different_filename && !edit->explicit_syntax)
428 edit_load_syntax (edit, 0, 0);
429 return 1;
430 } else {
431 free (exp);
432 edit_error_dialog (_(" Save as "), get_sys_error (_(" Error trying to save file. ")));
433 return 0;
434 }
435 }
436 } else
437 return 0;
438 }
439
440 /* {{{ Macro stuff starts here */
441
442 #ifdef MIDNIGHT
443 int raw_callback (struct Dlg_head *h, int key, int Msg)
444 {
445 switch (Msg) {
446 case DLG_DRAW:
447 attrset (REVERSE_COLOR);
448 dlg_erase (h);
449 draw_box (h, 1, 1, h->lines - 2, h->cols - 2);
450
451 attrset (COLOR_HOT_NORMAL);
452 dlg_move (h, 1, 2);
453 printw (h->title);
454 break;
455
456 case DLG_KEY:
457 h->running = 0;
458 h->ret_value = key;
459 return 1;
460 }
461 return 0;
462 }
463
464 /* gets a raw key from the keyboard. Passing cancel = 1 draws
465 a cancel button thus allowing c-c etc.. Alternatively, cancel = 0
466 will return the next key pressed */
467 int edit_raw_key_query (char *heading, char *query, int cancel)
468 {
469 int w = strlen (query) + 7;
470 struct Dlg_head *raw_dlg = create_dlg (0, 0, 7, w, dialog_colors,
471 /* NLS ? */
472 raw_callback, "[Raw Key Query]",
473 "raw_key_input",
474 DLG_CENTER | DLG_TRYUP);
475 x_set_dialog_title (raw_dlg, heading);
476 raw_dlg->raw = 1; /* to return even a tab key */
477 if (cancel)
478 add_widget (raw_dlg, button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON, "Cancel", 0, 0, 0));
479 add_widget (raw_dlg, label_new (3 - cancel, 2, query, 0));
480 add_widget (raw_dlg, input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0));
481 run_dlg (raw_dlg);
482 w = raw_dlg->ret_value;
483 destroy_dlg (raw_dlg);
484 if (cancel)
485 if (w == XCTRL ('g') || w == XCTRL ('c') || w == ESC_CHAR || w == B_CANCEL)
486 return 0;
487 /* hence ctrl-a (=B_CANCEL), ctrl-g, ctrl-c, and Esc are cannot returned */
488 return w;
489 }
490
491 #else
492
493 int edit_raw_key_query (char *heading, char *query, int cancel)
494 {
495 return CKeySymMod (CRawkeyQuery (0, 0, 0, heading, query));
496 }
497
498 #endif
499
500 /* creates a macro file if it doesn't exist */
501 static FILE *edit_open_macro_file (const char *r)
502 {
503 char *filename;
504 int file;
505 filename = catstrs (home_dir, MACRO_FILE, 0);
506 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
507 return 0;
508 close (file);
509 return fopen (filename, r);
510 }
511
512 #define MAX_MACROS 1024
513 static int saved_macro[MAX_MACROS + 1] =
514 {0, 0};
515 static int saved_macros_loaded = 0;
516
517 /*
518 This is just to stop the macro file be loaded over and over for keys
519 that aren't defined to anything. On slow systems this could be annoying.
520 */
521 int macro_exists (int k)
522 {
523 int i;
524 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
525 if (saved_macro[i] == k)
526 return i;
527 return -1;
528 }
529
530 /* returns 1 on error */
531 int edit_delete_macro (WEdit * edit, int k)
532 {
533 struct macro macro[MAX_MACRO_LENGTH];
534 FILE *f, *g;
535 int s, i, n, j = 0;
536
537 if (saved_macros_loaded)
538 if ((j = macro_exists (k)) < 0)
539 return 0;
540 g = fopen (catstrs (home_dir, TEMP_FILE, 0), "w");
541 if (!g) {
542 /* This heads the delete macro error dialog box */
543 edit_error_dialog (_(" Delete macro "),
544 /* 'Open' = load temp file */
545 get_sys_error (_(" Error trying to open temp file ")));
546 return 1;
547 }
548 f = edit_open_macro_file ("r");
549 if (!f) {
550 /* This heads the delete macro error dialog box */
551 edit_error_dialog (_(" Delete macro "),
552 /* 'Open' = load temp file */
553 get_sys_error (_(" Error trying to open macro file ")));
554 fclose (g);
555 return 1;
556 }
557 for (;;) {
558 n = fscanf (f, _("key '%d 0': "), &s);
559 if (!n || n == EOF)
560 break;
561 n = 0;
562 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
563 n++;
564 fscanf (f, ";\n");
565 if (s != k) {
566 fprintf (g, _("key '%d 0': "), s);
567 for (i = 0; i < n; i++)
568 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
569 fprintf (g, ";\n");
570 }
571 };
572 fclose (f);
573 fclose (g);
574 if (rename (catstrs (home_dir, TEMP_FILE, 0), catstrs (home_dir, MACRO_FILE, 0)) == -1) {
575 /* This heads the delete macro error dialog box */
576 edit_error_dialog (_(" Delete macro "),
577 get_sys_error (_(" Error trying to overwrite macro file ")));
578 return 1;
579 }
580 if (saved_macros_loaded)
581 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
582 return 0;
583 }
584
585 /* returns 0 on error */
586 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
587 {
588 FILE *f;
589 int s, i;
590
591 edit->force |= REDRAW_COMPLETELY;
592 edit_push_action (edit, KEY_PRESS + edit->start_display);
593 /* This heads the 'Macro' dialog box */
594 s = edit_raw_key_query (_(" Macro "),
595 /* Input line for a single key press follows the ':' */
596 _(" Press the macro's new hotkey: "), 1);
597 if (s) {
598 if (edit_delete_macro (edit, s))
599 return 0;
600 f = edit_open_macro_file ("a+");
601 if (f) {
602 fprintf (f, _("key '%d 0': "), s);
603 for (i = 0; i < n; i++)
604 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
605 fprintf (f, ";\n");
606 fclose (f);
607 if (saved_macros_loaded) {
608 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
609 saved_macro[i] = s;
610 }
611 return 1;
612 } else
613 /* This heads the 'Save Macro' dialog box */
614 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Error trying to open macro file ")));
615 }
616 return 0;
617 }
618
619 void edit_delete_macro_cmd (WEdit * edit)
620 {
621 int command;
622
623 #ifdef MIDNIGHT
624 command = CK_Macro (edit_raw_key_query (_(" Delete Macro "), _(" Press macro hotkey: "), 1));
625 #else
626 /* This heads the 'Delete Macro' dialog box */
627 command = CK_Macro (CKeySymMod (CRawkeyQuery (0, 0, 0, _(" Delete Macro "),
628 /* Input line for a single key press follows the ':' */
629 _(" Press macro hotkey: "))));
630 #endif
631
632 if (command == CK_Macro (0))
633 return;
634
635 edit_delete_macro (edit, command - 2000);
636 }
637
638 /* return 0 on error */
639 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
640 {
641 FILE *f;
642 int s, i = 0, found = 0;
643
644 if (saved_macros_loaded)
645 if (macro_exists (k) < 0)
646 return 0;
647
648 if ((f = edit_open_macro_file ("r"))) {
649 struct macro dummy;
650 do {
651 int u;
652 u = fscanf (f, _("key '%d 0': "), &s);
653 if (!u || u == EOF)
654 break;
655 if (!saved_macros_loaded)
656 saved_macro[i++] = s;
657 if (!found) {
658 *n = 0;
659 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
660 (*n)++;
661 } else {
662 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
663 }
664 fscanf (f, ";\n");
665 if (s == k)
666 found = 1;
667 } while (!found || !saved_macros_loaded);
668 if (!saved_macros_loaded) {
669 saved_macro[i] = 0;
670 saved_macros_loaded = 1;
671 }
672 fclose (f);
673 return found;
674 } else
675 /* This heads the 'Load Macro' dialog box */
676 edit_error_dialog (_(" Load macro "),
677 get_sys_error (_(" Error trying to open macro file ")));
678 return 0;
679 }
680
681 /* }}} Macro stuff starts here */
682
683 /* returns 1 on success */
684 int edit_save_confirm_cmd (WEdit * edit)
685 {
686 char *f;
687
688 if (edit_confirm_save) {
689 #ifdef MIDNIGHT
690 f = catstrs (_(" Confirm save file? : "), edit->filename, " ", 0);
691 #else
692 f = catstrs (_(" Confirm save file? : "), edit->dir, edit->filename, " ", 0);
693 #endif
694 /* Buttons to 'Confirm save file' query */
695 if (edit_query_dialog2 (_(" Save file "), f, _("Save"), _("Cancel")))
696 return 0;
697 }
698 return edit_save_cmd (edit);
699 }
700
701
702 /* returns 1 on success */
703 int edit_save_cmd (WEdit * edit)
704 {
705 edit->force |= REDRAW_COMPLETELY;
706 if (!edit_save_file (edit, catstrs (edit->dir, edit->filename, 0)))
707 return edit_save_as_cmd (edit);
708 edit->modified = 0;
709 #ifdef MIDNIGHT
710 edit->delete_file = 0;
711 #endif
712
713 return 1;
714 }
715
716
717 /* returns 1 on success */
718 int edit_new_cmd (WEdit * edit)
719 {
720 edit->force |= REDRAW_COMPLETELY;
721 if (edit->modified)
722 if (edit_query_dialog2 (_(" Warning "), _(" Current text was modified without a file save. \n Continue discards these changes. "), _("Continue"), _("Cancel")))
723 return 0;
724 edit->modified = 0;
725 return edit_renew (edit); /* if this gives an error, something has really screwed up */
726 }
727
728 int edit_load_cmd (WEdit * edit)
729 {
730 char *exp;
731 edit->force |= REDRAW_COMPLETELY;
732
733 if (edit->modified)
734 if (edit_query_dialog2 (_(" Warning "), _(" Current text was modified without a file save. \n Continue discards these changes. "), _("Continue"), _("Cancel")))
735 return 0;
736
737 exp = edit_get_load_file (edit->dir, edit->filename, _(" Load "));
738
739 if (exp) {
740 if (!*exp) {
741 free (exp);
742 } else {
743 int file;
744 if ((file = open ((char *) exp, O_RDONLY, MY_O_TEXT)) != -1) {
745 close (file);
746 edit_reload (edit, exp, 0, "", 0);
747 edit_split_filename (edit, exp);
748 free (exp);
749 edit->modified = 0;
750 return 1;
751 } else {
752 free (exp);
753 /* Heads the 'Load' file dialog box */
754 edit_error_dialog (_(" Load "), get_sys_error (_(" Error trying to open file for reading ")));
755 }
756 }
757 }
758 return 0;
759 }
760
761 /*
762 if mark2 is -1 then marking is from mark1 to the cursor.
763 Otherwise its between the markers. This handles this.
764 Returns 1 if no text is marked.
765 */
766 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
767 {
768 if (edit->mark1 != edit->mark2) {
769 if (edit->mark2 >= 0) {
770 *start_mark = min (edit->mark1, edit->mark2);
771 *end_mark = max (edit->mark1, edit->mark2);
772 } else {
773 *start_mark = min (edit->mark1, edit->curs1);
774 *end_mark = max (edit->mark1, edit->curs1);
775 edit->column2 = edit->curs_col;
776 }
777 return 0;
778 } else {
779 *start_mark = *end_mark = 0;
780 edit->column2 = edit->column1 = 0;
781 return 1;
782 }
783 }
784
785 /*Block copy, move and delete commands */
786
787 void edit_block_copy_cmd (WEdit * edit)
788 {
789 long start_mark, end_mark, current = edit->curs1;
790 long count;
791 char *copy_buf;
792
793 if (eval_marks (edit, &start_mark, &end_mark))
794 return;
795
796
797 copy_buf = malloc (end_mark - start_mark);
798
799 /* all that gets pushed are deletes hence little space is used on the stack */
800
801 edit_push_markers (edit);
802
803 count = start_mark;
804 while (count < end_mark) {
805 copy_buf[end_mark - count - 1] = edit_get_byte (edit, count);
806 count++;
807 }
808 while (count-- > start_mark) {
809 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
810 }
811 free (copy_buf);
812 edit_scroll_screen_over_cursor (edit);
813
814 if (start_mark < current && end_mark > current)
815 edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
816
817 edit->force |= REDRAW_PAGE;
818 }
819
820
821 void edit_block_move_cmd (WEdit * edit)
822 {
823 long count;
824 long current;
825 char *copy_buf;
826 long start_mark, end_mark;
827
828 if (eval_marks (edit, &start_mark, &end_mark))
829 return;
830
831 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
832 return;
833
834 if ((end_mark - start_mark) > option_max_undo / 2)
835 if (edit_query_dialog2 (_(" Warning "), _(" Block is large, you may not be able to undo this action. "), _("Continue"), _("Cancel")))
836 return;
837
838 copy_buf = malloc (end_mark - start_mark);
839
840 edit_push_markers (edit);
841
842 current = edit->curs1;
843 edit_cursor_move (edit, start_mark - edit->curs1);
844 edit_scroll_screen_over_cursor (edit);
845
846 count = start_mark;
847 while (count < end_mark) {
848 copy_buf[end_mark - count - 1] = edit_delete (edit);
849 count++;
850 }
851 edit_scroll_screen_over_cursor (edit);
852
853 edit_cursor_move (edit, current - edit->curs1
854 - (((current - edit->curs1) > 0) ? end_mark - start_mark : 0));
855 edit_scroll_screen_over_cursor (edit);
856
857 while (count-- > start_mark) {
858 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
859 edit_set_markers (edit, edit->curs1, edit->curs1 + end_mark - start_mark, 0, 0);
860 }
861 edit_scroll_screen_over_cursor (edit);
862
863 free (copy_buf);
864 edit->force |= REDRAW_PAGE;
865 }
866
867 void edit_cursor_to_bol (WEdit * edit);
868
869 extern int column_highlighting;
870
871 void edit_delete_column_of_text (WEdit * edit)
872 {
873 long p, q, r, m1, m2;
874 int b, c, d, fin;
875
876 eval_marks (edit, &m1, &m2);
877 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
878 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
879
880 b = min (c, d);
881 c = max (c, d);
882
883 fin = 0;
884 while (!fin) {
885 eval_marks (edit, &m1, &m2);
886 r = edit_bol (edit, edit->curs1);
887 p = edit_move_forward3 (edit, r, b, 0);
888 q = edit_move_forward3 (edit, r, c, 0);
889 if (p < m1)
890 p = m1;
891 if (q >= m2) {
892 q = m2;
893 fin = 1;
894 }
895 edit_cursor_move (edit, p - edit->curs1);
896 while (p != q) { /* delete line between margins */
897 if (edit_get_byte (edit, edit->curs1) != '\n')
898 edit_delete (edit);
899 q--;
900 }
901 if (!fin) /* next line */
902 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
903 }
904 }
905
906 /* returns 1 if canceelled by user */
907 int edit_block_delete_cmd (WEdit * edit)
908 {
909 long count;
910 long start_mark, end_mark;
911
912 if (eval_marks (edit, &start_mark, &end_mark)) {
913 start_mark = edit_bol (edit, edit->curs1);
914 end_mark = edit_eol (edit, edit->curs1) + 1;
915 }
916 if ((end_mark - start_mark) > option_max_undo / 2)
917 /* Warning message with a query to continue or cancel the operation */
918 if (edit_query_dialog2 (_(" Warning "), _(" Block is large, you may not be able to undo this action. "), _(" Continue "), _(" Cancel ")))
919 return 1;
920
921 edit_push_markers (edit);
922
923 edit_cursor_move (edit, start_mark - edit->curs1);
924 edit_scroll_screen_over_cursor (edit);
925
926 count = start_mark;
927 if (start_mark < end_mark) {
928 if (column_highlighting) {
929 edit_delete_column_of_text (edit);
930 } else {
931 while (count < end_mark) {
932 edit_delete (edit);
933 count++;
934 }
935 }
936 }
937 edit_set_markers (edit, 0, 0, 0, 0);
938 edit->force |= REDRAW_PAGE;
939
940 return 0;
941 }
942
943
944 #ifdef MIDNIGHT
945
946 #define INPUT_INDEX 9
947 #define SEARCH_DLG_HEIGHT 10
948 #define REPLACE_DLG_HEIGHT 15
949 #define B_REPLACE_ALL B_USER+1
950 #define B_SKIP_REPLACE B_USER+2
951
952 int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
953 {
954 if (replace_prompt) {
955 QuickWidget quick_widgets[] =
956 {
957 /* NLS for hotkeys? */
958 {quick_button, 14, 18, 3, 6, "&Cancel", 0, B_CANCEL, 0,
959 0, XV_WLAY_DONTCARE, NULL},
960 {quick_button, 9, 18, 3, 6, "Replace &all", 0, B_REPLACE_ALL, 0,
961 0, XV_WLAY_DONTCARE, NULL},
962 {quick_button, 6, 18, 3, 6, "&Skip", 0, B_SKIP_REPLACE, 0,
963 0, XV_WLAY_DONTCARE, NULL},
964 {quick_button, 2, 18, 3, 6, "&Replace", 0, B_ENTER, 0,
965 0, XV_WLAY_DONTCARE, NULL},
966 {quick_label, 2, 50, 2, 6, 0,
967 0, 0, 0, XV_WLAY_DONTCARE, 0},
968 {0}};
969
970 quick_widgets[4].text = catstrs (_(" Replace with: "), replace_text, 0);
971
972 {
973 QuickDialog Quick_input =
974 {66, 6, 0, 0, N_(" Replace "),
975 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
976
977 Quick_input.widgets = quick_widgets;
978
979 Quick_input.xpos = xpos;
980 Quick_input.ypos = ypos;
981 return quick_dialog (&Quick_input);
982 }
983 } else
984 return 0;
985 }
986
987
988
989 void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order)
990 {
991 int treplace_scanf = replace_scanf;
992 int treplace_regexp = replace_regexp;
993 int treplace_all = replace_all;
994 int treplace_prompt = replace_prompt;
995 int treplace_backwards = replace_backwards;
996 int treplace_whole = replace_whole;
997 int treplace_case = replace_case;
998
999 char *tsearch_text;
1000 char *treplace_text;
1001 char *targ_order;
1002 QuickWidget quick_widgets[] =
1003 {
1004 {quick_button, 6, 10, 12, REPLACE_DLG_HEIGHT, "&Cancel", 0, B_CANCEL, 0,
1005 0, XV_WLAY_DONTCARE, NULL},
1006 {quick_button, 2, 10, 12, REPLACE_DLG_HEIGHT, "&Ok", 0, B_ENTER, 0,
1007 0, XV_WLAY_DONTCARE, NULL},
1008 {quick_checkbox, 25, 50, 11, REPLACE_DLG_HEIGHT, "Scanf &expression", 0, 0,
1009 0, 0, XV_WLAY_DONTCARE, NULL},
1010 {quick_checkbox, 25, 50, 10, REPLACE_DLG_HEIGHT, "Replace &all", 0, 0,
1011 0, 0, XV_WLAY_DONTCARE, NULL},
1012 {quick_checkbox, 25, 50, 9, REPLACE_DLG_HEIGHT, "Pr&ompt on replace", 0, 0,
1013 0, 0, XV_WLAY_DONTCARE, NULL},
1014 {quick_checkbox, 4, 50, 11, REPLACE_DLG_HEIGHT, "&Backwards", 0, 0,
1015 0, 0, XV_WLAY_DONTCARE, NULL},
1016 {quick_checkbox, 4, 50, 10, REPLACE_DLG_HEIGHT, "&Regular exprssn", 0, 0,
1017 0, 0, XV_WLAY_DONTCARE, NULL},
1018 {quick_checkbox, 4, 50, 9, REPLACE_DLG_HEIGHT, "&Whole words only", 0, 0,
1019 0, 0, XV_WLAY_DONTCARE, NULL},
1020 {quick_checkbox, 4, 50, 8, REPLACE_DLG_HEIGHT, "Case &sensitive", 0, 0,
1021 0, 0, XV_WLAY_DONTCARE, NULL},
1022 {quick_input, 3, 50, 7, REPLACE_DLG_HEIGHT, "", 44, 0, 0,
1023 0, XV_WLAY_BELOWCLOSE, "edit-argord"},
1024 {quick_label, 2, 50, 6, REPLACE_DLG_HEIGHT, " Enter replacement argument order eg. 3,2,1,4 ", 0, 0,
1025 0, 0, XV_WLAY_DONTCARE, 0},
1026 {quick_input, 3, 50, 5, REPLACE_DLG_HEIGHT, "", 44, 0, 0,
1027 0, XV_WLAY_BELOWCLOSE, "edit-replace"},
1028 {quick_label, 2, 50, 4, REPLACE_DLG_HEIGHT, " Enter replacement string", 0, 0, 0,
1029 0, XV_WLAY_DONTCARE, 0},
1030 {quick_input, 3, 50, 3, REPLACE_DLG_HEIGHT, "", 44, 0, 0,
1031 0, XV_WLAY_BELOWCLOSE, "edit-search"},
1032 {quick_label, 2, 50, 2, REPLACE_DLG_HEIGHT, " Enter search string", 0, 0, 0,
1033 0, XV_WLAY_DONTCARE, 0},
1034 {0}};
1035
1036 quick_widgets[2].result = &treplace_scanf;
1037 quick_widgets[3].result = &treplace_all;
1038 quick_widgets[4].result = &treplace_prompt;
1039 quick_widgets[5].result = &treplace_backwards;
1040 quick_widgets[6].result = &treplace_regexp;
1041 quick_widgets[7].result = &treplace_whole;
1042 quick_widgets[8].result = &treplace_case;
1043 quick_widgets[9].str_result = &targ_order;
1044 quick_widgets[9].text = *arg_order;
1045 quick_widgets[11].str_result = &treplace_text;
1046 quick_widgets[11].text = *replace_text;
1047 quick_widgets[13].str_result = &tsearch_text;
1048 quick_widgets[13].text = *search_text;
1049 {
1050 QuickDialog Quick_input =
1051 {50, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "),
1052 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1053
1054 Quick_input.widgets = quick_widgets;
1055
1056 if (quick_dialog (&Quick_input) != B_CANCEL) {
1057 *arg_order = *(quick_widgets[INPUT_INDEX].str_result);
1058 *replace_text = *(quick_widgets[INPUT_INDEX + 2].str_result);
1059 *search_text = *(quick_widgets[INPUT_INDEX + 4].str_result);
1060 replace_scanf = treplace_scanf;
1061 replace_backwards = treplace_backwards;
1062 replace_regexp = treplace_regexp;
1063 replace_all = treplace_all;
1064 replace_prompt = treplace_prompt;
1065 replace_whole = treplace_whole;
1066 replace_case = treplace_case;
1067 return;
1068 } else {
1069 *arg_order = NULL;
1070 *replace_text = NULL;
1071 *search_text = NULL;
1072 return;
1073 }
1074 }
1075 }
1076
1077
1078 void edit_search_dialog (WEdit * edit, char **search_text)
1079 {
1080 int treplace_scanf = replace_scanf;
1081 int treplace_regexp = replace_regexp;
1082 int treplace_whole = replace_whole;
1083 int treplace_case = replace_case;
1084 int treplace_backwards = replace_backwards;
1085
1086 char *tsearch_text;
1087 QuickWidget quick_widgets[] =
1088 {
1089 {quick_button, 6, 10, 7, SEARCH_DLG_HEIGHT, "&Cancel", 0, B_CANCEL, 0,
1090 0, XV_WLAY_DONTCARE, NULL},
1091 {quick_button, 2, 10, 7, SEARCH_DLG_HEIGHT, "&Ok", 0, B_ENTER, 0,
1092 0, XV_WLAY_DONTCARE, NULL},
1093 {quick_checkbox, 25, 50, 6, SEARCH_DLG_HEIGHT, "Scanf &expression", 0, 0,
1094 0, 0, XV_WLAY_DONTCARE, NULL },
1095 {quick_checkbox, 25, 50, 5, SEARCH_DLG_HEIGHT, "&Backwards", 0, 0,
1096 0, 0, XV_WLAY_DONTCARE, NULL},
1097 {quick_checkbox, 4, 50, 6, SEARCH_DLG_HEIGHT, "&Regular exprssn", 0, 0,
1098 0, 0, XV_WLAY_DONTCARE, NULL},
1099 {quick_checkbox, 4, 50, 5, SEARCH_DLG_HEIGHT, "&Whole words only", 0, 0,
1100 0, 0, XV_WLAY_DONTCARE, NULL},
1101 {quick_checkbox, 4, 50, 4, SEARCH_DLG_HEIGHT, "Case &sensitive", 0, 0,
1102 0, 0, XV_WLAY_DONTCARE, NULL},
1103 {quick_input, 3, 50, 3, SEARCH_DLG_HEIGHT, "", 44, 0, 0,
1104 0, XV_WLAY_BELOWCLOSE, "edit-search"},
1105 {quick_label, 2, 50, 2, SEARCH_DLG_HEIGHT, " Enter search string", 0, 0, 0,
1106 0, XV_WLAY_DONTCARE, 0},
1107 {0}};
1108
1109 quick_widgets[2].result = &treplace_scanf;
1110 quick_widgets[3].result = &treplace_backwards;
1111 quick_widgets[4].result = &treplace_regexp;
1112 quick_widgets[5].result = &treplace_whole;
1113 quick_widgets[6].result = &treplace_case;
1114 quick_widgets[7].str_result = &tsearch_text;
1115 quick_widgets[7].text = *search_text;
1116
1117 {
1118 QuickDialog Quick_input =
1119 {50, SEARCH_DLG_HEIGHT, -1, 0, N_(" Search "),
1120 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1121
1122 Quick_input.widgets = quick_widgets;
1123
1124 if (quick_dialog (&Quick_input) != B_CANCEL) {
1125 *search_text = *(quick_widgets[7].str_result);
1126 replace_scanf = treplace_scanf;
1127 replace_backwards = treplace_backwards;
1128 replace_regexp = treplace_regexp;
1129 replace_whole = treplace_whole;
1130 replace_case = treplace_case;
1131 return;
1132 } else {
1133 *search_text = NULL;
1134 return;
1135 }
1136 }
1137 }
1138
1139
1140 #else
1141
1142 #define B_ENTER 0
1143 #define B_SKIP_REPLACE 1
1144 #define B_REPLACE_ALL 2
1145 #define B_CANCEL 3
1146
1147 extern CWidget *wedit;
1148
1149 void edit_search_replace_dialog (Window parent, int x, int y, char **search_text, char **replace_text, char **arg_order, char *heading, int option)
1150 {
1151 Window win;
1152 XEvent xev;
1153 CEvent cev;
1154 CState s;
1155 int xh, yh, h, xb, ys, yc, yb, yr;
1156 CWidget *m;
1157
1158 CBackupState (&s);
1159 CDisable ("*");
1160
1161 win = CDrawHeadedDialog ("replace", parent, x, y, heading);
1162 CGetHintPos (&xh, &h);
1163
1164 /* NLS hotkey ? */
1165 CIdent ("replace")->position = WINDOW_ALWAYS_RAISED;
1166 /* An input line comes after the ':' */
1167 (CDrawText ("replace.t1", win, xh, h, _(" Enter search text : ")))->hotkey = 'E';
1168
1169 CGetHintPos (0, &yh);
1170 (m = CDrawTextInput ("replace.sinp", win, xh, yh, 10, AUTO_HEIGHT, 256, *search_text))->hotkey = 'E';
1171
1172 if (replace_text) {
1173 CGetHintPos (0, &yh);
1174 (CDrawText ("replace.t2", win, xh, yh, _(" Enter replace text : ")))->hotkey = 'n';
1175 CGetHintPos (0, &yh);
1176 (CDrawTextInput ("replace.rinp", win, xh, yh, 10, AUTO_HEIGHT, 256, *replace_text))->hotkey = 'n';
1177 CGetHintPos (0, &yh);
1178 (CDrawText ("replace.t3", win, xh, yh, _(" Enter argument order : ")))->hotkey = 'o';
1179 CGetHintPos (0, &yh);
1180 (CDrawTextInput ("replace.ainp", win, xh, yh, 10, AUTO_HEIGHT, 256, *arg_order))->hotkey = 'o';
1181 /* Tool hint */
1182 CSetToolHint ("replace.ainp", _("Enter the order of replacement of your scanf format specifiers"));
1183 CSetToolHint ("replace.t3", _("Enter the order of replacement of your scanf format specifiers"));
1184 }
1185 CGetHintPos (0, &yh);
1186 ys = yh;
1187 /* The following are check boxes */
1188 CDrawSwitch ("replace.ww", win, xh, yh, replace_whole, _(" Whole words only "), 0);
1189 CGetHintPos (0, &yh);
1190 CDrawSwitch ("replace.case", win, xh, yh, replace_case, _(" Case sensitive "), 0);
1191 yc = yh;
1192 CGetHintPos (0, &yh);
1193 CDrawSwitch ("replace.reg", win, xh, yh, replace_regexp, _(" Regular expression "), 1);
1194 CSetToolHint ("replace.reg", _("See the regex man page for how to compose a regular expression"));
1195 CSetToolHint ("replace.reg.label", _("See the regex man page for how to compose a regular expression"));
1196 yb = yh;
1197 CGetHintPos (0, &yh);
1198 CGetHintPos (&xb, 0);
1199
1200 if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
1201 CDrawSwitch ("replace.bkwd", win, xh, yh, replace_backwards, _(" Backwards "), 0);
1202 /* Tool hint */
1203 CSetToolHint ("replace.bkwd", _("Warning: Searching backward can be slow"));
1204 CSetToolHint ("replace.bkwd.label", _("Warning: Searching backward can be slow"));
1205 yb = yh;
1206 }
1207 if (replace_text) {
1208 if (option & SEARCH_DIALOG_OPTION_BACKWARDS)
1209 yr = yc;
1210 else
1211 yr = ys;
1212 } else {
1213 yr = yb;
1214 }
1215
1216 if (replace_text) {
1217 CDrawSwitch ("replace.pr", win, xb, yr, replace_prompt, _(" Prompt on replace "), 0);
1218 /* Tool hint */
1219 CSetToolHint ("replace.pr", _("Ask before making each replacement"));
1220 CGetHintPos (0, &yr);
1221 CDrawSwitch ("replace.all", win, xb, yr, replace_all, _(" Replace all "), 0);
1222 CGetHintPos (0, &yr);
1223 }
1224 CDrawSwitch ("replace.scanf", win, xb, yr, replace_scanf, _(" Scanf expression "), 1);
1225 /* Tool hint */
1226 CSetToolHint ("replace.scanf", _("Allows entering of a C format string, see the scanf man page"));
1227
1228 get_hint_limits (&x, &y);
1229 CDrawPixmapButton ("replace.ok", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h, PIXMAP_BUTTON_TICK);
1230 /* Tool hint */
1231 CSetToolHint ("replace.ok", _("Begin search, Enter"));
1232 CDrawPixmapButton ("replace.cancel", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h + WIDGET_SPACING + TICK_BUTTON_WIDTH, PIXMAP_BUTTON_CROSS);
1233 /* Tool hint */
1234 CSetToolHint ("replace.cancel", _("Abort this dialog, Esc"));
1235 CSetSizeHintPos ("replace");
1236 CMapDialog ("replace");
1237
1238 m = CIdent ("replace");
1239 CSetWidgetSize ("replace.sinp", m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH, (CIdent ("replace.sinp"))->height);
1240 if (replace_text) {
1241 CSetWidgetSize ("replace.rinp", m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH, (CIdent ("replace.rinp"))->height);
1242 CSetWidgetSize ("replace.ainp", m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH, (CIdent ("replace.ainp"))->height);
1243 }
1244 CFocus (CIdent ("replace.sinp"));
1245
1246 for (;;) {
1247 CNextEvent (&xev, &cev);
1248 if (!CIdent ("replace")) {
1249 *search_text = 0;
1250 break;
1251 }
1252 if (!strcmp (cev.ident, "replace.cancel") || cev.command == CK_Cancel) {
1253 *search_text = 0;
1254 break;
1255 }
1256 if (!strcmp (cev.ident, "replace.reg") || !strcmp (cev.ident, "replace.scanf")) {
1257 if (CIdent ("replace.reg")->keypressed || CIdent ("replace.scanf")->keypressed) {
1258 if (!(CIdent ("replace.case")->keypressed)) {
1259 CIdent ("replace.case")->keypressed = 1;
1260 CExpose ("replace.case");
1261 }
1262 }
1263 }
1264 if (!strcmp (cev.ident, "replace.ok") || cev.command == CK_Enter) {
1265 if (replace_text) {
1266 replace_all = CIdent ("replace.all")->keypressed;
1267 replace_prompt = CIdent ("replace.pr")->keypressed;
1268 *replace_text = strdup (CIdent ("replace.rinp")->text);
1269 *arg_order = strdup (CIdent ("replace.ainp")->text);
1270 }
1271 *search_text = strdup (CIdent ("replace.sinp")->text);
1272 replace_whole = CIdent ("replace.ww")->keypressed;
1273 replace_case = CIdent ("replace.case")->keypressed;
1274 replace_scanf = CIdent ("replace.scanf")->keypressed;
1275 replace_regexp = CIdent ("replace.reg")->keypressed;
1276
1277 if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
1278 replace_backwards = CIdent ("replace.bkwd")->keypressed;
1279 } else {
1280 replace_backwards = 0;
1281 }
1282
1283 break;
1284 }
1285 }
1286 CDestroyWidget ("replace");
1287 CRestoreState (&s);
1288 }
1289
1290
1291
1292 void edit_search_dialog (WEdit * edit, char **search_text)
1293 {
1294 /* Heads the 'Search' dialog box */
1295 edit_search_replace_dialog (WIN_MESSAGES, search_text, 0, 0, _(" Search "), SEARCH_DIALOG_OPTION_BACKWARDS);
1296 }
1297
1298 void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order)
1299 {
1300 /* Heads the 'Replace' dialog box */
1301 edit_search_replace_dialog (WIN_MESSAGES, search_text, replace_text, arg_order, _(" Replace "), SEARCH_DIALOG_OPTION_BACKWARDS);
1302 }
1303
1304 int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
1305 {
1306 if (replace_prompt) {
1307 int q;
1308 char *p, *r = 0;
1309 r = p = malloc (strlen (replace_text) + NUM_REPL_ARGS * 2);
1310 strcpy (p, replace_text);
1311 while ((p = strchr (p, '%'))) { /* convert "%" to "%%" so no convertion is attempted */
1312 memmove (p + 2, p + 1, strlen (p) + 1);
1313 *(++p) = '%';
1314 p++;
1315 }
1316 edit->force |= REDRAW_COMPLETELY;
1317 q = edit_query_dialog4 (_(" Replace "),
1318 /* This is for the confirm replace dialog box. The replaced string comes after the ':' */
1319 catstrs (_(" Replace with: "), r, 0),
1320 /* Buttons for the confirm replace dialog box. */
1321 _("Replace"), _("Skip"), _("Replace all"), _("Cancel"));
1322 if (r)
1323 free (r);
1324 switch (q) {
1325 case 0:
1326 return B_ENTER;
1327 case 1:
1328 return B_SKIP_REPLACE;
1329 case 2:
1330 return B_REPLACE_ALL;
1331 case -1:
1332 case 3:
1333 return B_CANCEL;
1334 }
1335 }
1336 return 0;
1337 }
1338
1339
1340 #endif
1341
1342 long sargs[NUM_REPL_ARGS][256 / sizeof (long)];
1343
1344 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1345 sargs[4], sargs[5], sargs[6], sargs[7], \
1346 sargs[8], sargs[9], sargs[10], sargs[11], \
1347 sargs[12], sargs[13], sargs[14], sargs[15]
1348
1349 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1350 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1351 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1352 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1353
1354 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1355 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1356 int string_regexp_search (char *pattern, char *string, int len, int match_type, int match_bol, int icase, int *found_len)
1357 {
1358 static regex_t r;
1359 regmatch_t pmatch[1];
1360 static char *old_pattern = NULL;
1361 static int old_type, old_icase;
1362
1363 if (!old_pattern || strcmp (old_pattern, pattern) || old_type != match_type || old_icase != icase) {
1364 if (old_pattern) {
1365 regfree (&r);
1366 free (old_pattern);
1367 old_pattern = 0;
1368 }
1369 if (regcomp (&r, pattern, REG_EXTENDED | (icase ? REG_ICASE : 0))) {
1370 *found_len = 0;
1371 return -3;
1372 }
1373 old_pattern = strdup (pattern);
1374 old_type = match_type;
1375 old_icase = icase;
1376 }
1377 if (regexec (&r, string, 1, pmatch, ((match_bol || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) {
1378 *found_len = 0;
1379 return -1;
1380 }
1381 *found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
1382 return (pmatch[0].rm_so);
1383 }
1384
1385 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1386 (and the above) routines to work properly - paul */
1387
1388 long edit_find_string (long start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, int once_only)
1389 {
1390 long p, q = 0;
1391 long l = strlen ((char *) exp), f = 0;
1392 int n = 0;
1393
1394 for (p = 0; p < l; p++) /* count conversions... */
1395 if (exp[p] == '%')
1396 if (exp[++p] != '%') /* ...except for "%%" */
1397 n++;
1398
1399 if (replace_scanf || replace_regexp) {
1400 int c;
1401 unsigned char *buf;
1402 unsigned char mbuf[MAX_REPL_LEN * 2 + 3];
1403
1404 replace_scanf = (!replace_regexp); /* can't have both */
1405
1406 buf = mbuf;
1407
1408 if (replace_scanf) {
1409 unsigned char e[MAX_REPL_LEN];
1410 if (n >= NUM_REPL_ARGS)
1411 return -3;
1412
1413 if (replace_case) {
1414 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++)
1415 buf[p - start] = (*get_byte) (data, p);
1416 } else {
1417 for (p = 0; exp[p] != 0; p++)
1418 exp[p] = my_lower_case (exp[p]);
1419 for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) {
1420 c = (*get_byte) (data, p);
1421 buf[p - start] = my_lower_case (c);
1422 }
1423 }
1424
1425 buf[(q = p - start)] = 0;
1426 strcpy ((char *) e, (char *) exp);
1427 strcat ((char *) e, "%n");
1428 exp = e;
1429
1430 while (q) {
1431 *((int *) sargs[n]) = 0; /* --> here was the problem - now fixed: good */
1432 if (n == sscanf ((char *) buf, (char *) exp, SCANF_ARGS)) {
1433 if (*((int *) sargs[n])) {
1434 *len = *((int *) sargs[n]);
1435 return start;
1436 }
1437 }
1438 if (once_only)
1439 return -2;
1440 if (q + start < last_byte) {
1441 if (replace_case) {
1442 buf[q] = (*get_byte) (data, q + start);
1443 } else {
1444 c = (*get_byte) (data, q + start);
1445 buf[q] = my_lower_case (c);
1446 }
1447 q++;
1448 }
1449 buf[q] = 0;
1450 start++;
1451 buf++; /* move the window along */
1452 if (buf == mbuf + MAX_REPL_LEN) { /* the window is about to go past the end of array, so... */
1453 memmove (mbuf, buf, strlen ((char *) buf) + 1); /* reset it */
1454 buf = mbuf;
1455 }
1456 q--;
1457 }
1458 } else { /* regexp matching */
1459 long offset = 0;
1460 int found_start, match_bol, move_win = 0;
1461
1462 while (start + offset < last_byte) {
1463 match_bol = (offset == 0 || (*get_byte) (data, start + offset - 1) == '\n');
1464 if (!move_win) {
1465 p = start + offset;
1466 q = 0;
1467 }
1468 for (; p < last_byte && q < MAX_REPL_LEN; p++, q++) {
1469 mbuf[q] = (*get_byte) (data, p);
1470 if (mbuf[q] == '\n')
1471 break;
1472 }
1473 q++;
1474 offset += q;
1475 mbuf[q] = 0;
1476
1477 buf = mbuf;
1478 while (q) {
1479 found_start = string_regexp_search ((char *) exp, (char *) buf, q, match_normal, match_bol, !replace_case, len);
1480
1481 if (found_start <= -2) { /* regcomp/regexec error */
1482 *len = 0;
1483 return -3;
1484 }
1485 else if (found_start == -1) /* not found: try next line */
1486 break;
1487 else if (*len == 0) { /* null pattern: try again at next character */
1488 q--;
1489 buf++;
1490 match_bol = 0;
1491 continue;
1492 }
1493 else /* found */
1494 return (start + offset - q + found_start);
1495 }
1496 if (once_only)
1497 return -2;
1498
1499 if (buf[q - 1] != '\n') { /* incomplete line: try to recover */
1500 buf = mbuf + MAX_REPL_LEN / 2;
1501 q = strlen ((char *) buf);
1502 memmove (mbuf, buf, q);
1503 p = start + q;
1504 move_win = 1;
1505 }
1506 else
1507 move_win = 0;
1508 }
1509 }
1510 } else {
1511 *len = strlen ((char *) exp);
1512 if (replace_case) {
1513 for (p = start; p <= last_byte - l; p++) {
1514 if ((*get_byte) (data, p) == (unsigned char)exp[0]) { /* check if first char matches */
1515 for (f = 0, q = 0; q < l && f < 1; q++)
1516 if ((*get_byte) (data, q + p) != (unsigned char)exp[q])
1517 f = 1;
1518 if (f == 0)
1519 return p;
1520 }
1521 if (once_only)
1522 return -2;
1523 }
1524 } else {
1525 for (p = 0; exp[p] != 0; p++)
1526 exp[p] = my_lower_case (exp[p]);
1527
1528 for (p = start; p <= last_byte - l; p++) {
1529 if (my_lower_case ((*get_byte) (data, p)) == (unsigned char)exp[0]) {
1530 for (f = 0, q = 0; q < l && f < 1; q++)
1531 if (my_lower_case ((*get_byte) (data, q + p)) != (unsigned char)exp[q])
1532 f = 1;
1533 if (f == 0)
1534 return p;
1535 }
1536 if (once_only)
1537 return -2;
1538 }
1539 }
1540 }
1541 return -2;
1542 }
1543
1544
1545 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)
1546 { /*front end to find_string to check for
1547 whole words */
1548 long p;
1549 p = search_start;
1550
1551 while ((p = edit_find_string (p, exp, len, last_byte, get_byte, data, once_only)) >= 0) {
1552 if (replace_whole) {
1553 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1554 if (!strcasechr (option_whole_chars_search, (*get_byte) (data, p - 1))
1555 && !strcasechr (option_whole_chars_search, (*get_byte) (data, p + *len)))
1556 return p;
1557 if (once_only)
1558 return -2;
1559 } else
1560 return p;
1561 if (once_only)
1562 break;
1563 p++; /*not a whole word so continue search. */
1564 }
1565 return p;
1566 }
1567
1568 long edit_find (long search_start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data)
1569 {
1570 long p;
1571 if (replace_backwards) {
1572 while (search_start >= 0) {
1573 p = edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 1);
1574 if (p == search_start)
1575 return p;
1576 search_start--;
1577 }
1578 } else {
1579 return edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 0);
1580 }
1581 return -2;
1582 }
1583
1584 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1585
1586 #define snprintf(v) { \
1587 *p1++ = *p++; \
1588 *p1++ = '%'; \
1589 *p1++ = 'n'; \
1590 *p1 = '\0'; \
1591 sprintf(s,q1,v,&n); \
1592 s += n; \
1593 }
1594
1595 /* this function uses the sprintf command to do a vprintf */
1596 /* it takes pointers to arguments instead of the arguments themselves */
1597 int sprintf_p (char *str, const char *fmt,...)
1598 {
1599 va_list ap;
1600 int n;
1601 char *q, *p, *s = str;
1602 char q1[32];
1603 char *p1;
1604
1605 va_start (ap, fmt);
1606 p = q = (char *) fmt;
1607
1608 while ((p = strchr (p, '%'))) {
1609 n = (int) ((unsigned long) p - (unsigned long) q);
1610 strncpy (s, q, n); /* copy stuff between format specifiers */
1611 s += n;
1612 *s = 0;
1613 q = p;
1614 p1 = q1;
1615 *p1++ = *p++;
1616 if (*p == '%') {
1617 p++;
1618 *s++ = '%';
1619 q = p;
1620 continue;
1621 }
1622 if (*p == 'n') {
1623 p++;
1624 /* do nothing */
1625 q = p;
1626 continue;
1627 }
1628 if (*p == '#')
1629 *p1++ = *p++;
1630 if (*p == '0')
1631 *p1++ = *p++;
1632 if (*p == '-')
1633 *p1++ = *p++;
1634 if (*p == '+')
1635 *p1++ = *p++;
1636 if (*p == '*') {
1637 p++;
1638 strcpy (p1, itoa (*va_arg (ap, int *))); /* replace field width with a number */
1639 p1 += strlen (p1);
1640 } else {
1641 while (is_digit (*p))
1642 *p1++ = *p++;
1643 }
1644 if (*p == '.')
1645 *p1++ = *p++;
1646 if (*p == '*') {
1647 p++;
1648 strcpy (p1, itoa (*va_arg (ap, int *))); /* replace precision with a number */
1649 p1 += strlen (p1);
1650 } else {
1651 while (is_digit (*p))
1652 *p1++ = *p++;
1653 }
1654 /* flags done, now get argument */
1655 if (*p == 's') {
1656 snprintf (va_arg (ap, char *));
1657 } else if (*p == 'h') {
1658 if (strchr ("diouxX", *p))
1659 snprintf (*va_arg (ap, short *));
1660 } else if (*p == 'l') {
1661 *p1++ = *p++;
1662 if (strchr ("diouxX", *p))
1663 snprintf (*va_arg (ap, long *));
1664 } else if (strchr ("cdiouxX", *p)) {
1665 snprintf (*va_arg (ap, int *));
1666 } else if (*p == 'L') {
1667 *p1++ = *p++;
1668 if (strchr ("EefgG", *p))
1669 snprintf (*va_arg (ap, double *)); /* should be long double */
1670 } else if (strchr ("EefgG", *p)) {
1671 snprintf (*va_arg (ap, double *));
1672 } else if (strchr ("DOU", *p)) {
1673 snprintf (*va_arg (ap, long *));
1674 } else if (*p == 'p') {
1675 snprintf (*va_arg (ap, void **));
1676 }
1677 q = p;
1678 }
1679 va_end (ap);
1680 sprintf (s, q); /* print trailing leftover */
1681 return (unsigned long) s - (unsigned long) str + strlen (s);
1682 }
1683
1684 static void regexp_error (WEdit *edit)
1685 {
1686 /* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */
1687 edit_error_dialog (_(" Error "), _(" Invalid regular expression, or scanf expression with to many conversions "));
1688 }
1689
1690 /* call with edit = 0 before shutdown to close memory leaks */
1691 void edit_replace_cmd (WEdit * edit, int again)
1692 {
1693 static char *old1 = NULL;
1694 static char *old2 = NULL;
1695 static char *old3 = NULL;
1696 char *exp1 = "";
1697 char *exp2 = "";
1698 char *exp3 = "";
1699 int replace_yes;
1700 int replace_continue;
1701 int i = 0;
1702 long times_replaced = 0, last_search;
1703 char fin_string[32];
1704 int argord[NUM_REPL_ARGS];
1705
1706 if (!edit) {
1707 if (old1) {
1708 free (old1);
1709 old1 = 0;
1710 }
1711 if (old2) {
1712 free (old2);
1713 old2 = 0;
1714 }
1715 if (old3) {
1716 free (old3);
1717 old3 = 0;
1718 }
1719 return;
1720 }
1721
1722 last_search = edit->last_byte;
1723
1724 edit->force |= REDRAW_COMPLETELY;
1725
1726 exp1 = old1 ? old1 : exp1;
1727 exp2 = old2 ? old2 : exp2;
1728 exp3 = old3 ? old3 : exp3;
1729
1730 if (again) {
1731 if (!old1 || !old2)
1732 return;
1733 exp1 = strdup (old1);
1734 exp2 = strdup (old2);
1735 exp3 = strdup (old3);
1736 } else {
1737 edit_push_action (edit, KEY_PRESS + edit->start_display);
1738 edit_replace_dialog (edit, &exp1, &exp2, &exp3);
1739 }
1740
1741 if (!exp1 || !*exp1) {
1742 edit->force = REDRAW_COMPLETELY;
1743 if (exp1) {
1744 free (exp1);
1745 free (exp2);
1746 free (exp3);
1747 }
1748 return;
1749 }
1750 if (old1)
1751 free (old1);
1752 if (old2)
1753 free (old2);
1754 if (old3)
1755 free (old3);
1756 old1 = strdup (exp1);
1757 old2 = strdup (exp2);
1758 old3 = strdup (exp3);
1759
1760 {
1761 char *s;
1762 int ord;
1763 while ((s = strchr (exp3, ' ')))
1764 memmove (s, s + 1, strlen (s));
1765 s = exp3;
1766 for (i = 0; i < NUM_REPL_ARGS; i++) {
1767 if ((unsigned long) s != 1 && s < exp3 + strlen (exp3)) {
1768 if ((ord = atoi (s)))
1769 argord[i] = ord - 1;
1770 else
1771 argord[i] = i;
1772 s = strchr (s, ',') + 1;
1773 } else
1774 argord[i] = i;
1775 }
1776 }
1777
1778 replace_continue = replace_all;
1779
1780 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
1781 edit->search_start--;
1782
1783 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
1784 edit->search_start++;
1785
1786 do {
1787 int len = 0;
1788 long new_start;
1789 new_start = edit_find (edit->search_start, (unsigned char *) exp1, &len, last_search,
1790 (int (*) (void *, long)) edit_get_byte, (void *) edit);
1791 if (new_start == -3) {
1792 regexp_error (edit);
1793 break;
1794 }
1795 edit->search_start = new_start;
1796 /*returns negative on not found or error in pattern */
1797
1798 if (edit->search_start >= 0) {
1799 edit->found_start = edit->search_start;
1800 i = edit->found_len = len;
1801
1802 edit_cursor_move (edit, edit->search_start - edit->curs1);
1803 edit_scroll_screen_over_cursor (edit);
1804
1805 replace_yes = 1;
1806
1807 if (replace_prompt) {
1808 int l;
1809 l = edit->curs_row - edit->num_widget_lines / 3;
1810 if (l > 0)
1811 edit_scroll_downward (edit, l);
1812 if (l < 0)
1813 edit_scroll_upward (edit, -l);
1814
1815 edit_scroll_screen_over_cursor (edit);
1816 edit->force |= REDRAW_PAGE;
1817 edit_render_keypress (edit);
1818
1819 /*so that undo stops at each query */
1820 edit_push_key_press (edit);
1821
1822 switch (edit_replace_prompt (edit, exp2, /*and prompt 2/3 down */
1823 edit->num_widget_columns / 2 - 33, edit->num_widget_lines * 2 / 3)) {
1824 case B_ENTER:
1825 break;
1826 case B_SKIP_REPLACE:
1827 replace_yes = 0;
1828 break;
1829 case B_REPLACE_ALL:
1830 replace_prompt = 0;
1831 replace_continue = 1;
1832 break;
1833 case B_CANCEL:
1834 replace_yes = 0;
1835 replace_continue = 0;
1836 break;
1837 }
1838 }
1839 if (replace_yes) { /* delete then insert new */
1840 if (replace_scanf) {
1841 char repl_str[MAX_REPL_LEN + 2];
1842 if (sprintf_p (repl_str, exp2, PRINTF_ARGS) >= 0) {
1843 times_replaced++;
1844 while (i--)
1845 edit_delete (edit);
1846 while (repl_str[++i])
1847 edit_insert (edit, repl_str[i]);
1848 } else {
1849 edit_error_dialog (_(" Replace "),
1850 /* "Invalid regexp string or scanf string" */
1851 _(" Error in replacement format string. "));
1852 replace_continue = 0;
1853 }
1854 } else {
1855 times_replaced++;
1856 while (i--)
1857 edit_delete (edit);
1858 while (exp2[++i])
1859 edit_insert (edit, exp2[i]);
1860 }
1861 edit->found_len = i;
1862 }
1863 /* so that we don't find the same string again */
1864 if (replace_backwards) {
1865 last_search = edit->search_start;
1866 edit->search_start--;
1867 } else {
1868 edit->search_start += i;
1869 last_search = edit->last_byte;
1870 }
1871 edit_scroll_screen_over_cursor (edit);
1872 } else {
1873 edit->search_start = edit->curs1; /* try and find from right here for next search */
1874 edit_update_curs_col (edit);
1875
1876 edit->force |= REDRAW_PAGE;
1877 edit_render_keypress (edit);
1878 if (times_replaced) {
1879 sprintf (fin_string, _(" %ld replacements made. "), times_replaced);
1880 edit_message_dialog (_(" Replace "), fin_string);
1881 } else
1882 edit_message_dialog (_(" Replace "), _(" Search string not found. "));
1883 replace_continue = 0;
1884 }
1885 } while (replace_continue);
1886
1887 free (exp1);
1888 free (exp2);
1889 free (exp3);
1890 edit->force = REDRAW_COMPLETELY;
1891 edit_scroll_screen_over_cursor (edit);
1892 }
1893
1894
1895
1896
1897 void edit_search_cmd (WEdit * edit, int again)
1898 {
1899 static char *old = NULL;
1900 char *exp = "";
1901
1902 if (!edit) {
1903 if (old) {
1904 free (old);
1905 old = 0;
1906 }
1907 return;
1908 }
1909
1910 exp = old ? old : exp;
1911 if (again) { /*ctrl-hotkey for search again. */
1912 if (!old)
1913 return;
1914 exp = strdup (old);
1915 } else {
1916 edit_search_dialog (edit, &exp);
1917 edit_push_action (edit, KEY_PRESS + edit->start_display);
1918 }
1919
1920 if (exp) {
1921 if (*exp) {
1922 int len = 0;
1923 if (old)
1924 free (old);
1925 old = strdup (exp);
1926
1927 if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
1928 edit->search_start--;
1929
1930 if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
1931 edit->search_start++;
1932
1933 edit->search_start = edit_find (edit->search_start, (unsigned char *) exp, &len, edit->last_byte,
1934 (int (*)(void *, long)) edit_get_byte, (void *) edit);
1935
1936 if (edit->search_start >= 0) {
1937 edit->found_start = edit->search_start;
1938 edit->found_len = len;
1939
1940 edit_cursor_move (edit, edit->search_start - edit->curs1);
1941 edit_scroll_screen_over_cursor (edit);
1942 if (replace_backwards)
1943 edit->search_start--;
1944 else
1945 edit->search_start++;
1946 } else if (edit->search_start == -3) {
1947 edit->search_start = edit->curs1;
1948 regexp_error (edit);
1949 } else {
1950 edit->search_start = edit->curs1;
1951 edit_error_dialog (_(" Search "), _(" Search string not found. "));
1952 }
1953 }
1954 free (exp);
1955 }
1956 edit->force |= REDRAW_COMPLETELY;
1957 edit_scroll_screen_over_cursor (edit);
1958 }
1959
1960
1961 /* Real edit only */
1962 void edit_quit_cmd (WEdit * edit)
1963 {
1964 edit_push_action (edit, KEY_PRESS + edit->start_display);
1965
1966 edit->force |= REDRAW_COMPLETELY;
1967 if (edit->modified) {
1968 #ifdef MIDNIGHT
1969 switch (edit_query_dialog3 (_(" Quit "), _(" File was modified, Save with exit? "), _("Cancel quit"), _("&Yes"), _("&No"))) {
1970 #else
1971 /* Confirm 'Quit' dialog box */
1972 switch (edit_query_dialog3 (_(" Quit "),
1973 _(" Current text was modified without a file save. \n Save with exit? "), _(" &Cancel quit "), _(" &Yes "), _(" &No "))) {
1974 #endif
1975 case 1:
1976 edit_push_markers (edit);
1977 edit_set_markers (edit, 0, 0, 0, 0);
1978 if (!edit_save_cmd (edit))
1979 return;
1980 break;
1981 case 2:
1982 #ifdef MIDNIGHT
1983 if (edit->delete_file)
1984 unlink (catstrs (edit->dir, edit->filename, 0));
1985 #endif
1986 break;
1987 case 0:
1988 case -1:
1989 return;
1990 }
1991 }
1992 #ifdef MIDNIGHT
1993 else if (edit->delete_file)
1994 unlink (catstrs (edit->dir, edit->filename, 0));
1995
1996 edit->widget.parent->running = 0;
1997 #else
1998 edit->stopped = 1;
1999 #endif
2000 }
2001
2002 #define TEMP_BUF_LEN 1024
2003
2004 extern int column_highlighting;
2005
2006 /* returns a null terminated length of text. Result must be free'd */
2007 unsigned char *edit_get_block (WEdit * edit, long start, long finish, int *l)
2008 {
2009 unsigned char *s, *r;
2010 r = s = malloc (finish - start + 1);
2011 if (column_highlighting) {
2012 *l = 0;
2013 while (start < finish) { /* copy from buffer, excluding chars that are out of the column 'margins' */
2014 int c, x;
2015 x = edit_move_forward3 (edit, edit_bol (edit, start), 0, start);
2016 c = edit_get_byte (edit, start);
2017 if ((x >= edit->column1 && x < edit->column2)
2018 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
2019 *s++ = c;
2020 (*l)++;
2021 }
2022 start++;
2023 }
2024 } else {
2025 *l = finish - start;
2026 while (start < finish)
2027 *s++ = edit_get_byte (edit, start++);
2028 }
2029 *s = 0;
2030 return r;
2031 }
2032
2033 /* save block, returns 1 on success */
2034 int edit_save_block (WEdit * edit, const char *filename, long start, long finish)
2035 {
2036 long i = start, end, filelen = finish - start;
2037 int file;
2038 unsigned char *buf;
2039
2040 if ((file = open ((char *) filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
2041 return 0;
2042
2043 buf = malloc (TEMP_BUF_LEN);
2044 while (start != finish) {
2045 end = min (finish, start + TEMP_BUF_LEN);
2046 for (; i < end; i++)
2047 buf[i - start] = edit_get_byte (edit, i);
2048 filelen -= write (file, (char *) buf, end - start);
2049 start = end;
2050 }
2051 free (buf);
2052 close (file);
2053 if (filelen)
2054 return 0;
2055 return 1;
2056 }
2057
2058 /* copies a block to clipboard file */
2059 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
2060 {
2061 return edit_save_block (edit, catstrs (home_dir, CLIP_FILE, 0), start, finish);
2062 }
2063
2064 #ifndef MIDNIGHT
2065
2066 void paste_text (WEdit * edit, unsigned char *data, unsigned int nitems)
2067 {
2068 if (data) {
2069 data += nitems - 1;
2070 while (nitems--)
2071 edit_insert_ahead (edit, *data--);
2072 }
2073 edit->force |= REDRAW_COMPLETELY;
2074 }
2075
2076 char *selection_get_line (void *data, int line)
2077 {
2078 static unsigned char t[1024];
2079 struct selection *s;
2080 int i = 0;
2081 s = (struct selection *) data;
2082 line = (current_selection + line + 1) % NUM_SELECTION_HISTORY;
2083 if (s[line].text) {
2084 unsigned char *p = s[line].text;
2085 int c, j;
2086 for (j = 0; j < s[line].len; j++) {
2087 c = *p++;
2088 if ((c < ' ' || (c > '~' && c < 160)) && c != '\t') {
2089 t[i++] = '.';
2090 t[i++] = '\b';
2091 t[i++] = '.';
2092 } else
2093 t[i++] = c;
2094 if (i > 1020)
2095 break;
2096 }
2097 }
2098 t[i] = 0;
2099 return (char *) t;
2100 }
2101
2102 void edit_paste_from_history (WEdit * edit)
2103 {
2104 int i, c;
2105
2106 edit_update_curs_col (edit);
2107 edit_update_curs_row (edit);
2108
2109 c = max (20, edit->num_widget_columns - 5);
2110
2111 i = CListboxDialog (WIN_MESSAGES, c, 10,
2112 0, NUM_SELECTION_HISTORY - 10, NUM_SELECTION_HISTORY - 1, NUM_SELECTION_HISTORY,
2113 selection_get_line, (void *) selection_history);
2114
2115 if (i < 0)
2116 return;
2117
2118 i = (current_selection + i + 1) % NUM_SELECTION_HISTORY;
2119
2120 paste_text (edit, selection_history[i].text, selection_history[i].len);
2121 edit->force |= REDRAW_COMPLETELY;
2122 }
2123
2124 /* copies a block to the XWindows buffer */
2125 static int edit_XStore_block (WEdit * edit, long start, long finish)
2126 {
2127 edit_get_selection (edit);
2128 if (selection.len <= 512 * 1024) { /* we don't want to fill up the server */
2129 XStoreBytes (CDisplay, (char *) selection.text, (int) selection.len);
2130 return 0;
2131 } else
2132 return 1;
2133 }
2134
2135 int edit_copy_to_X_buf_cmd (WEdit * edit)
2136 {
2137 long start_mark, end_mark;
2138 if (eval_marks (edit, &start_mark, &end_mark))
2139 return 0;
2140 edit_XStore_block (edit, start_mark, end_mark);
2141 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2142 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2143 return 1;
2144 }
2145 XSetSelectionOwner (CDisplay, XA_PRIMARY, edit->widget->winid, CurrentTime);
2146 edit_mark_cmd (edit, 1);
2147 return 0;
2148 }
2149
2150 int edit_cut_to_X_buf_cmd (WEdit * edit)
2151 {
2152 long start_mark, end_mark;
2153 if (eval_marks (edit, &start_mark, &end_mark))
2154 return 0;
2155 edit_XStore_block (edit, start_mark, end_mark);
2156 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2157 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2158 return 1;
2159 }
2160 edit_block_delete_cmd (edit);
2161 XSetSelectionOwner (CDisplay, XA_PRIMARY, edit->widget->winid, CurrentTime);
2162 edit_mark_cmd (edit, 1);
2163 return 0;
2164 }
2165
2166 void selection_paste (WEdit * edit, Window win, unsigned prop, int delete);
2167
2168 void edit_paste_from_X_buf_cmd (WEdit * edit)
2169 {
2170 if (selection.text)
2171 paste_text (edit, selection.text, selection.len);
2172 else if (!XGetSelectionOwner (CDisplay, XA_PRIMARY))
2173 selection_paste (edit, CRoot, XA_CUT_BUFFER0, False);
2174 else
2175 XConvertSelection (CDisplay, XA_PRIMARY, XA_STRING,
2176 XInternAtom (CDisplay, "VT_SELECTION", False),
2177 edit->widget->winid, CurrentTime);
2178 edit->force |= REDRAW_PAGE;
2179 }
2180
2181 #else /* MIDNIGHT */
2182
2183 void edit_paste_from_history (WEdit *edit)
2184 {
2185 }
2186
2187 int edit_copy_to_X_buf_cmd (WEdit * edit)
2188 {
2189 long start_mark, end_mark;
2190 if (eval_marks (edit, &start_mark, &end_mark))
2191 return 0;
2192 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2193 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2194 return 1;
2195 }
2196 edit_mark_cmd (edit, 1);
2197 return 0;
2198 }
2199
2200 int edit_cut_to_X_buf_cmd (WEdit * edit)
2201 {
2202 long start_mark, end_mark;
2203 if (eval_marks (edit, &start_mark, &end_mark))
2204 return 0;
2205 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
2206 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2207 return 1;
2208 }
2209 edit_block_delete_cmd (edit);
2210 edit_mark_cmd (edit, 1);
2211 return 0;
2212 }
2213
2214 void edit_paste_from_X_buf_cmd (WEdit * edit)
2215 {
2216 edit_insert_file (edit, catstrs (home_dir, CLIP_FILE, 0));
2217 }
2218
2219 #endif /* MIDMIGHT */
2220
2221 void edit_goto_cmd (WEdit *edit)
2222 {
2223 char *f;
2224 static int l = 0;
2225 #ifdef MIDNIGHT
2226 char s[12];
2227 sprintf (s, "%d", l);
2228 f = input_dialog (_(" Goto line "), _(" Enter line: "), l ? s : "");
2229 #else
2230 f = CInputDialog ("goto", WIN_MESSAGES, 150, l ? itoa (l) : "", _(" Goto line "), _(" Enter line: "));
2231 #endif
2232 if (f) {
2233 if (*f) {
2234 l = atoi (f);
2235 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2236 edit_move_to_line (edit, l - 1);
2237 edit->force |= REDRAW_COMPLETELY;
2238 free (f);
2239 }
2240 }
2241 }
2242
2243 /*returns 1 on success */
2244 int edit_save_block_cmd (WEdit * edit) {
2245 long start_mark, end_mark;
2246 char *exp;
2247 if (eval_marks (edit, &start_mark, &end_mark))
2248 return 1;
2249
2250 exp = edit_get_save_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _(" Save Block "));
2251
2252 edit->force |= REDRAW_COMPLETELY;
2253 edit_push_action (edit, KEY_PRESS + edit->start_display);
2254
2255 if (exp) {
2256 if (!*exp) {
2257 free (exp);
2258 return 0;
2259 } else {
2260 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2261 free (exp);
2262 edit->force |= REDRAW_COMPLETELY;
2263 return 1;
2264 } else {
2265 free (exp);
2266 edit->force |= REDRAW_COMPLETELY;
2267 edit_error_dialog (_(" Save Block "), get_sys_error (_(" Error trying to save file. ")));
2268 return 0;
2269 }
2270 }
2271 } else
2272 return 0;
2273 }
2274
2275
2276 /* inserts a file at the cursor, returns 1 on success */
2277 int edit_insert_file (WEdit * edit, const char *filename)
2278 {
2279 int i, file, blocklen;
2280 long current = edit->curs1;
2281 unsigned char *buf;
2282
2283 if ((file = open ((char *) filename, O_RDONLY)) == -1)
2284 return 0;
2285 buf = malloc (TEMP_BUF_LEN);
2286 while ((blocklen = read (file, (char *) buf, TEMP_BUF_LEN)) > 0) {
2287 for (i = 0; i < blocklen; i++)
2288 edit_insert (edit, buf[i]);
2289 }
2290 edit_cursor_move (edit, current - edit->curs1);
2291 free (buf);
2292 close (file);
2293 if (blocklen)
2294 return 0;
2295 return 1;
2296 }
2297
2298
2299 /* returns 1 on success */
2300 int edit_insert_file_cmd (WEdit * edit) {
2301 char *exp = edit_get_load_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _(" Insert File "));
2302 edit->force |= REDRAW_COMPLETELY;
2303
2304 edit_push_action (edit, KEY_PRESS + edit->start_display);
2305
2306 if (exp) {
2307 if (!*exp) {
2308 free (exp);
2309 return 0;
2310 } else {
2311 if (edit_insert_file (edit, exp)) {
2312 free (exp);
2313 return 1;
2314 } else {
2315 free (exp);
2316 edit_error_dialog (_(" Insert file "), get_sys_error (_(" Error trying to insert file. ")));
2317 return 0;
2318 }
2319 }
2320 } else
2321 return 0;
2322 }
2323
2324 #ifdef MIDNIGHT
2325
2326 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2327 int edit_sort_cmd (WEdit * edit)
2328 {
2329 static char *old = 0;
2330 char *exp;
2331 long start_mark, end_mark;
2332 int e;
2333
2334 if (eval_marks (edit, &start_mark, &end_mark)) {
2335 /* Not essential to translate */
2336 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2337 return 0;
2338 }
2339 edit_save_block (edit, catstrs (home_dir, BLOCK_FILE, 0), start_mark, end_mark);
2340
2341 exp = old ? old : "";
2342
2343 exp = input_dialog (_(" Run Sort "),
2344 /* Not essential to translate */
2345 _(" Enter sort options (see manpage) separated by whitespace: "), "");
2346
2347 if (!exp)
2348 return 1;
2349 if (old)
2350 free (old);
2351 old = exp;
2352
2353 e = system (catstrs (" sort ", exp, " ", home_dir, BLOCK_FILE, " > ", home_dir, TEMP_FILE, 0));
2354 if (e) {
2355 if (e == -1 || e == 127) {
2356 edit_error_dialog (_(" Sort "),
2357 /* Not essential to translate */
2358 get_sys_error (_(" Error trying to execute sort command ")));
2359 } else {
2360 char q[8];
2361 sprintf (q, "%d ", e);
2362 edit_error_dialog (_(" Sort "),
2363 /* Not essential to translate */
2364 catstrs (_(" Sort returned non-zero: "), q, 0));
2365 }
2366 return -1;
2367 }
2368
2369 edit->force |= REDRAW_COMPLETELY;
2370
2371 if (edit_block_delete_cmd (edit))
2372 return 1;
2373 edit_insert_file (edit, catstrs (home_dir, TEMP_FILE, 0));
2374 return 0;
2375 }
2376
2377 /* if block is 1, a block must be highlighted and the shell command
2378 processes it. If block is 0 the shell command is a straight system
2379 command, that just produces some output which is to be inserted */
2380 void edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block)
2381 {
2382 long start_mark, end_mark;
2383 struct stat s;
2384 char *f = NULL, *b = NULL;
2385
2386 if (block) {
2387 if (eval_marks (edit, &start_mark, &end_mark)) {
2388 edit_error_dialog (_(" Process block "),
2389 /* Not essential to translate */
2390 _(" You must first highlight a block of text. "));
2391 return;
2392 }
2393 edit_save_block (edit, b = catstrs (home_dir, BLOCK_FILE, 0), start_mark, end_mark);
2394 my_system (0, shell, catstrs (home_dir, shell_cmd, 0));
2395 edit_refresh_cmd (edit);
2396 } else {
2397 my_system (0, shell, shell_cmd);
2398 edit_refresh_cmd (edit);
2399 }
2400
2401 edit->force |= REDRAW_COMPLETELY;
2402
2403 f = catstrs (home_dir, ERROR_FILE, 0);
2404
2405 if (block) {
2406 if (stat (f, &s) == 0) {
2407 if (!s.st_size) { /* no error messages */
2408 if (edit_block_delete_cmd (edit))
2409 return;
2410 edit_insert_file (edit, b);
2411 return;
2412 } else {
2413 edit_insert_file (edit, f);
2414 return;
2415 }
2416 } else {
2417 /* Not essential to translate */
2418 edit_error_dialog (_(" Process block "),
2419 /* Not essential to translate */
2420 get_sys_error (_(" Error trying to stat file ")));
2421 return;
2422 }
2423 }
2424 }
2425
2426 #endif
2427
2428 int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion);
2429
2430 /* prints at the cursor */
2431 /* returns the number of chars printed */
2432 int edit_print_string (WEdit * e, const char *s)
2433 {
2434 int i = 0;
2435 while (s[i])
2436 edit_execute_cmd (e, -1, s[i++]);
2437 e->force |= REDRAW_COMPLETELY;
2438 edit_update_screen (e);
2439 return i;
2440 }
2441
2442 int edit_printf (WEdit * e, const char *fmt,...)
2443 {
2444 int i;
2445 va_list pa;
2446 char s[1024];
2447 va_start (pa, fmt);
2448 sprintf (s, fmt, pa);
2449 i = edit_print_string (e, s);
2450 va_end (pa);
2451 return i;
2452 }
2453
2454 #ifdef MIDNIGHT
2455
2456 /* FIXME: does this function break NT_OS2 ? */
2457
2458 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2459 {
2460 FILE *p;
2461 char *s;
2462 s = malloc (4096);
2463 sprintf (s, "mail -s \"%s\" -c \"%s\" \"%s\"", subject, cc, to);
2464 p = popen (s, "w");
2465 if (!p) {
2466 free (s);
2467 return;
2468 } else {
2469 long i;
2470 for (i = 0; i < edit->last_byte; i++)
2471 fputc (edit_get_byte (edit, i), p);
2472 pclose (p);
2473 }
2474 free (s);
2475 }
2476
2477 #define MAIL_DLG_HEIGHT 12
2478
2479 void edit_mail_dialog (WEdit * edit)
2480 {
2481 char *tmail_to;
2482 char *tmail_subject;
2483 char *tmail_cc;
2484
2485 static char *mail_cc_last = 0;
2486 static char *mail_subject_last = 0;
2487 static char *mail_to_last = 0;
2488
2489 QuickDialog Quick_input =
2490 {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
2491 /* NLS ? */
2492 "[Input Line Keys]", "quick_input", 0};
2493
2494 QuickWidget quick_widgets[] =
2495 {
2496 /* NLS ? */
2497 {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, "&Cancel", 0, B_CANCEL, 0,
2498 0, XV_WLAY_DONTCARE, NULL},
2499 {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, "&Ok", 0, B_ENTER, 0,
2500 0, XV_WLAY_DONTCARE, NULL},
2501 {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2502 0, XV_WLAY_BELOWCLOSE, "mail-dlg-input"},
2503 {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, " Copies to", 0, 0, 0,
2504 0, XV_WLAY_DONTCARE, 0},
2505 {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2506 0, XV_WLAY_BELOWCLOSE, "mail-dlg-input-2"},
2507 {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, " Subject", 0, 0, 0,
2508 0, XV_WLAY_DONTCARE, 0},
2509 {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2510 0, XV_WLAY_BELOWCLOSE, "mail-dlg-input-3"},
2511 {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, " To", 0, 0, 0,
2512 0, XV_WLAY_DONTCARE, 0},
2513 {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, " mail -s <subject> -c <cc> <to>", 0, 0, 0,
2514 0, XV_WLAY_DONTCARE, 0},
2515 {0}};
2516
2517 quick_widgets[2].str_result = &tmail_cc;
2518 quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
2519 quick_widgets[4].str_result = &tmail_subject;
2520 quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
2521 quick_widgets[6].str_result = &tmail_to;
2522 quick_widgets[6].text = mail_to_last ? mail_to_last : "";
2523
2524 Quick_input.widgets = quick_widgets;
2525
2526 if (quick_dialog (&Quick_input) != B_CANCEL) {
2527 if (mail_cc_last)
2528 free (mail_cc_last);
2529 if (mail_subject_last)
2530 free (mail_subject_last);
2531 if (mail_to_last)
2532 free (mail_to_last);
2533 mail_cc_last = *(quick_widgets[2].str_result);
2534 mail_subject_last = *(quick_widgets[4].str_result);
2535 mail_to_last = *(quick_widgets[6].str_result);
2536 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2537 }
2538 }
2539
2540 #endif
2541