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-2024
   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 <http://www.gnu.org/licenses/>.
  26  */
  27 
  28 /** \file
  29  *  \brief Source: editor high level editing commands
  30  *  \author Paul Sheer
  31  *  \date 1996, 1997
  32  */
  33 
  34 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
  35 
  36 #include <config.h>
  37 
  38 #include <ctype.h>
  39 #include <stdio.h>
  40 #include <stdarg.h>
  41 #include <sys/types.h>
  42 #include <unistd.h>
  43 #include <string.h>
  44 #include <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     gchar *tmp;
 134     off_t filelen = 0;
 135     int this_save_mode, rv, fd = -1;
 136     vfs_path_t *real_filename_vpath;
 137     vfs_path_t *savename_vpath = NULL;
 138     const char *start_filename;
 139     const vfs_path_element_t *vpath_element;
 140     struct stat sb;
 141 
 142     vpath_element = vfs_path_get_by_index (filename_vpath, 0);
 143     if (vpath_element == NULL)
 144         return 0;
 145 
 146     start_filename = vpath_element->path;
 147     if (*start_filename == '\0')
 148         return 0;
 149 
 150     if (!IS_PATH_SEP (*start_filename) && edit->dir_vpath != NULL)
 151         real_filename_vpath = vfs_path_append_vpath_new (edit->dir_vpath, filename_vpath, NULL);
 152     else
 153         real_filename_vpath = vfs_path_clone (filename_vpath);
 154 
 155     this_save_mode = edit_options.save_mode;
 156     if (this_save_mode != EDIT_QUICK_SAVE)
 157     {
 158         if (!vfs_file_is_local (real_filename_vpath))
 159             /* The file does not exists yet, so no safe save or backup are necessary. */
 160             this_save_mode = EDIT_QUICK_SAVE;
 161         else
 162         {
 163             fd = mc_open (real_filename_vpath, O_RDONLY | O_BINARY);
 164             if (fd == -1)
 165                 /* The file does not exists yet, so no safe save or backup are necessary. */
 166                 this_save_mode = EDIT_QUICK_SAVE;
 167         }
 168 
 169         if (fd != -1)
 170             mc_close (fd);
 171     }
 172 
 173     rv = mc_stat (real_filename_vpath, &sb);
 174     if (rv == 0)
 175     {
 176         if (this_save_mode == EDIT_QUICK_SAVE && !edit->skip_detach_prompt && sb.st_nlink > 1)
 177         {
 178             rv = edit_query_dialog3 (_("Warning"),
 179                                      _("File has hard-links. Detach before saving?"),
 180                                      _("&Yes"), _("&No"), _("&Cancel"));
 181             switch (rv)
 182             {
 183             case 0:
 184                 this_save_mode = EDIT_SAFE_SAVE;
 185                 MC_FALLTHROUGH;
 186             case 1:
 187                 edit->skip_detach_prompt = 1;
 188                 break;
 189             default:
 190                 vfs_path_free (real_filename_vpath, TRUE);
 191                 return -1;
 192             }
 193         }
 194 
 195         /* Prevent overwriting changes from other editor sessions. */
 196         if (edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime)
 197         {
 198             /* The default action is "Cancel". */
 199             query_set_sel (1);
 200 
 201             rv = edit_query_dialog2 (_("Warning"),
 202                                      _("The file has been modified in the meantime. Save anyway?"),
 203                                      _("&Yes"), _("&Cancel"));
 204             if (rv != 0)
 205             {
 206                 vfs_path_free (real_filename_vpath, TRUE);
 207                 return -1;
 208             }
 209         }
 210     }
 211 
 212     if (this_save_mode == EDIT_QUICK_SAVE)
 213         savename_vpath = vfs_path_clone (real_filename_vpath);
 214     else
 215     {
 216         char *savedir, *saveprefix;
 217 
 218         savedir = vfs_path_tokens_get (real_filename_vpath, 0, -1);
 219         if (savedir == NULL)
 220             savedir = g_strdup (".");
 221 
 222         /* Token-related function never return leading slash, so we need add it manually */
 223         saveprefix = mc_build_filename (PATH_SEP_STR, savedir, "cooledit", (char *) NULL);
 224         g_free (savedir);
 225         fd = mc_mkstemps (&savename_vpath, saveprefix, NULL);
 226         g_free (saveprefix);
 227         if (savename_vpath == NULL)
 228         {
 229             vfs_path_free (real_filename_vpath, TRUE);
 230             return 0;
 231         }
 232         /* FIXME:
 233          * Close for now because mc_mkstemps use pure open system call
 234          * to create temporary file and it needs to be reopened by
 235          * VFS-aware mc_open().
 236          */
 237         close (fd);
 238     }
 239 
 240     (void) mc_chown (savename_vpath, edit->stat1.st_uid, edit->stat1.st_gid);
 241     (void) mc_chmod (savename_vpath, edit->stat1.st_mode);
 242 
 243     fd = mc_open (savename_vpath, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, edit->stat1.st_mode);
 244     if (fd == -1)
 245         goto error_save;
 246 
 247     /* pipe save */
 248     p = edit_get_write_filter (savename_vpath, real_filename_vpath);
 249     if (p != NULL)
 250     {
 251         FILE *file;
 252 
 253         mc_close (fd);
 254         file = (FILE *) popen (p, "w");
 255 
 256         if (file != NULL)
 257         {
 258             filelen = edit_write_stream (edit, file);
 259 #if 1
 260             pclose (file);
 261 #else
 262             if (pclose (file) != 0)
 263             {
 264                 tmp = g_strdup_printf (_("Error writing to pipe: %s"), p);
 265                 edit_error_dialog (_("Error"), tmp);
 266                 g_free (tmp);
 267                 g_free (p);
 268                 goto error_save;
 269             }
 270 #endif
 271         }
 272         else
 273         {
 274             tmp = g_strdup_printf (_("Cannot open pipe for writing: %s"), p);
 275             edit_error_dialog (_("Error"), get_sys_error (tmp));
 276             g_free (p);
 277             g_free (tmp);
 278             goto error_save;
 279         }
 280         g_free (p);
 281     }
 282     else if (edit->lb == LB_ASIS)
 283     {                           /* do not change line breaks */
 284         filelen = edit_buffer_write_file (&edit->buffer, fd);
 285 
 286         if (filelen != edit->buffer.size)
 287         {
 288             mc_close (fd);
 289             goto error_save;
 290         }
 291 
 292         if (mc_close (fd) != 0)
 293             goto error_save;
 294 
 295         /* Update the file information, especially the mtime. */
 296         if (mc_stat (savename_vpath, &edit->stat1) == -1)
 297             goto error_save;
 298     }
 299     else
 300     {                           /* change line breaks */
 301         FILE *file;
 302         const char *savename;
 303 
 304         mc_close (fd);
 305 
 306         savename = vfs_path_get_last_path_str (savename_vpath);
 307         file = (FILE *) fopen (savename, "w");
 308         if (file != NULL)
 309         {
 310             filelen = edit_write_stream (edit, file);
 311             fclose (file);
 312         }
 313         else
 314         {
 315             char *msg;
 316 
 317             msg = g_strdup_printf (_("Cannot open file for writing: %s"), savename);
 318             edit_error_dialog (_("Error"), msg);
 319             g_free (msg);
 320             goto error_save;
 321         }
 322     }
 323 
 324     if (filelen != edit->buffer.size)
 325         goto error_save;
 326 
 327     if (this_save_mode == EDIT_DO_BACKUP)
 328     {
 329         char *tmp_store_filename;
 330         vfs_path_element_t *last_vpath_element;
 331         vfs_path_t *tmp_vpath;
 332         gboolean ok;
 333 
 334         g_assert (edit_options.backup_ext != NULL);
 335 
 336         /* add backup extension to the path */
 337         tmp_vpath = vfs_path_clone (real_filename_vpath);
 338         last_vpath_element = (vfs_path_element_t *) vfs_path_get_by_index (tmp_vpath, -1);
 339         tmp_store_filename = last_vpath_element->path;
 340         last_vpath_element->path =
 341             g_strdup_printf ("%s%s", tmp_store_filename, edit_options.backup_ext);
 342         g_free (tmp_store_filename);
 343 
 344         ok = (mc_rename (real_filename_vpath, tmp_vpath) != -1);
 345         vfs_path_free (tmp_vpath, TRUE);
 346         if (!ok)
 347             goto error_save;
 348     }
 349 
 350     if (this_save_mode != EDIT_QUICK_SAVE && mc_rename (savename_vpath, real_filename_vpath) == -1)
 351         goto error_save;
 352 
 353     vfs_path_free (real_filename_vpath, TRUE);
 354     vfs_path_free (savename_vpath, TRUE);
 355     return 1;
 356   error_save:
 357     /*  FIXME: Is this safe ?
 358      *  if (this_save_mode != EDIT_QUICK_SAVE)
 359      *      mc_unlink (savename);
 360      */
 361     vfs_path_free (real_filename_vpath, TRUE);
 362     vfs_path_free (savename_vpath, TRUE);
 363     return 0;
 364 }
 365 
 366 /* --------------------------------------------------------------------------------------------- */
 367 
 368 static gboolean
 369 edit_check_newline (const edit_buffer_t * buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 370 {
 371     return !(edit_options.check_nl_at_eof && buf->size > 0
 372              && edit_buffer_get_byte (buf, buf->size - 1) != '\n'
 373              && edit_query_dialog2 (_("Warning"),
 374                                     _("The file you are saving does not end with a newline."),
 375                                     _("C&ontinue"), _("&Cancel")) != 0);
 376 }
 377 
 378 /* --------------------------------------------------------------------------------------------- */
 379 
 380 static vfs_path_t *
 381 edit_get_save_file_as (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 382 {
 383     static LineBreaks cur_lb = LB_ASIS;
 384     char *filename_res;
 385     vfs_path_t *ret_vpath = NULL;
 386 
 387     const char *lb_names[LB_NAMES] = {
 388         N_("&Do not change"),
 389         N_("&Unix format (LF)"),
 390         N_("&Windows/DOS format (CR LF)"),
 391         N_("&Macintosh format (CR)")
 392     };
 393 
 394     quick_widget_t quick_widgets[] = {
 395         /* *INDENT-OFF* */
 396         QUICK_LABELED_INPUT (N_("Enter file name:"), input_label_above,
 397                              vfs_path_as_str (edit->filename_vpath), "save-as",
 398                              &filename_res, NULL, FALSE, FALSE, INPUT_COMPLETE_FILENAMES),
 399         QUICK_SEPARATOR (TRUE),
 400         QUICK_LABEL (N_("Change line breaks to:"), NULL),
 401         QUICK_RADIO (LB_NAMES, lb_names, (int *) &cur_lb, NULL),
 402         QUICK_BUTTONS_OK_CANCEL,
 403         QUICK_END
 404         /* *INDENT-ON* */
 405     };
 406 
 407     WRect r = { -1, -1, 0, 64 };
 408 
 409     quick_dialog_t qdlg = {
 410         r, N_("Save As"), "[Save File As]",
 411         quick_widgets, NULL, NULL
 412     };
 413 
 414     if (quick_dialog (&qdlg) != B_CANCEL)
 415     {
 416         char *fname;
 417 
 418         edit->lb = cur_lb;
 419         fname = tilde_expand (filename_res);
 420         g_free (filename_res);
 421         ret_vpath = vfs_path_from_str (fname);
 422         g_free (fname);
 423     }
 424 
 425     return ret_vpath;
 426 }
 427 
 428 /* --------------------------------------------------------------------------------------------- */
 429 
 430 /** returns TRUE on success */
 431 
 432 static gboolean
 433 edit_save_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 434 {
 435     int res, save_lock = 0;
 436 
 437     if (!edit->locked && !edit->delete_file)
 438         save_lock = lock_file (edit->filename_vpath);
 439     res = edit_save_file (edit, edit->filename_vpath);
 440 
 441     /* Maintain modify (not save) lock on failure */
 442     if ((res > 0 && edit->locked) || save_lock)
 443         edit->locked = unlock_file (edit->filename_vpath);
 444 
 445     /* On failure try 'save as', it does locking on its own */
 446     if (res == 0)
 447         return edit_save_as_cmd (edit);
 448 
 449     if (res > 0)
 450     {
 451         edit->delete_file = 0;
 452         edit->modified = 0;
 453     }
 454 
 455     edit->force |= REDRAW_COMPLETELY;
 456 
 457     return TRUE;
 458 }
 459 
 460 /* --------------------------------------------------------------------------------------------- */
 461 
 462 static void
 463 edit_delete_column_of_text (WEdit * edit, off_t m1, off_t m2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 464 {
 465     off_t n;
 466     off_t r;
 467     long b, c, d;
 468 
 469     n = edit_buffer_get_forward_offset (&edit->buffer, m1, 0, m2) + 1;
 470     r = edit_buffer_get_bol (&edit->buffer, m1);
 471     c = (long) edit_move_forward3 (edit, r, 0, m1);
 472     r = edit_buffer_get_bol (&edit->buffer, m2);
 473     d = (long) edit_move_forward3 (edit, r, 0, m2);
 474     b = MAX (MIN (c, d), MIN (edit->column1, edit->column2));
 475     c = MAX (c, MAX (edit->column1, edit->column2));
 476 
 477     while (n-- != 0)
 478     {
 479         off_t p, q;
 480 
 481         r = edit_buffer_get_current_bol (&edit->buffer);
 482         p = edit_move_forward3 (edit, r, b, 0);
 483         q = edit_move_forward3 (edit, r, c, 0);
 484         p = MAX (p, m1);
 485         q = MIN (q, m2);
 486         edit_cursor_move (edit, p - edit->buffer.curs1);
 487         /* delete line between margins */
 488         for (; q > p; q--)
 489             if (edit_buffer_get_current_byte (&edit->buffer) != '\n')
 490                 edit_delete (edit, TRUE);
 491 
 492         /* move to next line except on the last delete */
 493         if (n != 0)
 494         {
 495             r = edit_buffer_get_forward_offset (&edit->buffer, edit->buffer.curs1, 1, 0);
 496             edit_cursor_move (edit, r - edit->buffer.curs1);
 497         }
 498     }
 499 }
 500 
 501 /* --------------------------------------------------------------------------------------------- */
 502 /** if success return TRUE */
 503 
 504 static gboolean
 505 edit_block_delete (WEdit * edit, off_t start_mark, off_t end_mark)
     /* [previous][next][first][last][top][bottom][index][help]  */
 506 {
 507     off_t curs_pos;
 508     long curs_line, c1, c2;
 509 
 510     if (edit->column_highlight && edit->mark2 < 0)
 511         edit_mark_cmd (edit, FALSE);
 512 
 513     /* Warning message with a query to continue or cancel the operation */
 514     if ((end_mark - start_mark) > max_undo / 2 &&
 515         edit_query_dialog2 (_("Warning"),
 516                             ("Block is large, you may not be able to undo this action"),
 517                             _("C&ontinue"), _("&Cancel")) != 0)
 518         return FALSE;
 519 
 520     c1 = MIN (edit->column1, edit->column2);
 521     c2 = MAX (edit->column1, edit->column2);
 522     edit->column1 = c1;
 523     edit->column2 = c2;
 524 
 525     edit_push_markers (edit);
 526 
 527     curs_line = edit->buffer.curs_line;
 528 
 529     curs_pos = edit->curs_col + edit->over_col;
 530 
 531     /* move cursor to start of selection */
 532     edit_cursor_move (edit, start_mark - edit->buffer.curs1);
 533     edit_scroll_screen_over_cursor (edit);
 534 
 535     if (start_mark < end_mark)
 536     {
 537         if (edit->column_highlight)
 538         {
 539             off_t b, e;
 540             off_t line_width;
 541 
 542             if (edit->mark2 < 0)
 543                 edit_mark_cmd (edit, FALSE);
 544             edit_delete_column_of_text (edit, start_mark, end_mark);
 545             /* move cursor to the saved position */
 546             edit_move_to_line (edit, curs_line);
 547             /* calculate line width and cursor position before cut */
 548             b = edit_buffer_get_current_bol (&edit->buffer);
 549             e = edit_buffer_get_current_eol (&edit->buffer);
 550             line_width = edit_move_forward3 (edit, b, 0, e);
 551             if (edit_options.cursor_beyond_eol && curs_pos > line_width)
 552                 edit->over_col = curs_pos - line_width;
 553         }
 554         else
 555         {
 556             off_t count;
 557 
 558             for (count = start_mark; count < end_mark; count++)
 559                 edit_delete (edit, TRUE);
 560         }
 561     }
 562 
 563     edit_set_markers (edit, 0, 0, 0, 0);
 564     edit->force |= REDRAW_PAGE;
 565 
 566     return TRUE;
 567 }
 568 
 569 /* --------------------------------------------------------------------------------------------- */
 570 /** Return a null terminated length of text. Result must be g_free'd */
 571 
 572 static unsigned char *
 573 edit_get_block (WEdit * edit, off_t start, off_t finish, off_t * l)
     /* [previous][next][first][last][top][bottom][index][help]  */
 574 {
 575     unsigned char *s, *r;
 576 
 577     r = s = g_malloc0 (finish - start + 1);
 578 
 579     if (edit->column_highlight)
 580     {
 581         *l = 0;
 582 
 583         /* copy from buffer, excluding chars that are out of the column 'margins' */
 584         for (; start < finish; start++)
 585         {
 586             int c;
 587             off_t x;
 588 
 589             x = edit_buffer_get_bol (&edit->buffer, start);
 590             x = edit_move_forward3 (edit, x, 0, start);
 591             c = edit_buffer_get_byte (&edit->buffer, start);
 592             if ((x >= edit->column1 && x < edit->column2)
 593                 || (x >= edit->column2 && x < edit->column1) || c == '\n')
 594             {
 595                 *s++ = c;
 596                 (*l)++;
 597             }
 598         }
 599     }
 600     else
 601     {
 602         *l = finish - start;
 603 
 604         for (; start < finish; start++)
 605             *s++ = edit_buffer_get_byte (&edit->buffer, start);
 606     }
 607 
 608     *s = '\0';
 609 
 610     return r;
 611 }
 612 
 613 /* --------------------------------------------------------------------------------------------- */
 614 /** copies a block to clipboard file */
 615 
 616 static gboolean
 617 edit_save_block_to_clip_file (WEdit * edit, off_t start, off_t finish)
     /* [previous][next][first][last][top][bottom][index][help]  */
 618 {
 619     gboolean ret;
 620     gchar *tmp;
 621 
 622     tmp = mc_config_get_full_path (EDIT_HOME_CLIP_FILE);
 623     ret = edit_save_block (edit, tmp, start, finish);
 624     g_free (tmp);
 625 
 626     return ret;
 627 }
 628 
 629 /* --------------------------------------------------------------------------------------------- */
 630 
 631 static void
 632 pipe_mail (const edit_buffer_t * buf, char *to, char *subject, char *cc)
     /* [previous][next][first][last][top][bottom][index][help]  */
 633 {
 634     FILE *p = 0;
 635     char *s = NULL;
 636 
 637     to = name_quote (to, FALSE);
 638     if (to != NULL)
 639     {
 640         subject = name_quote (subject, FALSE);
 641         if (subject != NULL)
 642         {
 643             cc = name_quote (cc, FALSE);
 644             if (cc == NULL)
 645                 s = g_strdup_printf ("mail -s %s %s", subject, to);
 646             else
 647             {
 648                 s = g_strdup_printf ("mail -s %s -c %s %s", subject, cc, to);
 649                 g_free (cc);
 650             }
 651 
 652             g_free (subject);
 653         }
 654 
 655         g_free (to);
 656     }
 657 
 658     if (s != NULL)
 659     {
 660         p = popen (s, "w");
 661         g_free (s);
 662     }
 663 
 664     if (p != NULL)
 665     {
 666         off_t i;
 667 
 668         for (i = 0; i < buf->size; i++)
 669             if (fputc (edit_buffer_get_byte (buf, i), p) < 0)
 670                 break;
 671         pclose (p);
 672     }
 673 }
 674 
 675 /* --------------------------------------------------------------------------------------------- */
 676 
 677 static void
 678 edit_insert_column_of_text (WEdit * edit, unsigned char *data, off_t size, long width,
     /* [previous][next][first][last][top][bottom][index][help]  */
 679                             off_t * start_pos, off_t * end_pos, long *col1, long *col2)
 680 {
 681     off_t i, cursor;
 682     long col;
 683 
 684     cursor = edit->buffer.curs1;
 685     col = edit_get_col (edit);
 686 
 687     for (i = 0; i < size; i++)
 688     {
 689         if (data[i] != '\n')
 690             edit_insert (edit, data[i]);
 691         else
 692         {                       /* fill in and move to next line */
 693             long l;
 694             off_t p;
 695 
 696             if (edit_buffer_get_current_byte (&edit->buffer) != '\n')
 697             {
 698                 for (l = width - (edit_get_col (edit) - col); l > 0; l -= space_width)
 699                     edit_insert (edit, ' ');
 700             }
 701             for (p = edit->buffer.curs1;; p++)
 702             {
 703                 if (p == edit->buffer.size)
 704                 {
 705                     edit_cursor_move (edit, edit->buffer.size - edit->buffer.curs1);
 706                     edit_insert_ahead (edit, '\n');
 707                     p++;
 708                     break;
 709                 }
 710                 if (edit_buffer_get_byte (&edit->buffer, p) == '\n')
 711                 {
 712                     p++;
 713                     break;
 714                 }
 715             }
 716             edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->buffer.curs1);
 717 
 718             for (l = col - edit_get_col (edit); l >= space_width; l -= space_width)
 719                 edit_insert (edit, ' ');
 720         }
 721     }
 722 
 723     *col1 = col;
 724     *col2 = col + width;
 725     *start_pos = cursor;
 726     *end_pos = edit->buffer.curs1;
 727     edit_cursor_move (edit, cursor - edit->buffer.curs1);
 728 }
 729 
 730 /* --------------------------------------------------------------------------------------------- */
 731 /**
 732  * Callback for the iteration of objects in the 'editors' array.
 733  * Toggle syntax highlighting in editor object.
 734  *
 735  * @param data      probably WEdit object
 736  * @param user_data unused
 737  */
 738 
 739 static void
 740 edit_syntax_onoff_cb (void *data, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 741 {
 742     (void) user_data;
 743 
 744     if (edit_widget_is_editor (CONST_WIDGET (data)))
 745     {
 746         WEdit *edit = EDIT (data);
 747 
 748         if (edit_options.syntax_highlighting)
 749             edit_load_syntax (edit, NULL, edit->syntax_type);
 750         edit->force |= REDRAW_PAGE;
 751     }
 752 }
 753 
 754 /* --------------------------------------------------------------------------------------------- */
 755 
 756 static cb_ret_t
 757 editcmd_dialog_raw_key_query_cb (Widget * w, Widget * sender, widget_msg_t msg, int parm,
     /* [previous][next][first][last][top][bottom][index][help]  */
 758                                  void *data)
 759 {
 760     WDialog *h = DIALOG (w);
 761 
 762     switch (msg)
 763     {
 764     case MSG_KEY:
 765         h->ret_value = parm;
 766         dlg_close (h);
 767         return MSG_HANDLED;
 768     default:
 769         return dlg_default_callback (w, sender, msg, parm, data);
 770     }
 771 }
 772 
 773 /* --------------------------------------------------------------------------------------------- */
 774 /*** public functions ****************************************************************************/
 775 /* --------------------------------------------------------------------------------------------- */
 776 
 777 void
 778 edit_refresh_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 779 {
 780     tty_clear_screen ();
 781     repaint_screen ();
 782     tty_keypad (TRUE);
 783 }
 784 
 785 /* --------------------------------------------------------------------------------------------- */
 786 /**
 787  * Toggle syntax highlighting in all editor windows.
 788  *
 789  * @param h root widget for all windows
 790  */
 791 
 792 void
 793 edit_syntax_onoff_cmd (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 794 {
 795     edit_options.syntax_highlighting = !edit_options.syntax_highlighting;
 796     g_list_foreach (GROUP (h)->widgets, edit_syntax_onoff_cb, NULL);
 797     widget_draw (WIDGET (h));
 798 }
 799 
 800 /* --------------------------------------------------------------------------------------------- */
 801 /**
 802  * Toggle tabs showing in all editor windows.
 803  *
 804  * @param h root widget for all windows
 805  */
 806 
 807 void
 808 edit_show_tabs_tws_cmd (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 809 {
 810     enable_show_tabs_tws = !enable_show_tabs_tws;
 811     widget_draw (WIDGET (h));
 812 }
 813 
 814 /* --------------------------------------------------------------------------------------------- */
 815 /**
 816  * Toggle right margin showing in all editor windows.
 817  *
 818  * @param h root widget for all windows
 819  */
 820 
 821 void
 822 edit_show_margin_cmd (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 823 {
 824     edit_options.show_right_margin = !edit_options.show_right_margin;
 825     widget_draw (WIDGET (h));
 826 }
 827 
 828 /* --------------------------------------------------------------------------------------------- */
 829 /**
 830  * Toggle line numbers showing in all editor windows.
 831  *
 832  * @param h root widget for all windows
 833  */
 834 
 835 void
 836 edit_show_numbers_cmd (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 837 {
 838     edit_options.line_state = !edit_options.line_state;
 839     edit_options.line_state_width = edit_options.line_state ? LINE_STATE_WIDTH : 0;
 840     widget_draw (WIDGET (h));
 841 }
 842 
 843 /* --------------------------------------------------------------------------------------------- */
 844 
 845 void
 846 edit_save_mode_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 847 {
 848     char *str_result = NULL;
 849 
 850     const char *str[] = {
 851         N_("&Quick save"),
 852         N_("&Safe save"),
 853         N_("&Do backups with following extension:")
 854     };
 855 
 856 #ifdef ENABLE_NLS
 857     size_t i;
 858 
 859     for (i = 0; i < 3; i++)
 860         str[i] = _(str[i]);
 861 #endif
 862 
 863     g_assert (edit_options.backup_ext != NULL);
 864 
 865     {
 866         quick_widget_t quick_widgets[] = {
 867             /* *INDENT-OFF* */
 868             QUICK_RADIO (3, str, &edit_options.save_mode, &edit_save_mode_radio_id),
 869             QUICK_INPUT (edit_options.backup_ext, "edit-backup-ext", &str_result,
 870                          &edit_save_mode_input_id, FALSE, FALSE, INPUT_COMPLETE_NONE),
 871             QUICK_SEPARATOR (TRUE),
 872             QUICK_CHECKBOX (N_("Check &POSIX new line"), &edit_options.check_nl_at_eof, NULL),
 873             QUICK_BUTTONS_OK_CANCEL,
 874             QUICK_END
 875             /* *INDENT-ON* */
 876         };
 877 
 878         WRect r = { -1, -1, 0, 38 };
 879 
 880         quick_dialog_t qdlg = {
 881             r, N_("Edit Save Mode"), "[Edit Save Mode]",
 882             quick_widgets, edit_save_mode_callback, NULL
 883         };
 884 
 885         if (quick_dialog (&qdlg) != B_CANCEL)
 886         {
 887             g_free (edit_options.backup_ext);
 888             edit_options.backup_ext = str_result;
 889         }
 890     }
 891 }
 892 
 893 /* --------------------------------------------------------------------------------------------- */
 894 
 895 void
 896 edit_set_filename (WEdit * edit, const vfs_path_t * name_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 897 {
 898     vfs_path_free (edit->filename_vpath, TRUE);
 899     edit->filename_vpath = vfs_path_clone (name_vpath);
 900 
 901     if (edit->dir_vpath == NULL)
 902         edit->dir_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
 903 }
 904 
 905 /* --------------------------------------------------------------------------------------------- */
 906 /* Here we want to warn the users of overwriting an existing file,
 907    but only if they have made a change to the filename */
 908 /* returns TRUE on success */
 909 gboolean
 910 edit_save_as_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 911 {
 912     /* This heads the 'Save As' dialog box */
 913     vfs_path_t *exp_vpath;
 914     int save_lock = 0;
 915     gboolean different_filename = FALSE;
 916     gboolean ret = FALSE;
 917 
 918     if (!edit_check_newline (&edit->buffer))
 919         return FALSE;
 920 
 921     exp_vpath = edit_get_save_file_as (edit);
 922     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
 923 
 924     if (exp_vpath != NULL && vfs_path_len (exp_vpath) != 0)
 925     {
 926         int rv;
 927 
 928         if (!vfs_path_equal (edit->filename_vpath, exp_vpath))
 929         {
 930             int file;
 931             struct stat sb;
 932 
 933             if (mc_stat (exp_vpath, &sb) == 0 && !S_ISREG (sb.st_mode))
 934             {
 935                 edit_error_dialog (_("Save as"),
 936                                    get_sys_error (_
 937                                                   ("Cannot save: destination is not a regular file")));
 938                 goto ret;
 939             }
 940 
 941             different_filename = TRUE;
 942             file = mc_open (exp_vpath, O_RDONLY | O_BINARY);
 943 
 944             if (file == -1)
 945                 edit->stat1.st_mode |= S_IWUSR;
 946             else
 947             {
 948                 /* the file exists */
 949                 mc_close (file);
 950                 /* Overwrite the current file or cancel the operation */
 951                 if (edit_query_dialog2
 952                     (_("Warning"),
 953                      _("A file already exists with this name"), _("&Overwrite"), _("&Cancel")))
 954                     goto ret;
 955             }
 956 
 957             save_lock = lock_file (exp_vpath);
 958         }
 959         else if (!edit->locked && !edit->delete_file)
 960             /* filenames equal, check if already locked */
 961             save_lock = lock_file (exp_vpath);
 962 
 963         if (different_filename)
 964             /* Allow user to write into saved (under another name) file
 965              * even if original file had r/o user permissions. */
 966             edit->stat1.st_mode |= S_IWUSR;
 967 
 968         rv = edit_save_file (edit, exp_vpath);
 969         switch (rv)
 970         {
 971         case 1:
 972             /* Successful, so unlock both files */
 973             if (different_filename)
 974             {
 975                 if (save_lock)
 976                     unlock_file (exp_vpath);
 977                 if (edit->locked)
 978                     edit->locked = unlock_file (edit->filename_vpath);
 979             }
 980             else if (edit->locked || save_lock)
 981                 edit->locked = unlock_file (edit->filename_vpath);
 982 
 983             edit_set_filename (edit, exp_vpath);
 984             if (edit->lb != LB_ASIS)
 985                 edit_reload (edit, exp_vpath);
 986             edit->modified = 0;
 987             edit->delete_file = 0;
 988             if (different_filename)
 989                 edit_load_syntax (edit, NULL, edit->syntax_type);
 990             ret = TRUE;
 991             break;
 992 
 993         default:
 994             edit_error_dialog (_("Save as"), get_sys_error (_("Cannot save file")));
 995             MC_FALLTHROUGH;
 996 
 997         case -1:
 998             /* Failed, so maintain modify (not save) lock */
 999             if (save_lock)
1000                 unlock_file (exp_vpath);
1001             break;
1002         }
1003     }
1004 
1005   ret:
1006     vfs_path_free (exp_vpath, TRUE);
1007     edit->force |= REDRAW_COMPLETELY;
1008     return ret;
1009 }
1010 
1011 /* --------------------------------------------------------------------------------------------- */
1012 /** returns TRUE on success */
1013 
1014 gboolean
1015 edit_save_confirm_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1016 {
1017     if (edit->filename_vpath == NULL)
1018         return edit_save_as_cmd (edit);
1019 
1020     if (!edit_check_newline (&edit->buffer))
1021         return FALSE;
1022 
1023     if (edit_options.confirm_save)
1024     {
1025         char *f;
1026         gboolean ok;
1027 
1028         f = g_strdup_printf (_("Confirm save file: \"%s\""),
1029                              vfs_path_as_str (edit->filename_vpath));
1030         ok = (edit_query_dialog2 (_("Save file"), f, _("&Save"), _("&Cancel")) == 0);
1031         g_free (f);
1032         if (!ok)
1033             return FALSE;
1034     }
1035 
1036     return edit_save_cmd (edit);
1037 }
1038 
1039 /* --------------------------------------------------------------------------------------------- */
1040 /**
1041   * Ask file to edit and load it.
1042   *
1043   * @return TRUE on success or cancel of ask.
1044   */
1045 
1046 gboolean
1047 edit_load_cmd (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
1048 {
1049     char *exp;
1050     gboolean ret = TRUE;        /* possible cancel */
1051 
1052     exp = input_expand_dialog (_("Load"), _("Enter file name:"),
1053                                MC_HISTORY_EDIT_LOAD, INPUT_LAST_TEXT,
1054                                INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD);
1055 
1056     if (exp != NULL && *exp != '\0')
1057     {
1058         vfs_path_t *exp_vpath;
1059 
1060         exp_vpath = vfs_path_from_str (exp);
1061         ret = edit_load_file_from_filename (h, exp_vpath, 0);
1062         vfs_path_free (exp_vpath, TRUE);
1063     }
1064 
1065     g_free (exp);
1066 
1067     return ret;
1068 }
1069 
1070 /* --------------------------------------------------------------------------------------------- */
1071 /**
1072  * Load file content
1073  *
1074  * @param h screen the owner of editor window
1075  * @param vpath vfs file path
1076  * @param line line number
1077  *
1078  * @return TRUE if file content was successfully loaded, FALSE otherwise
1079  */
1080 
1081 gboolean
1082 edit_load_file_from_filename (WDialog * h, const vfs_path_t * vpath, long line)
     /* [previous][next][first][last][top][bottom][index][help]  */
1083 {
1084     WRect r = WIDGET (h)->rect;
1085 
1086     rect_grow (&r, -1, 0);
1087 
1088     return edit_add_window (h, &r, vpath, line);
1089 }
1090 
1091 /* --------------------------------------------------------------------------------------------- */
1092 /**
1093   * Show history od edited or viewed files and open selected file.
1094   *
1095   * @return TRUE on success, FALSE otherwise.
1096   */
1097 
1098 gboolean
1099 edit_load_file_from_history (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
1100 {
1101     char *exp;
1102     int action;
1103     gboolean ret = TRUE;        /* possible cancel */
1104 
1105     exp = show_file_history (CONST_WIDGET (h), &action);
1106     if (exp != NULL && (action == CK_Edit || action == CK_Enter))
1107     {
1108         vfs_path_t *exp_vpath;
1109 
1110         exp_vpath = vfs_path_from_str (exp);
1111         ret = edit_load_file_from_filename (h, exp_vpath, 0);
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     gboolean ret = FALSE;
1133 
1134     if (geteuid () == 0)
1135         dir = query_dialog (_("Syntax file edit"),
1136                             _("Which syntax file you want to edit?"), D_NORMAL, 2,
1137                             _("&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         ret = edit_load_file_from_filename (h, user_syntax_file_vpath, 0);
1155         vfs_path_free (user_syntax_file_vpath, TRUE);
1156     }
1157     else if (dir == 1)
1158         ret = edit_load_file_from_filename (h, extdir_vpath, 0);
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     gboolean ret;
1179 
1180     query_set_sel (1);
1181     dir = query_dialog (_("Menu edit"),
1182                         _("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     ret = edit_load_file_from_filename (h, buffer_vpath, 0);
1224 
1225     vfs_path_free (buffer_vpath, TRUE);
1226     vfs_path_free (menufile_vpath, TRUE);
1227 
1228     return ret;
1229 }
1230 
1231 /* --------------------------------------------------------------------------------------------- */
1232 /**
1233   * Close window with opened file.
1234   *
1235   * @return TRUE if file was closed.
1236   */
1237 
1238 gboolean
1239 edit_close_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1240 {
1241     gboolean ret;
1242 
1243     ret = (edit != NULL) && edit_ok_to_exit (edit);
1244 
1245     if (ret)
1246     {
1247         Widget *w = WIDGET (edit);
1248         WGroup *g = w->owner;
1249 
1250         if (edit->locked != 0)
1251             unlock_file (edit->filename_vpath);
1252 
1253         group_remove_widget (w);
1254         widget_destroy (w);
1255 
1256         if (edit_widget_is_editor (CONST_WIDGET (g->current->data)))
1257             edit = EDIT (g->current->data);
1258         else
1259         {
1260             edit = edit_find_editor (DIALOG (g));
1261             if (edit != NULL)
1262                 widget_select (WIDGET (edit));
1263         }
1264     }
1265 
1266     if (edit != NULL)
1267         edit->force |= REDRAW_COMPLETELY;
1268 
1269     return ret;
1270 }
1271 
1272 /* --------------------------------------------------------------------------------------------- */
1273 
1274 void
1275 edit_block_copy_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1276 {
1277     off_t start_mark, end_mark, current = edit->buffer.curs1;
1278     off_t mark1 = 0, mark2 = 0;
1279     long c1 = 0, c2 = 0;
1280     off_t size;
1281     unsigned char *copy_buf;
1282 
1283     edit_update_curs_col (edit);
1284     if (!eval_marks (edit, &start_mark, &end_mark))
1285         return;
1286 
1287     copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1288 
1289     /* all that gets pushed are deletes hence little space is used on the stack */
1290 
1291     edit_push_markers (edit);
1292 
1293     if (edit->column_highlight)
1294     {
1295         long col_delta;
1296 
1297         col_delta = labs (edit->column2 - edit->column1);
1298         edit_insert_column_of_text (edit, copy_buf, size, col_delta, &mark1, &mark2, &c1, &c2);
1299     }
1300     else
1301     {
1302         int size_orig = size;
1303 
1304         while (size-- != 0)
1305             edit_insert_ahead (edit, copy_buf[size]);
1306 
1307         /* Place cursor at the end of text selection */
1308         if (edit_options.cursor_after_inserted_block)
1309             edit_cursor_move (edit, size_orig);
1310     }
1311 
1312     g_free (copy_buf);
1313     edit_scroll_screen_over_cursor (edit);
1314 
1315     if (edit->column_highlight)
1316         edit_set_markers (edit, edit->buffer.curs1, mark2, c1, c2);
1317     else if (start_mark < current && end_mark > current)
1318         edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
1319 
1320     edit->force |= REDRAW_PAGE;
1321 }
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)
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     edit_error_dialog (_("Error"), _("This function is not implemented"));
1578 }
1579 
1580 /* --------------------------------------------------------------------------------------------- */
1581 
1582 gboolean
1583 edit_copy_to_X_buf_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1584 {
1585     off_t start_mark, end_mark;
1586 
1587     if (!eval_marks (edit, &start_mark, &end_mark))
1588         return TRUE;
1589 
1590     if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
1591     {
1592         edit_error_dialog (_("Copy to clipboard"), get_sys_error (_("Unable to save to file")));
1593         return FALSE;
1594     }
1595     /* try use external clipboard utility */
1596     mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
1597 
1598     if (edit_options.drop_selection_on_copy)
1599         edit_mark_cmd (edit, TRUE);
1600 
1601     return TRUE;
1602 }
1603 
1604 /* --------------------------------------------------------------------------------------------- */
1605 
1606 gboolean
1607 edit_cut_to_X_buf_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1608 {
1609     off_t start_mark, end_mark;
1610 
1611     if (!eval_marks (edit, &start_mark, &end_mark))
1612         return TRUE;
1613 
1614     if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
1615     {
1616         edit_error_dialog (_("Cut to clipboard"), _("Unable to save to file"));
1617         return FALSE;
1618     }
1619     /* try use external clipboard utility */
1620     mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
1621 
1622     edit_block_delete_cmd (edit);
1623     edit_mark_cmd (edit, TRUE);
1624 
1625     return TRUE;
1626 }
1627 
1628 /* --------------------------------------------------------------------------------------------- */
1629 
1630 gboolean
1631 edit_paste_from_X_buf_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1632 {
1633     vfs_path_t *tmp;
1634     gboolean ret;
1635 
1636     /* try use external clipboard utility */
1637     mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_from_ext_clip", NULL);
1638     tmp = mc_config_get_full_vpath (EDIT_HOME_CLIP_FILE);
1639     ret = (edit_insert_file (edit, tmp) >= 0);
1640     vfs_path_free (tmp, TRUE);
1641 
1642     return ret;
1643 }
1644 
1645 /* --------------------------------------------------------------------------------------------- */
1646 /**
1647  * Ask user for the line and go to that line.
1648  * Negative numbers mean line from the end (i.e. -1 is the last line).
1649  */
1650 
1651 void
1652 edit_goto_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1653 {
1654     static gboolean first_run = TRUE;
1655 
1656     char *f;
1657     long l;
1658     char *error;
1659 
1660     f = input_dialog (_("Goto line"), _("Enter line:"), MC_HISTORY_EDIT_GOTO_LINE,
1661                       first_run ? NULL : INPUT_LAST_TEXT, INPUT_COMPLETE_NONE);
1662     if (f == NULL || *f == '\0')
1663     {
1664         g_free (f);
1665         return;
1666     }
1667 
1668     l = strtol (f, &error, 0);
1669     if (*error != '\0')
1670     {
1671         g_free (f);
1672         return;
1673     }
1674 
1675     if (l < 0)
1676         l = edit->buffer.lines + l + 2;
1677 
1678     edit_move_display (edit, l - WIDGET (edit)->rect.lines / 2 - 1);
1679     edit_move_to_line (edit, l - 1);
1680     edit->force |= REDRAW_COMPLETELY;
1681 
1682     g_free (f);
1683     first_run = FALSE;
1684 }
1685 
1686 /* --------------------------------------------------------------------------------------------- */
1687 /** Return TRUE on success */
1688 
1689 gboolean
1690 edit_save_block_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1691 {
1692     off_t start_mark, end_mark;
1693     char *exp, *tmp;
1694     gboolean ret = FALSE;
1695 
1696     if (!eval_marks (edit, &start_mark, &end_mark))
1697         return TRUE;
1698 
1699     tmp = mc_config_get_full_path (EDIT_HOME_CLIP_FILE);
1700     exp =
1701         input_expand_dialog (_("Save block"), _("Enter file name:"),
1702                              MC_HISTORY_EDIT_SAVE_BLOCK, 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             edit_error_dialog (_("Save block"), get_sys_error (_("Cannot save file")));
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             edit_error_dialog (_("Insert file"), get_sys_error (_("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         edit_error_dialog (_("Sort block"), _("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 =
1786         g_strconcat (" sort ", exp, " ", tmp_edit_block_name,
1787                      " > ", tmp_edit_temp_name, (char *) NULL);
1788     g_free (tmp_edit_temp_name);
1789     g_free (tmp_edit_block_name);
1790     g_free (exp);
1791 
1792     e = system (tmp);
1793     g_free (tmp);
1794     if (e != 0)
1795     {
1796         if (e == -1 || e == 127)
1797             edit_error_dialog (_("Sort"), get_sys_error (_("Cannot execute sort command")));
1798         else
1799         {
1800             char q[8];
1801 
1802             sprintf (q, "%d ", e);
1803             tmp = g_strdup_printf (_("Sort returned non-zero: %s"), q);
1804             edit_error_dialog (_("Sort"), tmp);
1805             g_free (tmp);
1806         }
1807 
1808         return -1;
1809     }
1810 
1811     edit->force |= REDRAW_COMPLETELY;
1812 
1813     if (!edit_block_delete_cmd (edit))
1814         return 1;
1815 
1816     {
1817         vfs_path_t *tmp_vpath;
1818 
1819         tmp_vpath = mc_config_get_full_vpath (EDIT_HOME_TEMP_FILE);
1820         edit_insert_file (edit, tmp_vpath);
1821         vfs_path_free (tmp_vpath, TRUE);
1822     }
1823 
1824     return 0;
1825 }
1826 
1827 /* --------------------------------------------------------------------------------------------- */
1828 /**
1829  * Ask user for a command, execute it and paste its output back to the
1830  * editor.
1831  */
1832 
1833 int
1834 edit_ext_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1835 {
1836     char *exp, *tmp, *tmp_edit_temp_file;
1837     int e;
1838 
1839     exp =
1840         input_dialog (_("Paste output of external command"),
1841                       _("Enter shell command(s):"), MC_HISTORY_EDIT_PASTE_EXTCMD, INPUT_LAST_TEXT,
1842                       INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_VARIABLES | INPUT_COMPLETE_USERNAMES
1843                       | INPUT_COMPLETE_HOSTNAMES | INPUT_COMPLETE_CD | INPUT_COMPLETE_COMMANDS |
1844                       INPUT_COMPLETE_SHELL_ESC);
1845 
1846     if (!exp)
1847         return 1;
1848 
1849     tmp_edit_temp_file = mc_config_get_full_path (EDIT_HOME_TEMP_FILE);
1850     tmp = g_strconcat (exp, " > ", tmp_edit_temp_file, (char *) NULL);
1851     g_free (tmp_edit_temp_file);
1852     e = system (tmp);
1853     g_free (tmp);
1854     g_free (exp);
1855 
1856     if (e != 0)
1857     {
1858         edit_error_dialog (_("External command"), get_sys_error (_("Cannot execute command")));
1859         return -1;
1860     }
1861 
1862     edit->force |= REDRAW_COMPLETELY;
1863 
1864     {
1865         vfs_path_t *tmp_vpath;
1866 
1867         tmp_vpath = mc_config_get_full_vpath (EDIT_HOME_TEMP_FILE);
1868         edit_insert_file (edit, tmp_vpath);
1869         vfs_path_free (tmp_vpath, TRUE);
1870     }
1871 
1872     return 0;
1873 }
1874 
1875 /* --------------------------------------------------------------------------------------------- */
1876 /** if block is 1, a block must be highlighted and the shell command
1877    processes it. If block is 0 the shell command is a straight system
1878    command, that just produces some output which is to be inserted */
1879 
1880 void
1881 edit_block_process_cmd (WEdit * edit, int macro_number)
     /* [previous][next][first][last][top][bottom][index][help]  */
1882 {
1883     char *fname;
1884     char *macros_fname = NULL;
1885 
1886     fname = g_strdup_printf ("%s.%i.sh", EDIT_HOME_MACRO_FILE, macro_number);
1887     macros_fname = g_build_filename (mc_config_get_data_path (), fname, (char *) NULL);
1888     edit_user_menu (edit, macros_fname, 0);
1889     g_free (fname);
1890     g_free (macros_fname);
1891     edit->force |= REDRAW_COMPLETELY;
1892 }
1893 
1894 /* --------------------------------------------------------------------------------------------- */
1895 
1896 void
1897 edit_mail_dialog (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1898 {
1899     char *mail_to, *mail_subject, *mail_cc;
1900 
1901     quick_widget_t quick_widgets[] = {
1902         /* *INDENT-OFF* */
1903         QUICK_LABEL (N_("mail -s <subject> -c <cc> <to>"), NULL),
1904         QUICK_LABELED_INPUT (N_("To"), input_label_above,
1905                              INPUT_LAST_TEXT, "mail-dlg-input-3",
1906                              &mail_to, NULL, FALSE, FALSE, INPUT_COMPLETE_USERNAMES),
1907         QUICK_LABELED_INPUT (N_("Subject"), input_label_above,
1908                               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,
1911                              INPUT_LAST_TEXT, "mail-dlg-input",
1912                              &mail_cc, NULL, FALSE, FALSE, INPUT_COMPLETE_USERNAMES),
1913         QUICK_BUTTONS_OK_CANCEL,
1914         QUICK_END
1915         /* *INDENT-ON* */
1916     };
1917 
1918     WRect r = { -1, -1, 0, 50 };
1919 
1920     quick_dialog_t qdlg = {
1921         r, N_("Mail"), "[Input Line Keys]",
1922         quick_widgets, NULL, NULL
1923     };
1924 
1925     if (quick_dialog (&qdlg) != B_CANCEL)
1926     {
1927         pipe_mail (&edit->buffer, mail_to, mail_subject, mail_cc);
1928         g_free (mail_to);
1929         g_free (mail_subject);
1930         g_free (mail_cc);
1931     }
1932 }
1933 
1934 /* --------------------------------------------------------------------------------------------- */
1935 
1936 #ifdef HAVE_CHARSET
1937 void
1938 edit_select_codepage_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1939 {
1940     if (do_select_codepage ())
1941         edit_set_codeset (edit);
1942 
1943     edit->force = REDRAW_PAGE;
1944     widget_draw (WIDGET (edit));
1945 }
1946 #endif
1947 
1948 /* --------------------------------------------------------------------------------------------- */
1949 
1950 void
1951 edit_insert_literal_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1952 {
1953     int char_for_insertion;
1954 
1955     char_for_insertion = editcmd_dialog_raw_key_query (_("Insert literal"),
1956                                                        _("Press any key:"), FALSE);
1957     edit_execute_key_command (edit, -1, ascii_alpha_to_cntrl (char_for_insertion));
1958 }
1959 
1960 /* --------------------------------------------------------------------------------------------- */
1961 
1962 gboolean
1963 edit_load_forward_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1964 {
1965     if (edit->modified
1966         && edit_query_dialog2 (_("Warning"),
1967                                _("Current text was modified without a file save.\n"
1968                                  "Continue discards these changes."), _("C&ontinue"),
1969                                _("&Cancel")) == 1)
1970     {
1971         edit->force |= REDRAW_COMPLETELY;
1972         return TRUE;
1973     }
1974 
1975     if (edit_stack_iterator + 1 >= MAX_HISTORY_MOVETO)
1976         return FALSE;
1977 
1978     if (edit_history_moveto[edit_stack_iterator + 1].line < 1)
1979         return FALSE;
1980 
1981     edit_stack_iterator++;
1982     if (edit_history_moveto[edit_stack_iterator].filename_vpath != NULL)
1983         return edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename_vpath,
1984                                  edit_history_moveto[edit_stack_iterator].line);
1985 
1986     return FALSE;
1987 }
1988 
1989 /* --------------------------------------------------------------------------------------------- */
1990 
1991 gboolean
1992 edit_load_back_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1993 {
1994     if (edit->modified
1995         && edit_query_dialog2 (_("Warning"),
1996                                _("Current text was modified without a file save.\n"
1997                                  "Continue discards these changes."), _("C&ontinue"),
1998                                _("&Cancel")) == 1)
1999     {
2000         edit->force |= REDRAW_COMPLETELY;
2001         return TRUE;
2002     }
2003 
2004     /* we are in the bottom of the stack, NO WAY! */
2005     if (edit_stack_iterator == 0)
2006         return FALSE;
2007 
2008     edit_stack_iterator--;
2009     if (edit_history_moveto[edit_stack_iterator].filename_vpath != NULL)
2010         return edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename_vpath,
2011                                  edit_history_moveto[edit_stack_iterator].line);
2012 
2013     return FALSE;
2014 }
2015 
2016 /* --------------------------------------------------------------------------------------------- */
2017 
2018 /* gets a raw key from the keyboard. Passing cancel = 1 draws
2019    a cancel button thus allowing c-c etc.  Alternatively, cancel = 0
2020    will return the next key pressed.  ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
2021    and Esc are cannot returned */
2022 
2023 int
2024 editcmd_dialog_raw_key_query (const char *heading, const char *query, gboolean cancel)
     /* [previous][next][first][last][top][bottom][index][help]  */
2025 {
2026     int w, wq;
2027     int y = 2;
2028     WDialog *raw_dlg;
2029     WGroup *g;
2030 
2031     w = str_term_width1 (heading) + 6;
2032     wq = str_term_width1 (query);
2033     w = MAX (w, wq + 3 * 2 + 1 + 2);
2034 
2035     raw_dlg =
2036         dlg_create (TRUE, 0, 0, cancel ? 7 : 5, w, WPOS_CENTER | WPOS_TRYUP, FALSE, dialog_colors,
2037                     editcmd_dialog_raw_key_query_cb, NULL, NULL, heading);
2038     g = GROUP (raw_dlg);
2039     widget_want_tab (WIDGET (raw_dlg), TRUE);
2040 
2041     group_add_widget (g, label_new (y, 3, query));
2042     group_add_widget (g,
2043                       input_new (y++, 3 + wq + 1, input_colors, w - (6 + wq + 1), "", 0,
2044                                  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]  */