root/src/editor/editcmd.c

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

DEFINITIONS

This source file includes following definitions.
  1. edit_save_mode_callback
  2. edit_save_file
  3. edit_check_newline
  4. edit_get_save_file_as
  5. edit_save_cmd
  6. edit_delete_column_of_text
  7. edit_block_delete
  8. edit_get_block
  9. edit_save_block_to_clip_file
  10. pipe_mail
  11. edit_insert_column_of_text
  12. edit_syntax_onoff_cb
  13. editcmd_dialog_raw_key_query_cb
  14. edit_refresh_cmd
  15. edit_syntax_onoff_cmd
  16. edit_show_tabs_tws_cmd
  17. edit_show_margin_cmd
  18. edit_show_numbers_cmd
  19. edit_save_mode_cmd
  20. edit_set_filename
  21. edit_save_as_cmd
  22. edit_save_confirm_cmd
  23. edit_load_cmd
  24. edit_load_file_from_filename
  25. edit_load_file_from_history
  26. edit_load_syntax_file
  27. edit_load_menu_file
  28. edit_close_cmd
  29. edit_block_copy_cmd
  30. edit_block_move_cmd
  31. edit_block_delete_cmd
  32. edit_ok_to_exit
  33. edit_save_block
  34. edit_paste_from_history
  35. edit_copy_to_X_buf_cmd
  36. edit_cut_to_X_buf_cmd
  37. edit_paste_from_X_buf_cmd
  38. edit_goto_cmd
  39. edit_save_block_cmd
  40. edit_insert_file_cmd
  41. edit_sort_cmd
  42. edit_ext_cmd
  43. edit_block_process_cmd
  44. edit_mail_dialog
  45. edit_select_codepage_cmd
  46. edit_insert_literal_cmd
  47. edit_load_forward_cmd
  48. edit_load_back_cmd
  49. editcmd_dialog_raw_key_query

   1 /*
   2    Editor high level editing commands
   3 
   4    Copyright (C) 1996-2025
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Paul Sheer, 1996, 1997
   9    Andrew Borodin <aborodin@vmail.ru>, 2012-2022
  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 <https://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 <sys/stat.h>
  45 #include <stdlib.h>
  46 
  47 #include "lib/global.h"
  48 #include "lib/tty/tty.h"
  49 #include "lib/tty/key.h"  // XCTRL
  50 #include "lib/strutil.h"  // utf string functions
  51 #include "lib/fileloc.h"
  52 #include "lib/lock.h"
  53 #include "lib/util.h"  // tilde_expand()
  54 #include "lib/vfs/vfs.h"
  55 #include "lib/widget.h"
  56 #include "lib/event.h"  // mc_event_raise()
  57 #ifdef HAVE_CHARSET
  58 #    include "lib/charsets.h"
  59 #endif
  60 
  61 #include "src/history.h"
  62 #include "src/file_history.h"  // show_file_history()
  63 #ifdef HAVE_CHARSET
  64 #    include "src/selcodepage.h"
  65 #endif
  66 #include "src/util.h"  // check_for_default()
  67 
  68 #include "edit-impl.h"
  69 #include "editwidget.h"
  70 #include "editsearch.h"
  71 #include "etags.h"
  72 
  73 /*** global variables ****************************************************************************/
  74 
  75 /* search and replace: */
  76 int search_create_bookmark = FALSE;
  77 
  78 /*** file scope macro definitions ****************************************************************/
  79 
  80 #define space_width  1
  81 
  82 #define TEMP_BUF_LEN 1024
  83 
  84 /*** file scope type declarations ****************************************************************/
  85 
  86 /*** forward declarations (file scope functions) *************************************************/
  87 
  88 /*** file scope variables ************************************************************************/
  89 
  90 static unsigned long edit_save_mode_radio_id, edit_save_mode_input_id;
  91 
  92 /* --------------------------------------------------------------------------------------------- */
  93 /*** file scope functions ************************************************************************/
  94 /* --------------------------------------------------------------------------------------------- */
  95 
  96 static cb_ret_t
  97 edit_save_mode_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
  98 {
  99     switch (msg)
 100     {
 101     case MSG_CHANGED_FOCUS:
 102         if (sender != NULL && sender->id == edit_save_mode_radio_id)
 103         {
 104             Widget *ww;
 105 
 106             ww = widget_find_by_id (w, edit_save_mode_input_id);
 107             widget_disable (ww, RADIO (sender)->sel != 2);
 108             return MSG_HANDLED;
 109         }
 110         return MSG_NOT_HANDLED;
 111 
 112     default:
 113         return dlg_default_callback (w, sender, msg, parm, data);
 114     }
 115 }
 116 
 117 /* --------------------------------------------------------------------------------------------- */
 118 
 119 /*  If 0 (quick save) then  a) create/truncate <filename> file,
 120    b) save to <filename>;
 121    if 1 (safe save) then   a) save to <tempnam>,
 122    b) rename <tempnam> to <filename>;
 123    if 2 (do backups) then  a) save to <tempnam>,
 124    b) rename <filename> to <filename.backup_ext>,
 125    c) rename <tempnam> to <filename>. */
 126 
 127 /* returns 0 on error, -1 on abort */
 128 
 129 static int
 130 edit_save_file (WEdit *edit, const vfs_path_t *filename_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 131 {
 132     char *p;
 133     off_t filelen = 0;
 134     int this_save_mode, rv, fd = -1;
 135     vfs_path_t *real_filename_vpath;
 136     vfs_path_t *savename_vpath = NULL;
 137     const char *start_filename;
 138     const vfs_path_element_t *vpath_element;
 139     struct stat sb;
 140 
 141     vpath_element = vfs_path_get_by_index (filename_vpath, 0);
 142     if (vpath_element == NULL)
 143         return 0;
 144 
 145     start_filename = vpath_element->path;
 146     if (*start_filename == '\0')
 147         return 0;
 148 
 149     if (!IS_PATH_SEP (*start_filename) && edit->dir_vpath != NULL)
 150         real_filename_vpath = vfs_path_append_vpath_new (edit->dir_vpath, filename_vpath, NULL);
 151     else
 152         real_filename_vpath = vfs_path_clone (filename_vpath);
 153 
 154     this_save_mode = edit_options.save_mode;
 155     if (this_save_mode != EDIT_QUICK_SAVE)
 156     {
 157         if (!vfs_file_is_local (real_filename_vpath))
 158             // The file does not exists yet, so no safe save or backup are necessary.
 159             this_save_mode = EDIT_QUICK_SAVE;
 160         else
 161         {
 162             fd = mc_open (real_filename_vpath, O_RDONLY | O_BINARY);
 163             if (fd == -1)
 164                 // The file does not exists yet, so no safe save or backup are necessary.
 165                 this_save_mode = EDIT_QUICK_SAVE;
 166         }
 167 
 168         if (fd != -1)
 169             mc_close (fd);
 170     }
 171 
 172     rv = mc_stat (real_filename_vpath, &sb);
 173     if (rv == 0)
 174     {
 175         if (this_save_mode == EDIT_QUICK_SAVE && edit->skip_detach_prompt == 0 && sb.st_nlink > 1)
 176         {
 177             rv =
 178                 edit_query_dialog3 (_ ("Warning"), _ ("File has hard-links. Detach before saving?"),
 179                                     _ ("&Yes"), _ ("&No"), _ ("&Cancel"));
 180             switch (rv)
 181             {
 182             case 0:
 183                 this_save_mode = EDIT_SAFE_SAVE;
 184                 MC_FALLTHROUGH;
 185             case 1:
 186                 edit->skip_detach_prompt = 1;
 187                 break;
 188             default:
 189                 vfs_path_free (real_filename_vpath, TRUE);
 190                 return -1;
 191             }
 192         }
 193 
 194         // Prevent overwriting changes from other editor sessions.
 195         if (edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime)
 196         {
 197             // The default action is "Cancel".
 198             query_set_sel (1);
 199 
 200             rv = edit_query_dialog2 (_ ("Warning"),
 201                                      _ ("The file has been modified in the meantime. Save anyway?"),
 202                                      _ ("&Yes"), _ ("&Cancel"));
 203             if (rv != 0)
 204             {
 205                 vfs_path_free (real_filename_vpath, TRUE);
 206                 return -1;
 207             }
 208         }
 209     }
 210 
 211     if (this_save_mode == EDIT_QUICK_SAVE)
 212         savename_vpath = vfs_path_clone (real_filename_vpath);
 213     else
 214     {
 215         char *savedir, *saveprefix;
 216 
 217         savedir = vfs_path_tokens_get (real_filename_vpath, 0, -1);
 218         if (savedir == NULL)
 219             savedir = g_strdup (".");
 220 
 221         // Token-related function never return leading slash, so we need add it manually
 222         saveprefix = mc_build_filename (PATH_SEP_STR, savedir, "cooledit", (char *) NULL);
 223         g_free (savedir);
 224         fd = mc_mkstemps (&savename_vpath, saveprefix, NULL);
 225         g_free (saveprefix);
 226         if (savename_vpath == NULL)
 227         {
 228             vfs_path_free (real_filename_vpath, TRUE);
 229             return 0;
 230         }
 231         /* FIXME:
 232          * Close for now because mc_mkstemps use pure open system call
 233          * to create temporary file and it needs to be reopened by
 234          * VFS-aware mc_open().
 235          */
 236         close (fd);
 237     }
 238 
 239     (void) mc_chown (savename_vpath, edit->stat1.st_uid, edit->stat1.st_gid);
 240     (void) mc_chmod (savename_vpath, edit->stat1.st_mode);
 241     if (edit->attrs_ok)
 242         (void) mc_fsetflags (savename_vpath, edit->attrs);
 243 
 244     fd = mc_open (savename_vpath, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, edit->stat1.st_mode);
 245     if (fd == -1)
 246         goto error_save;
 247 
 248     // pipe save
 249     p = edit_get_write_filter (savename_vpath, real_filename_vpath);
 250     if (p != NULL)
 251     {
 252         FILE *file;
 253 
 254         mc_close (fd);
 255         file = (FILE *) popen (p, "w");
 256 
 257         if (file != NULL)
 258         {
 259             filelen = edit_write_stream (edit, file);
 260 #if 1
 261             pclose (file);
 262 #else
 263             if (pclose (file) != 0)
 264             {
 265                 message (D_ERROR, MSG_ERROR, _ ("Error writing to pipe: %s"), p);
 266                 g_free (p);
 267                 goto error_save;
 268             }
 269 #endif
 270         }
 271         else
 272         {
 273             message (D_ERROR, MSG_ERROR, _ ("Cannot open pipe for writing: %s"), p);
 274             g_free (p);
 275             goto error_save;
 276         }
 277         g_free (p);
 278     }
 279     else if (edit->lb == LB_ASIS)
 280     {  // do not change line breaks
 281         filelen = edit_buffer_write_file (&edit->buffer, fd);
 282 
 283         if (filelen != edit->buffer.size)
 284         {
 285             mc_close (fd);
 286             goto error_save;
 287         }
 288 
 289         if (mc_close (fd) != 0)
 290             goto error_save;
 291 
 292         // Update the file information, especially the mtime.
 293         if (mc_stat (savename_vpath, &edit->stat1) == -1)
 294             goto error_save;
 295     }
 296     else
 297     {  // change line breaks
 298         FILE *file;
 299         const char *savename;
 300 
 301         mc_close (fd);
 302 
 303         savename = vfs_path_get_last_path_str (savename_vpath);
 304         file = (FILE *) fopen (savename, "w");
 305         if (file != NULL)
 306         {
 307             filelen = edit_write_stream (edit, file);
 308             fclose (file);
 309         }
 310         else
 311         {
 312             message (D_ERROR, MSG_ERROR, _ ("Cannot open file for writing: %s"), savename);
 313             goto error_save;
 314         }
 315     }
 316 
 317     if (filelen != edit->buffer.size)
 318         goto error_save;
 319 
 320     if (this_save_mode == EDIT_DO_BACKUP)
 321     {
 322         char *tmp_store_filename;
 323         vfs_path_element_t *last_vpath_element;
 324         vfs_path_t *tmp_vpath;
 325         gboolean ok;
 326 
 327         g_assert (edit_options.backup_ext != NULL);
 328 
 329         // add backup extension to the path
 330         tmp_vpath = vfs_path_clone (real_filename_vpath);
 331         last_vpath_element = (vfs_path_element_t *) vfs_path_get_by_index (tmp_vpath, -1);
 332         tmp_store_filename = last_vpath_element->path;
 333         last_vpath_element->path =
 334             g_strdup_printf ("%s%s", tmp_store_filename, edit_options.backup_ext);
 335         g_free (tmp_store_filename);
 336 
 337         ok = (mc_rename (real_filename_vpath, tmp_vpath) != -1);
 338         vfs_path_free (tmp_vpath, TRUE);
 339         if (!ok)
 340             goto error_save;
 341     }
 342 
 343     if (this_save_mode != EDIT_QUICK_SAVE && mc_rename (savename_vpath, real_filename_vpath) == -1)
 344         goto error_save;
 345 
 346     vfs_path_free (real_filename_vpath, TRUE);
 347     vfs_path_free (savename_vpath, TRUE);
 348     return 1;
 349 error_save:
 350     /*  FIXME: Is this safe ?
 351      *  if (this_save_mode != EDIT_QUICK_SAVE)
 352      *      mc_unlink (savename);
 353      */
 354     vfs_path_free (real_filename_vpath, TRUE);
 355     vfs_path_free (savename_vpath, TRUE);
 356     return 0;
 357 }
 358 
 359 /* --------------------------------------------------------------------------------------------- */
 360 
 361 static gboolean
 362 edit_check_newline (const edit_buffer_t *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 363 {
 364     return !(edit_options.check_nl_at_eof && buf->size > 0
 365              && edit_buffer_get_byte (buf, buf->size - 1) != '\n'
 366              && edit_query_dialog2 (_ ("Warning"),
 367                                     _ ("The file you are saving does not end with a newline."),
 368                                     _ ("C&ontinue"), _ ("&Cancel"))
 369                  != 0);
 370 }
 371 
 372 /* --------------------------------------------------------------------------------------------- */
 373 
 374 static vfs_path_t *
 375 edit_get_save_file_as (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 376 {
 377     static LineBreaks cur_lb = LB_ASIS;
 378     char *filename_res = NULL;
 379     vfs_path_t *ret_vpath = NULL;
 380 
 381     const char *lb_names[LB_NAMES] = {
 382         N_ ("&Do not change"),
 383         N_ ("&Unix format (LF)"),
 384         N_ ("&Windows/DOS format (CR LF)"),
 385         N_ ("&Macintosh format (CR)"),
 386     };
 387 
 388     quick_widget_t quick_widgets[] = {
 389         QUICK_LABELED_INPUT (N_ ("Enter file name:"), input_label_above,
 390                              vfs_path_as_str (edit->filename_vpath), "save-as", &filename_res, NULL,
 391                              FALSE, FALSE, INPUT_COMPLETE_FILENAMES),
 392         QUICK_SEPARATOR (TRUE),
 393         QUICK_LABEL (N_ ("Change line breaks to:"), NULL),
 394         QUICK_RADIO (LB_NAMES, lb_names, (int *) &cur_lb, NULL),
 395         QUICK_BUTTONS_OK_CANCEL,
 396         QUICK_END,
 397     };
 398 
 399     WRect r = { -1, -1, 0, 64 };
 400 
 401     quick_dialog_t qdlg = {
 402         .rect = r,
 403         .title = N_ ("Save As"),
 404         .help = "[Save File As]",
 405         .widgets = quick_widgets,
 406         .callback = NULL,
 407         .mouse_callback = NULL,
 408     };
 409 
 410     if (quick_dialog (&qdlg) != B_CANCEL)
 411     {
 412         char *fname;
 413 
 414         edit->lb = cur_lb;
 415         fname = tilde_expand (filename_res);
 416         g_free (filename_res);
 417         ret_vpath = vfs_path_from_str (fname);
 418         g_free (fname);
 419     }
 420 
 421     return ret_vpath;
 422 }
 423 
 424 /* --------------------------------------------------------------------------------------------- */
 425 
 426 /** returns TRUE on success */
 427 
 428 static gboolean
 429 edit_save_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 430 {
 431     int save_lock = 0;
 432 
 433     if (edit->locked == 0 && edit->delete_file == 0)
 434         save_lock = lock_file (edit->filename_vpath);
 435 
 436     const int res = edit_save_file (edit, edit->filename_vpath);
 437 
 438     // Maintain modify (not save) lock on failure
 439     if ((res > 0 && edit->locked != 0) || save_lock != 0)
 440         edit->locked = unlock_file (edit->filename_vpath);
 441 
 442     // On failure try 'save as', it does locking on its own
 443     if (res == 0)
 444         return edit_save_as_cmd (edit);
 445 
 446     if (res > 0)
 447     {
 448         edit->delete_file = 0;
 449         edit->modified = 0;
 450     }
 451 
 452     edit->force |= REDRAW_COMPLETELY;
 453 
 454     return TRUE;
 455 }
 456 
 457 /* --------------------------------------------------------------------------------------------- */
 458 
 459 static void
 460 edit_delete_column_of_text (WEdit *edit, off_t m1, off_t m2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 461 {
 462     off_t n;
 463     off_t r;
 464     long b, c, d;
 465 
 466     n = edit_buffer_get_forward_offset (&edit->buffer, m1, 0, m2) + 1;
 467     r = edit_buffer_get_bol (&edit->buffer, m1);
 468     c = (long) edit_move_forward3 (edit, r, 0, m1);
 469     r = edit_buffer_get_bol (&edit->buffer, m2);
 470     d = (long) edit_move_forward3 (edit, r, 0, m2);
 471     b = MAX (MIN (c, d), MIN (edit->column1, edit->column2));
 472     c = MAX (c, MAX (edit->column1, edit->column2));
 473 
 474     while (n-- != 0)
 475     {
 476         off_t p, q;
 477 
 478         r = edit_buffer_get_current_bol (&edit->buffer);
 479         p = edit_move_forward3 (edit, r, b, 0);
 480         q = edit_move_forward3 (edit, r, c, 0);
 481         p = MAX (p, m1);
 482         q = MIN (q, m2);
 483         edit_cursor_move (edit, p - edit->buffer.curs1);
 484         // delete line between margins
 485         for (; q > p; q--)
 486             if (edit_buffer_get_current_byte (&edit->buffer) != '\n')
 487                 edit_delete (edit, TRUE);
 488 
 489         // move to next line except on the last delete
 490         if (n != 0)
 491         {
 492             r = edit_buffer_get_forward_offset (&edit->buffer, edit->buffer.curs1, 1, 0);
 493             edit_cursor_move (edit, r - edit->buffer.curs1);
 494         }
 495     }
 496 }
 497 
 498 /* --------------------------------------------------------------------------------------------- */
 499 /** if success return TRUE */
 500 
 501 static gboolean
 502 edit_block_delete (WEdit *edit, off_t start_mark, off_t end_mark)
     /* [previous][next][first][last][top][bottom][index][help]  */
 503 {
 504     off_t curs_pos;
 505     long curs_line, c1, c2;
 506 
 507     if (edit->column_highlight && edit->mark2 < 0)
 508         edit_mark_cmd (edit, FALSE);
 509 
 510     // Warning message with a query to continue or cancel the operation
 511     if ((end_mark - start_mark) > max_undo / 2
 512         && edit_query_dialog2 (_ ("Warning"),
 513                                ("Block is large, you may not be able to undo this action"),
 514                                _ ("C&ontinue"), _ ("&Cancel"))
 515             != 0)
 516         return FALSE;
 517 
 518     c1 = MIN (edit->column1, edit->column2);
 519     c2 = MAX (edit->column1, edit->column2);
 520     edit->column1 = c1;
 521     edit->column2 = c2;
 522 
 523     edit_push_markers (edit);
 524 
 525     curs_line = edit->buffer.curs_line;
 526 
 527     curs_pos = edit->curs_col + edit->over_col;
 528 
 529     // move cursor to start of selection
 530     edit_cursor_move (edit, start_mark - edit->buffer.curs1);
 531     edit_scroll_screen_over_cursor (edit);
 532 
 533     if (start_mark < end_mark)
 534     {
 535         if (edit->column_highlight)
 536         {
 537             off_t b, e;
 538             off_t line_width;
 539 
 540             if (edit->mark2 < 0)
 541                 edit_mark_cmd (edit, FALSE);
 542             edit_delete_column_of_text (edit, start_mark, end_mark);
 543             // move cursor to the saved position
 544             edit_move_to_line (edit, curs_line);
 545             // calculate line width and cursor position before cut
 546             b = edit_buffer_get_current_bol (&edit->buffer);
 547             e = edit_buffer_get_current_eol (&edit->buffer);
 548             line_width = edit_move_forward3 (edit, b, 0, e);
 549             if (edit_options.cursor_beyond_eol && curs_pos > line_width)
 550                 edit->over_col = curs_pos - line_width;
 551         }
 552         else
 553         {
 554             off_t count;
 555 
 556             for (count = start_mark; count < end_mark; count++)
 557                 edit_delete (edit, TRUE);
 558         }
 559     }
 560 
 561     edit_set_markers (edit, 0, 0, 0, 0);
 562     edit->force |= REDRAW_PAGE;
 563 
 564     return TRUE;
 565 }
 566 
 567 /* --------------------------------------------------------------------------------------------- */
 568 /** Return a null terminated length of text. Result must be g_free'd */
 569 
 570 static unsigned char *
 571 edit_get_block (WEdit *edit, off_t start, off_t finish, off_t *l)
     /* [previous][next][first][last][top][bottom][index][help]  */
 572 {
 573     unsigned char *s, *r;
 574 
 575     r = s = g_malloc0 (finish - start + 1);
 576 
 577     if (edit->column_highlight)
 578     {
 579         *l = 0;
 580 
 581         // copy from buffer, excluding chars that are out of the column 'margins'
 582         for (; start < finish; start++)
 583         {
 584             int c;
 585             off_t x;
 586 
 587             x = edit_buffer_get_bol (&edit->buffer, start);
 588             x = edit_move_forward3 (edit, x, 0, start);
 589             c = edit_buffer_get_byte (&edit->buffer, start);
 590             if ((x >= edit->column1 && x < edit->column2)
 591                 || (x >= edit->column2 && x < edit->column1) || c == '\n')
 592             {
 593                 *s++ = c;
 594                 (*l)++;
 595             }
 596         }
 597     }
 598     else
 599     {
 600         *l = finish - start;
 601 
 602         for (; start < finish; start++)
 603             *s++ = edit_buffer_get_byte (&edit->buffer, start);
 604     }
 605 
 606     *s = '\0';
 607 
 608     return r;
 609 }
 610 
 611 /* --------------------------------------------------------------------------------------------- */
 612 /** copies a block to clipboard file */
 613 
 614 static gboolean
 615 edit_save_block_to_clip_file (WEdit *edit, off_t start, off_t finish)
     /* [previous][next][first][last][top][bottom][index][help]  */
 616 {
 617     gboolean ret;
 618     gchar *tmp;
 619 
 620     tmp = mc_config_get_full_path (EDIT_HOME_CLIP_FILE);
 621     ret = edit_save_block (edit, tmp, start, finish);
 622     g_free (tmp);
 623 
 624     return ret;
 625 }
 626 
 627 /* --------------------------------------------------------------------------------------------- */
 628 
 629 static void
 630 pipe_mail (const edit_buffer_t *buf, char *to, char *subject, char *cc)
     /* [previous][next][first][last][top][bottom][index][help]  */
 631 {
 632     FILE *p = 0;
 633     char *s = NULL;
 634 
 635     to = name_quote (to, FALSE);
 636     if (to != NULL)
 637     {
 638         subject = name_quote (subject, FALSE);
 639         if (subject != NULL)
 640         {
 641             cc = name_quote (cc, FALSE);
 642             if (cc == NULL)
 643                 s = g_strdup_printf ("mail -s %s %s", subject, to);
 644             else
 645             {
 646                 s = g_strdup_printf ("mail -s %s -c %s %s", subject, cc, to);
 647                 g_free (cc);
 648             }
 649 
 650             g_free (subject);
 651         }
 652 
 653         g_free (to);
 654     }
 655 
 656     if (s != NULL)
 657     {
 658         p = popen (s, "w");
 659         g_free (s);
 660     }
 661 
 662     if (p != NULL)
 663     {
 664         off_t i;
 665 
 666         for (i = 0; i < buf->size; i++)
 667             if (fputc (edit_buffer_get_byte (buf, i), p) < 0)
 668                 break;
 669         pclose (p);
 670     }
 671 }
 672 
 673 /* --------------------------------------------------------------------------------------------- */
 674 
 675 static void
 676 edit_insert_column_of_text (WEdit *edit, unsigned char *data, off_t size, long width,
     /* [previous][next][first][last][top][bottom][index][help]  */
 677                             off_t *start_pos, off_t *end_pos, long *col1, long *col2)
 678 {
 679     off_t i, cursor;
 680     long col;
 681 
 682     cursor = edit->buffer.curs1;
 683     col = edit_get_col (edit);
 684 
 685     for (i = 0; i < size; i++)
 686     {
 687         if (data[i] != '\n')
 688             edit_insert (edit, data[i]);
 689         else
 690         {  // fill in and move to next line
 691             long l;
 692             off_t p;
 693 
 694             if (edit_buffer_get_current_byte (&edit->buffer) != '\n')
 695             {
 696                 for (l = width - (edit_get_col (edit) - col); l > 0; l -= space_width)
 697                     edit_insert (edit, ' ');
 698             }
 699             for (p = edit->buffer.curs1;; p++)
 700             {
 701                 if (p == edit->buffer.size)
 702                 {
 703                     edit_cursor_move (edit, edit->buffer.size - edit->buffer.curs1);
 704                     edit_insert_ahead (edit, '\n');
 705                     p++;
 706                     break;
 707                 }
 708                 if (edit_buffer_get_byte (&edit->buffer, p) == '\n')
 709                 {
 710                     p++;
 711                     break;
 712                 }
 713             }
 714             edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->buffer.curs1);
 715 
 716             for (l = col - edit_get_col (edit); l >= space_width; l -= space_width)
 717                 edit_insert (edit, ' ');
 718         }
 719     }
 720 
 721     *col1 = col;
 722     *col2 = col + width;
 723     *start_pos = cursor;
 724     *end_pos = edit->buffer.curs1;
 725     edit_cursor_move (edit, cursor - edit->buffer.curs1);
 726 }
 727 
 728 /* --------------------------------------------------------------------------------------------- */
 729 /**
 730  * Callback for the iteration of objects in the 'editors' array.
 731  * Toggle syntax highlighting in editor object.
 732  *
 733  * @param data      probably WEdit object
 734  * @param user_data unused
 735  */
 736 
 737 static void
 738 edit_syntax_onoff_cb (void *data, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 739 {
 740     (void) user_data;
 741 
 742     if (edit_widget_is_editor (CONST_WIDGET (data)))
 743     {
 744         WEdit *edit = EDIT (data);
 745 
 746         if (edit_options.syntax_highlighting)
 747             edit_load_syntax (edit, NULL, edit->syntax_type);
 748         edit->force |= REDRAW_PAGE;
 749     }
 750 }
 751 
 752 /* --------------------------------------------------------------------------------------------- */
 753 
 754 static cb_ret_t
 755 editcmd_dialog_raw_key_query_cb (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 756 {
 757     WDialog *h = DIALOG (w);
 758 
 759     switch (msg)
 760     {
 761     case MSG_KEY:
 762         h->ret_value = parm;
 763         dlg_close (h);
 764         return MSG_HANDLED;
 765     default:
 766         return dlg_default_callback (w, sender, msg, parm, data);
 767     }
 768 }
 769 
 770 /* --------------------------------------------------------------------------------------------- */
 771 /*** public functions ****************************************************************************/
 772 /* --------------------------------------------------------------------------------------------- */
 773 
 774 void
 775 edit_refresh_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 776 {
 777     tty_clear_screen ();
 778     repaint_screen ();
 779     tty_keypad (TRUE);
 780 }
 781 
 782 /* --------------------------------------------------------------------------------------------- */
 783 /**
 784  * Toggle syntax highlighting in all editor windows.
 785  *
 786  * @param h root widget for all windows
 787  */
 788 
 789 void
 790 edit_syntax_onoff_cmd (WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 791 {
 792     edit_options.syntax_highlighting = !edit_options.syntax_highlighting;
 793     g_list_foreach (GROUP (h)->widgets, edit_syntax_onoff_cb, NULL);
 794     widget_draw (WIDGET (h));
 795 }
 796 
 797 /* --------------------------------------------------------------------------------------------- */
 798 /**
 799  * Toggle tabs showing in all editor windows.
 800  *
 801  * @param h root widget for all windows
 802  */
 803 
 804 void
 805 edit_show_tabs_tws_cmd (WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 806 {
 807     enable_show_tabs_tws = !enable_show_tabs_tws;
 808     widget_draw (WIDGET (h));
 809 }
 810 
 811 /* --------------------------------------------------------------------------------------------- */
 812 /**
 813  * Toggle right margin showing in all editor windows.
 814  *
 815  * @param h root widget for all windows
 816  */
 817 
 818 void
 819 edit_show_margin_cmd (WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 820 {
 821     edit_options.show_right_margin = !edit_options.show_right_margin;
 822     widget_draw (WIDGET (h));
 823 }
 824 
 825 /* --------------------------------------------------------------------------------------------- */
 826 /**
 827  * Toggle line numbers showing in all editor windows.
 828  *
 829  * @param h root widget for all windows
 830  */
 831 
 832 void
 833 edit_show_numbers_cmd (WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 834 {
 835     edit_options.line_state = !edit_options.line_state;
 836     edit_options.line_state_width = edit_options.line_state ? LINE_STATE_WIDTH : 0;
 837     widget_draw (WIDGET (h));
 838 }
 839 
 840 /* --------------------------------------------------------------------------------------------- */
 841 
 842 void
 843 edit_save_mode_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 844 {
 845     char *str_result = NULL;
 846 
 847     const char *str[] = {
 848         N_ ("&Quick save"),
 849         N_ ("&Safe save"),
 850         N_ ("&Do backups with following extension:"),
 851     };
 852 
 853 #ifdef ENABLE_NLS
 854     size_t i;
 855 
 856     for (i = 0; i < 3; i++)
 857         str[i] = _ (str[i]);
 858 #endif
 859 
 860     g_assert (edit_options.backup_ext != NULL);
 861 
 862     {
 863         quick_widget_t quick_widgets[] = {
 864             QUICK_RADIO (3, str, &edit_options.save_mode, &edit_save_mode_radio_id),
 865             QUICK_INPUT (edit_options.backup_ext, "edit-backup-ext", &str_result,
 866                          &edit_save_mode_input_id, FALSE, FALSE, INPUT_COMPLETE_NONE),
 867             QUICK_SEPARATOR (TRUE),
 868             QUICK_CHECKBOX (N_ ("Check &POSIX new line"), &edit_options.check_nl_at_eof, NULL),
 869             QUICK_BUTTONS_OK_CANCEL,
 870             QUICK_END,
 871         };
 872 
 873         WRect r = { -1, -1, 0, 38 };
 874 
 875         quick_dialog_t qdlg = {
 876             .rect = r,
 877             .title = N_ ("Edit Save Mode"),
 878             .help = "[Edit Save Mode]",
 879             .widgets = quick_widgets,
 880             .callback = edit_save_mode_callback,
 881             .mouse_callback = NULL,
 882         };
 883 
 884         if (quick_dialog (&qdlg) != B_CANCEL)
 885         {
 886             g_free (edit_options.backup_ext);
 887             edit_options.backup_ext = str_result;
 888         }
 889     }
 890 }
 891 
 892 /* --------------------------------------------------------------------------------------------- */
 893 
 894 void
 895 edit_set_filename (WEdit *edit, const vfs_path_t *name_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 896 {
 897     vfs_path_free (edit->filename_vpath, TRUE);
 898     edit->filename_vpath = vfs_path_clone (name_vpath);
 899 
 900     if (edit->dir_vpath == NULL)
 901         edit->dir_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
 902 }
 903 
 904 /* --------------------------------------------------------------------------------------------- */
 905 /* Here we want to warn the users of overwriting an existing file,
 906    but only if they have made a change to the filename */
 907 /* returns TRUE on success */
 908 gboolean
 909 edit_save_as_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 910 {
 911     // This heads the 'Save As' dialog box
 912     vfs_path_t *exp_vpath;
 913     int save_lock = 0;
 914     gboolean different_filename = FALSE;
 915     gboolean ret = FALSE;
 916 
 917     if (!edit_check_newline (&edit->buffer))
 918         return FALSE;
 919 
 920     exp_vpath = edit_get_save_file_as (edit);
 921     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
 922 
 923     if (exp_vpath != NULL && vfs_path_len (exp_vpath) != 0)
 924     {
 925         int rv;
 926 
 927         if (!vfs_path_equal (edit->filename_vpath, exp_vpath))
 928         {
 929             int file;
 930             struct stat sb;
 931 
 932             if (mc_stat (exp_vpath, &sb) == 0 && !S_ISREG (sb.st_mode))
 933             {
 934                 message (D_ERROR, MSG_ERROR, "%s",
 935                          _ ("Cannot save: destination is not a regular file"));
 936                 goto ret;
 937             }
 938 
 939             different_filename = TRUE;
 940             file = mc_open (exp_vpath, O_RDONLY | O_BINARY);
 941 
 942             if (file == -1)
 943                 edit->stat1.st_mode |= S_IWUSR;
 944             else
 945             {
 946                 // the file exists
 947                 mc_close (file);
 948                 // Overwrite the current file or cancel the operation
 949                 if (edit_query_dialog2 (_ ("Warning"), _ ("A file already exists with this name"),
 950                                         _ ("&Overwrite"), _ ("&Cancel")))
 951                     goto ret;
 952             }
 953 
 954             save_lock = lock_file (exp_vpath);
 955         }
 956         else if (edit->locked == 0 && edit->delete_file == 0)
 957             // filenames equal, check if already locked
 958             save_lock = lock_file (exp_vpath);
 959 
 960         if (different_filename)
 961             /* Allow user to write into saved (under another name) file
 962              * even if original file had r/o user permissions. */
 963             edit->stat1.st_mode |= S_IWUSR;
 964 
 965         rv = edit_save_file (edit, exp_vpath);
 966         switch (rv)
 967         {
 968         case 1:
 969             // Successful, so unlock both files
 970             if (different_filename)
 971             {
 972                 if (save_lock != 0)
 973                     unlock_file (exp_vpath);
 974                 if (edit->locked != 0)
 975                     edit->locked = unlock_file (edit->filename_vpath);
 976             }
 977             else if (edit->locked != 0 || save_lock != 0)
 978                 edit->locked = unlock_file (edit->filename_vpath);
 979 
 980             edit_set_filename (edit, exp_vpath);
 981             if (edit->lb != LB_ASIS)
 982                 edit_reload (edit, exp_vpath);
 983             edit->modified = 0;
 984             edit->delete_file = 0;
 985             if (different_filename)
 986                 edit_load_syntax (edit, NULL, edit->syntax_type);
 987             ret = TRUE;
 988             break;
 989 
 990         default:
 991             message (D_ERROR, MSG_ERROR, "%s", _ ("Cannot save file"));
 992             MC_FALLTHROUGH;
 993 
 994         case -1:
 995             // Failed, so maintain modify (not save) lock
 996             if (save_lock != 0)
 997                 unlock_file (exp_vpath);
 998             break;
 999         }
1000     }
1001 
1002 ret:
1003     vfs_path_free (exp_vpath, TRUE);
1004     edit->force |= REDRAW_COMPLETELY;
1005     return ret;
1006 }
1007 
1008 /* --------------------------------------------------------------------------------------------- */
1009 /** returns TRUE on success */
1010 
1011 gboolean
1012 edit_save_confirm_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1013 {
1014     if (edit->filename_vpath == NULL)
1015         return edit_save_as_cmd (edit);
1016 
1017     if (!edit_check_newline (&edit->buffer))
1018         return FALSE;
1019 
1020     if (edit_options.confirm_save)
1021     {
1022         char *f;
1023         gboolean ok;
1024 
1025         f = g_strdup_printf (_ ("Confirm save file: \"%s\""),
1026                              vfs_path_as_str (edit->filename_vpath));
1027         ok = (edit_query_dialog2 (_ ("Save file"), f, _ ("&Save"), _ ("&Cancel")) == 0);
1028         g_free (f);
1029         if (!ok)
1030             return FALSE;
1031     }
1032 
1033     return edit_save_cmd (edit);
1034 }
1035 
1036 /* --------------------------------------------------------------------------------------------- */
1037 /**
1038  * Ask file to edit and load it.
1039  *
1040  * @return TRUE on success or cancel of ask.
1041  */
1042 
1043 gboolean
1044 edit_load_cmd (WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
1045 {
1046     char *exp;
1047     gboolean ret = TRUE;  // possible cancel
1048 
1049     exp = input_expand_dialog (_ ("Load"), _ ("Enter file name:"), MC_HISTORY_EDIT_LOAD,
1050                                INPUT_LAST_TEXT, INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD);
1051 
1052     if (exp != NULL && *exp != '\0')
1053     {
1054         vfs_path_t *exp_vpath;
1055         edit_arg_t arg;
1056 
1057         exp_vpath = vfs_path_from_str (exp);
1058         edit_arg_init (&arg, exp_vpath, 0);
1059         ret = edit_load_file_from_filename (h, &arg);
1060         vfs_path_free (exp_vpath, TRUE);
1061     }
1062 
1063     g_free (exp);
1064 
1065     return ret;
1066 }
1067 
1068 /* --------------------------------------------------------------------------------------------- */
1069 /**
1070  * Load file content
1071  *
1072  * @param h screen the owner of editor window
1073  * @param vpath vfs file path
1074  * @param line line number
1075  *
1076  * @return TRUE if file content was successfully loaded, FALSE otherwise
1077  */
1078 
1079 gboolean
1080 edit_load_file_from_filename (WDialog *h, const edit_arg_t *arg)
     /* [previous][next][first][last][top][bottom][index][help]  */
1081 {
1082     WRect r = WIDGET (h)->rect;
1083 
1084     rect_grow (&r, -1, 0);
1085 
1086     return edit_add_window (h, &r, arg);
1087 }
1088 
1089 /* --------------------------------------------------------------------------------------------- */
1090 /**
1091  * Show history od edited or viewed files and open selected file.
1092  *
1093  * @return TRUE on success, FALSE otherwise.
1094  */
1095 
1096 gboolean
1097 edit_load_file_from_history (WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
1098 {
1099     char *exp;
1100     int action;
1101     gboolean ret = TRUE;  // possible cancel
1102 
1103     exp = show_file_history (CONST_WIDGET (h), &action);
1104     if (exp != NULL && (action == CK_Edit || action == CK_Enter))
1105     {
1106         vfs_path_t *exp_vpath;
1107         edit_arg_t arg;
1108 
1109         exp_vpath = vfs_path_from_str (exp);
1110         edit_arg_init (&arg, exp_vpath, 0);
1111         ret = edit_load_file_from_filename (h, &arg);
1112         vfs_path_free (exp_vpath, TRUE);
1113     }
1114 
1115     g_free (exp);
1116 
1117     return ret;
1118 }
1119 
1120 /* --------------------------------------------------------------------------------------------- */
1121 /**
1122  * Load syntax file to edit.
1123  *
1124  * @return TRUE on success
1125  */
1126 
1127 gboolean
1128 edit_load_syntax_file (WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
1129 {
1130     vfs_path_t *extdir_vpath;
1131     int dir = 0;
1132     edit_arg_t arg;
1133     gboolean ret = FALSE;
1134 
1135     if (geteuid () == 0)
1136         dir = query_dialog (_ ("Syntax file edit"), _ ("Which syntax file you want to edit?"),
1137                             D_NORMAL, 2, _ ("&User"), _ ("&System wide"));
1138 
1139     extdir_vpath =
1140         vfs_path_build_filename (mc_global.sysconfig_dir, EDIT_SYNTAX_FILE, (char *) NULL);
1141     if (!exist_file (vfs_path_get_last_path_str (extdir_vpath)))
1142     {
1143         vfs_path_free (extdir_vpath, TRUE);
1144         extdir_vpath =
1145             vfs_path_build_filename (mc_global.share_data_dir, EDIT_SYNTAX_FILE, (char *) NULL);
1146     }
1147 
1148     if (dir == 0)
1149     {
1150         vfs_path_t *user_syntax_file_vpath;
1151 
1152         user_syntax_file_vpath = mc_config_get_full_vpath (EDIT_SYNTAX_FILE);
1153         check_for_default (extdir_vpath, user_syntax_file_vpath);
1154         edit_arg_init (&arg, user_syntax_file_vpath, 0);
1155         ret = edit_load_file_from_filename (h, &arg);
1156         vfs_path_free (user_syntax_file_vpath, TRUE);
1157     }
1158     else if (dir == 1)
1159     {
1160         edit_arg_init (&arg, extdir_vpath, 0);
1161         ret = edit_load_file_from_filename (h, &arg);
1162     }
1163 
1164     vfs_path_free (extdir_vpath, TRUE);
1165 
1166     return ret;
1167 }
1168 
1169 /* --------------------------------------------------------------------------------------------- */
1170 /**
1171  * Load menu file to edit.
1172  *
1173  * @return TRUE on success
1174  */
1175 
1176 gboolean
1177 edit_load_menu_file (WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
1178 {
1179     vfs_path_t *buffer_vpath;
1180     vfs_path_t *menufile_vpath;
1181     int dir;
1182     edit_arg_t arg;
1183     gboolean ret;
1184 
1185     query_set_sel (1);
1186     dir = query_dialog (_ ("Menu edit"), _ ("Which menu file do you want to edit?"), D_NORMAL,
1187                         geteuid () != 0 ? 2 : 3, _ ("&Local"), _ ("&User"), _ ("&System wide"));
1188 
1189     menufile_vpath =
1190         vfs_path_build_filename (mc_global.sysconfig_dir, EDIT_GLOBAL_MENU, (char *) NULL);
1191     if (!exist_file (vfs_path_get_last_path_str (menufile_vpath)))
1192     {
1193         vfs_path_free (menufile_vpath, TRUE);
1194         menufile_vpath =
1195             vfs_path_build_filename (mc_global.share_data_dir, EDIT_GLOBAL_MENU, (char *) NULL);
1196     }
1197 
1198     switch (dir)
1199     {
1200     case 0:
1201         buffer_vpath = vfs_path_from_str (EDIT_LOCAL_MENU);
1202         check_for_default (menufile_vpath, buffer_vpath);
1203         chmod (vfs_path_get_last_path_str (buffer_vpath), 0600);
1204         break;
1205 
1206     case 1:
1207         buffer_vpath = mc_config_get_full_vpath (EDIT_HOME_MENU);
1208         check_for_default (menufile_vpath, buffer_vpath);
1209         break;
1210 
1211     case 2:
1212         buffer_vpath =
1213             vfs_path_build_filename (mc_global.sysconfig_dir, EDIT_GLOBAL_MENU, (char *) NULL);
1214         if (!exist_file (vfs_path_get_last_path_str (buffer_vpath)))
1215         {
1216             vfs_path_free (buffer_vpath, TRUE);
1217             buffer_vpath =
1218                 vfs_path_build_filename (mc_global.share_data_dir, EDIT_GLOBAL_MENU, (char *) NULL);
1219         }
1220         break;
1221 
1222     default:
1223         vfs_path_free (menufile_vpath, TRUE);
1224         return FALSE;
1225     }
1226 
1227     edit_arg_init (&arg, buffer_vpath, 0);
1228     ret = edit_load_file_from_filename (h, &arg);
1229 
1230     vfs_path_free (buffer_vpath, TRUE);
1231     vfs_path_free (menufile_vpath, TRUE);
1232 
1233     return ret;
1234 }
1235 
1236 /* --------------------------------------------------------------------------------------------- */
1237 /**
1238  * Close window with opened file.
1239  *
1240  * @return TRUE if file was closed.
1241  */
1242 
1243 gboolean
1244 edit_close_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1245 {
1246     gboolean ret;
1247 
1248     ret = (edit != NULL) && edit_ok_to_exit (edit);
1249 
1250     if (ret)
1251     {
1252         Widget *w = WIDGET (edit);
1253         WGroup *g = w->owner;
1254 
1255         if (edit->locked != 0)
1256             edit->locked = unlock_file (edit->filename_vpath);
1257 
1258         group_remove_widget (w);
1259         widget_destroy (w);
1260 
1261         if (edit_widget_is_editor (CONST_WIDGET (g->current->data)))
1262             edit = EDIT (g->current->data);
1263         else
1264         {
1265             edit = edit_find_editor (DIALOG (g));
1266             if (edit != NULL)
1267                 widget_select (WIDGET (edit));
1268         }
1269     }
1270 
1271     if (edit != NULL)
1272         edit->force |= REDRAW_COMPLETELY;
1273 
1274     return ret;
1275 }
1276 
1277 /* --------------------------------------------------------------------------------------------- */
1278 
1279 void
1280 edit_block_copy_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1281 {
1282     off_t start_mark, end_mark, current = edit->buffer.curs1;
1283     off_t mark1 = 0, mark2 = 0;
1284     long c1 = 0, c2 = 0;
1285     off_t size;
1286     unsigned char *copy_buf;
1287 
1288     edit_update_curs_col (edit);
1289     if (!eval_marks (edit, &start_mark, &end_mark))
1290         return;
1291 
1292     copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1293 
1294     // all that gets pushed are deletes hence little space is used on the stack
1295 
1296     edit_push_markers (edit);
1297 
1298     if (edit->column_highlight)
1299     {
1300         long col_delta;
1301 
1302         col_delta = labs (edit->column2 - edit->column1);
1303         edit_insert_column_of_text (edit, copy_buf, size, col_delta, &mark1, &mark2, &c1, &c2);
1304     }
1305     else
1306     {
1307         int size_orig = size;
1308 
1309         while (size-- != 0)
1310             edit_insert_ahead (edit, copy_buf[size]);
1311 
1312         // Place cursor at the end of text selection
1313         if (edit_options.cursor_after_inserted_block)
1314             edit_cursor_move (edit, size_orig);
1315     }
1316 
1317     g_free (copy_buf);
1318     edit_scroll_screen_over_cursor (edit);
1319 
1320     if (edit->column_highlight)
1321         edit_set_markers (edit, edit->buffer.curs1, mark2, c1, c2);
1322     else if (start_mark < current && end_mark > current)
1323         edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
1324 
1325     edit->force |= REDRAW_PAGE;
1326 }
1327 
1328 /* --------------------------------------------------------------------------------------------- */
1329 
1330 void
1331 edit_block_move_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1332 {
1333     off_t current;
1334     unsigned char *copy_buf = NULL;
1335     off_t start_mark, end_mark;
1336 
1337     if (!eval_marks (edit, &start_mark, &end_mark))
1338         return;
1339 
1340     if (!edit->column_highlight && edit->buffer.curs1 > start_mark && edit->buffer.curs1 < end_mark)
1341         return;
1342 
1343     if (edit->mark2 < 0)
1344         edit_mark_cmd (edit, FALSE);
1345     edit_push_markers (edit);
1346 
1347     if (edit->column_highlight)
1348     {
1349         off_t mark1, mark2;
1350         off_t size;
1351         long c1, c2, b_width;
1352         long x, x2;
1353         off_t b1, b2;
1354 
1355         c1 = MIN (edit->column1, edit->column2);
1356         c2 = MAX (edit->column1, edit->column2);
1357         b_width = c2 - c1;
1358 
1359         edit_update_curs_col (edit);
1360 
1361         x = edit->curs_col;
1362         x2 = x + edit->over_col;
1363 
1364         // do nothing when cursor inside first line of selected area
1365         b1 = edit_buffer_get_eol (&edit->buffer, edit->buffer.curs1);
1366         b2 = edit_buffer_get_eol (&edit->buffer, start_mark);
1367         if (b1 == b2 && x2 > c1 && x2 <= c2)
1368             return;
1369 
1370         if (edit->buffer.curs1 > start_mark
1371             && edit->buffer.curs1 < edit_buffer_get_eol (&edit->buffer, end_mark))
1372         {
1373             if (x > c2)
1374                 x -= b_width;
1375             else if (x > c1 && x <= c2)
1376                 x = c1;
1377         }
1378         // save current selection into buffer
1379         copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1380 
1381         // remove current selection
1382         edit_block_delete_cmd (edit);
1383 
1384         edit->over_col = MAX (0, edit->over_col - b_width);
1385         // calculate the cursor pos after delete block
1386         b1 = edit_buffer_get_current_bol (&edit->buffer);
1387         current = edit_move_forward3 (edit, b1, x, 0);
1388         edit_cursor_move (edit, current - edit->buffer.curs1);
1389         edit_scroll_screen_over_cursor (edit);
1390 
1391         // add TWS if need before block insertion
1392         if (edit_options.cursor_beyond_eol && edit->over_col > 0)
1393             edit_insert_over (edit);
1394 
1395         edit_insert_column_of_text (edit, copy_buf, size, b_width, &mark1, &mark2, &c1, &c2);
1396         edit_set_markers (edit, mark1, mark2, c1, c2);
1397     }
1398     else
1399     {
1400         off_t count, count_orig;
1401         off_t x;
1402 
1403         current = edit->buffer.curs1;
1404         copy_buf = g_malloc0 (end_mark - start_mark);
1405         edit_cursor_move (edit, start_mark - edit->buffer.curs1);
1406         edit_scroll_screen_over_cursor (edit);
1407 
1408         for (count = start_mark; count < end_mark; count++)
1409             copy_buf[end_mark - count - 1] = edit_delete (edit, TRUE);
1410 
1411         edit_scroll_screen_over_cursor (edit);
1412         x = current > edit->buffer.curs1 ? end_mark - start_mark : 0;
1413         edit_cursor_move (edit, current - edit->buffer.curs1 - x);
1414         edit_scroll_screen_over_cursor (edit);
1415         count_orig = count;
1416         while (count-- > start_mark)
1417             edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1418 
1419         edit_set_markers (edit, edit->buffer.curs1, edit->buffer.curs1 + end_mark - start_mark, 0,
1420                           0);
1421 
1422         // Place cursor at the end of text selection
1423         if (edit_options.cursor_after_inserted_block)
1424             edit_cursor_move (edit, count_orig - start_mark);
1425     }
1426 
1427     edit_scroll_screen_over_cursor (edit);
1428     g_free (copy_buf);
1429     edit->force |= REDRAW_PAGE;
1430 }
1431 
1432 /* --------------------------------------------------------------------------------------------- */
1433 /** returns FALSE if canceelled by user */
1434 
1435 gboolean
1436 edit_block_delete_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1437 {
1438     off_t start_mark, end_mark;
1439 
1440     if (eval_marks (edit, &start_mark, &end_mark))
1441         return edit_block_delete (edit, start_mark, end_mark);
1442 
1443     edit_delete_line (edit);
1444 
1445     return TRUE;
1446 }
1447 
1448 /* --------------------------------------------------------------------------------------------- */
1449 /**
1450  * Check if it's OK to close the file. If there are unsaved changes, ask user.
1451  *
1452  * @return TRUE if it's OK to exit, FALSE to continue editing.
1453  */
1454 
1455 gboolean
1456 edit_ok_to_exit (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1457 {
1458     const char *fname = N_ ("[NoName]");
1459     char *msg;
1460     int act;
1461 
1462     if (edit->modified == 0)
1463         return TRUE;
1464 
1465     if (edit->filename_vpath != NULL)
1466         fname = vfs_path_as_str (edit->filename_vpath);
1467 #ifdef ENABLE_NLS
1468     else
1469         fname = _ (fname);
1470 #endif
1471 
1472     if (!mc_global.midnight_shutdown)
1473     {
1474         query_set_sel (2);
1475 
1476         msg = g_strdup_printf (_ ("File %s was modified.\nSave before close?"), fname);
1477         act = edit_query_dialog3 (_ ("Close file"), msg, _ ("&Yes"), _ ("&No"), _ ("&Cancel"));
1478     }
1479     else
1480     {
1481         msg = g_strdup_printf (_ ("Midnight Commander is being shut down.\nSave modified file %s?"),
1482                                fname);
1483         act = edit_query_dialog2 (_ ("Quit"), msg, _ ("&Yes"), _ ("&No"));
1484 
1485         // Esc is No
1486         if (act == -1)
1487             act = 1;
1488     }
1489 
1490     g_free (msg);
1491 
1492     switch (act)
1493     {
1494     case 0:  // Yes
1495         if (!mc_global.midnight_shutdown && !edit_check_newline (&edit->buffer))
1496             return FALSE;
1497         edit_push_markers (edit);
1498         edit_set_markers (edit, 0, 0, 0, 0);
1499         if (!edit_save_cmd (edit) || mc_global.midnight_shutdown)
1500             return mc_global.midnight_shutdown;
1501         break;
1502     case 1:  // No
1503     default:
1504         break;
1505     case 2:   // Cancel quit
1506     case -1:  // Esc
1507         return FALSE;
1508     }
1509 
1510     return TRUE;
1511 }
1512 
1513 /* --------------------------------------------------------------------------------------------- */
1514 /** save block, returns TRUE on success */
1515 
1516 gboolean
1517 edit_save_block (WEdit *edit, const char *filename, off_t start, off_t finish)
     /* [previous][next][first][last][top][bottom][index][help]  */
1518 {
1519     int file;
1520     off_t len = 1;
1521     vfs_path_t *vpath;
1522 
1523     vpath = vfs_path_from_str (filename);
1524     file = mc_open (vpath, O_CREAT | O_WRONLY | O_TRUNC,
1525                     S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY);
1526     vfs_path_free (vpath, TRUE);
1527     if (file == -1)
1528         return FALSE;
1529 
1530     if (edit->column_highlight)
1531     {
1532         int r;
1533 
1534         r = mc_write (file, VERTICAL_MAGIC, sizeof (VERTICAL_MAGIC));
1535         if (r > 0)
1536         {
1537             unsigned char *block, *p;
1538 
1539             p = block = edit_get_block (edit, start, finish, &len);
1540             while (len != 0)
1541             {
1542                 r = mc_write (file, p, len);
1543                 if (r < 0)
1544                     break;
1545                 p += r;
1546                 len -= r;
1547             }
1548             g_free (block);
1549         }
1550     }
1551     else
1552     {
1553         unsigned char *buf;
1554         off_t i = start;
1555 
1556         len = finish - start;
1557         buf = g_malloc0 (TEMP_BUF_LEN);
1558         while (start != finish)
1559         {
1560             off_t end;
1561 
1562             end = MIN (finish, start + TEMP_BUF_LEN);
1563             for (; i < end; i++)
1564                 buf[i - start] = edit_buffer_get_byte (&edit->buffer, i);
1565             len -= mc_write (file, (char *) buf, end - start);
1566             start = end;
1567         }
1568         g_free (buf);
1569     }
1570     mc_close (file);
1571 
1572     return (len == 0);
1573 }
1574 
1575 /* --------------------------------------------------------------------------------------------- */
1576 
1577 void
1578 edit_paste_from_history (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1579 {
1580     (void) edit;
1581 
1582     message (D_ERROR, MSG_ERROR, "%s", _ ("This function is not implemented"));
1583 }
1584 
1585 /* --------------------------------------------------------------------------------------------- */
1586 
1587 gboolean
1588 edit_copy_to_X_buf_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1589 {
1590     off_t start_mark, end_mark;
1591 
1592     if (!eval_marks (edit, &start_mark, &end_mark))
1593         return TRUE;
1594 
1595     if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
1596     {
1597         message (D_ERROR, MSG_ERROR, "%s", _ ("Unable to save to file"));
1598         return FALSE;
1599     }
1600     // try use external clipboard utility
1601     mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
1602 
1603     if (edit_options.drop_selection_on_copy)
1604         edit_mark_cmd (edit, TRUE);
1605 
1606     return TRUE;
1607 }
1608 
1609 /* --------------------------------------------------------------------------------------------- */
1610 
1611 gboolean
1612 edit_cut_to_X_buf_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1613 {
1614     off_t start_mark, end_mark;
1615 
1616     if (!eval_marks (edit, &start_mark, &end_mark))
1617         return TRUE;
1618 
1619     if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
1620     {
1621         message (D_ERROR, MSG_ERROR, "%s", _ ("Unable to save to file"));
1622         return FALSE;
1623     }
1624     // try use external clipboard utility
1625     mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
1626 
1627     edit_block_delete_cmd (edit);
1628     edit_mark_cmd (edit, TRUE);
1629 
1630     return TRUE;
1631 }
1632 
1633 /* --------------------------------------------------------------------------------------------- */
1634 
1635 gboolean
1636 edit_paste_from_X_buf_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1637 {
1638     vfs_path_t *tmp;
1639     gboolean ret;
1640 
1641     // try use external clipboard utility
1642     mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_from_ext_clip", NULL);
1643     tmp = mc_config_get_full_vpath (EDIT_HOME_CLIP_FILE);
1644     ret = (edit_insert_file (edit, tmp) >= 0);
1645     vfs_path_free (tmp, TRUE);
1646 
1647     return ret;
1648 }
1649 
1650 /* --------------------------------------------------------------------------------------------- */
1651 /**
1652  * Ask user for the line and go to that line.
1653  * Negative numbers mean line from the end (i.e. -1 is the last line).
1654  */
1655 
1656 void
1657 edit_goto_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1658 {
1659     static gboolean first_run = TRUE;
1660 
1661     char *f;
1662     long l;
1663     char *error;
1664 
1665     f = input_dialog (_ ("Goto line"), _ ("Enter line:"), MC_HISTORY_EDIT_GOTO_LINE,
1666                       first_run ? NULL : INPUT_LAST_TEXT, INPUT_COMPLETE_NONE);
1667     if (f == NULL || *f == '\0')
1668     {
1669         g_free (f);
1670         return;
1671     }
1672 
1673     l = strtol (f, &error, 0);
1674     if (*error != '\0')
1675     {
1676         g_free (f);
1677         return;
1678     }
1679 
1680     if (l < 0)
1681         l = edit->buffer.lines + l + 2;
1682 
1683     edit_move_display (edit, l - WIDGET (edit)->rect.lines / 2 - 1);
1684     edit_move_to_line (edit, l - 1);
1685     edit->force |= REDRAW_COMPLETELY;
1686 
1687     g_free (f);
1688     first_run = FALSE;
1689 }
1690 
1691 /* --------------------------------------------------------------------------------------------- */
1692 /** Return TRUE on success */
1693 
1694 gboolean
1695 edit_save_block_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1696 {
1697     off_t start_mark, end_mark;
1698     char *exp, *tmp;
1699     gboolean ret = FALSE;
1700 
1701     if (!eval_marks (edit, &start_mark, &end_mark))
1702         return TRUE;
1703 
1704     tmp = mc_config_get_full_path (EDIT_HOME_CLIP_FILE);
1705     exp = input_expand_dialog (_ ("Save block"), _ ("Enter file name:"), MC_HISTORY_EDIT_SAVE_BLOCK,
1706                                tmp, INPUT_COMPLETE_FILENAMES);
1707     g_free (tmp);
1708     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
1709 
1710     if (exp != NULL && *exp != '\0')
1711     {
1712         if (edit_save_block (edit, exp, start_mark, end_mark))
1713             ret = TRUE;
1714         else
1715             message (D_ERROR, MSG_ERROR, "%s", _ ("Cannot save block"));
1716 
1717         edit->force |= REDRAW_COMPLETELY;
1718     }
1719 
1720     g_free (exp);
1721 
1722     return ret;
1723 }
1724 
1725 /* --------------------------------------------------------------------------------------------- */
1726 
1727 /** returns TRUE on success */
1728 gboolean
1729 edit_insert_file_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1730 {
1731     char *tmp;
1732     char *exp;
1733     gboolean ret = FALSE;
1734 
1735     tmp = mc_config_get_full_path (EDIT_HOME_CLIP_FILE);
1736     exp = input_expand_dialog (_ ("Insert file"), _ ("Enter file name:"),
1737                                MC_HISTORY_EDIT_INSERT_FILE, tmp, INPUT_COMPLETE_FILENAMES);
1738     g_free (tmp);
1739 
1740     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
1741 
1742     if (exp != NULL && *exp != '\0')
1743     {
1744         vfs_path_t *exp_vpath;
1745 
1746         exp_vpath = vfs_path_from_str (exp);
1747         ret = (edit_insert_file (edit, exp_vpath) >= 0);
1748         vfs_path_free (exp_vpath, TRUE);
1749 
1750         if (!ret)
1751             message (D_ERROR, MSG_ERROR, "%s", _ ("Cannot insert file"));
1752     }
1753 
1754     g_free (exp);
1755 
1756     edit->force |= REDRAW_COMPLETELY;
1757     return ret;
1758 }
1759 
1760 /* --------------------------------------------------------------------------------------------- */
1761 /** sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
1762 
1763 int
1764 edit_sort_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1765 {
1766     char *exp, *tmp, *tmp_edit_block_name, *tmp_edit_temp_name;
1767     off_t start_mark, end_mark;
1768     int e;
1769 
1770     if (!eval_marks (edit, &start_mark, &end_mark))
1771     {
1772         message (D_ERROR, MSG_ERROR, "%s", _ ("You must first highlight a block of text"));
1773         return 0;
1774     }
1775 
1776     tmp = mc_config_get_full_path (EDIT_HOME_BLOCK_FILE);
1777     edit_save_block (edit, tmp, start_mark, end_mark);
1778     g_free (tmp);
1779 
1780     exp = input_dialog (_ ("Run sort"),
1781                         _ ("Enter sort options (see sort(1) manpage) separated by whitespace:"),
1782                         MC_HISTORY_EDIT_SORT, INPUT_LAST_TEXT, INPUT_COMPLETE_NONE);
1783 
1784     if (exp == NULL)
1785         return 1;
1786 
1787     tmp_edit_block_name = mc_config_get_full_path (EDIT_HOME_BLOCK_FILE);
1788     tmp_edit_temp_name = mc_config_get_full_path (EDIT_HOME_TEMP_FILE);
1789     tmp = g_strconcat (" sort ", exp, " ", tmp_edit_block_name, " > ", tmp_edit_temp_name,
1790                        (char *) NULL);
1791     g_free (tmp_edit_temp_name);
1792     g_free (tmp_edit_block_name);
1793     g_free (exp);
1794 
1795     e = system (tmp);
1796     g_free (tmp);
1797     if (e != 0)
1798     {
1799         if (e == -1 || e == 127)
1800             message (D_ERROR, MSG_ERROR, "%s", _ ("Cannot execute sort command"));
1801         else
1802         {
1803             char q[8];
1804 
1805             sprintf (q, "%d ", e);
1806             message (D_ERROR, MSG_ERROR, _ ("Sort returned non-zero: %s"), q);
1807         }
1808 
1809         return -1;
1810     }
1811 
1812     edit->force |= REDRAW_COMPLETELY;
1813 
1814     if (!edit_block_delete_cmd (edit))
1815         return 1;
1816 
1817     {
1818         vfs_path_t *tmp_vpath;
1819 
1820         tmp_vpath = mc_config_get_full_vpath (EDIT_HOME_TEMP_FILE);
1821         edit_insert_file (edit, tmp_vpath);
1822         vfs_path_free (tmp_vpath, TRUE);
1823     }
1824 
1825     return 0;
1826 }
1827 
1828 /* --------------------------------------------------------------------------------------------- */
1829 /**
1830  * Ask user for a command, execute it and paste its output back to the
1831  * editor.
1832  */
1833 
1834 int
1835 edit_ext_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1836 {
1837     char *exp, *tmp, *tmp_edit_temp_file;
1838     int e;
1839 
1840     exp =
1841         input_dialog (_ ("Paste output of external command"), _ ("Enter shell command(s):"),
1842                       MC_HISTORY_EDIT_PASTE_EXTCMD, INPUT_LAST_TEXT,
1843                       INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_VARIABLES | INPUT_COMPLETE_USERNAMES
1844                           | INPUT_COMPLETE_HOSTNAMES | INPUT_COMPLETE_CD | INPUT_COMPLETE_COMMANDS
1845                           | INPUT_COMPLETE_SHELL_ESC);
1846 
1847     if (!exp)
1848         return 1;
1849 
1850     tmp_edit_temp_file = mc_config_get_full_path (EDIT_HOME_TEMP_FILE);
1851     tmp = g_strconcat (exp, " > ", tmp_edit_temp_file, (char *) NULL);
1852     g_free (tmp_edit_temp_file);
1853     e = system (tmp);
1854     g_free (tmp);
1855     g_free (exp);
1856 
1857     if (e != 0)
1858     {
1859         message (D_ERROR, MSG_ERROR, "%s", _ ("Cannot execute external command"));
1860         return -1;
1861     }
1862 
1863     edit->force |= REDRAW_COMPLETELY;
1864 
1865     {
1866         vfs_path_t *tmp_vpath;
1867 
1868         tmp_vpath = mc_config_get_full_vpath (EDIT_HOME_TEMP_FILE);
1869         edit_insert_file (edit, tmp_vpath);
1870         vfs_path_free (tmp_vpath, TRUE);
1871     }
1872 
1873     return 0;
1874 }
1875 
1876 /* --------------------------------------------------------------------------------------------- */
1877 /** if block is 1, a block must be highlighted and the shell command
1878    processes it. If block is 0 the shell command is a straight system
1879    command, that just produces some output which is to be inserted */
1880 
1881 void
1882 edit_block_process_cmd (WEdit *edit, int macro_number)
     /* [previous][next][first][last][top][bottom][index][help]  */
1883 {
1884     char *fname;
1885     char *macros_fname = NULL;
1886 
1887     fname = g_strdup_printf ("%s.%i.sh", EDIT_HOME_MACRO_FILE, macro_number);
1888     macros_fname = g_build_filename (mc_config_get_data_path (), fname, (char *) NULL);
1889     edit_user_menu (edit, macros_fname, 0);
1890     g_free (fname);
1891     g_free (macros_fname);
1892     edit->force |= REDRAW_COMPLETELY;
1893 }
1894 
1895 /* --------------------------------------------------------------------------------------------- */
1896 
1897 void
1898 edit_mail_dialog (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1899 {
1900     char *mail_to = NULL;
1901     char *mail_subject = NULL;
1902     char *mail_cc = NULL;
1903 
1904     quick_widget_t quick_widgets[] = {
1905         QUICK_LABEL (N_ ("mail -s <subject> -c <cc> <to>"), NULL),
1906         QUICK_LABELED_INPUT (N_ ("To"), input_label_above, INPUT_LAST_TEXT, "mail-dlg-input-3",
1907                              &mail_to, NULL, FALSE, FALSE, INPUT_COMPLETE_USERNAMES),
1908         QUICK_LABELED_INPUT (N_ ("Subject"), input_label_above, INPUT_LAST_TEXT, "mail-dlg-input-2",
1909                              &mail_subject, NULL, FALSE, FALSE, INPUT_COMPLETE_NONE),
1910         QUICK_LABELED_INPUT (N_ ("Copies to"), input_label_above, INPUT_LAST_TEXT, "mail-dlg-input",
1911                              &mail_cc, NULL, FALSE, FALSE, INPUT_COMPLETE_USERNAMES),
1912         QUICK_BUTTONS_OK_CANCEL,
1913         QUICK_END,
1914     };
1915 
1916     WRect r = { -1, -1, 0, 50 };
1917 
1918     quick_dialog_t qdlg = {
1919         .rect = r,
1920         .title = N_ ("Mail"),
1921         .help = "[Input Line Keys]",
1922         .widgets = quick_widgets,
1923         .callback = NULL,
1924         .mouse_callback = NULL,
1925     };
1926 
1927     if (quick_dialog (&qdlg) != B_CANCEL)
1928     {
1929         pipe_mail (&edit->buffer, mail_to, mail_subject, mail_cc);
1930         g_free (mail_to);
1931         g_free (mail_subject);
1932         g_free (mail_cc);
1933     }
1934 }
1935 
1936 /* --------------------------------------------------------------------------------------------- */
1937 
1938 #ifdef HAVE_CHARSET
1939 void
1940 edit_select_codepage_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1941 {
1942     if (do_select_codepage ())
1943         edit_set_codeset (edit);
1944 
1945     edit->force = REDRAW_PAGE;
1946     widget_draw (WIDGET (edit));
1947 }
1948 #endif
1949 
1950 /* --------------------------------------------------------------------------------------------- */
1951 
1952 void
1953 edit_insert_literal_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1954 {
1955     int char_for_insertion;
1956 
1957     char_for_insertion =
1958         editcmd_dialog_raw_key_query (_ ("Insert literal"), _ ("Press any key:"), FALSE);
1959     edit_execute_key_command (edit, -1, ascii_alpha_to_cntrl (char_for_insertion));
1960 }
1961 
1962 /* --------------------------------------------------------------------------------------------- */
1963 
1964 gboolean
1965 edit_load_forward_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1966 {
1967     if (edit->modified != 0
1968         && edit_query_dialog2 (_ ("Warning"),
1969                                _ ("Current text was modified without a file save.\n"
1970                                   "Continue discards these changes."),
1971                                _ ("C&ontinue"), _ ("&Cancel"))
1972             == 1)
1973     {
1974         edit->force |= REDRAW_COMPLETELY;
1975         return TRUE;
1976     }
1977 
1978     if (edit_stack_iterator + 1 >= MAX_HISTORY_MOVETO)
1979         return FALSE;
1980 
1981     if (edit_history_moveto[edit_stack_iterator + 1].line_number < 1)
1982         return FALSE;
1983 
1984     edit_stack_iterator++;
1985     if (edit_history_moveto[edit_stack_iterator].file_vpath != NULL)
1986         return edit_reload_line (edit, &edit_history_moveto[edit_stack_iterator]);
1987 
1988     return FALSE;
1989 }
1990 
1991 /* --------------------------------------------------------------------------------------------- */
1992 
1993 gboolean
1994 edit_load_back_cmd (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1995 {
1996     if (edit->modified != 0
1997         && edit_query_dialog2 (_ ("Warning"),
1998                                _ ("Current text was modified without a file save.\n"
1999                                   "Continue discards these changes."),
2000                                _ ("C&ontinue"), _ ("&Cancel"))
2001             == 1)
2002     {
2003         edit->force |= REDRAW_COMPLETELY;
2004         return TRUE;
2005     }
2006 
2007     // we are in the bottom of the stack, NO WAY!
2008     if (edit_stack_iterator == 0)
2009         return FALSE;
2010 
2011     edit_stack_iterator--;
2012     if (edit_history_moveto[edit_stack_iterator].file_vpath != NULL)
2013         return edit_reload_line (edit, &edit_history_moveto[edit_stack_iterator]);
2014 
2015     return FALSE;
2016 }
2017 
2018 /* --------------------------------------------------------------------------------------------- */
2019 
2020 /* gets a raw key from the keyboard. Passing cancel = 1 draws
2021    a cancel button thus allowing c-c etc.  Alternatively, cancel = 0
2022    will return the next key pressed.  ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
2023    and Esc are cannot returned */
2024 
2025 int
2026 editcmd_dialog_raw_key_query (const char *heading, const char *query, gboolean cancel)
     /* [previous][next][first][last][top][bottom][index][help]  */
2027 {
2028     int w, wq;
2029     int y = 2;
2030     WDialog *raw_dlg;
2031     WGroup *g;
2032 
2033     w = str_term_width1 (heading) + 6;
2034     wq = str_term_width1 (query);
2035     w = MAX (w, wq + 3 * 2 + 1 + 2);
2036 
2037     raw_dlg = dlg_create (TRUE, 0, 0, cancel ? 7 : 5, w, WPOS_CENTER | WPOS_TRYUP, FALSE,
2038                           dialog_colors, editcmd_dialog_raw_key_query_cb, NULL, NULL, heading);
2039     g = GROUP (raw_dlg);
2040     widget_want_tab (WIDGET (raw_dlg), TRUE);
2041 
2042     group_add_widget (g, label_new (y, 3, query));
2043     group_add_widget (
2044         g, input_new (y++, 3 + wq + 1, input_colors, w - (6 + wq + 1), "", 0, INPUT_COMPLETE_NONE));
2045     if (cancel)
2046     {
2047         group_add_widget (g, hline_new (y++, -1, -1));
2048         // Button w/o hotkey to allow use any key as raw or macro one
2049         group_add_widget_autopos (g, button_new (y, 1, B_CANCEL, NORMAL_BUTTON, _ ("Cancel"), NULL),
2050                                   WPOS_KEEP_TOP | WPOS_CENTER_HORZ, NULL);
2051     }
2052 
2053     w = dlg_run (raw_dlg);
2054     widget_destroy (WIDGET (raw_dlg));
2055 
2056     return (cancel && (w == ESC_CHAR || w == B_CANCEL)) ? 0 : w;
2057 }
2058 
2059 /* --------------------------------------------------------------------------------------------- */

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