root/src/editor/editcmd.c

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

DEFINITIONS

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

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

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