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. undelete_cmd
  36. quick_cd_cmd
  37. smart_dirsize_cmd
  38. single_dirsize_cmd
  39. dirsizes_cmd
  40. save_setup_cmd
  41. info_cmd_no_menu
  42. quick_cmd_no_menu
  43. listing_cmd
  44. setup_listing_format_cmd
  45. panel_tree_cmd
  46. info_cmd
  47. quick_view_cmd
  48. encoding_cmd

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

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