Manual pages: mcmcdiffmceditmcview

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. editcmd_check_and_create_user_syntax_directory
  15. edit_refresh_cmd
  16. edit_syntax_onoff_cmd
  17. edit_show_tabs_tws_cmd
  18. edit_show_margin_cmd
  19. edit_show_numbers_cmd
  20. edit_save_mode_cmd
  21. edit_set_filename
  22. edit_save_as_cmd
  23. edit_save_confirm_cmd
  24. edit_load_cmd
  25. edit_load_file_from_filename
  26. edit_load_file_from_history
  27. edit_load_syntax_file
  28. edit_load_menu_file
  29. edit_close_cmd
  30. edit_block_copy_cmd
  31. edit_block_move_cmd
  32. edit_block_delete_cmd
  33. edit_ok_to_quit
  34. edit_save_block
  35. edit_paste_from_history
  36. edit_copy_to_X_buf_cmd
  37. edit_cut_to_X_buf_cmd
  38. edit_paste_from_X_buf_cmd
  39. edit_goto_cmd
  40. edit_save_block_cmd
  41. edit_insert_file_cmd
  42. edit_sort_cmd
  43. edit_ext_cmd
  44. edit_block_process_cmd
  45. edit_mail_dialog
  46. edit_select_codepage_cmd
  47. edit_insert_literal_cmd
  48. edit_load_forward_cmd
  49. edit_load_back_cmd
  50. editcmd_dialog_raw_key_query

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

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