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. eval_marks
  30. edit_block_copy_cmd
  31. edit_block_move_cmd
  32. edit_block_delete_cmd
  33. edit_ok_to_exit
  34. edit_save_block
  35. edit_paste_from_history
  36. edit_copy_to_X_buf_cmd
  37. edit_cut_to_X_buf_cmd
  38. edit_paste_from_X_buf_cmd
  39. edit_goto_cmd
  40. edit_save_block_cmd
  41. edit_insert_file_cmd
  42. edit_sort_cmd
  43. edit_ext_cmd
  44. edit_block_process_cmd
  45. edit_mail_dialog
  46. edit_select_codepage_cmd
  47. edit_insert_literal_cmd
  48. edit_load_forward_cmd
  49. edit_load_back_cmd
  50. editcmd_dialog_raw_key_query

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

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