Manual pages: mcmcdiffmceditmcview

root/src/filemanager/cmd.c

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

DEFINITIONS

This source file includes following definitions.
  1. do_view_cmd
  2. do_edit
  3. compare_files
  4. compare_dir
  5. do_link
  6. nice_cd
  7. configure_panel_listing
  8. switch_to_listing
  9. view_file_at_line
  10. view_file
  11. view_cmd
  12. view_file_cmd
  13. view_raw_cmd
  14. view_filtered_cmd
  15. edit_file_at_line
  16. edit_cmd
  17. edit_cmd_force_internal
  18. edit_cmd_new
  19. mkdir_cmd
  20. reread_cmd
  21. ext_cmd
  22. edit_mc_menu_cmd
  23. edit_fhl_cmd
  24. hotlist_cmd
  25. vfs_list
  26. compare_dirs_cmd
  27. diff_view_cmd
  28. swap_cmd
  29. link_cmd
  30. edit_symlink_cmd
  31. help_cmd
  32. ftplink_cmd
  33. sftplink_cmd
  34. shelllink_cmd
  35. quick_cd_cmd
  36. smart_dirsize_cmd
  37. single_dirsize_cmd
  38. dirsizes_cmd
  39. save_setup_cmd
  40. info_cmd_no_menu
  41. quick_cmd_no_menu
  42. listing_cmd
  43. setup_listing_format_cmd
  44. panel_tree_cmd
  45. info_cmd
  46. quick_view_cmd
  47. encoding_cmd

   1 /*
   2    Routines invoked by a function key
   3    They normally operate on the current panel.
   4 
   5    Copyright (C) 1994-2026
   6    Free Software Foundation, Inc.
   7 
   8    Written by:
   9    Andrew Borodin <aborodin@vmail.ru>, 2013-2022
  10 
  11    This file is part of the Midnight Commander.
  12 
  13    The Midnight Commander is free software: you can redistribute it
  14    and/or modify it under the terms of the GNU General Public License as
  15    published by the Free Software Foundation, either version 3 of the License,
  16    or (at your option) any later version.
  17 
  18    The Midnight Commander is distributed in the hope that it will be useful,
  19    but WITHOUT ANY WARRANTY; without even the implied warranty of
  20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21    GNU General Public License for more details.
  22 
  23    You should have received a copy of the GNU General Public License
  24    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  25  */
  26 
  27 /** \file cmd.c
  28  *  \brief Source: routines invoked by a function key
  29  *
  30  *  They normally operate on the current panel.
  31  */
  32 
  33 #include <config.h>
  34 
  35 #include <errno.h>
  36 #include <stdio.h>
  37 #include <string.h>
  38 
  39 #include <sys/types.h>
  40 #include <sys/stat.h>
  41 #ifdef ENABLE_VFS_NET
  42 #include <netdb.h>
  43 #endif
  44 #include <unistd.h>
  45 #include <stdlib.h>
  46 #include <pwd.h>
  47 #include <grp.h>
  48 
  49 #include "lib/global.h"
  50 
  51 #include "lib/tty/tty.h"  // LINES, tty_touch_screen()
  52 #include "lib/tty/key.h"  // ALT() macro
  53 #include "lib/mcconfig.h"
  54 #include "lib/filehighlight.h"  // MC_FHL_INI_FILE
  55 #include "lib/vfs/vfs.h"
  56 #include "lib/fileloc.h"
  57 #include "lib/strutil.h"
  58 #include "lib/file-entry.h"
  59 #include "lib/util.h"
  60 #include "lib/widget.h"
  61 #include "lib/keybind.h"  // CK_Down, CK_History
  62 #include "lib/event.h"    // mc_event_raise()
  63 
  64 #include "src/setup.h"
  65 #include "src/execute.h"  // toggle_panels()
  66 #include "src/history.h"
  67 #include "src/util.h"  // check_for_default(), file_error_message()
  68 
  69 #include "src/viewer/mcviewer.h"
  70 
  71 #ifdef USE_INTERNAL_EDIT
  72 #include "src/editor/edit.h"
  73 #endif
  74 
  75 #ifdef USE_DIFF_VIEW
  76 #include "src/diffviewer/ydiff.h"
  77 #endif
  78 
  79 #include "filegui.h"
  80 #include "hotlist.h"      // hotlist_show()
  81 #include "tree.h"         // tree_chdir()
  82 #include "filemanager.h"  // change_panel()
  83 #include "command.h"      // cmdline
  84 #include "layout.h"       // get_current_type()
  85 #include "ext.h"          // regex_command()
  86 #include "boxes.h"        // cd_box()
  87 #include "dir.h"
  88 #include "cd.h"
  89 #include "ioblksize.h"  // IO_BUFSIZE
  90 
  91 #include "cmd.h"  // Our definitions
  92 
  93 /*** global variables ****************************************************************************/
  94 
  95 /*** file scope macro definitions ****************************************************************/
  96 
  97 /*** file scope type declarations ****************************************************************/
  98 
  99 enum CompareMode
 100 {
 101     compare_quick = 0,
 102     compare_size_only,
 103     compare_thourough
 104 };
 105 
 106 /*** forward declarations (file scope functions) *************************************************/
 107 
 108 /*** file scope variables ************************************************************************/
 109 
 110 #ifdef ENABLE_VFS_NET
 111 static const char *machine_str = N_ ("Enter machine name (F1 for details):");
 112 #endif
 113 
 114 /* --------------------------------------------------------------------------------------------- */
 115 /*** file scope functions ************************************************************************/
 116 /* --------------------------------------------------------------------------------------------- */
 117 /**
 118  * Run viewer (internal or external) on the current file.
 119  * If @plain_view is TRUE, force internal viewer and raw mode (used for F13).
 120  */
 121 static void
 122 do_view_cmd (WPanel *panel, gboolean plain_view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 123 {
 124     const file_entry_t *fe;
 125 
 126     fe = panel_current_entry (panel);
 127     if (fe == NULL)
 128         return;
 129 
 130     // Directories are viewed by changing to them
 131     if (S_ISDIR (fe->st.st_mode) || link_isdir (fe))
 132     {
 133         vfs_path_t *fname_vpath;
 134 
 135         if (confirm_view_dir && (panel->marked != 0 || panel->dirs_marked != 0)
 136             && query_dialog (_ ("Confirmation"), _ ("Files tagged, want to cd?"), D_NORMAL, 2,
 137                              _ ("&Yes"), _ ("&No"))
 138                 != 0)
 139             return;
 140 
 141         fname_vpath = vfs_path_from_str (fe->fname->str);
 142         if (!panel_cd (panel, fname_vpath, cd_exact))
 143             cd_error_message (fe->fname->str);
 144         vfs_path_free (fname_vpath, TRUE);
 145     }
 146     else
 147     {
 148         vfs_path_t *filename_vpath;
 149 
 150         filename_vpath = vfs_path_from_str (fe->fname->str);
 151         view_file (filename_vpath, plain_view, use_internal_view);
 152         vfs_path_free (filename_vpath, TRUE);
 153     }
 154 
 155     repaint_screen ();
 156 }
 157 
 158 /* --------------------------------------------------------------------------------------------- */
 159 
 160 static inline void
 161 do_edit (const vfs_path_t *what_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 162 {
 163     edit_file_at_line (what_vpath, use_internal_edit, 0);
 164 }
 165 
 166 /* --------------------------------------------------------------------------------------------- */
 167 
 168 static int
 169 compare_files (const vfs_path_t *vpath1, const vfs_path_t *vpath2, off_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 170 {
 171     int file1;
 172     int result = -1;  // Different by default
 173 
 174     if (size == 0)
 175         return 0;
 176 
 177     file1 = open (vfs_path_as_str (vpath1), O_RDONLY);
 178     if (file1 >= 0)
 179     {
 180         int file2;
 181 
 182         file2 = open (vfs_path_as_str (vpath2), O_RDONLY);
 183         if (file2 >= 0)
 184         {
 185             char buf1[IO_BUFSIZE], buf2[IO_BUFSIZE];
 186             ssize_t n1, n2;
 187 
 188             rotate_dash (TRUE);
 189             do
 190             {
 191                 while ((n1 = read (file1, buf1, sizeof (buf1))) == -1 && errno == EINTR)
 192                     ;
 193                 while ((n2 = read (file2, buf2, sizeof (buf2))) == -1 && errno == EINTR)
 194                     ;
 195             }
 196             while (n1 == n2 && n1 == sizeof (buf1) && memcmp (buf1, buf2, sizeof (buf1)) == 0);
 197             result = (n1 != n2) || (memcmp (buf1, buf2, MIN ((size_t) n1, sizeof (buf1))) != 0);
 198             rotate_dash (FALSE);
 199 
 200             close (file2);
 201         }
 202         close (file1);
 203     }
 204 
 205     return result;
 206 }
 207 
 208 /* --------------------------------------------------------------------------------------------- */
 209 
 210 static void
 211 compare_dir (WPanel *panel, const WPanel *other, enum CompareMode mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 212 {
 213     int i, j;
 214 
 215     // No marks by default
 216     panel->marked = 0;
 217     panel->total = 0;
 218     panel->dirs_marked = 0;
 219 
 220     // Handle all files in the panel
 221     for (i = 0; i < panel->dir.len; i++)
 222     {
 223         file_entry_t *source = &panel->dir.list[i];
 224         const char *source_fname;
 225 
 226         // Default: unmarked
 227         file_mark (panel, i, 0);
 228 
 229         // Skip directories
 230         if (S_ISDIR (source->st.st_mode))
 231             continue;
 232 
 233         source_fname = source->fname->str;
 234         if (panel->is_panelized)
 235             source_fname = x_basename (source_fname);
 236 
 237         // Search the corresponding entry from the other panel
 238         for (j = 0; j < other->dir.len; j++)
 239         {
 240             const char *other_fname;
 241 
 242             other_fname = other->dir.list[j].fname->str;
 243             if (other->is_panelized)
 244                 other_fname = x_basename (other_fname);
 245 
 246             if (strcmp (source_fname, other_fname) == 0)
 247                 break;
 248         }
 249 
 250         if (j >= other->dir.len)
 251             // Not found -> mark
 252             do_file_mark (panel, i, 1);
 253         else
 254         {
 255             // Found
 256             file_entry_t *target = &other->dir.list[j];
 257 
 258             if (mode != compare_size_only)
 259                 // Older version is not marked
 260                 if (source->st.st_mtime < target->st.st_mtime)
 261                     continue;
 262 
 263             // Newer version with different size is marked
 264             if (source->st.st_size != target->st.st_size)
 265             {
 266                 do_file_mark (panel, i, 1);
 267                 continue;
 268             }
 269 
 270             if (mode == compare_size_only)
 271                 continue;
 272 
 273             if (mode == compare_quick)
 274             {
 275                 // Thorough compare off, compare only time stamps
 276                 // Mark newer version, don't mark version with the same date
 277                 if (source->st.st_mtime > target->st.st_mtime)
 278                     do_file_mark (panel, i, 1);
 279 
 280                 continue;
 281             }
 282 
 283             // Thorough compare on, do byte-by-byte comparison
 284             {
 285                 vfs_path_t *src_name, *dst_name;
 286 
 287                 src_name =
 288                     vfs_path_append_new (panel->cwd_vpath, source->fname->str, (char *) NULL);
 289                 dst_name =
 290                     vfs_path_append_new (other->cwd_vpath, target->fname->str, (char *) NULL);
 291                 if (compare_files (src_name, dst_name, source->st.st_size))
 292                     do_file_mark (panel, i, 1);
 293                 vfs_path_free (src_name, TRUE);
 294                 vfs_path_free (dst_name, TRUE);
 295             }
 296         }
 297     }  // for (i ...)
 298 }
 299 
 300 /* --------------------------------------------------------------------------------------------- */
 301 
 302 static void
 303 do_link (link_type_t link_type, const char *fname)
     /* [previous][next][first][last][top][bottom][index][help]  */
 304 {
 305     char *dest = NULL, *src = NULL;
 306     vfs_path_t *dest_vpath = NULL;
 307 
 308     if (link_type == LINK_HARDLINK)
 309     {
 310         vfs_path_t *fname_vpath;
 311 
 312         src = g_strdup_printf (_ ("Link %s to:"), str_trunc (fname, 46));
 313         dest =
 314             input_expand_dialog (_ ("Link"), src, MC_HISTORY_FM_LINK, "", INPUT_COMPLETE_FILENAMES);
 315         if (dest == NULL || *dest == '\0')
 316             goto cleanup;
 317 
 318         save_cwds_stat ();
 319 
 320         fname_vpath = vfs_path_from_str (fname);
 321         dest_vpath = vfs_path_from_str (dest);
 322         if (mc_link (fname_vpath, dest_vpath) == -1)
 323             file_error_message (_ ("Cannot create link\n%s"), dest);
 324         vfs_path_free (fname_vpath, TRUE);
 325     }
 326     else
 327     {
 328         vfs_path_t *s, *d;
 329 
 330         /* suggest the full path for symlink, and either the full or
 331            relative path to the file it points to  */
 332         s = vfs_path_append_new (current_panel->cwd_vpath, fname, (char *) NULL);
 333 
 334         if (get_other_type () == view_listing)
 335             d = vfs_path_append_new (other_panel->cwd_vpath, fname, (char *) NULL);
 336         else
 337             d = vfs_path_from_str (fname);
 338 
 339         if (link_type == LINK_SYMLINK_RELATIVE)
 340         {
 341             char *s_str;
 342 
 343             s_str = diff_two_paths (other_panel->cwd_vpath, s);
 344             vfs_path_free (s, TRUE);
 345             s = vfs_path_from_str_flags (s_str, VPF_NO_CANON);
 346             g_free (s_str);
 347         }
 348 
 349         symlink_box (s, d, &dest, &src);
 350         vfs_path_free (d, TRUE);
 351         vfs_path_free (s, TRUE);
 352 
 353         if (dest == NULL || *dest == '\0' || src == NULL || *src == '\0')
 354             goto cleanup;
 355 
 356         save_cwds_stat ();
 357 
 358         dest_vpath = vfs_path_from_str_flags (dest, VPF_NO_CANON);
 359 
 360         s = vfs_path_from_str (src);
 361         if (mc_symlink (dest_vpath, s) == -1)
 362             file_error_message (_ ("Cannot create symbolic link\n%s"), dest);
 363         vfs_path_free (s, TRUE);
 364     }
 365 
 366     update_panels (UP_OPTIMIZE, UP_KEEPSEL);
 367     repaint_screen ();
 368 
 369 cleanup:
 370     vfs_path_free (dest_vpath, TRUE);
 371     g_free (src);
 372     g_free (dest);
 373 }
 374 
 375 /* --------------------------------------------------------------------------------------------- */
 376 
 377 #if defined(ENABLE_VFS_NET)
 378 static void
 379 nice_cd (const char *text, const char *xtext, const char *help, const char *history_name,
     /* [previous][next][first][last][top][bottom][index][help]  */
 380          const char *prefix, int to_home, gboolean strip_password)
 381 {
 382     char *machine;
 383     char *cd_path;
 384 
 385     machine = input_dialog_help (text, xtext, help, history_name, INPUT_LAST_TEXT, strip_password,
 386                                  INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD
 387                                      | INPUT_COMPLETE_HOSTNAMES | INPUT_COMPLETE_USERNAMES);
 388     if (machine == NULL)
 389         return;
 390 
 391     to_home = 0; /* FIXME: how to solve going to home nicely? /~/ is
 392                     ugly as hell and leads to problems in vfs layer */
 393 
 394     if (strncmp (prefix, machine, strlen (prefix)) == 0)
 395         cd_path = g_strconcat (machine, to_home ? "/~/" : (char *) NULL, (char *) NULL);
 396     else
 397         cd_path = g_strconcat (prefix, machine, to_home ? "/~/" : (char *) NULL, (char *) NULL);
 398 
 399     g_free (machine);
 400 
 401     if (!IS_PATH_SEP (*cd_path))
 402     {
 403         char *tmp = cd_path;
 404 
 405         cd_path = g_strconcat (PATH_SEP_STR, tmp, (char *) NULL);
 406         g_free (tmp);
 407     }
 408 
 409     {
 410         panel_view_mode_t save_type;
 411         vfs_path_t *cd_vpath;
 412 
 413         save_type = get_panel_type (MENU_PANEL_IDX);
 414 
 415         if (save_type != view_listing)
 416             create_panel (MENU_PANEL_IDX, view_listing);
 417 
 418         cd_vpath = vfs_path_from_str_flags (cd_path, VPF_NO_CANON);
 419         if (!panel_do_cd (MENU_PANEL, cd_vpath, cd_parse_command))
 420         {
 421             cd_error_message (cd_path);
 422 
 423             if (save_type != view_listing)
 424                 create_panel (MENU_PANEL_IDX, save_type);
 425         }
 426         vfs_path_free (cd_vpath, TRUE);
 427     }
 428     g_free (cd_path);
 429 
 430     // In case of passive panel, restore current VFS directory that was changed in panel_do_cd()
 431     if (MENU_PANEL != current_panel)
 432         (void) mc_chdir (current_panel->cwd_vpath);
 433 }
 434 #endif
 435 
 436 /* --------------------------------------------------------------------------------------------- */
 437 
 438 static void
 439 configure_panel_listing (WPanel *p, int list_format, int brief_cols, gboolean use_msformat,
     /* [previous][next][first][last][top][bottom][index][help]  */
 440                          char **user, char **status)
 441 {
 442     p->user_mini_status = use_msformat;
 443     p->list_format = list_format;
 444 
 445     if (list_format == list_brief)
 446         p->brief_cols = brief_cols;
 447 
 448     if (list_format == list_user || use_msformat)
 449     {
 450         g_free (p->user_format);
 451         p->user_format = *user;
 452         *user = NULL;
 453 
 454         g_free (p->user_status_format[list_format]);
 455         p->user_status_format[list_format] = *status;
 456         *status = NULL;
 457 
 458         set_panel_formats (p);
 459     }
 460 
 461     set_panel_formats (p);
 462     do_refresh ();
 463 }
 464 
 465 /* --------------------------------------------------------------------------------------------- */
 466 
 467 static void
 468 switch_to_listing (int panel_index)
     /* [previous][next][first][last][top][bottom][index][help]  */
 469 {
 470     if (get_panel_type (panel_index) != view_listing)
 471         create_panel (panel_index, view_listing);
 472 }
 473 
 474 /* --------------------------------------------------------------------------------------------- */
 475 /*** public functions ****************************************************************************/
 476 /* --------------------------------------------------------------------------------------------- */
 477 
 478 gboolean
 479 view_file_at_line (const vfs_path_t *filename_vpath, gboolean plain_view, gboolean internal,
     /* [previous][next][first][last][top][bottom][index][help]  */
 480                    long start_line, off_t search_start, off_t search_end)
 481 {
 482     gboolean ret = TRUE;
 483 
 484     if (plain_view)
 485     {
 486         mcview_mode_flags_t changed_flags;
 487 
 488         mcview_clear_mode_flags (&changed_flags);
 489         mcview_altered_flags.hex = FALSE;
 490         mcview_altered_flags.magic = FALSE;
 491         mcview_altered_flags.nroff = FALSE;
 492         if (mcview_global_flags.hex)
 493             changed_flags.hex = TRUE;
 494         if (mcview_global_flags.magic)
 495             changed_flags.magic = TRUE;
 496         if (mcview_global_flags.nroff)
 497             changed_flags.nroff = TRUE;
 498         mcview_global_flags.hex = FALSE;
 499         mcview_global_flags.magic = FALSE;
 500         mcview_global_flags.nroff = FALSE;
 501 
 502         ret = mcview_viewer (NULL, filename_vpath, start_line, search_start, search_end);
 503 
 504         if (changed_flags.hex && !mcview_altered_flags.hex)
 505             mcview_global_flags.hex = TRUE;
 506         if (changed_flags.magic && !mcview_altered_flags.magic)
 507             mcview_global_flags.magic = TRUE;
 508         if (changed_flags.nroff && !mcview_altered_flags.nroff)
 509             mcview_global_flags.nroff = TRUE;
 510 
 511         dialog_switch_process_pending ();
 512     }
 513     else if (internal)
 514     {
 515         char view_entry[BUF_TINY];
 516 
 517         if (start_line > 0)
 518             g_snprintf (view_entry, sizeof (view_entry), "View:%ld", start_line);
 519         else
 520             strcpy (view_entry, "View");
 521 
 522         ret = (regex_command (filename_vpath, view_entry) == 0);
 523         if (ret)
 524         {
 525             ret = mcview_viewer (NULL, filename_vpath, start_line, search_start, search_end);
 526             dialog_switch_process_pending ();
 527         }
 528     }
 529     else
 530     {
 531         static const char *viewer = NULL;
 532 
 533         if (viewer == NULL)
 534         {
 535             viewer = getenv ("VIEWER");
 536             if (viewer == NULL)
 537                 viewer = getenv ("PAGER");
 538             if (viewer == NULL)
 539                 viewer = "view";
 540         }
 541 
 542         execute_external_editor_or_viewer (viewer, filename_vpath, start_line);
 543     }
 544 
 545     return ret;
 546 }
 547 
 548 /* --------------------------------------------------------------------------------------------- */
 549 /** view_file (filename, plain_view, internal)
 550  *
 551  * Inputs:
 552  *   filename_vpath: The file name to view
 553  *   plain_view:     If set does not do any fancy pre-processing (no filtering) and
 554  *                   always invokes the internal viewer.
 555  *   internal:       If set uses the internal viewer, otherwise an external viewer.
 556  */
 557 
 558 gboolean
 559 view_file (const vfs_path_t *filename_vpath, gboolean plain_view, gboolean internal)
     /* [previous][next][first][last][top][bottom][index][help]  */
 560 {
 561     return view_file_at_line (filename_vpath, plain_view, internal, 0, 0, 0);
 562 }
 563 
 564 /* --------------------------------------------------------------------------------------------- */
 565 /** Run user's preferred viewer on the current file */
 566 
 567 void
 568 view_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 569 {
 570     do_view_cmd (panel, FALSE);
 571 }
 572 
 573 /* --------------------------------------------------------------------------------------------- */
 574 /** Ask for file and run user's preferred viewer on it */
 575 
 576 void
 577 view_file_cmd (const WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 578 {
 579     const file_entry_t *fe;
 580     char *filename;
 581     vfs_path_t *vpath;
 582 
 583     fe = panel_current_entry (panel);
 584     if (fe == NULL)
 585         return;
 586 
 587     filename = input_expand_dialog (_ ("View file"), _ ("Filename:"), MC_HISTORY_FM_VIEW_FILE,
 588                                     fe->fname->str, INPUT_COMPLETE_FILENAMES);
 589     if (filename == NULL)
 590         return;
 591 
 592     vpath = vfs_path_from_str (filename);
 593     g_free (filename);
 594     view_file (vpath, FALSE, use_internal_view);
 595     vfs_path_free (vpath, TRUE);
 596 }
 597 
 598 /* --------------------------------------------------------------------------------------------- */
 599 /** Run plain internal viewer on the current file */
 600 void
 601 view_raw_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 602 {
 603     do_view_cmd (panel, TRUE);
 604 }
 605 
 606 /* --------------------------------------------------------------------------------------------- */
 607 
 608 void
 609 view_filtered_cmd (const WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 610 {
 611     char *command;
 612     const char *initial_command;
 613 
 614     if (input_is_empty (cmdline))
 615     {
 616         const file_entry_t *fe;
 617 
 618         fe = panel_current_entry (panel);
 619         if (fe == NULL)
 620             return;
 621 
 622         initial_command = fe->fname->str;
 623     }
 624     else
 625         initial_command = input_get_ctext (cmdline);
 626 
 627     command = input_dialog (_ ("Filtered view"), _ ("Filter command and arguments:"),
 628                             MC_HISTORY_FM_FILTERED_VIEW, initial_command,
 629                             INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_COMMANDS);
 630 
 631     if (command != NULL)
 632     {
 633         mcview_viewer (command, NULL, 0, 0, 0);
 634         g_free (command);
 635         dialog_switch_process_pending ();
 636     }
 637 }
 638 
 639 /* --------------------------------------------------------------------------------------------- */
 640 
 641 void
 642 edit_file_at_line (const vfs_path_t *what_vpath, gboolean internal, long start_line)
     /* [previous][next][first][last][top][bottom][index][help]  */
 643 {
 644 #ifdef USE_INTERNAL_EDIT
 645     if (internal)
 646     {
 647         const edit_arg_t arg = { (vfs_path_t *) what_vpath, start_line };
 648 
 649         edit_file (&arg);
 650         dialog_switch_process_pending ();
 651     }
 652     else
 653 #endif
 654     {
 655         static const char *editor = NULL;
 656 
 657         (void) internal;
 658 
 659         if (editor == NULL)
 660         {
 661             editor = getenv ("EDITOR");
 662             if (editor == NULL)
 663                 editor = get_default_editor ();
 664         }
 665 
 666         execute_external_editor_or_viewer (editor, what_vpath, start_line);
 667     }
 668 }
 669 
 670 /* --------------------------------------------------------------------------------------------- */
 671 
 672 void
 673 edit_cmd (const WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 674 {
 675     const file_entry_t *fe;
 676     vfs_path_t *fname;
 677 
 678     fe = panel_current_entry (panel);
 679     if (fe == NULL)
 680         return;
 681 
 682     fname = vfs_path_from_str (fe->fname->str);
 683     if (regex_command (fname, "Edit") == 0)
 684         do_edit (fname);
 685     vfs_path_free (fname, TRUE);
 686 }
 687 
 688 /* --------------------------------------------------------------------------------------------- */
 689 
 690 #ifdef USE_INTERNAL_EDIT
 691 void
 692 edit_cmd_force_internal (const WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 693 {
 694     const file_entry_t *fe;
 695     vfs_path_t *fname;
 696 
 697     fe = panel_current_entry (panel);
 698     if (fe == NULL)
 699         return;
 700 
 701     fname = vfs_path_from_str (fe->fname->str);
 702     if (regex_command (fname, "Edit") == 0)
 703         edit_file_at_line (fname, TRUE, 1);
 704     vfs_path_free (fname, TRUE);
 705 }
 706 #endif
 707 
 708 /* --------------------------------------------------------------------------------------------- */
 709 
 710 void
 711 edit_cmd_new (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 712 {
 713     vfs_path_t *fname_vpath = NULL;
 714 
 715     if (editor_ask_filename_before_edit)
 716     {
 717         char *fname;
 718 
 719         fname = input_expand_dialog (_ ("Edit file"), _ ("Enter file name:"), MC_HISTORY_EDIT_LOAD,
 720                                      "", INPUT_COMPLETE_FILENAMES);
 721         if (fname == NULL)
 722             return;
 723 
 724         if (*fname != '\0')
 725             fname_vpath = vfs_path_from_str (fname);
 726 
 727         g_free (fname);
 728     }
 729 
 730     mc_global.source_codepage = default_source_codepage;
 731     do_edit (fname_vpath);
 732 
 733     vfs_path_free (fname_vpath, TRUE);
 734 }
 735 
 736 /* --------------------------------------------------------------------------------------------- */
 737 
 738 void
 739 mkdir_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 740 {
 741     const file_entry_t *fe;
 742     char *dir;
 743     const char *name = "";
 744 
 745     fe = panel_current_entry (panel);
 746     if (fe == NULL)
 747         return;
 748 
 749     // If 'on' then automatically fills name with current item name
 750     if (auto_fill_mkdir_name && !DIR_IS_DOTDOT (fe->fname->str))
 751         name = fe->fname->str;
 752 
 753     dir = input_expand_dialog (_ ("Create a new Directory"), _ ("Enter directory name:"),
 754                                MC_HISTORY_FM_MKDIR, name, INPUT_COMPLETE_FILENAMES);
 755 
 756     if (dir != NULL && *dir != '\0')
 757     {
 758         vfs_path_t *absdir;
 759 
 760         if (IS_PATH_SEP (dir[0]) || dir[0] == '~')
 761             absdir = vfs_path_from_str (dir);
 762         else
 763         {
 764             // possible escaped '~'
 765             // allow create directory with name '~'
 766             char *tmpdir = dir;
 767 
 768             if (dir[0] == '\\' && dir[1] == '~')
 769                 tmpdir = dir + 1;
 770 
 771             absdir = vfs_path_append_new (panel->cwd_vpath, tmpdir, (char *) NULL);
 772         }
 773 
 774         save_cwds_stat ();
 775 
 776         if (mc_mkdir (absdir, 0777) != 0)
 777             file_error_message (_ ("Cannot create directory\n%s"), vfs_path_as_str (absdir));
 778         else
 779         {
 780             update_panels (UP_OPTIMIZE, dir);
 781             repaint_screen ();
 782             select_item (panel);
 783         }
 784 
 785         vfs_path_free (absdir, TRUE);
 786     }
 787     g_free (dir);
 788 }
 789 
 790 /* --------------------------------------------------------------------------------------------- */
 791 
 792 void
 793 reread_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 794 {
 795     panel_update_flags_t flag = UP_ONLY_CURRENT;
 796 
 797     if (get_current_type () == view_listing && get_other_type () == view_listing
 798         && vfs_path_equal (current_panel->cwd_vpath, other_panel->cwd_vpath))
 799         flag = UP_OPTIMIZE;
 800 
 801     update_panels (UP_RELOAD | flag, UP_KEEPSEL);
 802     repaint_screen ();
 803 }
 804 
 805 /* --------------------------------------------------------------------------------------------- */
 806 
 807 void
 808 ext_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 809 {
 810     vfs_path_t *extdir_vpath;
 811     int dir = 0;
 812 
 813     if (geteuid () == 0)
 814         dir = query_dialog (_ ("Extension file edit"), _ ("Which extension file you want to edit?"),
 815                             D_NORMAL, 2, _ ("&User"), _ ("&System Wide"));
 816 
 817     extdir_vpath = vfs_path_build_filename (mc_global.sysconfig_dir, MC_EXT_FILE, (char *) NULL);
 818 
 819     if (dir == 0)
 820     {
 821         vfs_path_t *buffer_vpath;
 822 
 823         buffer_vpath = mc_config_get_full_vpath (MC_EXT_FILE);
 824         check_for_default (extdir_vpath, buffer_vpath);
 825         do_edit (buffer_vpath);
 826         vfs_path_free (buffer_vpath, TRUE);
 827     }
 828     else if (dir == 1)
 829     {
 830         if (!exist_file (vfs_path_get_last_path_str (extdir_vpath)))
 831         {
 832             vfs_path_free (extdir_vpath, TRUE);
 833             extdir_vpath =
 834                 vfs_path_build_filename (mc_global.share_data_dir, MC_EXT_FILE, (char *) NULL);
 835         }
 836         do_edit (extdir_vpath);
 837     }
 838 
 839     vfs_path_free (extdir_vpath, TRUE);
 840     flush_extension_file ();
 841 }
 842 
 843 /* --------------------------------------------------------------------------------------------- */
 844 /** edit file menu for mc */
 845 
 846 void
 847 edit_mc_menu_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 848 {
 849     vfs_path_t *buffer_vpath;
 850     vfs_path_t *menufile_vpath;
 851     int dir = 0;
 852 
 853     query_set_sel (1);
 854     dir = query_dialog (_ ("Menu edit"), _ ("Which menu file do you want to edit?"), D_NORMAL,
 855                         geteuid () ? 2 : 3, _ ("&Local"), _ ("&User"), _ ("&System Wide"));
 856 
 857     menufile_vpath =
 858         vfs_path_build_filename (mc_global.sysconfig_dir, MC_GLOBAL_MENU, (char *) NULL);
 859 
 860     if (!exist_file (vfs_path_get_last_path_str (menufile_vpath)))
 861     {
 862         vfs_path_free (menufile_vpath, TRUE);
 863         menufile_vpath =
 864             vfs_path_build_filename (mc_global.share_data_dir, MC_GLOBAL_MENU, (char *) NULL);
 865     }
 866 
 867     switch (dir)
 868     {
 869     case 0:
 870         buffer_vpath = vfs_path_from_str (MC_LOCAL_MENU);
 871         check_for_default (menufile_vpath, buffer_vpath);
 872         chmod (vfs_path_get_last_path_str (buffer_vpath), 0600);
 873         break;
 874 
 875     case 1:
 876         buffer_vpath = mc_config_get_full_vpath (MC_USERMENU_FILE);
 877         check_for_default (menufile_vpath, buffer_vpath);
 878         break;
 879 
 880     case 2:
 881         buffer_vpath =
 882             vfs_path_build_filename (mc_global.sysconfig_dir, MC_GLOBAL_MENU, (char *) NULL);
 883         if (!exist_file (vfs_path_get_last_path_str (buffer_vpath)))
 884         {
 885             vfs_path_free (buffer_vpath, TRUE);
 886             buffer_vpath =
 887                 vfs_path_build_filename (mc_global.share_data_dir, MC_GLOBAL_MENU, (char *) NULL);
 888         }
 889         break;
 890 
 891     default:
 892         vfs_path_free (menufile_vpath, TRUE);
 893         return;
 894     }
 895 
 896     do_edit (buffer_vpath);
 897 
 898     vfs_path_free (buffer_vpath, TRUE);
 899     vfs_path_free (menufile_vpath, TRUE);
 900 }
 901 
 902 /* --------------------------------------------------------------------------------------------- */
 903 
 904 void
 905 edit_fhl_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 906 {
 907     vfs_path_t *fhlfile_vpath = NULL;
 908     int dir = 0;
 909 
 910     if (geteuid () == 0)
 911         dir = query_dialog (_ ("Highlighting groups file edit"),
 912                             _ ("Which highlighting file you want to edit?"), D_NORMAL, 2,
 913                             _ ("&User"), _ ("&System Wide"));
 914 
 915     fhlfile_vpath =
 916         vfs_path_build_filename (mc_global.sysconfig_dir, MC_FHL_INI_FILE, (char *) NULL);
 917 
 918     if (dir == 0)
 919     {
 920         vfs_path_t *buffer_vpath;
 921 
 922         buffer_vpath = mc_config_get_full_vpath (MC_FHL_INI_FILE);
 923         check_for_default (fhlfile_vpath, buffer_vpath);
 924         do_edit (buffer_vpath);
 925         vfs_path_free (buffer_vpath, TRUE);
 926     }
 927     else if (dir == 1)
 928     {
 929         if (!exist_file (vfs_path_get_last_path_str (fhlfile_vpath)))
 930         {
 931             vfs_path_free (fhlfile_vpath, TRUE);
 932             fhlfile_vpath =
 933                 vfs_path_build_filename (mc_global.sysconfig_dir, MC_FHL_INI_FILE, (char *) NULL);
 934         }
 935         do_edit (fhlfile_vpath);
 936     }
 937 
 938     vfs_path_free (fhlfile_vpath, TRUE);
 939     // refresh highlighting rules
 940     mc_fhl_free (&mc_filehighlight);
 941     mc_filehighlight = mc_fhl_new (TRUE);
 942 }
 943 
 944 /* --------------------------------------------------------------------------------------------- */
 945 
 946 void
 947 hotlist_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 948 {
 949     char *target;
 950 
 951     target = hotlist_show (LIST_HOTLIST, panel);
 952     if (target == NULL)
 953         return;
 954 
 955     if (get_current_type () == view_tree)
 956     {
 957         vfs_path_t *vpath;
 958 
 959         vpath = vfs_path_from_str (target);
 960         tree_chdir (the_tree, vpath);
 961         vfs_path_free (vpath, TRUE);
 962     }
 963     else
 964     {
 965         vfs_path_t *deprecated_vpath;
 966         const char *deprecated_path;
 967 
 968         deprecated_vpath = vfs_path_from_str_flags (target, VPF_USE_DEPRECATED_PARSER);
 969         deprecated_path = vfs_path_as_str (deprecated_vpath);
 970         cd_to (deprecated_path);
 971         vfs_path_free (deprecated_vpath, TRUE);
 972     }
 973 
 974     g_free (target);
 975 }
 976 
 977 /* --------------------------------------------------------------------------------------------- */
 978 
 979 #ifdef ENABLE_VFS
 980 void
 981 vfs_list (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 982 {
 983     char *target;
 984     vfs_path_t *target_vpath;
 985 
 986     target = hotlist_show (LIST_VFSLIST, panel);
 987     if (target == NULL)
 988         return;
 989 
 990     target_vpath = vfs_path_from_str (target);
 991     if (!panel_cd (current_panel, target_vpath, cd_exact))
 992         cd_error_message (target);
 993     vfs_path_free (target_vpath, TRUE);
 994     g_free (target);
 995 }
 996 #endif
 997 
 998 /* --------------------------------------------------------------------------------------------- */
 999 
1000 void
1001 compare_dirs_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1002 {
1003     int choice;
1004     enum CompareMode thorough_flag;
1005 
1006     choice = query_dialog (_ ("Compare directories"), _ ("Select compare method:"), D_NORMAL, 4,
1007                            _ ("&Quick"), _ ("&Size only"), _ ("&Thorough"), _ ("&Cancel"));
1008 
1009     if (choice < 0 || choice > 2)
1010         return;
1011 
1012     thorough_flag = choice;
1013 
1014     if (get_current_type () == view_listing && get_other_type () == view_listing)
1015     {
1016         compare_dir (current_panel, other_panel, thorough_flag);
1017         compare_dir (other_panel, current_panel, thorough_flag);
1018     }
1019     else
1020         message (D_ERROR, MSG_ERROR,
1021                  _ ("Both panels should be in the listing mode\nto use this command"));
1022 }
1023 
1024 /* --------------------------------------------------------------------------------------------- */
1025 
1026 #ifdef USE_DIFF_VIEW
1027 void
1028 diff_view_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1029 {
1030     // both panels must be in the list mode
1031     if (get_current_type () == view_listing && get_other_type () == view_listing)
1032     {
1033         if (get_current_index () == 0)
1034             dview_diff_cmd (current_panel, other_panel);
1035         else
1036             dview_diff_cmd (other_panel, current_panel);
1037 
1038         if (mc_global.mc_run_mode == MC_RUN_FULL)
1039             update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1040 
1041         dialog_switch_process_pending ();
1042     }
1043 }
1044 #endif
1045 
1046 /* --------------------------------------------------------------------------------------------- */
1047 
1048 void
1049 swap_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1050 {
1051     swap_panels ();
1052     tty_touch_screen ();
1053     repaint_screen ();
1054 }
1055 
1056 /* --------------------------------------------------------------------------------------------- */
1057 
1058 void
1059 link_cmd (link_type_t link_type)
     /* [previous][next][first][last][top][bottom][index][help]  */
1060 {
1061     const file_entry_t *fe;
1062 
1063     fe = panel_current_entry (current_panel);
1064     if (fe != NULL)
1065         do_link (link_type, fe->fname->str);
1066 }
1067 
1068 /* --------------------------------------------------------------------------------------------- */
1069 
1070 void
1071 edit_symlink_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1072 {
1073     const file_entry_t *fe;
1074     const char *p;
1075 
1076     fe = panel_current_entry (current_panel);
1077     if (fe == NULL)
1078         return;
1079 
1080     p = fe->fname->str;
1081 
1082     if (!S_ISLNK (fe->st.st_mode))
1083         message (D_ERROR, MSG_ERROR, _ ("'%s' is not a symbolic link"), p);
1084     else
1085     {
1086         char buffer[MC_MAXPATHLEN];
1087         int i;
1088 
1089         i = readlink (p, buffer, sizeof (buffer) - 1);
1090         if (i > 0)
1091         {
1092             char *q, *dest;
1093 
1094             buffer[i] = '\0';
1095 
1096             q = g_strdup_printf (_ ("Symlink '%s\' points to:"), str_trunc (p, 32));
1097             dest = input_expand_dialog (_ ("Edit symlink"), q, MC_HISTORY_FM_EDIT_LINK, buffer,
1098                                         INPUT_COMPLETE_FILENAMES);
1099             g_free (q);
1100 
1101             if (dest != NULL && *dest != '\0' && strcmp (buffer, dest) != 0)
1102             {
1103                 vfs_path_t *p_vpath;
1104 
1105                 p_vpath = vfs_path_from_str (p);
1106 
1107                 save_cwds_stat ();
1108 
1109                 if (mc_unlink (p_vpath) == -1)
1110                     file_error_message (_ ("Edit symlink, unable to remove\n%s"), p);
1111                 else
1112                 {
1113                     vfs_path_t *dest_vpath;
1114 
1115                     dest_vpath = vfs_path_from_str_flags (dest, VPF_NO_CANON);
1116                     if (mc_symlink (dest_vpath, p_vpath) == -1)
1117                         file_error_message (_ ("Cannot edit symlink\n%s"),
1118                                             vfs_path_as_str (dest_vpath));
1119                     vfs_path_free (dest_vpath, TRUE);
1120                 }
1121 
1122                 vfs_path_free (p_vpath, TRUE);
1123 
1124                 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1125                 repaint_screen ();
1126             }
1127 
1128             g_free (dest);
1129         }
1130     }
1131 }
1132 
1133 /* --------------------------------------------------------------------------------------------- */
1134 
1135 void
1136 help_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1137 {
1138     ev_help_t event_data = { NULL, NULL };
1139 
1140     if (current_panel->quick_search.active)
1141         event_data.node = "[Quick search]";
1142     else
1143         event_data.node = "[main]";
1144 
1145     mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
1146 }
1147 
1148 /* --------------------------------------------------------------------------------------------- */
1149 
1150 #ifdef ENABLE_VFS_FTP
1151 void
1152 ftplink_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1153 {
1154     nice_cd (_ ("FTP to machine"), _ (machine_str), "[FTP File System]",
1155              ":ftplink_cmd: FTP to machine ", "ftp://", 1, TRUE);
1156 }
1157 #endif
1158 
1159 /* --------------------------------------------------------------------------------------------- */
1160 
1161 #ifdef ENABLE_VFS_SFTP
1162 void
1163 sftplink_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1164 {
1165     nice_cd (_ ("SFTP to machine"), _ (machine_str),
1166              "[SFTP (SSH File Transfer Protocol) filesystem]", ":sftplink_cmd: SFTP to machine ",
1167              "sftp://", 1, TRUE);
1168 }
1169 #endif
1170 
1171 /* --------------------------------------------------------------------------------------------- */
1172 
1173 #ifdef ENABLE_VFS_SHELL
1174 void
1175 shelllink_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1176 {
1177     nice_cd (_ ("Shell link to machine"), _ (machine_str), "[FIle transfer over SHell filesystem]",
1178              ":fishlink_cmd: Shell link to machine ", "sh://", 1, TRUE);
1179 }
1180 #endif
1181 
1182 /* --------------------------------------------------------------------------------------------- */
1183 
1184 void
1185 quick_cd_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
1186 {
1187     char *p;
1188 
1189     p = cd_box (panel);
1190     if (p != NULL && *p != '\0')
1191         cd_to (p);
1192     g_free (p);
1193 }
1194 
1195 /* --------------------------------------------------------------------------------------------- */
1196 /*!
1197    \brief calculate dirs sizes
1198 
1199    calculate dirs sizes and resort panel:
1200    dirs_selected = show size for selected dirs,
1201    otherwise = show size for dir under cursor:
1202    dir under cursor ".." = show size for all dirs,
1203    otherwise = show size for dir under cursor
1204  */
1205 
1206 void
1207 smart_dirsize_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
1208 {
1209     const file_entry_t *entry;
1210 
1211     entry = panel_current_entry (panel);
1212     if ((entry != NULL && S_ISDIR (entry->st.st_mode) && DIR_IS_DOTDOT (entry->fname->str))
1213         || panel->dirs_marked)
1214         dirsizes_cmd (panel);
1215     else
1216         single_dirsize_cmd (panel);
1217 }
1218 
1219 /* --------------------------------------------------------------------------------------------- */
1220 
1221 void
1222 single_dirsize_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
1223 {
1224     file_entry_t *entry;
1225 
1226     entry = panel_current_entry (panel);
1227 
1228     if (entry != NULL && S_ISDIR (entry->st.st_mode) && !DIR_IS_DOTDOT (entry->fname->str))
1229     {
1230         size_t dir_count = 0;
1231         size_t count = 0;
1232         uintmax_t total = 0;
1233         dirsize_status_msg_t dsm;
1234         vfs_path_t *p;
1235 
1236         p = vfs_path_from_str (entry->fname->str);
1237 
1238         memset (&dsm, 0, sizeof (dsm));
1239         status_msg_init (STATUS_MSG (&dsm), _ ("Directory scanning"), 0, dirsize_status_init_cb,
1240                          dirsize_status_update_cb, dirsize_status_deinit_cb);
1241 
1242         if (compute_dir_size (p, &dsm, &dir_count, &count, &total, FALSE) == FILE_CONT)
1243         {
1244             entry->st.st_size = (off_t) total;
1245             entry->f.dir_size_computed = 1;
1246         }
1247 
1248         vfs_path_free (p, TRUE);
1249 
1250         status_msg_deinit (STATUS_MSG (&dsm));
1251     }
1252 
1253     if (panels_options.mark_moves_down)
1254         send_message (panel, NULL, MSG_ACTION, CK_Down, NULL);
1255 
1256     recalculate_panel_summary (panel);
1257 
1258     if (panel->sort_field->sort_routine == (GCompareFunc) sort_size)
1259         panel_re_sort (panel);
1260 
1261     panel->dirty = TRUE;
1262 }
1263 
1264 /* --------------------------------------------------------------------------------------------- */
1265 
1266 void
1267 dirsizes_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
1268 {
1269     int i;
1270     dirsize_status_msg_t dsm;
1271 
1272     memset (&dsm, 0, sizeof (dsm));
1273     status_msg_init (STATUS_MSG (&dsm), _ ("Directory scanning"), 0, dirsize_status_init_cb,
1274                      dirsize_status_update_cb, dirsize_status_deinit_cb);
1275 
1276     for (i = 0; i < panel->dir.len; i++)
1277         if (S_ISDIR (panel->dir.list[i].st.st_mode)
1278             && ((panel->dirs_marked != 0 && panel->dir.list[i].f.marked != 0)
1279                 || panel->dirs_marked == 0)
1280             && !DIR_IS_DOTDOT (panel->dir.list[i].fname->str))
1281         {
1282             vfs_path_t *p;
1283             size_t dir_count = 0;
1284             size_t count = 0;
1285             uintmax_t total = 0;
1286             gboolean ok;
1287 
1288             p = vfs_path_from_str (panel->dir.list[i].fname->str);
1289             ok = compute_dir_size (p, &dsm, &dir_count, &count, &total, FALSE) != FILE_CONT;
1290             vfs_path_free (p, TRUE);
1291             if (ok)
1292                 break;
1293 
1294             panel->dir.list[i].st.st_size = (off_t) total;
1295             panel->dir.list[i].f.dir_size_computed = 1;
1296         }
1297 
1298     status_msg_deinit (STATUS_MSG (&dsm));
1299 
1300     recalculate_panel_summary (panel);
1301 
1302     if (panel->sort_field->sort_routine == (GCompareFunc) sort_size)
1303         panel_re_sort (panel);
1304 
1305     panel->dirty = TRUE;
1306 }
1307 
1308 /* --------------------------------------------------------------------------------------------- */
1309 
1310 void
1311 save_setup_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1312 {
1313     vfs_path_t *vpath;
1314     const char *path;
1315 
1316     vpath = vfs_path_from_str_flags (mc_config_get_path (), VPF_STRIP_HOME);
1317     path = vfs_path_as_str (vpath);
1318 
1319     if (save_setup (TRUE, TRUE))
1320         message (D_NORMAL, _ ("Setup"), _ ("Setup saved to %s"), path);
1321     else
1322         message (D_ERROR, _ ("Setup"), _ ("Unable to save setup to %s"), path);
1323 
1324     vfs_path_free (vpath, TRUE);
1325 }
1326 
1327 /* --------------------------------------------------------------------------------------------- */
1328 
1329 void
1330 info_cmd_no_menu (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1331 {
1332     if (get_panel_type (0) == view_info)
1333         create_panel (0, view_listing);
1334     else if (get_panel_type (1) == view_info)
1335         create_panel (1, view_listing);
1336     else
1337         create_panel (current_panel == left_panel ? 1 : 0, view_info);
1338 }
1339 
1340 /* --------------------------------------------------------------------------------------------- */
1341 
1342 void
1343 quick_cmd_no_menu (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1344 {
1345     if (get_panel_type (0) == view_quick)
1346         create_panel (0, view_listing);
1347     else if (get_panel_type (1) == view_quick)
1348         create_panel (1, view_listing);
1349     else
1350         create_panel (current_panel == left_panel ? 1 : 0, view_quick);
1351 }
1352 
1353 /* --------------------------------------------------------------------------------------------- */
1354 
1355 void
1356 listing_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1357 {
1358     WPanel *p;
1359 
1360     switch_to_listing (MENU_PANEL_IDX);
1361 
1362     p = PANEL (get_panel_widget (MENU_PANEL_IDX));
1363 
1364     p->is_panelized = FALSE;
1365     panel_set_filter (p, NULL);  // including panel reload
1366 }
1367 
1368 /* --------------------------------------------------------------------------------------------- */
1369 
1370 void
1371 setup_listing_format_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1372 {
1373     int list_format;
1374     gboolean use_msformat;
1375     int brief_cols;
1376     char *user, *status;
1377     WPanel *p = NULL;
1378 
1379     if (SELECTED_IS_PANEL)
1380         p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1381 
1382     list_format = panel_listing_box (p, MENU_PANEL_IDX, &user, &status, &use_msformat, &brief_cols);
1383     if (list_format != -1)
1384     {
1385         switch_to_listing (MENU_PANEL_IDX);
1386         p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1387         configure_panel_listing (p, list_format, brief_cols, use_msformat, &user, &status);
1388         g_free (user);
1389         g_free (status);
1390     }
1391 }
1392 
1393 /* --------------------------------------------------------------------------------------------- */
1394 
1395 void
1396 panel_tree_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1397 {
1398     create_panel (MENU_PANEL_IDX, view_tree);
1399 }
1400 
1401 /* --------------------------------------------------------------------------------------------- */
1402 
1403 void
1404 info_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1405 {
1406     create_panel (MENU_PANEL_IDX, view_info);
1407 }
1408 
1409 /* --------------------------------------------------------------------------------------------- */
1410 
1411 void
1412 quick_view_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1413 {
1414     if (PANEL (get_panel_widget (MENU_PANEL_IDX)) == current_panel)
1415         (void) change_panel ();
1416     create_panel (MENU_PANEL_IDX, view_quick);
1417 }
1418 
1419 /* --------------------------------------------------------------------------------------------- */
1420 
1421 void
1422 encoding_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1423 {
1424     if (SELECTED_IS_PANEL)
1425         panel_change_encoding (MENU_PANEL);
1426 }
1427 
1428 /* --------------------------------------------------------------------------------------------- */

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