root/src/editor/editcmd.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. edit_search_status_update_cb
  2. edit_save_mode_callback
  3. edit_save_file
  4. edit_check_newline
  5. edit_get_save_file_as
  6. edit_save_cmd
  7. edit_load_file_from_filename
  8. edit_delete_column_of_text
  9. edit_block_delete
  10. edit_search_get_current_end_line_char
  11. edit_get_search_line_type
  12. edit_calculate_start_of_next_line
  13. edit_calculate_end_of_previous_line
  14. edit_calculate_start_of_previous_line
  15. edit_calculate_start_of_current_line
  16. edit_search_fix_search_start_if_selection
  17. editcmd_find
  18. edit_replace_cmd__conv_to_display
  19. edit_replace_cmd__conv_to_input
  20. edit_show_search_error
  21. edit_do_search
  22. edit_search
  23. edit_get_block
  24. edit_save_block_to_clip_file
  25. pipe_mail
  26. edit_find_word_start
  27. edit_collect_completions_get_current_word
  28. edit_completion_string_free
  29. edit_collect_completion_from_one_buffer
  30. edit_collect_completions
  31. edit_insert_column_of_text
  32. edit_macro_comparator
  33. edit_macro_sort_by_hotkey
  34. edit_get_macro
  35. edit_delete_macro
  36. edit_syntax_onoff_cb
  37. edit_complete_word_insert_recoded_completion
  38. edit_refresh_cmd
  39. edit_syntax_onoff_cmd
  40. edit_show_tabs_tws_cmd
  41. edit_show_margin_cmd
  42. edit_show_numbers_cmd
  43. edit_save_mode_cmd
  44. edit_set_filename
  45. edit_save_as_cmd
  46. edit_delete_macro_cmd
  47. edit_execute_macro
  48. edit_store_macro_cmd
  49. edit_repeat_macro_cmd
  50. edit_load_macro_cmd
  51. edit_save_confirm_cmd
  52. edit_load_cmd
  53. edit_load_file_from_history
  54. edit_load_syntax_file
  55. edit_load_menu_file
  56. edit_close_cmd
  57. eval_marks
  58. edit_block_copy_cmd
  59. edit_block_move_cmd
  60. edit_block_delete_cmd
  61. edit_replace_cmd
  62. edit_search_cmd_callback
  63. edit_search_update_callback
  64. edit_search_cmd
  65. edit_ok_to_exit
  66. edit_save_block
  67. edit_paste_from_history
  68. edit_copy_to_X_buf_cmd
  69. edit_cut_to_X_buf_cmd
  70. edit_paste_from_X_buf_cmd
  71. edit_goto_cmd
  72. edit_save_block_cmd
  73. edit_insert_file_cmd
  74. edit_sort_cmd
  75. edit_ext_cmd
  76. edit_block_process_cmd
  77. edit_mail_dialog
  78. edit_complete_word_cmd
  79. edit_select_codepage_cmd
  80. edit_insert_literal_cmd
  81. edit_begin_end_macro_cmd
  82. edit_begin_end_repeat_cmd
  83. edit_load_forward_cmd
  84. edit_load_back_cmd
  85. edit_get_match_keyword_cmd
  86. edit_suggest_current_word
  87. edit_spellcheck_file
  88. edit_set_spell_lang

   1 /*
   2    Editor high level editing commands
   3 
   4    Copyright (C) 1996-2021
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Paul Sheer, 1996, 1997
   9    Andrew Borodin <aborodin@vmail.ru>, 2012-2021
  10    Ilia Maslakov <il.smind@gmail.com>, 2012
  11 
  12    This file is part of the Midnight Commander.
  13 
  14    The Midnight Commander is free software: you can redistribute it
  15    and/or modify it under the terms of the GNU General Public License as
  16    published by the Free Software Foundation, either version 3 of the License,
  17    or (at your option) any later version.
  18 
  19    The Midnight Commander is distributed in the hope that it will be useful,
  20    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22    GNU General Public License for more details.
  23 
  24    You should have received a copy of the GNU General Public License
  25    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  26  */
  27 
  28 /** \file
  29  *  \brief Source: editor high level editing commands
  30  *  \author Paul Sheer
  31  *  \date 1996, 1997
  32  */
  33 
  34 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
  35 
  36 #include <config.h>
  37 
  38 #include <ctype.h>
  39 #include <stdio.h>
  40 #include <stdarg.h>
  41 #include <sys/types.h>
  42 #include <unistd.h>
  43 #include <string.h>
  44 #include <errno.h>
  45 #include <sys/stat.h>
  46 #include <stdlib.h>
  47 
  48 #include "lib/global.h"
  49 #include "lib/tty/tty.h"
  50 #include "lib/tty/key.h"        /* XCTRL */
  51 #include "lib/mcconfig.h"
  52 #include "lib/skin.h"
  53 #include "lib/strutil.h"        /* utf string functions */
  54 #include "lib/fileloc.h"
  55 #include "lib/lock.h"
  56 #include "lib/util.h"           /* tilde_expand() */
  57 #include "lib/vfs/vfs.h"
  58 #include "lib/widget.h"
  59 #include "lib/event.h"          /* mc_event_raise() */
  60 #ifdef HAVE_CHARSET
  61 #include "lib/charsets.h"
  62 #endif
  63 
  64 #include "src/history.h"
  65 #include "src/file_history.h"   /* show_file_history() */
  66 #include "src/setup.h"          /* option_tab_spacing */
  67 #ifdef HAVE_CHARSET
  68 #include "src/selcodepage.h"
  69 #endif
  70 #include "src/keymap.h"
  71 #include "src/util.h"           /* check_for_default() */
  72 
  73 #include "edit-impl.h"
  74 #include "editwidget.h"
  75 #include "editcmd_dialogs.h"
  76 #ifdef HAVE_ASPELL
  77 #include "spell.h"
  78 #include "spell_dialogs.h"
  79 #endif
  80 #include "etags.h"
  81 
  82 /*** global variables ****************************************************************************/
  83 
  84 /* search and replace: */
  85 int search_create_bookmark = FALSE;
  86 
  87 /* queries on a save */
  88 gboolean edit_confirm_save = TRUE;
  89 
  90 /* whether we need to drop selection on copy to buffer */
  91 gboolean option_drop_selection_on_copy = TRUE;
  92 
  93 /*** file scope macro definitions ****************************************************************/
  94 
  95 #define space_width 1
  96 
  97 #define TEMP_BUF_LEN 1024
  98 
  99 /*** file scope type declarations ****************************************************************/
 100 
 101 typedef struct
 102 {
 103     simple_status_msg_t status_msg;     /* base class */
 104 
 105     gboolean first;
 106     WEdit *edit;
 107     off_t offset;
 108 } edit_search_status_msg_t;
 109 
 110 /*** file scope variables ************************************************************************/
 111 
 112 static unsigned long edit_save_mode_radio_id, edit_save_mode_input_id;
 113 
 114 /* --------------------------------------------------------------------------------------------- */
 115 /*** file scope functions ************************************************************************/
 116 /* --------------------------------------------------------------------------------------------- */
 117 
 118 static int
 119 edit_search_status_update_cb (status_msg_t * sm)
     /* [previous][next][first][last][top][bottom][index][help]  */
 120 {
 121     simple_status_msg_t *ssm = SIMPLE_STATUS_MSG (sm);
 122     edit_search_status_msg_t *esm = (edit_search_status_msg_t *) sm;
 123     Widget *wd = WIDGET (sm->dlg);
 124 
 125     if (verbose)
 126         label_set_textv (ssm->label, _("Searching %s: %3d%%"), esm->edit->last_search_string,
 127                          edit_buffer_calc_percent (&esm->edit->buffer, esm->offset));
 128     else
 129         label_set_textv (ssm->label, _("Searching %s"), esm->edit->last_search_string);
 130 
 131     if (esm->first)
 132     {
 133         int wd_width;
 134         Widget *lw = WIDGET (ssm->label);
 135 
 136         wd_width = MAX (wd->cols, lw->cols + 6);
 137         widget_set_size (wd, wd->y, wd->x, wd->lines, wd_width);
 138         widget_set_size (lw, lw->y, wd->x + (wd->cols - lw->cols) / 2, lw->lines, lw->cols);
 139         esm->first = FALSE;
 140     }
 141 
 142     return status_msg_common_update (sm);
 143 }
 144 
 145 /* --------------------------------------------------------------------------------------------- */
 146 
 147 static cb_ret_t
 148 edit_save_mode_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 149 {
 150     switch (msg)
 151     {
 152     case MSG_CHANGED_FOCUS:
 153         if (sender != NULL && sender->id == edit_save_mode_radio_id)
 154         {
 155             Widget *ww;
 156 
 157             ww = widget_find_by_id (w, edit_save_mode_input_id);
 158             widget_disable (ww, RADIO (sender)->sel != 2);
 159             return MSG_HANDLED;
 160         }
 161         return MSG_NOT_HANDLED;
 162 
 163     default:
 164         return dlg_default_callback (w, sender, msg, parm, data);
 165     }
 166 }
 167 
 168 /* --------------------------------------------------------------------------------------------- */
 169 
 170 /*  If 0 (quick save) then  a) create/truncate <filename> file,
 171    b) save to <filename>;
 172    if 1 (safe save) then   a) save to <tempnam>,
 173    b) rename <tempnam> to <filename>;
 174    if 2 (do backups) then  a) save to <tempnam>,
 175    b) rename <filename> to <filename.backup_ext>,
 176    c) rename <tempnam> to <filename>. */
 177 
 178 /* returns 0 on error, -1 on abort */
 179 
 180 static int
 181 edit_save_file (WEdit * edit, const vfs_path_t * filename_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 182 {
 183     char *p;
 184     gchar *tmp;
 185     off_t filelen = 0;
 186     int this_save_mode, rv, fd = -1;
 187     vfs_path_t *real_filename_vpath;
 188     vfs_path_t *savename_vpath = NULL;
 189     const char *start_filename;
 190     const vfs_path_element_t *vpath_element;
 191     struct stat sb;
 192 
 193     vpath_element = vfs_path_get_by_index (filename_vpath, 0);
 194     if (vpath_element == NULL)
 195         return 0;
 196 
 197     start_filename = vpath_element->path;
 198     if (*start_filename == '\0')
 199         return 0;
 200 
 201     if (!IS_PATH_SEP (*start_filename) && edit->dir_vpath != NULL)
 202         real_filename_vpath = vfs_path_append_vpath_new (edit->dir_vpath, filename_vpath, NULL);
 203     else
 204         real_filename_vpath = vfs_path_clone (filename_vpath);
 205 
 206     this_save_mode = option_save_mode;
 207     if (this_save_mode != EDIT_QUICK_SAVE)
 208     {
 209         if (!vfs_file_is_local (real_filename_vpath))
 210             /* The file does not exists yet, so no safe save or backup are necessary. */
 211             this_save_mode = EDIT_QUICK_SAVE;
 212         else
 213         {
 214             fd = mc_open (real_filename_vpath, O_RDONLY | O_BINARY);
 215             if (fd == -1)
 216                 /* The file does not exists yet, so no safe save or backup are necessary. */
 217                 this_save_mode = EDIT_QUICK_SAVE;
 218         }
 219 
 220         if (fd != -1)
 221             mc_close (fd);
 222     }
 223 
 224     rv = mc_stat (real_filename_vpath, &sb);
 225     if (rv == 0)
 226     {
 227         if (this_save_mode == EDIT_QUICK_SAVE && !edit->skip_detach_prompt && sb.st_nlink > 1)
 228         {
 229             rv = edit_query_dialog3 (_("Warning"),
 230                                      _("File has hard-links. Detach before saving?"),
 231                                      _("&Yes"), _("&No"), _("&Cancel"));
 232             switch (rv)
 233             {
 234             case 0:
 235                 this_save_mode = EDIT_SAFE_SAVE;
 236                 MC_FALLTHROUGH;
 237             case 1:
 238                 edit->skip_detach_prompt = 1;
 239                 break;
 240             default:
 241                 vfs_path_free (real_filename_vpath, TRUE);
 242                 return -1;
 243             }
 244         }
 245 
 246         /* Prevent overwriting changes from other editor sessions. */
 247         if (edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime)
 248         {
 249             /* The default action is "Cancel". */
 250             query_set_sel (1);
 251 
 252             rv = edit_query_dialog2 (_("Warning"),
 253                                      _("The file has been modified in the meantime. Save anyway?"),
 254                                      _("&Yes"), _("&Cancel"));
 255             if (rv != 0)
 256             {
 257                 vfs_path_free (real_filename_vpath, TRUE);
 258                 return -1;
 259             }
 260         }
 261     }
 262 
 263     if (this_save_mode == EDIT_QUICK_SAVE)
 264         savename_vpath = vfs_path_clone (real_filename_vpath);
 265     else
 266     {
 267         char *savedir, *saveprefix;
 268 
 269         savedir = vfs_path_tokens_get (real_filename_vpath, 0, -1);
 270         if (savedir == NULL)
 271             savedir = g_strdup (".");
 272 
 273         /* Token-related function never return leading slash, so we need add it manually */
 274         saveprefix = mc_build_filename (PATH_SEP_STR, savedir, "cooledit", (char *) NULL);
 275         g_free (savedir);
 276         fd = mc_mkstemps (&savename_vpath, saveprefix, NULL);
 277         g_free (saveprefix);
 278         if (savename_vpath == NULL)
 279         {
 280             vfs_path_free (real_filename_vpath, TRUE);
 281             return 0;
 282         }
 283         /* FIXME:
 284          * Close for now because mc_mkstemps use pure open system call
 285          * to create temporary file and it needs to be reopened by
 286          * VFS-aware mc_open().
 287          */
 288         close (fd);
 289     }
 290 
 291     (void) mc_chown (savename_vpath, edit->stat1.st_uid, edit->stat1.st_gid);
 292     (void) mc_chmod (savename_vpath, edit->stat1.st_mode);
 293 
 294     fd = mc_open (savename_vpath, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, edit->stat1.st_mode);
 295     if (fd == -1)
 296         goto error_save;
 297 
 298     /* pipe save */
 299     p = edit_get_write_filter (savename_vpath, real_filename_vpath);
 300     if (p != NULL)
 301     {
 302         FILE *file;
 303 
 304         mc_close (fd);
 305         file = (FILE *) popen (p, "w");
 306 
 307         if (file != NULL)
 308         {
 309             filelen = edit_write_stream (edit, file);
 310 #if 1
 311             pclose (file);
 312 #else
 313             if (pclose (file) != 0)
 314             {
 315                 tmp = g_strdup_printf (_("Error writing to pipe: %s"), p);
 316                 edit_error_dialog (_("Error"), tmp);
 317                 g_free (tmp);
 318                 g_free (p);
 319                 goto error_save;
 320             }
 321 #endif
 322         }
 323         else
 324         {
 325             tmp = g_strdup_printf (_("Cannot open pipe for writing: %s"), p);
 326             edit_error_dialog (_("Error"), get_sys_error (tmp));
 327             g_free (p);
 328             g_free (tmp);
 329             goto error_save;
 330         }
 331         g_free (p);
 332     }
 333     else if (edit->lb == LB_ASIS)
 334     {                           /* do not change line breaks */
 335         filelen = edit_buffer_write_file (&edit->buffer, fd);
 336 
 337         if (filelen != edit->buffer.size)
 338         {
 339             mc_close (fd);
 340             goto error_save;
 341         }
 342 
 343         if (mc_close (fd) != 0)
 344             goto error_save;
 345 
 346         /* Update the file information, especially the mtime. */
 347         if (mc_stat (savename_vpath, &edit->stat1) == -1)
 348             goto error_save;
 349     }
 350     else
 351     {                           /* change line breaks */
 352         FILE *file;
 353         const vfs_path_element_t *path_element;
 354 
 355         mc_close (fd);
 356 
 357         path_element = vfs_path_get_by_index (savename_vpath, -1);
 358         file = (FILE *) fopen (path_element->path, "w");
 359         if (file != NULL)
 360         {
 361             filelen = edit_write_stream (edit, file);
 362             fclose (file);
 363         }
 364         else
 365         {
 366             char *msg;
 367 
 368             msg = g_strdup_printf (_("Cannot open file for writing: %s"), path_element->path);
 369             edit_error_dialog (_("Error"), msg);
 370             g_free (msg);
 371             goto error_save;
 372         }
 373     }
 374 
 375     if (filelen != edit->buffer.size)
 376         goto error_save;
 377 
 378     if (this_save_mode == EDIT_DO_BACKUP)
 379     {
 380         char *tmp_store_filename;
 381         vfs_path_element_t *last_vpath_element;
 382         vfs_path_t *tmp_vpath;
 383         gboolean ok;
 384 
 385         g_assert (option_backup_ext != NULL);
 386 
 387         /* add backup extension to the path */
 388         tmp_vpath = vfs_path_clone (real_filename_vpath);
 389         last_vpath_element = (vfs_path_element_t *) vfs_path_get_by_index (tmp_vpath, -1);
 390         tmp_store_filename = last_vpath_element->path;
 391         last_vpath_element->path = g_strdup_printf ("%s%s", tmp_store_filename, option_backup_ext);
 392         g_free (tmp_store_filename);
 393 
 394         ok = (mc_rename (real_filename_vpath, tmp_vpath) != -1);
 395         vfs_path_free (tmp_vpath, TRUE);
 396         if (!ok)
 397             goto error_save;
 398     }
 399 
 400     if (this_save_mode != EDIT_QUICK_SAVE && mc_rename (savename_vpath, real_filename_vpath) == -1)
 401         goto error_save;
 402 
 403     vfs_path_free (real_filename_vpath, TRUE);
 404     vfs_path_free (savename_vpath, TRUE);
 405     return 1;
 406   error_save:
 407     /*  FIXME: Is this safe ?
 408      *  if (this_save_mode != EDIT_QUICK_SAVE)
 409      *      mc_unlink (savename);
 410      */
 411     vfs_path_free (real_filename_vpath, TRUE);
 412     vfs_path_free (savename_vpath, TRUE);
 413     return 0;
 414 }
 415 
 416 /* --------------------------------------------------------------------------------------------- */
 417 
 418 static gboolean
 419 edit_check_newline (const edit_buffer_t * buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 420 {
 421     return !(option_check_nl_at_eof && buf->size > 0
 422              && edit_buffer_get_byte (buf, buf->size - 1) != '\n'
 423              && edit_query_dialog2 (_("Warning"),
 424                                     _("The file you are saving does not end with a newline."),
 425                                     _("C&ontinue"), _("&Cancel")) != 0);
 426 }
 427 
 428 /* --------------------------------------------------------------------------------------------- */
 429 
 430 static vfs_path_t *
 431 edit_get_save_file_as (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 432 {
 433     static LineBreaks cur_lb = LB_ASIS;
 434     char *filename_res;
 435     vfs_path_t *ret_vpath = NULL;
 436 
 437     const char *lb_names[LB_NAMES] = {
 438         N_("&Do not change"),
 439         N_("&Unix format (LF)"),
 440         N_("&Windows/DOS format (CR LF)"),
 441         N_("&Macintosh format (CR)")
 442     };
 443 
 444     quick_widget_t quick_widgets[] = {
 445         /* *INDENT-OFF* */
 446         QUICK_LABELED_INPUT (N_("Enter file name:"), input_label_above,
 447                              vfs_path_as_str (edit->filename_vpath), "save-as",
 448                              &filename_res, NULL, FALSE, FALSE, INPUT_COMPLETE_FILENAMES),
 449         QUICK_SEPARATOR (TRUE),
 450         QUICK_LABEL (N_("Change line breaks to:"), NULL),
 451         QUICK_RADIO (LB_NAMES, lb_names, (int *) &cur_lb, NULL),
 452         QUICK_BUTTONS_OK_CANCEL,
 453         QUICK_END
 454         /* *INDENT-ON* */
 455     };
 456 
 457     quick_dialog_t qdlg = {
 458         -1, -1, 64,
 459         N_("Save As"), "[Save File As]",
 460         quick_widgets, NULL, NULL
 461     };
 462 
 463     if (quick_dialog (&qdlg) != B_CANCEL)
 464     {
 465         char *fname;
 466 
 467         edit->lb = cur_lb;
 468         fname = tilde_expand (filename_res);
 469         g_free (filename_res);
 470         ret_vpath = vfs_path_from_str (fname);
 471         g_free (fname);
 472     }
 473 
 474     return ret_vpath;
 475 }
 476 
 477 /* --------------------------------------------------------------------------------------------- */
 478 
 479 /** returns TRUE on success */
 480 
 481 static gboolean
 482 edit_save_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 483 {
 484     int res, save_lock = 0;
 485 
 486     if (!edit->locked && !edit->delete_file)
 487         save_lock = lock_file (edit->filename_vpath);
 488     res = edit_save_file (edit, edit->filename_vpath);
 489 
 490     /* Maintain modify (not save) lock on failure */
 491     if ((res > 0 && edit->locked) || save_lock)
 492         edit->locked = unlock_file (edit->filename_vpath);
 493 
 494     /* On failure try 'save as', it does locking on its own */
 495     if (res == 0)
 496         return edit_save_as_cmd (edit);
 497 
 498     if (res > 0)
 499     {
 500         edit->delete_file = 0;
 501         edit->modified = 0;
 502     }
 503 
 504     edit->force |= REDRAW_COMPLETELY;
 505 
 506     return TRUE;
 507 }
 508 
 509 /* --------------------------------------------------------------------------------------------- */
 510 /**
 511  * Load file content
 512  *
 513  * @param h screen the owner of editor window
 514  * @param vpath vfs file path
 515  * @return TRUE if file content was successfully loaded, FALSE otherwise
 516  */
 517 
 518 static inline gboolean
 519 edit_load_file_from_filename (WDialog * h, const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 520 {
 521     Widget *w = WIDGET (h);
 522 
 523     return edit_add_window (h, w->y + 1, w->x, w->lines - 2, w->cols, vpath, 0);
 524 }
 525 
 526 /* --------------------------------------------------------------------------------------------- */
 527 
 528 static void
 529 edit_delete_column_of_text (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 530 {
 531     off_t m1, m2;
 532     off_t n;
 533     long b, c, d;
 534 
 535     eval_marks (edit, &m1, &m2);
 536     n = edit_buffer_get_forward_offset (&edit->buffer, m1, 0, m2) + 1;
 537     c = (long) edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, m1), 0, m1);
 538     d = (long) edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, m2), 0, m2);
 539     b = MAX (MIN (c, d), MIN (edit->column1, edit->column2));
 540     c = MAX (c, MAX (edit->column1, edit->column2));
 541 
 542     while (n-- != 0)
 543     {
 544         off_t r, p, q;
 545 
 546         r = edit_buffer_get_current_bol (&edit->buffer);
 547         p = edit_move_forward3 (edit, r, b, 0);
 548         q = edit_move_forward3 (edit, r, c, 0);
 549         p = MAX (p, m1);
 550         q = MIN (q, m2);
 551         edit_cursor_move (edit, p - edit->buffer.curs1);
 552         /* delete line between margins */
 553         for (; q > p; q--)
 554             if (edit_buffer_get_current_byte (&edit->buffer) != '\n')
 555                 edit_delete (edit, TRUE);
 556 
 557         /* move to next line except on the last delete */
 558         if (n != 0)
 559             edit_cursor_move (edit,
 560                               edit_buffer_get_forward_offset (&edit->buffer, edit->buffer.curs1, 1,
 561                                                               0) - edit->buffer.curs1);
 562     }
 563 }
 564 
 565 /* --------------------------------------------------------------------------------------------- */
 566 /** if success return 0 */
 567 
 568 static int
 569 edit_block_delete (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 570 {
 571     off_t start_mark, end_mark;
 572     off_t curs_pos;
 573     long curs_line, c1, c2;
 574 
 575     if (!eval_marks (edit, &start_mark, &end_mark))
 576         return 0;
 577 
 578     if (edit->column_highlight && edit->mark2 < 0)
 579         edit_mark_cmd (edit, FALSE);
 580 
 581     /* Warning message with a query to continue or cancel the operation */
 582     if ((end_mark - start_mark) > option_max_undo / 2 &&
 583         edit_query_dialog2 (_("Warning"),
 584                             ("Block is large, you may not be able to undo this action"),
 585                             _("C&ontinue"), _("&Cancel")) != 0)
 586         return 1;
 587 
 588     c1 = MIN (edit->column1, edit->column2);
 589     c2 = MAX (edit->column1, edit->column2);
 590     edit->column1 = c1;
 591     edit->column2 = c2;
 592 
 593     edit_push_markers (edit);
 594 
 595     curs_line = edit->buffer.curs_line;
 596 
 597     curs_pos = edit->curs_col + edit->over_col;
 598 
 599     /* move cursor to start of selection */
 600     edit_cursor_move (edit, start_mark - edit->buffer.curs1);
 601     edit_scroll_screen_over_cursor (edit);
 602 
 603     if (start_mark < end_mark)
 604     {
 605         if (edit->column_highlight)
 606         {
 607             off_t line_width;
 608 
 609             if (edit->mark2 < 0)
 610                 edit_mark_cmd (edit, FALSE);
 611             edit_delete_column_of_text (edit);
 612             /* move cursor to the saved position */
 613             edit_move_to_line (edit, curs_line);
 614             /* calculate line width and cursor position before cut */
 615             line_width = edit_move_forward3 (edit, edit_buffer_get_current_bol (&edit->buffer), 0,
 616                                              edit_buffer_get_current_eol (&edit->buffer));
 617             if (option_cursor_beyond_eol && curs_pos > line_width)
 618                 edit->over_col = curs_pos - line_width;
 619         }
 620         else
 621         {
 622             off_t count;
 623 
 624             for (count = start_mark; count < end_mark; count++)
 625                 edit_delete (edit, TRUE);
 626         }
 627     }
 628 
 629     edit_set_markers (edit, 0, 0, 0, 0);
 630     edit->force |= REDRAW_PAGE;
 631 
 632     return 0;
 633 }
 634 
 635 /* --------------------------------------------------------------------------------------------- */
 636 /**
 637  * Get EOL symbol for searching.
 638  *
 639  * @param edit editor object
 640  * @return EOL symbol
 641  */
 642 
 643 static inline char
 644 edit_search_get_current_end_line_char (const WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 645 {
 646     switch (edit->lb)
 647     {
 648     case LB_MAC:
 649         return '\r';
 650     default:
 651         return '\n';
 652     }
 653 }
 654 
 655 /* --------------------------------------------------------------------------------------------- */
 656 /**
 657  * Checking if search condition have BOL(^) or EOL ($) regexp special characters.
 658  *
 659  * @param search search object
 660  * @return result of checks.
 661  */
 662 
 663 static edit_search_line_t
 664 edit_get_search_line_type (mc_search_t * search)
     /* [previous][next][first][last][top][bottom][index][help]  */
 665 {
 666     edit_search_line_t search_line_type = 0;
 667 
 668     if (search->search_type != MC_SEARCH_T_REGEX)
 669         return search_line_type;
 670 
 671     if (*search->original == '^')
 672         search_line_type |= AT_START_LINE;
 673 
 674     if (search->original[search->original_len - 1] == '$')
 675         search_line_type |= AT_END_LINE;
 676     return search_line_type;
 677 }
 678 
 679 /* --------------------------------------------------------------------------------------------- */
 680 /**
 681  * Calculating the start position of next line.
 682  *
 683  * @param buf               editor buffer object
 684  * @param current_pos       current position
 685  * @param max_pos           max position
 686  * @param end_string_symbol end of line symbol
 687  * @return start position of next line
 688  */
 689 
 690 static off_t
 691 edit_calculate_start_of_next_line (const edit_buffer_t * buf, off_t current_pos, off_t max_pos,
     /* [previous][next][first][last][top][bottom][index][help]  */
 692                                    char end_string_symbol)
 693 {
 694     off_t i;
 695 
 696     for (i = current_pos; i < max_pos; i++)
 697     {
 698         current_pos++;
 699         if (edit_buffer_get_byte (buf, i) == end_string_symbol)
 700             break;
 701     }
 702 
 703     return current_pos;
 704 }
 705 
 706 /* --------------------------------------------------------------------------------------------- */
 707 /**
 708  * Calculating the end position of previous line.
 709  *
 710  * @param buf               editor buffer object
 711  * @param current_pos       current position
 712  * @param end_string_symbol end of line symbol
 713  * @return end position of previous line
 714  */
 715 
 716 static off_t
 717 edit_calculate_end_of_previous_line (const edit_buffer_t * buf, off_t current_pos,
     /* [previous][next][first][last][top][bottom][index][help]  */
 718                                      char end_string_symbol)
 719 {
 720     off_t i;
 721 
 722     for (i = current_pos - 1; i >= 0; i--)
 723         if (edit_buffer_get_byte (buf, i) == end_string_symbol)
 724             break;
 725 
 726     return i;
 727 }
 728 
 729 /* --------------------------------------------------------------------------------------------- */
 730 /**
 731  * Calculating the start position of previous line.
 732  *
 733  * @param buf               editor buffer object
 734  * @param current_pos       current position
 735  * @param end_string_symbol end of line symbol
 736  * @return start position of previous line
 737  */
 738 
 739 static inline off_t
 740 edit_calculate_start_of_previous_line (const edit_buffer_t * buf, off_t current_pos,
     /* [previous][next][first][last][top][bottom][index][help]  */
 741                                        char end_string_symbol)
 742 {
 743     current_pos = edit_calculate_end_of_previous_line (buf, current_pos, end_string_symbol);
 744     current_pos = edit_calculate_end_of_previous_line (buf, current_pos, end_string_symbol);
 745 
 746     return (current_pos + 1);
 747 }
 748 
 749 /* --------------------------------------------------------------------------------------------- */
 750 /**
 751  * Calculating the start position of current line.
 752  *
 753  * @param buf               editor buffer object
 754  * @param current_pos       current position
 755  * @param end_string_symbol end of line symbol
 756  * @return start position of current line
 757  */
 758 
 759 static inline off_t
 760 edit_calculate_start_of_current_line (const edit_buffer_t * buf, off_t current_pos,
     /* [previous][next][first][last][top][bottom][index][help]  */
 761                                       char end_string_symbol)
 762 {
 763     current_pos = edit_calculate_end_of_previous_line (buf, current_pos, end_string_symbol);
 764 
 765     return (current_pos + 1);
 766 }
 767 
 768 /* --------------------------------------------------------------------------------------------- */
 769 /**
 770  * Fixing (if needed) search start position if 'only in selection' option present.
 771  *
 772  * @param edit              editor object
 773  */
 774 
 775 static void
 776 edit_search_fix_search_start_if_selection (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 777 {
 778     off_t start_mark = 0;
 779     off_t end_mark = 0;
 780 
 781     if (!edit_search_options.only_in_selection)
 782         return;
 783 
 784     if (!eval_marks (edit, &start_mark, &end_mark))
 785         return;
 786 
 787     if (edit_search_options.backwards)
 788     {
 789         if (edit->search_start > end_mark || edit->search_start <= start_mark)
 790             edit->search_start = end_mark;
 791     }
 792     else
 793     {
 794         if (edit->search_start < start_mark || edit->search_start >= end_mark)
 795             edit->search_start = start_mark;
 796     }
 797 }
 798 
 799 /* --------------------------------------------------------------------------------------------- */
 800 
 801 static gboolean
 802 editcmd_find (edit_search_status_msg_t * esm, gsize * len)
     /* [previous][next][first][last][top][bottom][index][help]  */
 803 {
 804     WEdit *edit = esm->edit;
 805     off_t search_start = edit->search_start;
 806     off_t search_end;
 807     off_t start_mark = 0;
 808     off_t end_mark = edit->buffer.size;
 809     char end_string_symbol;
 810 
 811     end_string_symbol = edit_search_get_current_end_line_char (edit);
 812 
 813     /* prepare for search */
 814     if (edit_search_options.only_in_selection)
 815     {
 816         if (!eval_marks (edit, &start_mark, &end_mark))
 817         {
 818             mc_search_set_error (edit->search, MC_SEARCH_E_NOTFOUND, "%s", _(STR_E_NOTFOUND));
 819             return FALSE;
 820         }
 821 
 822         /* fix the start and the end of search block positions */
 823         if ((edit->search_line_type & AT_START_LINE) != 0
 824             && (start_mark != 0
 825                 || edit_buffer_get_byte (&edit->buffer, start_mark - 1) != end_string_symbol))
 826             start_mark =
 827                 edit_calculate_start_of_next_line (&edit->buffer, start_mark, edit->buffer.size,
 828                                                    end_string_symbol);
 829 
 830         if ((edit->search_line_type & AT_END_LINE) != 0
 831             && (end_mark - 1 != edit->buffer.size
 832                 || edit_buffer_get_byte (&edit->buffer, end_mark) != end_string_symbol))
 833             end_mark =
 834                 edit_calculate_end_of_previous_line (&edit->buffer, end_mark, end_string_symbol);
 835 
 836         if (start_mark >= end_mark)
 837         {
 838             mc_search_set_error (edit->search, MC_SEARCH_E_NOTFOUND, "%s", _(STR_E_NOTFOUND));
 839             return FALSE;
 840         }
 841     }
 842     else if (edit_search_options.backwards)
 843         end_mark = MAX (1, edit->buffer.curs1) - 1;
 844 
 845     /* search */
 846     if (edit_search_options.backwards)
 847     {
 848         /* backward search */
 849         search_end = end_mark;
 850 
 851         if ((edit->search_line_type & AT_START_LINE) != 0)
 852             search_start =
 853                 edit_calculate_start_of_current_line (&edit->buffer, search_start,
 854                                                       end_string_symbol);
 855 
 856         while (search_start >= start_mark)
 857         {
 858             gboolean ok;
 859 
 860             if (search_end > (off_t) (search_start + edit->search->original_len)
 861                 && mc_search_is_fixed_search_str (edit->search))
 862                 search_end = search_start + edit->search->original_len;
 863 
 864             ok = mc_search_run (edit->search, (void *) esm, search_start, search_end, len);
 865 
 866             if (ok && edit->search->normal_offset == search_start)
 867                 return TRUE;
 868 
 869             /* We abort the search in case of a pattern error, or if the user aborts
 870                the search. In other words: in all cases except "string not found". */
 871             if (!ok && edit->search->error != MC_SEARCH_E_NOTFOUND)
 872                 return FALSE;
 873 
 874             if ((edit->search_line_type & AT_START_LINE) != 0)
 875                 search_start =
 876                     edit_calculate_start_of_previous_line (&edit->buffer, search_start,
 877                                                            end_string_symbol);
 878             else
 879                 search_start--;
 880         }
 881 
 882         mc_search_set_error (edit->search, MC_SEARCH_E_NOTFOUND, "%s", _(STR_E_NOTFOUND));
 883         return FALSE;
 884     }
 885 
 886     /* forward search */
 887     if ((edit->search_line_type & AT_START_LINE) != 0 && search_start != start_mark)
 888         search_start =
 889             edit_calculate_start_of_next_line (&edit->buffer, search_start, end_mark,
 890                                                end_string_symbol);
 891 
 892     return mc_search_run (edit->search, (void *) esm, search_start, end_mark, len);
 893 }
 894 
 895 /* --------------------------------------------------------------------------------------------- */
 896 
 897 static char *
 898 edit_replace_cmd__conv_to_display (const char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
 899 {
 900 #ifdef HAVE_CHARSET
 901     GString *tmp;
 902 
 903     tmp = str_convert_to_display (str);
 904     if (tmp != NULL)
 905     {
 906         if (tmp->len != 0)
 907             return g_string_free (tmp, FALSE);
 908         g_string_free (tmp, TRUE);
 909     }
 910 #endif
 911     return g_strdup (str);
 912 }
 913 
 914 /* --------------------------------------------------------------------------------------------- */
 915 
 916 static char *
 917 edit_replace_cmd__conv_to_input (char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
 918 {
 919 #ifdef HAVE_CHARSET
 920     GString *tmp;
 921 
 922     tmp = str_convert_to_input (str);
 923     if (tmp->len != 0)
 924         return g_string_free (tmp, FALSE);
 925     g_string_free (tmp, TRUE);
 926 #endif
 927     return g_strdup (str);
 928 }
 929 
 930 /* --------------------------------------------------------------------------------------------- */
 931 
 932 static void
 933 edit_show_search_error (const WEdit * edit, const char *title)
     /* [previous][next][first][last][top][bottom][index][help]  */
 934 {
 935     if (edit->search->error == MC_SEARCH_E_NOTFOUND)
 936         edit_query_dialog (title, _(STR_E_NOTFOUND));
 937     else if (edit->search->error_str != NULL)
 938         edit_query_dialog (title, edit->search->error_str);
 939 }
 940 
 941 /* --------------------------------------------------------------------------------------------- */
 942 
 943 static void
 944 edit_do_search (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 945 {
 946     edit_search_status_msg_t esm;
 947     gsize len = 0;
 948 
 949     if (edit->search == NULL)
 950         edit->search_start = edit->buffer.curs1;
 951 
 952     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
 953 
 954     esm.first = TRUE;
 955     esm.edit = edit;
 956     esm.offset = edit->search_start;
 957 
 958     status_msg_init (STATUS_MSG (&esm), _("Search"), 1.0, simple_status_msg_init_cb,
 959                      edit_search_status_update_cb, NULL);
 960 
 961     if (search_create_bookmark)
 962     {
 963         gboolean found = FALSE;
 964         long l = 0, l_last = -1;
 965         long q = 0;
 966 
 967         search_create_bookmark = FALSE;
 968         book_mark_flush (edit, -1);
 969 
 970         while (mc_search_run (edit->search, (void *) &esm, q, edit->buffer.size, &len))
 971         {
 972             if (!found)
 973                 edit->search_start = edit->search->normal_offset;
 974             found = TRUE;
 975 
 976             l += edit_buffer_count_lines (&edit->buffer, q, edit->search->normal_offset);
 977             if (l != l_last)
 978                 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
 979             l_last = l;
 980             q = edit->search->normal_offset + 1;
 981         }
 982 
 983         if (!found)
 984             edit_error_dialog (_("Search"), _(STR_E_NOTFOUND));
 985         else
 986             edit_cursor_move (edit, edit->search_start - edit->buffer.curs1);
 987     }
 988     else
 989     {
 990         if (edit->found_len != 0 && edit->search_start == edit->found_start + 1
 991             && edit_search_options.backwards)
 992             edit->search_start--;
 993 
 994         if (edit->found_len != 0 && edit->search_start == edit->found_start - 1
 995             && !edit_search_options.backwards)
 996             edit->search_start++;
 997 
 998         if (editcmd_find (&esm, &len))
 999         {
1000             edit->found_start = edit->search_start = edit->search->normal_offset;
1001             edit->found_len = len;
1002             edit->over_col = 0;
1003             edit_cursor_move (edit, edit->search_start - edit->buffer.curs1);
1004             edit_scroll_screen_over_cursor (edit);
1005             if (edit_search_options.backwards)
1006                 edit->search_start--;
1007             else
1008                 edit->search_start++;
1009         }
1010         else
1011         {
1012             edit->search_start = edit->buffer.curs1;
1013             edit_show_search_error (edit, _("Search"));
1014         }
1015     }
1016 
1017     status_msg_deinit (STATUS_MSG (&esm));
1018 
1019     edit->force |= REDRAW_COMPLETELY;
1020     edit_scroll_screen_over_cursor (edit);
1021 }
1022 
1023 /* --------------------------------------------------------------------------------------------- */
1024 
1025 static void
1026 edit_search (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1027 {
1028     if (editcmd_dialog_search_show (edit))
1029     {
1030         edit->search_line_type = edit_get_search_line_type (edit->search);
1031         edit_search_fix_search_start_if_selection (edit);
1032         edit_do_search (edit);
1033     }
1034 }
1035 
1036 /* --------------------------------------------------------------------------------------------- */
1037 /** Return a null terminated length of text. Result must be g_free'd */
1038 
1039 static unsigned char *
1040 edit_get_block (WEdit * edit, off_t start, off_t finish, off_t * l)
     /* [previous][next][first][last][top][bottom][index][help]  */
1041 {
1042     unsigned char *s, *r;
1043 
1044     r = s = g_malloc0 (finish - start + 1);
1045 
1046     if (edit->column_highlight)
1047     {
1048         *l = 0;
1049 
1050         /* copy from buffer, excluding chars that are out of the column 'margins' */
1051         for (; start < finish; start++)
1052         {
1053             int c;
1054             off_t x;
1055 
1056             x = edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, start), 0, start);
1057             c = edit_buffer_get_byte (&edit->buffer, start);
1058             if ((x >= edit->column1 && x < edit->column2)
1059                 || (x >= edit->column2 && x < edit->column1) || c == '\n')
1060             {
1061                 *s++ = c;
1062                 (*l)++;
1063             }
1064         }
1065     }
1066     else
1067     {
1068         *l = finish - start;
1069 
1070         for (; start < finish; start++)
1071             *s++ = edit_buffer_get_byte (&edit->buffer, start);
1072     }
1073 
1074     *s = '\0';
1075 
1076     return r;
1077 }
1078 
1079 /* --------------------------------------------------------------------------------------------- */
1080 /** copies a block to clipboard file */
1081 
1082 static gboolean
1083 edit_save_block_to_clip_file (WEdit * edit, off_t start, off_t finish)
     /* [previous][next][first][last][top][bottom][index][help]  */
1084 {
1085     gboolean ret;
1086     gchar *tmp;
1087 
1088     tmp = mc_config_get_full_path (EDIT_HOME_CLIP_FILE);
1089     ret = edit_save_block (edit, tmp, start, finish);
1090     g_free (tmp);
1091 
1092     return ret;
1093 }
1094 
1095 /* --------------------------------------------------------------------------------------------- */
1096 
1097 static void
1098 pipe_mail (const edit_buffer_t * buf, char *to, char *subject, char *cc)
     /* [previous][next][first][last][top][bottom][index][help]  */
1099 {
1100     FILE *p = 0;
1101     char *s;
1102 
1103     to = name_quote (to, FALSE);
1104     subject = name_quote (subject, FALSE);
1105     cc = name_quote (cc, FALSE);
1106     s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "", cc, " ", to, (char *) NULL);
1107     g_free (to);
1108     g_free (subject);
1109     g_free (cc);
1110 
1111     if (s != NULL)
1112     {
1113         p = popen (s, "w");
1114         g_free (s);
1115     }
1116 
1117     if (p != NULL)
1118     {
1119         off_t i;
1120 
1121         for (i = 0; i < buf->size; i++)
1122             if (fputc (edit_buffer_get_byte (buf, i), p) < 0)
1123                 break;
1124         pclose (p);
1125     }
1126 }
1127 
1128 /* --------------------------------------------------------------------------------------------- */
1129 /** find first character of current word */
1130 
1131 static gboolean
1132 edit_find_word_start (const edit_buffer_t * buf, off_t * word_start, gsize * word_len)
     /* [previous][next][first][last][top][bottom][index][help]  */
1133 {
1134     int c;
1135     off_t i;
1136 
1137     /* return if at begin of file */
1138     if (buf->curs1 <= 0)
1139         return FALSE;
1140 
1141     c = edit_buffer_get_previous_byte (buf);
1142     /* return if not at end or in word */
1143     if (is_break_char (c))
1144         return FALSE;
1145 
1146     /* search start of word to be completed */
1147     for (i = 1;; i++)
1148     {
1149         int last;
1150 
1151         last = c;
1152         c = edit_buffer_get_byte (buf, buf->curs1 - i - 1);
1153 
1154         if (is_break_char (c))
1155         {
1156             /* return if word starts with digit */
1157             if (isdigit (last))
1158                 return FALSE;
1159 
1160             break;
1161         }
1162     }
1163 
1164     /* success */
1165     *word_start = buf->curs1 - i;       /* start found */
1166     *word_len = (gsize) i;
1167 
1168     return TRUE;
1169 }
1170 
1171 /* --------------------------------------------------------------------------------------------- */
1172 /**
1173  * Get current word under cursor
1174  *
1175  * @param esm status message window
1176  * @param srch mc_search object
1177  * @param word_start start word position
1178  *
1179  * @return newly allocated string or NULL if no any words under cursor
1180  */
1181 
1182 static GString *
1183 edit_collect_completions_get_current_word (edit_search_status_msg_t * esm, mc_search_t * srch,
     /* [previous][next][first][last][top][bottom][index][help]  */
1184                                            off_t word_start)
1185 {
1186     WEdit *edit = esm->edit;
1187     gsize len = 0;
1188     GString *temp = NULL;
1189 
1190     if (mc_search_run (srch, (void *) esm, word_start, edit->buffer.size, &len))
1191     {
1192         off_t i;
1193 
1194         for (i = 0; i < (off_t) len; i++)
1195         {
1196             int chr;
1197 
1198             chr = edit_buffer_get_byte (&edit->buffer, word_start + i);
1199             if (!isspace (chr))
1200             {
1201                 if (temp == NULL)
1202                     temp = g_string_sized_new (len);
1203 
1204                 g_string_append_c (temp, chr);
1205             }
1206         }
1207     }
1208 
1209     return temp;
1210 }
1211 
1212 /* --------------------------------------------------------------------------------------------- */
1213 
1214 static void
1215 edit_completion_string_free (gpointer data)
     /* [previous][next][first][last][top][bottom][index][help]  */
1216 {
1217     g_string_free ((GString *) data, TRUE);
1218 }
1219 
1220 /* --------------------------------------------------------------------------------------------- */
1221 /**
1222  * collect the possible completions from one buffer
1223  */
1224 
1225 static void
1226 edit_collect_completion_from_one_buffer (gboolean active_buffer, GQueue ** compl,
     /* [previous][next][first][last][top][bottom][index][help]  */
1227                                          mc_search_t * srch, edit_search_status_msg_t * esm,
1228                                          off_t word_start, gsize word_len, off_t last_byte,
1229                                          GString * current_word, int *max_width)
1230 {
1231     GString *temp = NULL;
1232     gsize len = 0;
1233     off_t start = -1;
1234 
1235     while (mc_search_run (srch, (void *) esm, start + 1, last_byte, &len))
1236     {
1237         gsize i;
1238         int width;
1239 
1240         if (temp == NULL)
1241             temp = g_string_sized_new (8);
1242         else
1243             g_string_set_size (temp, 0);
1244 
1245         start = srch->normal_offset;
1246 
1247         /* add matched completion if not yet added */
1248         for (i = 0; i < len; i++)
1249         {
1250             int ch;
1251 
1252             ch = edit_buffer_get_byte (&esm->edit->buffer, start + i);
1253             if (isspace (ch))
1254                 continue;
1255 
1256             /* skip current word */
1257             if (start + (off_t) i == word_start)
1258                 break;
1259 
1260             g_string_append_c (temp, ch);
1261         }
1262 
1263         if (temp->len == 0)
1264             continue;
1265 
1266         if (current_word != NULL && g_string_equal (current_word, temp))
1267             continue;
1268 
1269         if (*compl == NULL)
1270             *compl = g_queue_new ();
1271         else
1272         {
1273             GList *l;
1274 
1275             for (l = g_queue_peek_head_link (*compl); l != NULL; l = g_list_next (l))
1276             {
1277                 GString *s = (GString *) l->data;
1278 
1279                 /* skip if already added */
1280                 if (strncmp (s->str + word_len, temp->str + word_len,
1281                              MAX (len, s->len) - word_len) == 0)
1282                     break;
1283             }
1284 
1285             if (l != NULL)
1286             {
1287                 /* resort completion in main buffer only:
1288                  * these completions must be at the top of list in the completion dialog */
1289                 if (!active_buffer && l != g_queue_peek_tail_link (*compl))
1290                 {
1291                     /* move to the end */
1292                     g_queue_unlink (*compl, l);
1293                     g_queue_push_tail_link (*compl, l);
1294                 }
1295 
1296                 continue;
1297             }
1298         }
1299 
1300 #ifdef HAVE_CHARSET
1301         {
1302             GString *recoded;
1303 
1304             recoded = str_convert_to_display (temp->str);
1305             if (recoded->len != 0)
1306                 mc_g_string_copy (temp, recoded);
1307 
1308             g_string_free (recoded, TRUE);
1309         }
1310 #endif
1311         if (active_buffer)
1312             g_queue_push_tail (*compl, temp);
1313         else
1314             g_queue_push_head (*compl, temp);
1315 
1316         start += len;
1317 
1318         /* note the maximal length needed for the completion dialog */
1319         width = str_term_width1 (temp->str);
1320         *max_width = MAX (*max_width, width);
1321 
1322         temp = NULL;
1323     }
1324 
1325     if (temp != NULL)
1326         g_string_free (temp, TRUE);
1327 }
1328 
1329 /* --------------------------------------------------------------------------------------------- */
1330 /**
1331  * collect the possible completions from all buffers
1332  */
1333 
1334 static GQueue *
1335 edit_collect_completions (WEdit * edit, off_t word_start, gsize word_len,
     /* [previous][next][first][last][top][bottom][index][help]  */
1336                           const char *match_expr, int *max_width)
1337 {
1338     GQueue *compl = NULL;
1339     mc_search_t *srch;
1340     off_t last_byte;
1341     GString *current_word;
1342     gboolean entire_file, all_files;
1343     edit_search_status_msg_t esm;
1344 
1345 #ifdef HAVE_CHARSET
1346     srch = mc_search_new (match_expr, cp_source);
1347 #else
1348     srch = mc_search_new (match_expr, NULL);
1349 #endif
1350     if (srch == NULL)
1351         return NULL;
1352 
1353     entire_file =
1354         mc_config_get_bool (mc_global.main_config, CONFIG_APP_SECTION,
1355                             "editor_wordcompletion_collect_entire_file", FALSE);
1356 
1357     last_byte = entire_file ? edit->buffer.size : word_start;
1358 
1359     srch->search_type = MC_SEARCH_T_REGEX;
1360     srch->is_case_sensitive = TRUE;
1361     srch->search_fn = edit_search_cmd_callback;
1362     srch->update_fn = edit_search_update_callback;
1363 
1364     esm.first = TRUE;
1365     esm.edit = edit;
1366     esm.offset = entire_file ? 0 : word_start;
1367 
1368     status_msg_init (STATUS_MSG (&esm), _("Collect completions"), 1.0, simple_status_msg_init_cb,
1369                      edit_search_status_update_cb, NULL);
1370 
1371     current_word = edit_collect_completions_get_current_word (&esm, srch, word_start);
1372 
1373     *max_width = 0;
1374 
1375     /* collect completions from current buffer at first */
1376     edit_collect_completion_from_one_buffer (TRUE, &compl, srch, &esm, word_start, word_len,
1377                                              last_byte, current_word, max_width);
1378 
1379     /* collect completions from other buffers */
1380     all_files =
1381         mc_config_get_bool (mc_global.main_config, CONFIG_APP_SECTION,
1382                             "editor_wordcompletion_collect_all_files", TRUE);
1383     if (all_files)
1384     {
1385         const WGroup *owner = CONST_GROUP (CONST_WIDGET (edit)->owner);
1386         gboolean saved_verbose;
1387         GList *w;
1388 
1389         /* don't show incorrect percentage in edit_search_status_update_cb() */
1390         saved_verbose = verbose;
1391         verbose = FALSE;
1392 
1393         for (w = owner->widgets; w != NULL; w = g_list_next (w))
1394         {
1395             Widget *ww = WIDGET (w->data);
1396             WEdit *e;
1397 
1398             if (!edit_widget_is_editor (ww))
1399                 continue;
1400 
1401             e = (WEdit *) ww;
1402 
1403             if (e == edit)
1404                 continue;
1405 
1406             /* search in entire file */
1407             word_start = 0;
1408             last_byte = e->buffer.size;
1409             esm.edit = e;
1410             esm.offset = 0;
1411 
1412             edit_collect_completion_from_one_buffer (FALSE, &compl, srch, &esm, word_start,
1413                                                      word_len, last_byte, current_word, max_width);
1414         }
1415 
1416         verbose = saved_verbose;
1417     }
1418 
1419     status_msg_deinit (STATUS_MSG (&esm));
1420     mc_search_free (srch);
1421     if (current_word != NULL)
1422         g_string_free (current_word, TRUE);
1423 
1424     return compl;
1425 }
1426 
1427 /* --------------------------------------------------------------------------------------------- */
1428 
1429 static void
1430 edit_insert_column_of_text (WEdit * edit, unsigned char *data, off_t size, long width,
     /* [previous][next][first][last][top][bottom][index][help]  */
1431                             off_t * start_pos, off_t * end_pos, long *col1, long *col2)
1432 {
1433     off_t i, cursor;
1434     long col;
1435 
1436     cursor = edit->buffer.curs1;
1437     col = edit_get_col (edit);
1438 
1439     for (i = 0; i < size; i++)
1440     {
1441         if (data[i] != '\n')
1442             edit_insert (edit, data[i]);
1443         else
1444         {                       /* fill in and move to next line */
1445             long l;
1446             off_t p;
1447 
1448             if (edit_buffer_get_current_byte (&edit->buffer) != '\n')
1449             {
1450                 for (l = width - (edit_get_col (edit) - col); l > 0; l -= space_width)
1451                     edit_insert (edit, ' ');
1452             }
1453             for (p = edit->buffer.curs1;; p++)
1454             {
1455                 if (p == edit->buffer.size)
1456                 {
1457                     edit_cursor_move (edit, edit->buffer.size - edit->buffer.curs1);
1458                     edit_insert_ahead (edit, '\n');
1459                     p++;
1460                     break;
1461                 }
1462                 if (edit_buffer_get_byte (&edit->buffer, p) == '\n')
1463                 {
1464                     p++;
1465                     break;
1466                 }
1467             }
1468             edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->buffer.curs1);
1469 
1470             for (l = col - edit_get_col (edit); l >= space_width; l -= space_width)
1471                 edit_insert (edit, ' ');
1472         }
1473     }
1474 
1475     *col1 = col;
1476     *col2 = col + width;
1477     *start_pos = cursor;
1478     *end_pos = edit->buffer.curs1;
1479     edit_cursor_move (edit, cursor - edit->buffer.curs1);
1480 }
1481 
1482 /* --------------------------------------------------------------------------------------------- */
1483 
1484 static int
1485 edit_macro_comparator (gconstpointer * macro1, gconstpointer * macro2)
     /* [previous][next][first][last][top][bottom][index][help]  */
1486 {
1487     const macros_t *m1 = (const macros_t *) macro1;
1488     const macros_t *m2 = (const macros_t *) macro2;
1489 
1490     return m1->hotkey - m2->hotkey;
1491 }
1492 
1493 /* --------------------------------------------------------------------------------------------- */
1494 
1495 static void
1496 edit_macro_sort_by_hotkey (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1497 {
1498     if (macros_list != NULL && macros_list->len != 0)
1499         g_array_sort (macros_list, (GCompareFunc) edit_macro_comparator);
1500 }
1501 
1502 /* --------------------------------------------------------------------------------------------- */
1503 
1504 static int
1505 edit_get_macro (WEdit * edit, int hotkey)
     /* [previous][next][first][last][top][bottom][index][help]  */
1506 {
1507     macros_t *array_start;
1508     macros_t *result;
1509     macros_t search_macro = {
1510         .hotkey = hotkey
1511     };
1512 
1513     (void) edit;
1514 
1515     result = bsearch (&search_macro, macros_list->data, macros_list->len,
1516                       sizeof (macros_t), (GCompareFunc) edit_macro_comparator);
1517 
1518     if (result == NULL || result->macro == NULL)
1519         return (-1);
1520 
1521     array_start = &g_array_index (macros_list, struct macros_t, 0);
1522 
1523     return (int) (result - array_start);
1524 }
1525 
1526 /* --------------------------------------------------------------------------------------------- */
1527 /** returns FALSE on error */
1528 
1529 static gboolean
1530 edit_delete_macro (WEdit * edit, int hotkey)
     /* [previous][next][first][last][top][bottom][index][help]  */
1531 {
1532     mc_config_t *macros_config = NULL;
1533     const char *section_name = "editor";
1534     gchar *macros_fname;
1535     int indx;
1536     char *skeyname;
1537 
1538     /* clear array of actions for current hotkey */
1539     while ((indx = edit_get_macro (edit, hotkey) != -1))
1540     {
1541         macros_t *macros;
1542 
1543         macros = &g_array_index (macros_list, struct macros_t, indx);
1544         g_array_free (macros->macro, TRUE);
1545         g_array_remove_index (macros_list, indx);
1546         edit_macro_sort_by_hotkey ();
1547     }
1548 
1549     macros_fname = mc_config_get_full_path (MC_MACRO_FILE);
1550     macros_config = mc_config_init (macros_fname, FALSE);
1551     g_free (macros_fname);
1552 
1553     if (macros_config == NULL)
1554         return FALSE;
1555 
1556     skeyname = lookup_key_by_code (hotkey);
1557     while (mc_config_del_key (macros_config, section_name, skeyname))
1558         ;
1559     g_free (skeyname);
1560     mc_config_save_file (macros_config, NULL);
1561     mc_config_deinit (macros_config);
1562     return TRUE;
1563 }
1564 
1565 /* --------------------------------------------------------------------------------------------- */
1566 /**
1567  * Callback for the iteration of objects in the 'editors' array.
1568  * Toggle syntax highlighting in editor object.
1569  *
1570  * @param data      probably WEdit object
1571  * @param user_data unused
1572  */
1573 
1574 static void
1575 edit_syntax_onoff_cb (void *data, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help]  */
1576 {
1577     (void) user_data;
1578 
1579     if (edit_widget_is_editor (CONST_WIDGET (data)))
1580     {
1581         WEdit *edit = (WEdit *) data;
1582 
1583         if (option_syntax_highlighting)
1584             edit_load_syntax (edit, NULL, edit->syntax_type);
1585         edit->force |= REDRAW_PAGE;
1586     }
1587 }
1588 
1589 /* --------------------------------------------------------------------------------------------- */
1590 /**
1591  * Insert autocompleted word into editor.
1592  *
1593  * @param edit       editor object
1594  * @param completion word for completion
1595  * @param word_len   offset from beginning for insert
1596  */
1597 
1598 static void
1599 edit_complete_word_insert_recoded_completion (WEdit * edit, char *completion, gsize word_len)
     /* [previous][next][first][last][top][bottom][index][help]  */
1600 {
1601 #ifdef HAVE_CHARSET
1602     GString *temp;
1603 
1604     temp = str_convert_to_input (completion);
1605 
1606     for (completion = temp->str + word_len; *completion != '\0'; completion++)
1607         edit_insert (edit, *completion);
1608     g_string_free (temp, TRUE);
1609 #else
1610     for (completion += word_len; *completion != '\0'; completion++)
1611         edit_insert (edit, *completion);
1612 #endif
1613 }
1614 
1615 /* --------------------------------------------------------------------------------------------- */
1616 /*** public functions ****************************************************************************/
1617 /* --------------------------------------------------------------------------------------------- */
1618 
1619 void
1620 edit_refresh_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1621 {
1622     tty_clear_screen ();
1623     repaint_screen ();
1624     tty_keypad (TRUE);
1625 }
1626 
1627 /* --------------------------------------------------------------------------------------------- */
1628 /**
1629  * Toggle syntax highlighting in all editor windows.
1630  *
1631  * @param h root widget for all windows
1632  */
1633 
1634 void
1635 edit_syntax_onoff_cmd (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
1636 {
1637     option_syntax_highlighting = !option_syntax_highlighting;
1638     g_list_foreach (GROUP (h)->widgets, edit_syntax_onoff_cb, NULL);
1639     widget_draw (WIDGET (h));
1640 }
1641 
1642 /* --------------------------------------------------------------------------------------------- */
1643 /**
1644  * Toggle tabs showing in all editor windows.
1645  *
1646  * @param h root widget for all windows
1647  */
1648 
1649 void
1650 edit_show_tabs_tws_cmd (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
1651 {
1652     enable_show_tabs_tws = !enable_show_tabs_tws;
1653     widget_draw (WIDGET (h));
1654 }
1655 
1656 /* --------------------------------------------------------------------------------------------- */
1657 /**
1658  * Toggle right margin showing in all editor windows.
1659  *
1660  * @param h root widget for all windows
1661  */
1662 
1663 void
1664 edit_show_margin_cmd (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
1665 {
1666     show_right_margin = !show_right_margin;
1667     widget_draw (WIDGET (h));
1668 }
1669 
1670 /* --------------------------------------------------------------------------------------------- */
1671 /**
1672  * Toggle line numbers showing in all editor windows.
1673  *
1674  * @param h root widget for all windows
1675  */
1676 
1677 void
1678 edit_show_numbers_cmd (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
1679 {
1680     option_line_state = !option_line_state;
1681     option_line_state_width = option_line_state ? LINE_STATE_WIDTH : 0;
1682     widget_draw (WIDGET (h));
1683 }
1684 
1685 /* --------------------------------------------------------------------------------------------- */
1686 
1687 void
1688 edit_save_mode_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1689 {
1690     char *str_result = NULL;
1691 
1692     const char *str[] = {
1693         N_("&Quick save"),
1694         N_("&Safe save"),
1695         N_("&Do backups with following extension:")
1696     };
1697 
1698 #ifdef ENABLE_NLS
1699     size_t i;
1700 
1701     for (i = 0; i < 3; i++)
1702         str[i] = _(str[i]);
1703 #endif
1704 
1705     g_assert (option_backup_ext != NULL);
1706 
1707     {
1708         quick_widget_t quick_widgets[] = {
1709             /* *INDENT-OFF* */
1710             QUICK_RADIO (3, str, &option_save_mode, &edit_save_mode_radio_id),
1711             QUICK_INPUT (option_backup_ext, "edit-backup-ext", &str_result,
1712                          &edit_save_mode_input_id, FALSE, FALSE, INPUT_COMPLETE_NONE),
1713             QUICK_SEPARATOR (TRUE),
1714             QUICK_CHECKBOX (N_("Check &POSIX new line"), &option_check_nl_at_eof, NULL),
1715             QUICK_BUTTONS_OK_CANCEL,
1716             QUICK_END
1717             /* *INDENT-ON* */
1718         };
1719 
1720         quick_dialog_t qdlg = {
1721             -1, -1, 38,
1722             N_("Edit Save Mode"), "[Edit Save Mode]",
1723             quick_widgets, edit_save_mode_callback, NULL
1724         };
1725 
1726         if (quick_dialog (&qdlg) != B_CANCEL)
1727         {
1728             g_free (option_backup_ext);
1729             option_backup_ext = str_result;
1730         }
1731     }
1732 }
1733 
1734 /* --------------------------------------------------------------------------------------------- */
1735 
1736 void
1737 edit_set_filename (WEdit * edit, const vfs_path_t * name_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1738 {
1739     vfs_path_free (edit->filename_vpath, TRUE);
1740     edit->filename_vpath = vfs_path_clone (name_vpath);
1741 
1742     if (edit->dir_vpath == NULL)
1743         edit->dir_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
1744 }
1745 
1746 /* --------------------------------------------------------------------------------------------- */
1747 /* Here we want to warn the users of overwriting an existing file,
1748    but only if they have made a change to the filename */
1749 /* returns TRUE on success */
1750 gboolean
1751 edit_save_as_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1752 {
1753     /* This heads the 'Save As' dialog box */
1754     vfs_path_t *exp_vpath;
1755     int save_lock = 0;
1756     gboolean different_filename = FALSE;
1757     gboolean ret = FALSE;
1758 
1759     if (!edit_check_newline (&edit->buffer))
1760         return FALSE;
1761 
1762     exp_vpath = edit_get_save_file_as (edit);
1763     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
1764 
1765     if (exp_vpath != NULL && vfs_path_len (exp_vpath) != 0)
1766     {
1767         int rv;
1768 
1769         if (!vfs_path_equal (edit->filename_vpath, exp_vpath))
1770         {
1771             int file;
1772             struct stat sb;
1773 
1774             if (mc_stat (exp_vpath, &sb) == 0 && !S_ISREG (sb.st_mode))
1775             {
1776                 edit_error_dialog (_("Save as"),
1777                                    get_sys_error (_
1778                                                   ("Cannot save: destination is not a regular file")));
1779                 goto ret;
1780             }
1781 
1782             different_filename = TRUE;
1783             file = mc_open (exp_vpath, O_RDONLY | O_BINARY);
1784 
1785             if (file == -1)
1786                 edit->stat1.st_mode |= S_IWUSR;
1787             else
1788             {
1789                 /* the file exists */
1790                 mc_close (file);
1791                 /* Overwrite the current file or cancel the operation */
1792                 if (edit_query_dialog2
1793                     (_("Warning"),
1794                      _("A file already exists with this name"), _("&Overwrite"), _("&Cancel")))
1795                     goto ret;
1796             }
1797 
1798             save_lock = lock_file (exp_vpath);
1799         }
1800         else if (!edit->locked && !edit->delete_file)
1801             /* filenames equal, check if already locked */
1802             save_lock = lock_file (exp_vpath);
1803 
1804         if (different_filename)
1805             /* Allow user to write into saved (under another name) file
1806              * even if original file had r/o user permissions. */
1807             edit->stat1.st_mode |= S_IWRITE;
1808 
1809         rv = edit_save_file (edit, exp_vpath);
1810         switch (rv)
1811         {
1812         case 1:
1813             /* Successful, so unlock both files */
1814             if (different_filename)
1815             {
1816                 if (save_lock)
1817                     unlock_file (exp_vpath);
1818                 if (edit->locked)
1819                     edit->locked = unlock_file (edit->filename_vpath);
1820             }
1821             else if (edit->locked || save_lock)
1822                 edit->locked = unlock_file (edit->filename_vpath);
1823 
1824             edit_set_filename (edit, exp_vpath);
1825             if (edit->lb != LB_ASIS)
1826                 edit_reload (edit, exp_vpath);
1827             edit->modified = 0;
1828             edit->delete_file = 0;
1829             if (different_filename)
1830                 edit_load_syntax (edit, NULL, edit->syntax_type);
1831             ret = TRUE;
1832             break;
1833 
1834         default:
1835             edit_error_dialog (_("Save as"), get_sys_error (_("Cannot save file")));
1836             MC_FALLTHROUGH;
1837 
1838         case -1:
1839             /* Failed, so maintain modify (not save) lock */
1840             if (save_lock)
1841                 unlock_file (exp_vpath);
1842             break;
1843         }
1844     }
1845 
1846   ret:
1847     vfs_path_free (exp_vpath, TRUE);
1848     edit->force |= REDRAW_COMPLETELY;
1849     return ret;
1850 }
1851 
1852 /* {{{ Macro stuff starts here */
1853 /* --------------------------------------------------------------------------------------------- */
1854 
1855 void
1856 edit_delete_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1857 {
1858     int hotkey;
1859 
1860     hotkey = editcmd_dialog_raw_key_query (_("Delete macro"), _("Press macro hotkey:"), TRUE);
1861 
1862     if (hotkey != 0 && !edit_delete_macro (edit, hotkey))
1863         message (D_ERROR, _("Delete macro"), _("Macro not deleted"));
1864 }
1865 
1866 /* --------------------------------------------------------------------------------------------- */
1867 
1868 /** returns FALSE on error */
1869 gboolean
1870 edit_execute_macro (WEdit * edit, int hotkey)
     /* [previous][next][first][last][top][bottom][index][help]  */
1871 {
1872     gboolean res = FALSE;
1873 
1874     if (hotkey != 0)
1875     {
1876         int indx;
1877 
1878         indx = edit_get_macro (edit, hotkey);
1879         if (indx != -1)
1880         {
1881             const macros_t *macros;
1882 
1883             macros = &g_array_index (macros_list, struct macros_t, indx);
1884             if (macros->macro->len != 0)
1885             {
1886                 guint i;
1887 
1888                 edit->force |= REDRAW_PAGE;
1889 
1890                 for (i = 0; i < macros->macro->len; i++)
1891                 {
1892                     const macro_action_t *m_act;
1893 
1894                     m_act = &g_array_index (macros->macro, struct macro_action_t, i);
1895                     edit_execute_cmd (edit, m_act->action, m_act->ch);
1896                     res = TRUE;
1897                 }
1898             }
1899         }
1900     }
1901 
1902     return res;
1903 }
1904 
1905 /* --------------------------------------------------------------------------------------------- */
1906 
1907 /** returns FALSE on error */
1908 gboolean
1909 edit_store_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1910 {
1911     int i;
1912     int hotkey;
1913     GString *macros_string = NULL;
1914     const char *section_name = "editor";
1915     gchar *macros_fname;
1916     GArray *macros = NULL;
1917     int tmp_act;
1918     mc_config_t *macros_config;
1919     char *skeyname;
1920 
1921     hotkey =
1922         editcmd_dialog_raw_key_query (_("Save macro"), _("Press the macro's new hotkey:"), TRUE);
1923     if (hotkey == ESC_CHAR)
1924         return FALSE;
1925 
1926     tmp_act = keybind_lookup_keymap_command (WIDGET (edit)->keymap, hotkey);
1927     /* return FALSE if try assign macro into restricted hotkeys */
1928     if (tmp_act == CK_MacroStartRecord
1929         || tmp_act == CK_MacroStopRecord || tmp_act == CK_MacroStartStopRecord)
1930         return FALSE;
1931 
1932     edit_delete_macro (edit, hotkey);
1933 
1934     macros_fname = mc_config_get_full_path (MC_MACRO_FILE);
1935     macros_config = mc_config_init (macros_fname, FALSE);
1936     g_free (macros_fname);
1937 
1938     if (macros_config == NULL)
1939         return FALSE;
1940 
1941     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
1942 
1943     skeyname = lookup_key_by_code (hotkey);
1944 
1945     for (i = 0; i < macro_index; i++)
1946     {
1947         macro_action_t m_act;
1948         const char *action_name;
1949 
1950         action_name = keybind_lookup_actionname (record_macro_buf[i].action);
1951         if (action_name == NULL)
1952             break;
1953 
1954         if (macros == NULL)
1955         {
1956             macros = g_array_new (TRUE, FALSE, sizeof (macro_action_t));
1957             macros_string = g_string_sized_new (250);
1958         }
1959 
1960         m_act.action = record_macro_buf[i].action;
1961         m_act.ch = record_macro_buf[i].ch;
1962         g_array_append_val (macros, m_act);
1963         g_string_append_printf (macros_string, "%s:%i;", action_name, (int) record_macro_buf[i].ch);
1964     }
1965 
1966     if (macros == NULL)
1967         mc_config_del_key (macros_config, section_name, skeyname);
1968     else
1969     {
1970         macros_t macro;
1971 
1972         macro.hotkey = hotkey;
1973         macro.macro = macros;
1974         g_array_append_val (macros_list, macro);
1975         mc_config_set_string (macros_config, section_name, skeyname, macros_string->str);
1976     }
1977 
1978     g_free (skeyname);
1979 
1980     edit_macro_sort_by_hotkey ();
1981 
1982     if (macros_string != NULL)
1983         g_string_free (macros_string, TRUE);
1984     mc_config_save_file (macros_config, NULL);
1985     mc_config_deinit (macros_config);
1986 
1987     return TRUE;
1988 }
1989 
1990  /* --------------------------------------------------------------------------------------------- */
1991 
1992 gboolean
1993 edit_repeat_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1994 {
1995     gboolean ok;
1996     char *f;
1997     long count_repeat = 0;
1998 
1999     f = input_dialog (_("Repeat last commands"), _("Repeat times:"), MC_HISTORY_EDIT_REPEAT, NULL,
2000                       INPUT_COMPLETE_NONE);
2001     ok = (f != NULL && *f != '\0');
2002 
2003     if (ok)
2004     {
2005         char *error = NULL;
2006 
2007         count_repeat = strtol (f, &error, 0);
2008 
2009         ok = (*error == '\0');
2010     }
2011 
2012     g_free (f);
2013 
2014     if (ok)
2015     {
2016         int i, j;
2017 
2018         edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
2019         edit->force |= REDRAW_PAGE;
2020 
2021         for (j = 0; j < count_repeat; j++)
2022             for (i = 0; i < macro_index; i++)
2023                 edit_execute_cmd (edit, record_macro_buf[i].action, record_macro_buf[i].ch);
2024 
2025         edit_update_screen (edit);
2026     }
2027 
2028     return ok;
2029 }
2030 
2031 /* --------------------------------------------------------------------------------------------- */
2032 /** return FALSE on error */
2033 
2034 gboolean
2035 edit_load_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2036 {
2037     mc_config_t *macros_config = NULL;
2038     gchar **profile_keys, **keys;
2039     gchar **values, **curr_values;
2040     const char *section_name = "editor";
2041     gchar *macros_fname;
2042 
2043     (void) edit;
2044 
2045     if (macros_list == NULL || macros_list->len != 0)
2046         return FALSE;
2047 
2048     macros_fname = mc_config_get_full_path (MC_MACRO_FILE);
2049     macros_config = mc_config_init (macros_fname, TRUE);
2050     g_free (macros_fname);
2051 
2052     if (macros_config == NULL)
2053         return FALSE;
2054 
2055     keys = mc_config_get_keys (macros_config, section_name, NULL);
2056 
2057     for (profile_keys = keys; *profile_keys != NULL; profile_keys++)
2058     {
2059         int hotkey;
2060         GArray *macros = NULL;
2061         macros_t macro;
2062 
2063         values = mc_config_get_string_list (macros_config, section_name, *profile_keys, NULL);
2064         hotkey = lookup_key (*profile_keys, NULL);
2065 
2066         for (curr_values = values; *curr_values != NULL && *curr_values[0] != '\0'; curr_values++)
2067         {
2068             char **macro_pair;
2069 
2070             macro_pair = g_strsplit (*curr_values, ":", 2);
2071 
2072             if (macro_pair != NULL)
2073             {
2074                 macro_action_t m_act = {
2075                     .action = 0,
2076                     .ch = -1
2077                 };
2078 
2079                 if (macro_pair[0] != NULL && macro_pair[0][0] != '\0')
2080                     m_act.action = keybind_lookup_action (macro_pair[0]);
2081 
2082                 if (macro_pair[1] != NULL && macro_pair[1][0] != '\0')
2083                     m_act.ch = strtol (macro_pair[1], NULL, 0);
2084 
2085                 if (m_act.action != 0)
2086                 {
2087                     /* a shell command */
2088                     if ((m_act.action / CK_PipeBlock (0)) == 1)
2089                     {
2090                         m_act.action = CK_PipeBlock (0);
2091                         if (m_act.ch > 0)
2092                             m_act.action += m_act.ch;
2093                         m_act.ch = -1;
2094                     }
2095 
2096                     if (macros == NULL)
2097                         macros = g_array_new (TRUE, FALSE, sizeof (m_act));
2098 
2099                     g_array_append_val (macros, m_act);
2100                 }
2101 
2102                 g_strfreev (macro_pair);
2103             }
2104         }
2105 
2106         if (macros != NULL)
2107         {
2108             macro.hotkey = hotkey;
2109             macro.macro = macros;
2110             g_array_append_val (macros_list, macro);
2111         }
2112 
2113         g_strfreev (values);
2114     }
2115 
2116     g_strfreev (keys);
2117     mc_config_deinit (macros_config);
2118     edit_macro_sort_by_hotkey ();
2119 
2120     return TRUE;
2121 }
2122 
2123 /* }}} Macro stuff end here */
2124 
2125 /* --------------------------------------------------------------------------------------------- */
2126 /** returns TRUE on success */
2127 
2128 gboolean
2129 edit_save_confirm_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2130 {
2131     if (edit->filename_vpath == NULL)
2132         return edit_save_as_cmd (edit);
2133 
2134     if (!edit_check_newline (&edit->buffer))
2135         return FALSE;
2136 
2137     if (edit_confirm_save)
2138     {
2139         char *f;
2140         gboolean ok;
2141 
2142         f = g_strdup_printf (_("Confirm save file: \"%s\""),
2143                              vfs_path_as_str (edit->filename_vpath));
2144         ok = (edit_query_dialog2 (_("Save file"), f, _("&Save"), _("&Cancel")) == 0);
2145         g_free (f);
2146         if (!ok)
2147             return FALSE;
2148     }
2149 
2150     return edit_save_cmd (edit);
2151 }
2152 
2153 /* --------------------------------------------------------------------------------------------- */
2154 /**
2155   * Ask file to edit and load it.
2156   *
2157   * @return TRUE on success or cancel of ask.
2158   */
2159 
2160 gboolean
2161 edit_load_cmd (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
2162 {
2163     char *exp;
2164     gboolean ret = TRUE;        /* possible cancel */
2165 
2166     exp = input_expand_dialog (_("Load"), _("Enter file name:"),
2167                                MC_HISTORY_EDIT_LOAD, INPUT_LAST_TEXT,
2168                                INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD);
2169 
2170     if (exp != NULL && *exp != '\0')
2171     {
2172         vfs_path_t *exp_vpath;
2173 
2174         exp_vpath = vfs_path_from_str (exp);
2175         ret = edit_load_file_from_filename (h, exp_vpath);
2176         vfs_path_free (exp_vpath, TRUE);
2177     }
2178 
2179     g_free (exp);
2180 
2181     return ret;
2182 }
2183 
2184 /* --------------------------------------------------------------------------------------------- */
2185 /**
2186   * Show history od edited or viewed files and open selected file.
2187   *
2188   * @return TRUE on success, FALSE otherwise.
2189   */
2190 
2191 gboolean
2192 edit_load_file_from_history (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
2193 {
2194     char *exp;
2195     int action;
2196     gboolean ret = TRUE;        /* possible cancel */
2197 
2198     exp = show_file_history (CONST_WIDGET (h), &action);
2199     if (exp != NULL && (action == CK_Edit || action == CK_Enter))
2200     {
2201         vfs_path_t *exp_vpath;
2202 
2203         exp_vpath = vfs_path_from_str (exp);
2204         ret = edit_load_file_from_filename (h, exp_vpath);
2205         vfs_path_free (exp_vpath, TRUE);
2206     }
2207 
2208     g_free (exp);
2209 
2210     return ret;
2211 }
2212 
2213 /* --------------------------------------------------------------------------------------------- */
2214 /**
2215   * Load syntax file to edit.
2216   *
2217   * @return TRUE on success
2218   */
2219 
2220 gboolean
2221 edit_load_syntax_file (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
2222 {
2223     vfs_path_t *extdir_vpath;
2224     int dir = 0;
2225     gboolean ret = FALSE;
2226 
2227     if (geteuid () == 0)
2228         dir = query_dialog (_("Syntax file edit"),
2229                             _("Which syntax file you want to edit?"), D_NORMAL, 2,
2230                             _("&User"), _("&System wide"));
2231 
2232     extdir_vpath =
2233         vfs_path_build_filename (mc_global.sysconfig_dir, "syntax", "Syntax", (char *) NULL);
2234     if (!exist_file (vfs_path_get_last_path_str (extdir_vpath)))
2235     {
2236         vfs_path_free (extdir_vpath, TRUE);
2237         extdir_vpath =
2238             vfs_path_build_filename (mc_global.share_data_dir, "syntax", "Syntax", (char *) NULL);
2239     }
2240 
2241     if (dir == 0)
2242     {
2243         vfs_path_t *user_syntax_file_vpath;
2244 
2245         user_syntax_file_vpath = mc_config_get_full_vpath (EDIT_HOME_SYNTAX_FILE);
2246         check_for_default (extdir_vpath, user_syntax_file_vpath);
2247         ret = edit_load_file_from_filename (h, user_syntax_file_vpath);
2248         vfs_path_free (user_syntax_file_vpath, TRUE);
2249     }
2250     else if (dir == 1)
2251         ret = edit_load_file_from_filename (h, extdir_vpath);
2252 
2253     vfs_path_free (extdir_vpath, TRUE);
2254 
2255     return ret;
2256 }
2257 
2258 /* --------------------------------------------------------------------------------------------- */
2259 /**
2260   * Load menu file to edit.
2261   *
2262   * @return TRUE on success
2263   */
2264 
2265 gboolean
2266 edit_load_menu_file (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
2267 {
2268     vfs_path_t *buffer_vpath;
2269     vfs_path_t *menufile_vpath;
2270     int dir;
2271     gboolean ret;
2272 
2273     query_set_sel (1);
2274     dir = query_dialog (_("Menu edit"),
2275                         _("Which menu file do you want to edit?"), D_NORMAL,
2276                         geteuid () != 0 ? 2 : 3, _("&Local"), _("&User"), _("&System wide"));
2277 
2278     menufile_vpath =
2279         vfs_path_build_filename (mc_global.sysconfig_dir, EDIT_GLOBAL_MENU, (char *) NULL);
2280     if (!exist_file (vfs_path_get_last_path_str (menufile_vpath)))
2281     {
2282         vfs_path_free (menufile_vpath, TRUE);
2283         menufile_vpath =
2284             vfs_path_build_filename (mc_global.share_data_dir, EDIT_GLOBAL_MENU, (char *) NULL);
2285     }
2286 
2287     switch (dir)
2288     {
2289     case 0:
2290         buffer_vpath = vfs_path_from_str (EDIT_LOCAL_MENU);
2291         check_for_default (menufile_vpath, buffer_vpath);
2292         chmod (vfs_path_get_last_path_str (buffer_vpath), 0600);
2293         break;
2294 
2295     case 1:
2296         buffer_vpath = mc_config_get_full_vpath (EDIT_HOME_MENU);
2297         check_for_default (menufile_vpath, buffer_vpath);
2298         break;
2299 
2300     case 2:
2301         buffer_vpath =
2302             vfs_path_build_filename (mc_global.sysconfig_dir, EDIT_GLOBAL_MENU, (char *) NULL);
2303         if (!exist_file (vfs_path_get_last_path_str (buffer_vpath)))
2304         {
2305             vfs_path_free (buffer_vpath, TRUE);
2306             buffer_vpath =
2307                 vfs_path_build_filename (mc_global.share_data_dir, EDIT_GLOBAL_MENU, (char *) NULL);
2308         }
2309         break;
2310 
2311     default:
2312         vfs_path_free (menufile_vpath, TRUE);
2313         return FALSE;
2314     }
2315 
2316     ret = edit_load_file_from_filename (h, buffer_vpath);
2317 
2318     vfs_path_free (buffer_vpath, TRUE);
2319     vfs_path_free (menufile_vpath, TRUE);
2320 
2321     return ret;
2322 }
2323 
2324 /* --------------------------------------------------------------------------------------------- */
2325 /**
2326   * Close window with opened file.
2327   *
2328   * @return TRUE if file was closed.
2329   */
2330 
2331 gboolean
2332 edit_close_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2333 {
2334     gboolean ret;
2335 
2336     ret = (edit != NULL) && edit_ok_to_exit (edit);
2337 
2338     if (ret)
2339     {
2340         Widget *w = WIDGET (edit);
2341         WGroup *g = w->owner;
2342 
2343         if (edit->locked != 0)
2344             unlock_file (edit->filename_vpath);
2345 
2346         group_remove_widget (w);
2347         widget_destroy (w);
2348 
2349         if (edit_widget_is_editor (CONST_WIDGET (g->current->data)))
2350             edit = (WEdit *) (g->current->data);
2351         else
2352         {
2353             edit = find_editor (DIALOG (g));
2354             if (edit != NULL)
2355                 widget_select (w);
2356         }
2357     }
2358 
2359     if (edit != NULL)
2360         edit->force |= REDRAW_COMPLETELY;
2361 
2362     return ret;
2363 }
2364 
2365 /* --------------------------------------------------------------------------------------------- */
2366 /**
2367    if mark2 is -1 then marking is from mark1 to the cursor.
2368    Otherwise its between the markers. This handles this.
2369    Returns FALSE if no text is marked.
2370  */
2371 
2372 gboolean
2373 eval_marks (WEdit * edit, off_t * start_mark, off_t * end_mark)
     /* [previous][next][first][last][top][bottom][index][help]  */
2374 {
2375     long end_mark_curs;
2376 
2377     if (edit->mark1 == edit->mark2)
2378     {
2379         *start_mark = *end_mark = 0;
2380         edit->column2 = edit->column1 = 0;
2381         return FALSE;
2382     }
2383 
2384     if (edit->end_mark_curs < 0)
2385         end_mark_curs = edit->buffer.curs1;
2386     else
2387         end_mark_curs = edit->end_mark_curs;
2388 
2389     if (edit->mark2 >= 0)
2390     {
2391         *start_mark = MIN (edit->mark1, edit->mark2);
2392         *end_mark = MAX (edit->mark1, edit->mark2);
2393     }
2394     else
2395     {
2396         *start_mark = MIN (edit->mark1, end_mark_curs);
2397         *end_mark = MAX (edit->mark1, end_mark_curs);
2398         edit->column2 = edit->curs_col + edit->over_col;
2399     }
2400 
2401     if (edit->column_highlight
2402         && ((edit->mark1 > end_mark_curs && edit->column1 < edit->column2)
2403             || (edit->mark1 < end_mark_curs && edit->column1 > edit->column2)))
2404     {
2405         off_t start_bol, start_eol;
2406         off_t end_bol, end_eol;
2407         long col1, col2;
2408         off_t diff1, diff2;
2409 
2410         start_bol = edit_buffer_get_bol (&edit->buffer, *start_mark);
2411         start_eol = edit_buffer_get_eol (&edit->buffer, start_bol - 1) + 1;
2412         end_bol = edit_buffer_get_bol (&edit->buffer, *end_mark);
2413         end_eol = edit_buffer_get_eol (&edit->buffer, *end_mark);
2414         col1 = MIN (edit->column1, edit->column2);
2415         col2 = MAX (edit->column1, edit->column2);
2416 
2417         diff1 = edit_move_forward3 (edit, start_bol, col2, 0) -
2418             edit_move_forward3 (edit, start_bol, col1, 0);
2419         diff2 = edit_move_forward3 (edit, end_bol, col2, 0) -
2420             edit_move_forward3 (edit, end_bol, col1, 0);
2421 
2422         *start_mark -= diff1;
2423         *end_mark += diff2;
2424         *start_mark = MAX (*start_mark, start_eol);
2425         *end_mark = MIN (*end_mark, end_eol);
2426     }
2427 
2428     return TRUE;
2429 }
2430 
2431 /* --------------------------------------------------------------------------------------------- */
2432 
2433 void
2434 edit_block_copy_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2435 {
2436     off_t start_mark, end_mark, current = edit->buffer.curs1;
2437     off_t mark1 = 0, mark2 = 0;
2438     long c1 = 0, c2 = 0;
2439     off_t size;
2440     unsigned char *copy_buf;
2441 
2442     edit_update_curs_col (edit);
2443     if (!eval_marks (edit, &start_mark, &end_mark))
2444         return;
2445 
2446     copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
2447 
2448     /* all that gets pushed are deletes hence little space is used on the stack */
2449 
2450     edit_push_markers (edit);
2451 
2452     if (edit->column_highlight)
2453     {
2454         long col_delta;
2455 
2456         col_delta = labs (edit->column2 - edit->column1);
2457         edit_insert_column_of_text (edit, copy_buf, size, col_delta, &mark1, &mark2, &c1, &c2);
2458     }
2459     else
2460     {
2461         int size_orig = size;
2462 
2463         while (size-- != 0)
2464             edit_insert_ahead (edit, copy_buf[size]);
2465 
2466         /* Place cursor at the end of text selection */
2467         if (option_cursor_after_inserted_block)
2468             edit_cursor_move (edit, size_orig);
2469     }
2470 
2471     g_free (copy_buf);
2472     edit_scroll_screen_over_cursor (edit);
2473 
2474     if (edit->column_highlight)
2475         edit_set_markers (edit, edit->buffer.curs1, mark2, c1, c2);
2476     else if (start_mark < current && end_mark > current)
2477         edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
2478 
2479     edit->force |= REDRAW_PAGE;
2480 }
2481 
2482 
2483 /* --------------------------------------------------------------------------------------------- */
2484 
2485 void
2486 edit_block_move_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2487 {
2488     off_t current;
2489     unsigned char *copy_buf = NULL;
2490     off_t start_mark, end_mark;
2491 
2492     if (!eval_marks (edit, &start_mark, &end_mark))
2493         return;
2494 
2495     if (!edit->column_highlight && edit->buffer.curs1 > start_mark && edit->buffer.curs1 < end_mark)
2496         return;
2497 
2498     if (edit->mark2 < 0)
2499         edit_mark_cmd (edit, FALSE);
2500     edit_push_markers (edit);
2501 
2502     if (edit->column_highlight)
2503     {
2504         off_t mark1, mark2;
2505         off_t size;
2506         long c1, c2, b_width;
2507         long x, x2;
2508 
2509         c1 = MIN (edit->column1, edit->column2);
2510         c2 = MAX (edit->column1, edit->column2);
2511         b_width = c2 - c1;
2512 
2513         edit_update_curs_col (edit);
2514 
2515         x = edit->curs_col;
2516         x2 = x + edit->over_col;
2517 
2518         /* do nothing when cursor inside first line of selected area */
2519         if ((edit_buffer_get_eol (&edit->buffer, edit->buffer.curs1) ==
2520              edit_buffer_get_eol (&edit->buffer, start_mark)) && x2 > c1 && x2 <= c2)
2521             return;
2522 
2523         if (edit->buffer.curs1 > start_mark
2524             && edit->buffer.curs1 < edit_buffer_get_eol (&edit->buffer, end_mark))
2525         {
2526             if (x > c2)
2527                 x -= b_width;
2528             else if (x > c1 && x <= c2)
2529                 x = c1;
2530         }
2531         /* save current selection into buffer */
2532         copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
2533 
2534         /* remove current selection */
2535         edit_block_delete_cmd (edit);
2536 
2537         edit->over_col = MAX (0, edit->over_col - b_width);
2538         /* calculate the cursor pos after delete block */
2539         current = edit_move_forward3 (edit, edit_buffer_get_current_bol (&edit->buffer), x, 0);
2540         edit_cursor_move (edit, current - edit->buffer.curs1);
2541         edit_scroll_screen_over_cursor (edit);
2542 
2543         /* add TWS if need before block insertion */
2544         if (option_cursor_beyond_eol && edit->over_col > 0)
2545             edit_insert_over (edit);
2546 
2547         edit_insert_column_of_text (edit, copy_buf, size, b_width, &mark1, &mark2, &c1, &c2);
2548         edit_set_markers (edit, mark1, mark2, c1, c2);
2549     }
2550     else
2551     {
2552         off_t count, count_orig;
2553 
2554         current = edit->buffer.curs1;
2555         copy_buf = g_malloc0 (end_mark - start_mark);
2556         edit_cursor_move (edit, start_mark - edit->buffer.curs1);
2557         edit_scroll_screen_over_cursor (edit);
2558 
2559         for (count = start_mark; count < end_mark; count++)
2560             copy_buf[end_mark - count - 1] = edit_delete (edit, TRUE);
2561 
2562         edit_scroll_screen_over_cursor (edit);
2563         edit_cursor_move (edit,
2564                           current - edit->buffer.curs1 -
2565                           (((current - edit->buffer.curs1) > 0) ? end_mark - start_mark : 0));
2566         edit_scroll_screen_over_cursor (edit);
2567         count_orig = count;
2568         while (count-- > start_mark)
2569             edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
2570 
2571         edit_set_markers (edit, edit->buffer.curs1, edit->buffer.curs1 + end_mark - start_mark, 0,
2572                           0);
2573 
2574         /* Place cursor at the end of text selection */
2575         if (option_cursor_after_inserted_block)
2576             edit_cursor_move (edit, count_orig - start_mark);
2577     }
2578 
2579     edit_scroll_screen_over_cursor (edit);
2580     g_free (copy_buf);
2581     edit->force |= REDRAW_PAGE;
2582 }
2583 
2584 /* --------------------------------------------------------------------------------------------- */
2585 /** returns 1 if canceelled by user */
2586 
2587 int
2588 edit_block_delete_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2589 {
2590     off_t start_mark, end_mark;
2591 
2592     if (eval_marks (edit, &start_mark, &end_mark))
2593         return edit_block_delete (edit);
2594 
2595     edit_delete_line (edit);
2596 
2597     return 0;
2598 }
2599 
2600 /* --------------------------------------------------------------------------------------------- */
2601 /** call with edit = 0 before shutdown to close memory leaks */
2602 
2603 void
2604 edit_replace_cmd (WEdit * edit, gboolean again)
     /* [previous][next][first][last][top][bottom][index][help]  */
2605 {
2606     /* 1 = search string, 2 = replace with */
2607     static char *saved1 = NULL; /* saved default[123] */
2608     static char *saved2 = NULL;
2609     char *input1 = NULL;        /* user input from the dialog */
2610     char *input2 = NULL;
2611     GString *input2_str = NULL;
2612     char *disp1 = NULL;
2613     char *disp2 = NULL;
2614     long times_replaced = 0;
2615     gboolean once_found = FALSE;
2616     edit_search_status_msg_t esm;
2617 
2618     if (edit == NULL)
2619     {
2620         MC_PTR_FREE (saved1);
2621         MC_PTR_FREE (saved2);
2622         return;
2623     }
2624 
2625     edit->force |= REDRAW_COMPLETELY;
2626 
2627     if (again && saved1 == NULL && saved2 == NULL)
2628         again = FALSE;
2629 
2630     if (again)
2631     {
2632         input1 = g_strdup (saved1 != NULL ? saved1 : "");
2633         input2 = g_strdup (saved2 != NULL ? saved2 : "");
2634     }
2635     else
2636     {
2637         char *tmp_inp1, *tmp_inp2;
2638 
2639         disp1 = edit_replace_cmd__conv_to_display (saved1 != NULL ? saved1 : "");
2640         disp2 = edit_replace_cmd__conv_to_display (saved2 != NULL ? saved2 : "");
2641 
2642         edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
2643 
2644         editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2);
2645 
2646         g_free (disp1);
2647         g_free (disp2);
2648 
2649         if (input1 == NULL || *input1 == '\0')
2650         {
2651             edit->force = REDRAW_COMPLETELY;
2652             goto cleanup;
2653         }
2654 
2655         tmp_inp1 = input1;
2656         tmp_inp2 = input2;
2657         input1 = edit_replace_cmd__conv_to_input (input1);
2658         input2 = edit_replace_cmd__conv_to_input (input2);
2659         g_free (tmp_inp1);
2660         g_free (tmp_inp2);
2661 
2662         g_free (saved1);
2663         saved1 = g_strdup (input1);
2664         g_free (saved2);
2665         saved2 = g_strdup (input2);
2666 
2667         mc_search_free (edit->search);
2668         edit->search = NULL;
2669     }
2670 
2671     input2_str = g_string_new (input2);
2672 
2673     if (edit->search == NULL)
2674     {
2675 #ifdef HAVE_CHARSET
2676         edit->search = mc_search_new (input1, cp_source);
2677 #else
2678         edit->search = mc_search_new (input1, NULL);
2679 #endif
2680         if (edit->search == NULL)
2681         {
2682             edit->search_start = edit->buffer.curs1;
2683             goto cleanup;
2684         }
2685         edit->search->search_type = edit_search_options.type;
2686 #ifdef HAVE_CHARSET
2687         edit->search->is_all_charsets = edit_search_options.all_codepages;
2688 #endif
2689         edit->search->is_case_sensitive = edit_search_options.case_sens;
2690         edit->search->whole_words = edit_search_options.whole_words;
2691         edit->search->search_fn = edit_search_cmd_callback;
2692         edit->search->update_fn = edit_search_update_callback;
2693         edit->search_line_type = edit_get_search_line_type (edit->search);
2694         edit_search_fix_search_start_if_selection (edit);
2695     }
2696 
2697     if (edit->found_len != 0 && edit->search_start == edit->found_start + 1
2698         && edit_search_options.backwards)
2699         edit->search_start--;
2700 
2701     if (edit->found_len != 0 && edit->search_start == edit->found_start - 1
2702         && !edit_search_options.backwards)
2703         edit->search_start++;
2704 
2705     esm.first = TRUE;
2706     esm.edit = edit;
2707     esm.offset = edit->search_start;
2708 
2709     status_msg_init (STATUS_MSG (&esm), _("Search"), 1.0, simple_status_msg_init_cb,
2710                      edit_search_status_update_cb, NULL);
2711 
2712     do
2713     {
2714         gsize len = 0;
2715 
2716         if (!editcmd_find (&esm, &len))
2717         {
2718             if (!(edit->search->error == MC_SEARCH_E_OK ||
2719                   (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND)))
2720                 edit_show_search_error (edit, _("Search"));
2721             break;
2722         }
2723 
2724         once_found = TRUE;
2725 
2726         edit->search_start = edit->search->normal_offset;
2727         /* returns negative on not found or error in pattern */
2728 
2729         if (edit->search_start >= 0 && edit->search_start < edit->buffer.size)
2730         {
2731             gsize i;
2732             GString *repl_str;
2733 
2734             edit->found_start = edit->search_start;
2735             i = edit->found_len = len;
2736 
2737             edit_cursor_move (edit, edit->search_start - edit->buffer.curs1);
2738             edit_scroll_screen_over_cursor (edit);
2739 
2740             if (edit->replace_mode == 0)
2741             {
2742                 long l;
2743                 int prompt;
2744 
2745                 l = edit->curs_row - WIDGET (edit)->lines / 3;
2746                 if (l > 0)
2747                     edit_scroll_downward (edit, l);
2748                 if (l < 0)
2749                     edit_scroll_upward (edit, -l);
2750 
2751                 edit_scroll_screen_over_cursor (edit);
2752                 edit->force |= REDRAW_PAGE;
2753                 edit_render_keypress (edit);
2754 
2755                 /*so that undo stops at each query */
2756                 edit_push_key_press (edit);
2757                 /* and prompt 2/3 down */
2758                 disp1 = edit_replace_cmd__conv_to_display (saved1);
2759                 disp2 = edit_replace_cmd__conv_to_display (saved2);
2760                 prompt = editcmd_dialog_replace_prompt_show (edit, disp1, disp2, -1, -1);
2761                 g_free (disp1);
2762                 g_free (disp2);
2763 
2764                 if (prompt == B_REPLACE_ALL)
2765                     edit->replace_mode = 1;
2766                 else if (prompt == B_SKIP_REPLACE)
2767                 {
2768                     if (edit_search_options.backwards)
2769                         edit->search_start--;
2770                     else
2771                         edit->search_start++;
2772                     continue;   /* loop */
2773                 }
2774                 else if (prompt == B_CANCEL)
2775                 {
2776                     edit->replace_mode = -1;
2777                     break;      /* loop */
2778                 }
2779             }
2780 
2781             repl_str = mc_search_prepare_replace_str (edit->search, input2_str);
2782 
2783             if (edit->search->error != MC_SEARCH_E_OK)
2784             {
2785                 edit_show_search_error (edit, _("Replace"));
2786                 if (repl_str != NULL)
2787                     g_string_free (repl_str, TRUE);
2788                 break;
2789             }
2790 
2791             /* delete then insert new */
2792             for (i = 0; i < len; i++)
2793                 edit_delete (edit, TRUE);
2794 
2795             for (i = 0; i < repl_str->len; i++)
2796                 edit_insert (edit, repl_str->str[i]);
2797 
2798             edit->found_len = repl_str->len;
2799             g_string_free (repl_str, TRUE);
2800             times_replaced++;
2801 
2802             /* so that we don't find the same string again */
2803             if (edit_search_options.backwards)
2804                 edit->search_start--;
2805             else
2806             {
2807                 edit->search_start += edit->found_len + (len == 0 ? 1 : 0);
2808 
2809                 if (edit->search_start >= edit->buffer.size)
2810                     break;
2811             }
2812 
2813             edit_scroll_screen_over_cursor (edit);
2814         }
2815         else
2816         {
2817             /* try and find from right here for next search */
2818             edit->search_start = edit->buffer.curs1;
2819             edit_update_curs_col (edit);
2820 
2821             edit->force |= REDRAW_PAGE;
2822             edit_render_keypress (edit);
2823 
2824             if (times_replaced == 0)
2825                 query_dialog (_("Replace"), _(STR_E_NOTFOUND), D_NORMAL, 1, _("&OK"));
2826             break;
2827         }
2828     }
2829     while (edit->replace_mode >= 0);
2830 
2831     status_msg_deinit (STATUS_MSG (&esm));
2832     edit_scroll_screen_over_cursor (edit);
2833     edit->force |= REDRAW_COMPLETELY;
2834     edit_render_keypress (edit);
2835 
2836     if (edit->replace_mode == 1 && times_replaced != 0)
2837         message (D_NORMAL, _("Replace"), _("%ld replacements made"), times_replaced);
2838 
2839   cleanup:
2840     g_free (input1);
2841     g_free (input2);
2842     if (input2_str != NULL)
2843         g_string_free (input2_str, TRUE);
2844 }
2845 
2846 /* --------------------------------------------------------------------------------------------- */
2847 
2848 mc_search_cbret_t
2849 edit_search_cmd_callback (const void *user_data, gsize char_offset, int *current_char)
     /* [previous][next][first][last][top][bottom][index][help]  */
2850 {
2851     WEdit *edit = ((const edit_search_status_msg_t *) user_data)->edit;
2852 
2853     *current_char = edit_buffer_get_byte (&edit->buffer, (off_t) char_offset);
2854 
2855     return MC_SEARCH_CB_OK;
2856 }
2857 
2858 /* --------------------------------------------------------------------------------------------- */
2859 
2860 mc_search_cbret_t
2861 edit_search_update_callback (const void *user_data, gsize char_offset)
     /* [previous][next][first][last][top][bottom][index][help]  */
2862 {
2863     status_msg_t *sm = STATUS_MSG (user_data);
2864 
2865     ((edit_search_status_msg_t *) sm)->offset = (off_t) char_offset;
2866 
2867     return (sm->update (sm) == B_CANCEL ? MC_SEARCH_CB_ABORT : MC_SEARCH_CB_OK);
2868 }
2869 
2870 /* --------------------------------------------------------------------------------------------- */
2871 
2872 void
2873 edit_search_cmd (WEdit * edit, gboolean again)
     /* [previous][next][first][last][top][bottom][index][help]  */
2874 {
2875     if (edit == NULL)
2876         return;
2877 
2878     if (!again)
2879         edit_search (edit);
2880     else if (edit->last_search_string != NULL)
2881         edit_do_search (edit);
2882     else
2883     {
2884         /* find last search string in history */
2885         GList *history;
2886 
2887         history = mc_config_history_get (MC_HISTORY_SHARED_SEARCH);
2888         if (history != NULL && history->data != NULL)
2889         {
2890             edit->last_search_string = (char *) history->data;
2891             history->data = NULL;
2892             history = g_list_first (history);
2893             g_list_free_full (history, g_free);
2894 
2895 #ifdef HAVE_CHARSET
2896             edit->search = mc_search_new (edit->last_search_string, cp_source);
2897 #else
2898             edit->search = mc_search_new (edit->last_search_string, NULL);
2899 #endif
2900             if (edit->search == NULL)
2901             {
2902                 /* if not... then ask for an expression */
2903                 MC_PTR_FREE (edit->last_search_string);
2904                 edit_search (edit);
2905             }
2906             else
2907             {
2908                 edit->search->search_type = edit_search_options.type;
2909 #ifdef HAVE_CHARSET
2910                 edit->search->is_all_charsets = edit_search_options.all_codepages;
2911 #endif
2912                 edit->search->is_case_sensitive = edit_search_options.case_sens;
2913                 edit->search->whole_words = edit_search_options.whole_words;
2914                 edit->search->search_fn = edit_search_cmd_callback;
2915                 edit->search->update_fn = edit_search_update_callback;
2916                 edit->search_line_type = edit_get_search_line_type (edit->search);
2917                 edit_do_search (edit);
2918             }
2919         }
2920         else
2921         {
2922             /* if not... then ask for an expression */
2923             MC_PTR_FREE (edit->last_search_string);
2924             edit_search (edit);
2925         }
2926     }
2927 }
2928 
2929 /* --------------------------------------------------------------------------------------------- */
2930 /**
2931   * Check if it's OK to close the file. If there are unsaved changes, ask user.
2932   *
2933   * @return TRUE if it's OK to exit, FALSE to continue editing.
2934   */
2935 
2936 gboolean
2937 edit_ok_to_exit (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2938 {
2939     const char *fname = N_("[NoName]");
2940     char *msg;
2941     int act;
2942 
2943     if (!edit->modified)
2944         return TRUE;
2945 
2946     if (edit->filename_vpath != NULL)
2947         fname = vfs_path_as_str (edit->filename_vpath);
2948 #ifdef ENABLE_NLS
2949     else
2950         fname = _(fname);
2951 #endif
2952 
2953     if (!mc_global.midnight_shutdown)
2954     {
2955         query_set_sel (2);
2956 
2957         msg = g_strdup_printf (_("File %s was modified.\nSave before close?"), fname);
2958         act = edit_query_dialog3 (_("Close file"), msg, _("&Yes"), _("&No"), _("&Cancel"));
2959     }
2960     else
2961     {
2962         msg = g_strdup_printf (_("Midnight Commander is being shut down.\nSave modified file %s?"),
2963                                fname);
2964         act = edit_query_dialog2 (_("Quit"), msg, _("&Yes"), _("&No"));
2965 
2966         /* Esc is No */
2967         if (act == -1)
2968             act = 1;
2969     }
2970 
2971     g_free (msg);
2972 
2973     switch (act)
2974     {
2975     case 0:                    /* Yes */
2976         if (!mc_global.midnight_shutdown && !edit_check_newline (&edit->buffer))
2977             return FALSE;
2978         edit_push_markers (edit);
2979         edit_set_markers (edit, 0, 0, 0, 0);
2980         if (!edit_save_cmd (edit) || mc_global.midnight_shutdown)
2981             return mc_global.midnight_shutdown;
2982         break;
2983     case 1:                    /* No */
2984     default:
2985         break;
2986     case 2:                    /* Cancel quit */
2987     case -1:                   /* Esc */
2988         return FALSE;
2989     }
2990 
2991     return TRUE;
2992 }
2993 
2994 /* --------------------------------------------------------------------------------------------- */
2995 /** save block, returns TRUE on success */
2996 
2997 gboolean
2998 edit_save_block (WEdit * edit, const char *filename, off_t start, off_t finish)
     /* [previous][next][first][last][top][bottom][index][help]  */
2999 {
3000     int file;
3001     off_t len = 1;
3002     vfs_path_t *vpath;
3003 
3004     vpath = vfs_path_from_str (filename);
3005     file = mc_open (vpath, O_CREAT | O_WRONLY | O_TRUNC,
3006                     S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY);
3007     vfs_path_free (vpath, TRUE);
3008     if (file == -1)
3009         return FALSE;
3010 
3011     if (edit->column_highlight)
3012     {
3013         int r;
3014 
3015         r = mc_write (file, VERTICAL_MAGIC, sizeof (VERTICAL_MAGIC));
3016         if (r > 0)
3017         {
3018             unsigned char *block, *p;
3019 
3020             p = block = edit_get_block (edit, start, finish, &len);
3021             while (len != 0)
3022             {
3023                 r = mc_write (file, p, len);
3024                 if (r < 0)
3025                     break;
3026                 p += r;
3027                 len -= r;
3028             }
3029             g_free (block);
3030         }
3031     }
3032     else
3033     {
3034         unsigned char *buf;
3035         off_t i = start;
3036 
3037         len = finish - start;
3038         buf = g_malloc0 (TEMP_BUF_LEN);
3039         while (start != finish)
3040         {
3041             off_t end;
3042 
3043             end = MIN (finish, start + TEMP_BUF_LEN);
3044             for (; i < end; i++)
3045                 buf[i - start] = edit_buffer_get_byte (&edit->buffer, i);
3046             len -= mc_write (file, (char *) buf, end - start);
3047             start = end;
3048         }
3049         g_free (buf);
3050     }
3051     mc_close (file);
3052 
3053     return (len == 0);
3054 }
3055 
3056 /* --------------------------------------------------------------------------------------------- */
3057 
3058 void
3059 edit_paste_from_history (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3060 {
3061     (void) edit;
3062     edit_error_dialog (_("Error"), _("This function is not implemented"));
3063 }
3064 
3065 /* --------------------------------------------------------------------------------------------- */
3066 
3067 gboolean
3068 edit_copy_to_X_buf_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3069 {
3070     off_t start_mark, end_mark;
3071 
3072     if (!eval_marks (edit, &start_mark, &end_mark))
3073         return TRUE;
3074 
3075     if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
3076     {
3077         edit_error_dialog (_("Copy to clipboard"), get_sys_error (_("Unable to save to file")));
3078         return FALSE;
3079     }
3080     /* try use external clipboard utility */
3081     mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
3082 
3083     if (option_drop_selection_on_copy)
3084         edit_mark_cmd (edit, TRUE);
3085 
3086     return TRUE;
3087 }
3088 
3089 /* --------------------------------------------------------------------------------------------- */
3090 
3091 gboolean
3092 edit_cut_to_X_buf_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3093 {
3094     off_t start_mark, end_mark;
3095 
3096     if (!eval_marks (edit, &start_mark, &end_mark))
3097         return TRUE;
3098 
3099     if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
3100     {
3101         edit_error_dialog (_("Cut to clipboard"), _("Unable to save to file"));
3102         return FALSE;
3103     }
3104     /* try use external clipboard utility */
3105     mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
3106 
3107     edit_block_delete_cmd (edit);
3108     edit_mark_cmd (edit, TRUE);
3109 
3110     return TRUE;
3111 }
3112 
3113 /* --------------------------------------------------------------------------------------------- */
3114 
3115 gboolean
3116 edit_paste_from_X_buf_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3117 {
3118     vfs_path_t *tmp;
3119     gboolean ret;
3120 
3121     /* try use external clipboard utility */
3122     mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_from_ext_clip", NULL);
3123     tmp = mc_config_get_full_vpath (EDIT_HOME_CLIP_FILE);
3124     ret = (edit_insert_file (edit, tmp) >= 0);
3125     vfs_path_free (tmp, TRUE);
3126 
3127     return ret;
3128 }
3129 
3130 /* --------------------------------------------------------------------------------------------- */
3131 /**
3132  * Ask user for the line and go to that line.
3133  * Negative numbers mean line from the end (i.e. -1 is the last line).
3134  */
3135 
3136 void
3137 edit_goto_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3138 {
3139     static gboolean first_run = TRUE;
3140 
3141     char *f;
3142     long l;
3143     char *error;
3144 
3145     f = input_dialog (_("Goto line"), _("Enter line:"), MC_HISTORY_EDIT_GOTO_LINE,
3146                       first_run ? NULL : INPUT_LAST_TEXT, INPUT_COMPLETE_NONE);
3147     if (f == NULL || *f == '\0')
3148     {
3149         g_free (f);
3150         return;
3151     }
3152 
3153     l = strtol (f, &error, 0);
3154     if (*error != '\0')
3155     {
3156         g_free (f);
3157         return;
3158     }
3159 
3160     if (l < 0)
3161         l = edit->buffer.lines + l + 2;
3162 
3163     edit_move_display (edit, l - WIDGET (edit)->lines / 2 - 1);
3164     edit_move_to_line (edit, l - 1);
3165     edit->force |= REDRAW_COMPLETELY;
3166 
3167     g_free (f);
3168     first_run = FALSE;
3169 }
3170 
3171 /* --------------------------------------------------------------------------------------------- */
3172 /** Return TRUE on success */
3173 
3174 gboolean
3175 edit_save_block_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3176 {
3177     off_t start_mark, end_mark;
3178     char *exp, *tmp;
3179     gboolean ret = FALSE;
3180 
3181     if (!eval_marks (edit, &start_mark, &end_mark))
3182         return TRUE;
3183 
3184     tmp = mc_config_get_full_path (EDIT_HOME_CLIP_FILE);
3185     exp =
3186         input_expand_dialog (_("Save block"), _("Enter file name:"),
3187                              MC_HISTORY_EDIT_SAVE_BLOCK, tmp, INPUT_COMPLETE_FILENAMES);
3188     g_free (tmp);
3189     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
3190 
3191     if (exp != NULL && *exp != '\0')
3192     {
3193         if (edit_save_block (edit, exp, start_mark, end_mark))
3194             ret = TRUE;
3195         else
3196             edit_error_dialog (_("Save block"), get_sys_error (_("Cannot save file")));
3197 
3198         edit->force |= REDRAW_COMPLETELY;
3199     }
3200 
3201     g_free (exp);
3202 
3203     return ret;
3204 }
3205 
3206 /* --------------------------------------------------------------------------------------------- */
3207 
3208 /** returns TRUE on success */
3209 gboolean
3210 edit_insert_file_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3211 {
3212     char *tmp;
3213     char *exp;
3214     gboolean ret = FALSE;
3215 
3216     tmp = mc_config_get_full_path (EDIT_HOME_CLIP_FILE);
3217     exp = input_expand_dialog (_("Insert file"), _("Enter file name:"),
3218                                MC_HISTORY_EDIT_INSERT_FILE, tmp, INPUT_COMPLETE_FILENAMES);
3219     g_free (tmp);
3220 
3221     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
3222 
3223     if (exp != NULL && *exp != '\0')
3224     {
3225         vfs_path_t *exp_vpath;
3226 
3227         exp_vpath = vfs_path_from_str (exp);
3228         ret = (edit_insert_file (edit, exp_vpath) >= 0);
3229         vfs_path_free (exp_vpath, TRUE);
3230 
3231         if (!ret)
3232             edit_error_dialog (_("Insert file"), get_sys_error (_("Cannot insert file")));
3233     }
3234 
3235     g_free (exp);
3236 
3237     edit->force |= REDRAW_COMPLETELY;
3238     return ret;
3239 }
3240 
3241 /* --------------------------------------------------------------------------------------------- */
3242 /** sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
3243 
3244 int
3245 edit_sort_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3246 {
3247     char *exp, *tmp, *tmp_edit_block_name, *tmp_edit_temp_name;
3248     off_t start_mark, end_mark;
3249     int e;
3250 
3251     if (!eval_marks (edit, &start_mark, &end_mark))
3252     {
3253         edit_error_dialog (_("Sort block"), _("You must first highlight a block of text"));
3254         return 0;
3255     }
3256 
3257     tmp = mc_config_get_full_path (EDIT_HOME_BLOCK_FILE);
3258     edit_save_block (edit, tmp, start_mark, end_mark);
3259     g_free (tmp);
3260 
3261     exp = input_dialog (_("Run sort"),
3262                         _("Enter sort options (see manpage) separated by whitespace:"),
3263                         MC_HISTORY_EDIT_SORT, INPUT_LAST_TEXT, INPUT_COMPLETE_NONE);
3264 
3265     if (exp == NULL)
3266         return 1;
3267 
3268     tmp_edit_block_name = mc_config_get_full_path (EDIT_HOME_BLOCK_FILE);
3269     tmp_edit_temp_name = mc_config_get_full_path (EDIT_HOME_TEMP_FILE);
3270     tmp =
3271         g_strconcat (" sort ", exp, " ", tmp_edit_block_name,
3272                      " > ", tmp_edit_temp_name, (char *) NULL);
3273     g_free (tmp_edit_temp_name);
3274     g_free (tmp_edit_block_name);
3275     g_free (exp);
3276 
3277     e = system (tmp);
3278     g_free (tmp);
3279     if (e != 0)
3280     {
3281         if (e == -1 || e == 127)
3282             edit_error_dialog (_("Sort"), get_sys_error (_("Cannot execute sort command")));
3283         else
3284         {
3285             char q[8];
3286 
3287             sprintf (q, "%d ", e);
3288             tmp = g_strdup_printf (_("Sort returned non-zero: %s"), q);
3289             edit_error_dialog (_("Sort"), tmp);
3290             g_free (tmp);
3291         }
3292 
3293         return -1;
3294     }
3295 
3296     edit->force |= REDRAW_COMPLETELY;
3297 
3298     if (edit_block_delete_cmd (edit))
3299         return 1;
3300 
3301     {
3302         vfs_path_t *tmp_vpath;
3303 
3304         tmp_vpath = mc_config_get_full_vpath (EDIT_HOME_TEMP_FILE);
3305         edit_insert_file (edit, tmp_vpath);
3306         vfs_path_free (tmp_vpath, TRUE);
3307     }
3308 
3309     return 0;
3310 }
3311 
3312 /* --------------------------------------------------------------------------------------------- */
3313 /**
3314  * Ask user for a command, execute it and paste its output back to the
3315  * editor.
3316  */
3317 
3318 int
3319 edit_ext_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3320 {
3321     char *exp, *tmp, *tmp_edit_temp_file;
3322     int e;
3323 
3324     exp =
3325         input_dialog (_("Paste output of external command"),
3326                       _("Enter shell command(s):"), MC_HISTORY_EDIT_PASTE_EXTCMD, INPUT_LAST_TEXT,
3327                       INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_VARIABLES | INPUT_COMPLETE_USERNAMES
3328                       | INPUT_COMPLETE_HOSTNAMES | INPUT_COMPLETE_CD | INPUT_COMPLETE_COMMANDS |
3329                       INPUT_COMPLETE_SHELL_ESC);
3330 
3331     if (!exp)
3332         return 1;
3333 
3334     tmp_edit_temp_file = mc_config_get_full_path (EDIT_HOME_TEMP_FILE);
3335     tmp = g_strconcat (exp, " > ", tmp_edit_temp_file, (char *) NULL);
3336     g_free (tmp_edit_temp_file);
3337     e = system (tmp);
3338     g_free (tmp);
3339     g_free (exp);
3340 
3341     if (e != 0)
3342     {
3343         edit_error_dialog (_("External command"), get_sys_error (_("Cannot execute command")));
3344         return -1;
3345     }
3346 
3347     edit->force |= REDRAW_COMPLETELY;
3348 
3349     {
3350         vfs_path_t *tmp_vpath;
3351 
3352         tmp_vpath = mc_config_get_full_vpath (EDIT_HOME_TEMP_FILE);
3353         edit_insert_file (edit, tmp_vpath);
3354         vfs_path_free (tmp_vpath, TRUE);
3355     }
3356 
3357     return 0;
3358 }
3359 
3360 /* --------------------------------------------------------------------------------------------- */
3361 /** if block is 1, a block must be highlighted and the shell command
3362    processes it. If block is 0 the shell command is a straight system
3363    command, that just produces some output which is to be inserted */
3364 
3365 void
3366 edit_block_process_cmd (WEdit * edit, int macro_number)
     /* [previous][next][first][last][top][bottom][index][help]  */
3367 {
3368     char *fname;
3369     char *macros_fname = NULL;
3370 
3371     fname = g_strdup_printf ("%s.%i.sh", EDIT_HOME_MACRO_FILE, macro_number);
3372     macros_fname = g_build_filename (mc_config_get_data_path (), fname, (char *) NULL);
3373     user_menu (edit, macros_fname, 0);
3374     g_free (fname);
3375     g_free (macros_fname);
3376     edit->force |= REDRAW_COMPLETELY;
3377 }
3378 
3379 /* --------------------------------------------------------------------------------------------- */
3380 
3381 void
3382 edit_mail_dialog (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3383 {
3384     char *mail_to, *mail_subject, *mail_cc;
3385 
3386     quick_widget_t quick_widgets[] = {
3387         /* *INDENT-OFF* */
3388         QUICK_LABEL (N_("mail -s <subject> -c <cc> <to>"), NULL),
3389         QUICK_LABELED_INPUT (N_("To"), input_label_above,
3390                              INPUT_LAST_TEXT, "mail-dlg-input-3",
3391                              &mail_to, NULL, FALSE, FALSE, INPUT_COMPLETE_USERNAMES),
3392         QUICK_LABELED_INPUT (N_("Subject"), input_label_above,
3393                               INPUT_LAST_TEXT, "mail-dlg-input-2",
3394                               &mail_subject, NULL, FALSE, FALSE, INPUT_COMPLETE_NONE),
3395         QUICK_LABELED_INPUT (N_("Copies to"), input_label_above,
3396                              INPUT_LAST_TEXT, "mail-dlg-input",
3397                              &mail_cc, NULL, FALSE, FALSE, INPUT_COMPLETE_USERNAMES),
3398         QUICK_BUTTONS_OK_CANCEL,
3399         QUICK_END
3400         /* *INDENT-ON* */
3401     };
3402 
3403     quick_dialog_t qdlg = {
3404         -1, -1, 50,
3405         N_("Mail"), "[Input Line Keys]",
3406         quick_widgets, NULL, NULL
3407     };
3408 
3409     if (quick_dialog (&qdlg) != B_CANCEL)
3410     {
3411         pipe_mail (&edit->buffer, mail_to, mail_subject, mail_cc);
3412         g_free (mail_to);
3413         g_free (mail_subject);
3414         g_free (mail_cc);
3415     }
3416 }
3417 
3418 /* --------------------------------------------------------------------------------------------- */
3419 
3420 /*******************/
3421 /* Word Completion */
3422 /*******************/
3423 
3424 /**
3425  * Complete current word using regular expression search
3426  * backwards beginning at the current cursor position.
3427  */
3428 
3429 void
3430 edit_complete_word_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3431 {
3432     off_t word_start = 0;
3433     gsize word_len = 0;
3434     GString *match_expr;
3435     gsize i;
3436     GQueue *compl;              /* completions: list of GString* */
3437     int max_width;
3438 
3439     /* search start of word to be completed */
3440     if (!edit_find_word_start (&edit->buffer, &word_start, &word_len))
3441         return;
3442 
3443     /* prepare match expression */
3444     /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
3445     match_expr = g_string_new ("(^|\\s+|\\b)");
3446     for (i = 0; i < word_len; i++)
3447         g_string_append_c (match_expr, edit_buffer_get_byte (&edit->buffer, word_start + i));
3448     g_string_append (match_expr,
3449                      "[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+");
3450 
3451     /* collect possible completions */
3452     compl = edit_collect_completions (edit, word_start, word_len, match_expr->str, &max_width);
3453 
3454     g_string_free (match_expr, TRUE);
3455 
3456     if (compl == NULL)
3457         return;
3458 
3459     if (g_queue_get_length (compl) == 1)
3460     {
3461         /* insert completed word if there is only one match */
3462 
3463         GString *curr_compl;
3464 
3465         curr_compl = (GString *) g_queue_peek_head (compl);
3466         edit_complete_word_insert_recoded_completion (edit, curr_compl->str, word_len);
3467     }
3468     else
3469     {
3470         /* more than one possible completion => ask the user */
3471 
3472         char *curr_compl;
3473 
3474         /* let the user select the preferred completion */
3475         curr_compl = editcmd_dialog_completion_show (edit, compl, max_width);
3476         if (curr_compl != NULL)
3477         {
3478             edit_complete_word_insert_recoded_completion (edit, curr_compl, word_len);
3479             g_free (curr_compl);
3480         }
3481     }
3482 
3483     g_queue_free_full (compl, edit_completion_string_free);
3484 }
3485 
3486 /* --------------------------------------------------------------------------------------------- */
3487 
3488 #ifdef HAVE_CHARSET
3489 void
3490 edit_select_codepage_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3491 {
3492     if (do_select_codepage ())
3493         edit_set_codeset (edit);
3494 
3495     edit->force = REDRAW_PAGE;
3496     widget_draw (WIDGET (edit));
3497 }
3498 #endif
3499 
3500 /* --------------------------------------------------------------------------------------------- */
3501 
3502 void
3503 edit_insert_literal_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3504 {
3505     int char_for_insertion;
3506 
3507     char_for_insertion = editcmd_dialog_raw_key_query (_("Insert literal"),
3508                                                        _("Press any key:"), FALSE);
3509     edit_execute_key_command (edit, -1, ascii_alpha_to_cntrl (char_for_insertion));
3510 }
3511 
3512 /* --------------------------------------------------------------------------------------------- */
3513 
3514 void
3515 edit_begin_end_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3516 {
3517     /* edit is a pointer to the widget */
3518     if (edit != NULL)
3519     {
3520         long command = macro_index < 0 ? CK_MacroStartRecord : CK_MacroStopRecord;
3521 
3522         edit_execute_key_command (edit, command, -1);
3523     }
3524 }
3525 
3526  /* --------------------------------------------------------------------------------------------- */
3527 
3528 void
3529 edit_begin_end_repeat_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3530 {
3531     /* edit is a pointer to the widget */
3532     if (edit != NULL)
3533     {
3534         long command = macro_index < 0 ? CK_RepeatStartRecord : CK_RepeatStopRecord;
3535 
3536         edit_execute_key_command (edit, command, -1);
3537     }
3538 }
3539 
3540 /* --------------------------------------------------------------------------------------------- */
3541 
3542 gboolean
3543 edit_load_forward_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3544 {
3545     if (edit->modified
3546         && edit_query_dialog2 (_("Warning"),
3547                                _("Current text was modified without a file save.\n"
3548                                  "Continue discards these changes."), _("C&ontinue"),
3549                                _("&Cancel")) == 1)
3550     {
3551         edit->force |= REDRAW_COMPLETELY;
3552         return TRUE;
3553     }
3554 
3555     if (edit_stack_iterator + 1 >= MAX_HISTORY_MOVETO)
3556         return FALSE;
3557 
3558     if (edit_history_moveto[edit_stack_iterator + 1].line < 1)
3559         return FALSE;
3560 
3561     edit_stack_iterator++;
3562     if (edit_history_moveto[edit_stack_iterator].filename_vpath != NULL)
3563         return edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename_vpath,
3564                                  edit_history_moveto[edit_stack_iterator].line);
3565 
3566     return FALSE;
3567 }
3568 
3569 /* --------------------------------------------------------------------------------------------- */
3570 
3571 gboolean
3572 edit_load_back_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3573 {
3574     if (edit->modified
3575         && edit_query_dialog2 (_("Warning"),
3576                                _("Current text was modified without a file save.\n"
3577                                  "Continue discards these changes."), _("C&ontinue"),
3578                                _("&Cancel")) == 1)
3579     {
3580         edit->force |= REDRAW_COMPLETELY;
3581         return TRUE;
3582     }
3583 
3584     /* we are in the bottom of the stack, NO WAY! */
3585     if (edit_stack_iterator == 0)
3586         return FALSE;
3587 
3588     edit_stack_iterator--;
3589     if (edit_history_moveto[edit_stack_iterator].filename_vpath != NULL)
3590         return edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename_vpath,
3591                                  edit_history_moveto[edit_stack_iterator].line);
3592 
3593     return FALSE;
3594 }
3595 
3596 /* --------------------------------------------------------------------------------------------- */
3597 
3598 void
3599 edit_get_match_keyword_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3600 {
3601     gsize word_len = 0;
3602     gsize i;
3603     off_t word_start = 0;
3604     GString *match_expr;
3605     char *path = NULL;
3606     char *ptr = NULL;
3607     char *tagfile = NULL;
3608     GPtrArray *def_hash = NULL;
3609 
3610     /* search start of word to be completed */
3611     if (!edit_find_word_start (&edit->buffer, &word_start, &word_len))
3612         return;
3613 
3614     /* prepare match expression */
3615     match_expr = g_string_sized_new (word_len);
3616     for (i = 0; i < word_len; i++)
3617         g_string_append_c (match_expr, edit_buffer_get_byte (&edit->buffer, word_start + i));
3618 
3619     ptr = g_get_current_dir ();
3620     path = g_strconcat (ptr, PATH_SEP_STR, (char *) NULL);
3621     g_free (ptr);
3622 
3623     /* Recursive search file 'TAGS' in parent dirs */
3624     do
3625     {
3626         ptr = g_path_get_dirname (path);
3627         g_free (path);
3628         path = ptr;
3629         g_free (tagfile);
3630         tagfile = mc_build_filename (path, TAGS_NAME, (char *) NULL);
3631         if (tagfile != NULL && exist_file (tagfile))
3632             break;
3633     }
3634     while (strcmp (path, PATH_SEP_STR) != 0);
3635 
3636     if (tagfile != NULL)
3637     {
3638         def_hash = etags_set_definition_hash (tagfile, path, match_expr->str);
3639         g_free (tagfile);
3640     }
3641     g_free (path);
3642 
3643     if (def_hash != NULL)
3644     {
3645         editcmd_dialog_select_definition_show (edit, match_expr->str, def_hash);
3646 
3647         g_ptr_array_free (def_hash, TRUE);
3648     }
3649 
3650     g_string_free (match_expr, TRUE);
3651 }
3652 
3653 /* --------------------------------------------------------------------------------------------- */
3654 
3655 #ifdef HAVE_ASPELL
3656 int
3657 edit_suggest_current_word (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3658 {
3659     gsize cut_len = 0;
3660     gsize word_len = 0;
3661     off_t word_start = 0;
3662     int retval = B_SKIP_WORD;
3663     GString *match_word;
3664 
3665     /* search start of word to spell check */
3666     match_word = edit_buffer_get_word_from_pos (&edit->buffer, edit->buffer.curs1, &word_start,
3667                                                 &cut_len);
3668     word_len = match_word->len;
3669 
3670 #ifdef HAVE_CHARSET
3671     if (mc_global.source_codepage >= 0 && mc_global.source_codepage != mc_global.display_codepage)
3672     {
3673         GString *tmp_word;
3674 
3675         tmp_word = str_convert_to_display (match_word->str);
3676         g_string_free (match_word, TRUE);
3677         match_word = tmp_word;
3678     }
3679 #endif
3680     if (!aspell_check (match_word->str, (int) word_len))
3681     {
3682         GArray *suggest;
3683         unsigned int res;
3684         guint i;
3685 
3686         suggest = g_array_new (TRUE, FALSE, sizeof (char *));
3687 
3688         res = aspell_suggest (suggest, match_word->str, (int) word_len);
3689         if (res != 0)
3690         {
3691             char *new_word = NULL;
3692 
3693             edit->found_start = word_start;
3694             edit->found_len = word_len;
3695             edit->force |= REDRAW_PAGE;
3696             edit_scroll_screen_over_cursor (edit);
3697             edit_render_keypress (edit);
3698 
3699             retval = spell_dialog_spell_suggest_show (edit, match_word->str, &new_word, suggest);
3700             edit_cursor_move (edit, word_len - cut_len);
3701 
3702             if (retval == B_ENTER && new_word != NULL)
3703             {
3704                 char *cp_word;
3705 
3706 #ifdef HAVE_CHARSET
3707                 if (mc_global.source_codepage >= 0 &&
3708                     (mc_global.source_codepage != mc_global.display_codepage))
3709                 {
3710                     GString *tmp_word;
3711 
3712                     tmp_word = str_convert_to_input (new_word);
3713                     g_free (new_word);
3714                     new_word = g_string_free (tmp_word, FALSE);
3715                 }
3716 #endif
3717                 cp_word = new_word;
3718                 for (i = 0; i < word_len; i++)
3719                     edit_backspace (edit, TRUE);
3720                 for (; *new_word; new_word++)
3721                     edit_insert (edit, *new_word);
3722                 g_free (cp_word);
3723             }
3724             else if (retval == B_ADD_WORD)
3725                 aspell_add_to_dict (match_word->str, (int) word_len);
3726         }
3727 
3728         for (i = 0; i < suggest->len; i++)
3729         {
3730             char *cur_sugg_word;
3731 
3732             cur_sugg_word = g_array_index (suggest, char *, i);
3733             g_free (cur_sugg_word);
3734         }
3735         g_array_free (suggest, TRUE);
3736         edit->found_start = 0;
3737         edit->found_len = 0;
3738     }
3739 
3740     g_string_free (match_word, TRUE);
3741 
3742     return retval;
3743 }
3744 
3745 /* --------------------------------------------------------------------------------------------- */
3746 
3747 void
3748 edit_spellcheck_file (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3749 {
3750     if (edit->buffer.curs_line > 0)
3751     {
3752         edit_cursor_move (edit, -edit->buffer.curs1);
3753         edit_move_to_prev_col (edit, 0);
3754         edit_update_curs_row (edit);
3755     }
3756 
3757     do
3758     {
3759         int c1, c2;
3760 
3761         c2 = edit_buffer_get_current_byte (&edit->buffer);
3762 
3763         do
3764         {
3765             if (edit->buffer.curs1 >= edit->buffer.size)
3766                 return;
3767 
3768             c1 = c2;
3769             edit_cursor_move (edit, 1);
3770             c2 = edit_buffer_get_current_byte (&edit->buffer);
3771         }
3772         while (is_break_char (c1) || is_break_char (c2));
3773     }
3774     while (edit_suggest_current_word (edit) != B_CANCEL);
3775 }
3776 
3777 /* --------------------------------------------------------------------------------------------- */
3778 
3779 void
3780 edit_set_spell_lang (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
3781 {
3782     GArray *lang_list;
3783 
3784     lang_list = g_array_new (TRUE, FALSE, sizeof (char *));
3785     if (aspell_get_lang_list (lang_list) != 0)
3786     {
3787         char *lang;
3788 
3789         lang = spell_dialog_lang_list_show (lang_list);
3790         if (lang != NULL)
3791         {
3792             (void) aspell_set_lang (lang);
3793             g_free (lang);
3794         }
3795     }
3796     aspell_array_clean (lang_list);
3797 }
3798 #endif /* HAVE_ASPELL */
3799 
3800 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */