Manual pages: mcmcdiffmceditmcview

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

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