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()
  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             message (D_ERROR, MSG_ERROR, _ ("link: %s"), unix_error_string (errno));
 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             message (D_ERROR, MSG_ERROR, _ ("symlink: %s"), unix_error_string (errno));
 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             message (D_ERROR, MSG_ERROR, "%s", unix_error_string (errno));
 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                     message (D_ERROR, MSG_ERROR, _ ("edit symlink, unable to remove %s: %s"), p,
1112                              unix_error_string (errno));
1113                 else
1114                 {
1115                     vfs_path_t *dest_vpath;
1116 
1117                     dest_vpath = vfs_path_from_str_flags (dest, VPF_NO_CANON);
1118                     if (mc_symlink (dest_vpath, p_vpath) == -1)
1119                         message (D_ERROR, MSG_ERROR, _ ("edit symlink: %s"),
1120                                  unix_error_string (errno));
1121                     vfs_path_free (dest_vpath, TRUE);
1122                 }
1123 
1124                 vfs_path_free (p_vpath, TRUE);
1125 
1126                 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1127                 repaint_screen ();
1128             }
1129 
1130             g_free (dest);
1131         }
1132     }
1133 }
1134 
1135 /* --------------------------------------------------------------------------------------------- */
1136 
1137 void
1138 help_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1139 {
1140     ev_help_t event_data = { NULL, NULL };
1141 
1142     if (current_panel->quick_search.active)
1143         event_data.node = "[Quick search]";
1144     else
1145         event_data.node = "[main]";
1146 
1147     mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
1148 }
1149 
1150 /* --------------------------------------------------------------------------------------------- */
1151 
1152 #ifdef ENABLE_VFS_FTP
1153 void
1154 ftplink_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1155 {
1156     nice_cd (_ ("FTP to machine"), _ (machine_str), "[FTP File System]",
1157              ":ftplink_cmd: FTP to machine ", "ftp://", 1, TRUE);
1158 }
1159 #endif
1160 
1161 /* --------------------------------------------------------------------------------------------- */
1162 
1163 #ifdef ENABLE_VFS_SFTP
1164 void
1165 sftplink_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1166 {
1167     nice_cd (_ ("SFTP to machine"), _ (machine_str),
1168              "[SFTP (SSH File Transfer Protocol) filesystem]", ":sftplink_cmd: SFTP to machine ",
1169              "sftp://", 1, TRUE);
1170 }
1171 #endif
1172 
1173 /* --------------------------------------------------------------------------------------------- */
1174 
1175 #ifdef ENABLE_VFS_SHELL
1176 void
1177 shelllink_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1178 {
1179     nice_cd (_ ("Shell link to machine"), _ (machine_str), "[FIle transfer over SHell filesystem]",
1180              ":fishlink_cmd: Shell link to machine ", "sh://", 1, TRUE);
1181 }
1182 #endif
1183 
1184 /* --------------------------------------------------------------------------------------------- */
1185 
1186 #ifdef ENABLE_VFS_UNDELFS
1187 void
1188 undelete_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1189 {
1190     nice_cd (_ ("Undelete files on an ext2 file system"),
1191              _ ("Enter device (without /dev/) to undelete\nfiles on: (F1 for details)"),
1192              "[Undelete File System]", ":undelete_cmd: Undel on ext2 fs ", "undel://", 0, FALSE);
1193 }
1194 #endif
1195 
1196 /* --------------------------------------------------------------------------------------------- */
1197 
1198 void
1199 quick_cd_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
1200 {
1201     char *p;
1202 
1203     p = cd_box (panel);
1204     if (p != NULL && *p != '\0')
1205         cd_to (p);
1206     g_free (p);
1207 }
1208 
1209 /* --------------------------------------------------------------------------------------------- */
1210 /*!
1211    \brief calculate dirs sizes
1212 
1213    calculate dirs sizes and resort panel:
1214    dirs_selected = show size for selected dirs,
1215    otherwise = show size for dir under cursor:
1216    dir under cursor ".." = show size for all dirs,
1217    otherwise = show size for dir under cursor
1218  */
1219 
1220 void
1221 smart_dirsize_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
1222 {
1223     const file_entry_t *entry;
1224 
1225     entry = panel_current_entry (panel);
1226     if ((entry != NULL && S_ISDIR (entry->st.st_mode) && DIR_IS_DOTDOT (entry->fname->str))
1227         || panel->dirs_marked)
1228         dirsizes_cmd (panel);
1229     else
1230         single_dirsize_cmd (panel);
1231 }
1232 
1233 /* --------------------------------------------------------------------------------------------- */
1234 
1235 void
1236 single_dirsize_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
1237 {
1238     file_entry_t *entry;
1239 
1240     entry = panel_current_entry (panel);
1241 
1242     if (entry != NULL && S_ISDIR (entry->st.st_mode) && !DIR_IS_DOTDOT (entry->fname->str))
1243     {
1244         size_t dir_count = 0;
1245         size_t count = 0;
1246         uintmax_t total = 0;
1247         dirsize_status_msg_t dsm;
1248         vfs_path_t *p;
1249 
1250         p = vfs_path_from_str (entry->fname->str);
1251 
1252         memset (&dsm, 0, sizeof (dsm));
1253         status_msg_init (STATUS_MSG (&dsm), _ ("Directory scanning"), 0, dirsize_status_init_cb,
1254                          dirsize_status_update_cb, dirsize_status_deinit_cb);
1255 
1256         if (compute_dir_size (p, &dsm, &dir_count, &count, &total, FALSE) == FILE_CONT)
1257         {
1258             entry->st.st_size = (off_t) total;
1259             entry->f.dir_size_computed = 1;
1260         }
1261 
1262         vfs_path_free (p, TRUE);
1263 
1264         status_msg_deinit (STATUS_MSG (&dsm));
1265     }
1266 
1267     if (panels_options.mark_moves_down)
1268         send_message (panel, NULL, MSG_ACTION, CK_Down, NULL);
1269 
1270     recalculate_panel_summary (panel);
1271 
1272     if (panel->sort_field->sort_routine == (GCompareFunc) sort_size)
1273         panel_re_sort (panel);
1274 
1275     panel->dirty = TRUE;
1276 }
1277 
1278 /* --------------------------------------------------------------------------------------------- */
1279 
1280 void
1281 dirsizes_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
1282 {
1283     int i;
1284     dirsize_status_msg_t dsm;
1285 
1286     memset (&dsm, 0, sizeof (dsm));
1287     status_msg_init (STATUS_MSG (&dsm), _ ("Directory scanning"), 0, dirsize_status_init_cb,
1288                      dirsize_status_update_cb, dirsize_status_deinit_cb);
1289 
1290     for (i = 0; i < panel->dir.len; i++)
1291         if (S_ISDIR (panel->dir.list[i].st.st_mode)
1292             && ((panel->dirs_marked != 0 && panel->dir.list[i].f.marked != 0)
1293                 || panel->dirs_marked == 0)
1294             && !DIR_IS_DOTDOT (panel->dir.list[i].fname->str))
1295         {
1296             vfs_path_t *p;
1297             size_t dir_count = 0;
1298             size_t count = 0;
1299             uintmax_t total = 0;
1300             gboolean ok;
1301 
1302             p = vfs_path_from_str (panel->dir.list[i].fname->str);
1303             ok = compute_dir_size (p, &dsm, &dir_count, &count, &total, FALSE) != FILE_CONT;
1304             vfs_path_free (p, TRUE);
1305             if (ok)
1306                 break;
1307 
1308             panel->dir.list[i].st.st_size = (off_t) total;
1309             panel->dir.list[i].f.dir_size_computed = 1;
1310         }
1311 
1312     status_msg_deinit (STATUS_MSG (&dsm));
1313 
1314     recalculate_panel_summary (panel);
1315 
1316     if (panel->sort_field->sort_routine == (GCompareFunc) sort_size)
1317         panel_re_sort (panel);
1318 
1319     panel->dirty = TRUE;
1320 }
1321 
1322 /* --------------------------------------------------------------------------------------------- */
1323 
1324 void
1325 save_setup_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1326 {
1327     vfs_path_t *vpath;
1328     const char *path;
1329 
1330     vpath = vfs_path_from_str_flags (mc_config_get_path (), VPF_STRIP_HOME);
1331     path = vfs_path_as_str (vpath);
1332 
1333     if (save_setup (TRUE, TRUE))
1334         message (D_NORMAL, _ ("Setup"), _ ("Setup saved to %s"), path);
1335     else
1336         message (D_ERROR, _ ("Setup"), _ ("Unable to save setup to %s"), path);
1337 
1338     vfs_path_free (vpath, TRUE);
1339 }
1340 
1341 /* --------------------------------------------------------------------------------------------- */
1342 
1343 void
1344 info_cmd_no_menu (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1345 {
1346     if (get_panel_type (0) == view_info)
1347         create_panel (0, view_listing);
1348     else if (get_panel_type (1) == view_info)
1349         create_panel (1, view_listing);
1350     else
1351         create_panel (current_panel == left_panel ? 1 : 0, view_info);
1352 }
1353 
1354 /* --------------------------------------------------------------------------------------------- */
1355 
1356 void
1357 quick_cmd_no_menu (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1358 {
1359     if (get_panel_type (0) == view_quick)
1360         create_panel (0, view_listing);
1361     else if (get_panel_type (1) == view_quick)
1362         create_panel (1, view_listing);
1363     else
1364         create_panel (current_panel == left_panel ? 1 : 0, view_quick);
1365 }
1366 
1367 /* --------------------------------------------------------------------------------------------- */
1368 
1369 void
1370 listing_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1371 {
1372     WPanel *p;
1373 
1374     switch_to_listing (MENU_PANEL_IDX);
1375 
1376     p = PANEL (get_panel_widget (MENU_PANEL_IDX));
1377 
1378     p->is_panelized = FALSE;
1379     panel_set_filter (p, NULL);  // including panel reload
1380 }
1381 
1382 /* --------------------------------------------------------------------------------------------- */
1383 
1384 void
1385 setup_listing_format_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1386 {
1387     int list_format;
1388     gboolean use_msformat;
1389     int brief_cols;
1390     char *user, *status;
1391     WPanel *p = NULL;
1392 
1393     if (SELECTED_IS_PANEL)
1394         p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1395 
1396     list_format = panel_listing_box (p, MENU_PANEL_IDX, &user, &status, &use_msformat, &brief_cols);
1397     if (list_format != -1)
1398     {
1399         switch_to_listing (MENU_PANEL_IDX);
1400         p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1401         configure_panel_listing (p, list_format, brief_cols, use_msformat, &user, &status);
1402         g_free (user);
1403         g_free (status);
1404     }
1405 }
1406 
1407 /* --------------------------------------------------------------------------------------------- */
1408 
1409 void
1410 panel_tree_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1411 {
1412     create_panel (MENU_PANEL_IDX, view_tree);
1413 }
1414 
1415 /* --------------------------------------------------------------------------------------------- */
1416 
1417 void
1418 info_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1419 {
1420     create_panel (MENU_PANEL_IDX, view_info);
1421 }
1422 
1423 /* --------------------------------------------------------------------------------------------- */
1424 
1425 void
1426 quick_view_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1427 {
1428     if (PANEL (get_panel_widget (MENU_PANEL_IDX)) == current_panel)
1429         (void) change_panel ();
1430     create_panel (MENU_PANEL_IDX, view_quick);
1431 }
1432 
1433 /* --------------------------------------------------------------------------------------------- */
1434 
1435 void
1436 encoding_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1437 {
1438     if (SELECTED_IS_PANEL)
1439         panel_change_encoding (MENU_PANEL);
1440 }
1441 
1442 /* --------------------------------------------------------------------------------------------- */

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