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

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