home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / mc454src.zip / mc-4.5.4.src / mc-4.5.4 / gtkedit / editcmd.c < prev    next >
C/C++ Source or Header  |  1999-01-04  |  77KB  |  2,866 lines

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