root/src/editor/editcmd.c

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

DEFINITIONS

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

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

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