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_collect_completions
  29. edit_insert_column_of_text
  30. edit_macro_comparator
  31. edit_macro_sort_by_hotkey
  32. edit_get_macro
  33. edit_delete_macro
  34. edit_syntax_onoff_cb
  35. edit_redraw_page_cb
  36. edit_complete_word_insert_recoded_completion
  37. edit_refresh_cmd
  38. edit_syntax_onoff_cmd
  39. edit_show_tabs_tws_cmd
  40. edit_show_margin_cmd
  41. edit_show_numbers_cmd
  42. edit_save_mode_cmd
  43. edit_set_filename
  44. edit_save_as_cmd
  45. edit_delete_macro_cmd
  46. edit_execute_macro
  47. edit_store_macro_cmd
  48. edit_repeat_macro_cmd
  49. edit_load_macro_cmd
  50. edit_save_confirm_cmd
  51. edit_load_cmd
  52. edit_load_file_from_history
  53. edit_load_syntax_file
  54. edit_load_menu_file
  55. edit_close_cmd
  56. eval_marks
  57. edit_block_copy_cmd
  58. edit_block_move_cmd
  59. edit_block_delete_cmd
  60. edit_replace_cmd
  61. edit_search_cmd_callback
  62. edit_search_update_callback
  63. edit_search_cmd
  64. edit_ok_to_exit
  65. edit_save_block
  66. edit_paste_from_history
  67. edit_copy_to_X_buf_cmd
  68. edit_cut_to_X_buf_cmd
  69. edit_paste_from_X_buf_cmd
  70. edit_goto_cmd
  71. edit_save_block_cmd
  72. edit_insert_file_cmd
  73. edit_sort_cmd
  74. edit_ext_cmd
  75. edit_block_process_cmd
  76. edit_mail_dialog
  77. edit_complete_word_cmd
  78. edit_select_codepage_cmd
  79. edit_insert_literal_cmd
  80. edit_begin_end_macro_cmd
  81. edit_begin_end_repeat_cmd
  82. edit_load_forward_cmd
  83. edit_load_back_cmd
  84. edit_get_match_keyword_cmd
  85. edit_suggest_current_word
  86. edit_spellcheck_file
  87. edit_set_spell_lang

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

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