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, n1) != 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 #ifdef HAVE_CHARSET
 732     mc_global.source_codepage = default_source_codepage;
 733 #endif
 734     do_edit (fname_vpath);
 735 
 736     vfs_path_free (fname_vpath, TRUE);
 737 }
 738 
 739 /* --------------------------------------------------------------------------------------------- */
 740 
 741 void
 742 mkdir_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 743 {
 744     const file_entry_t *fe;
 745     char *dir;
 746     const char *name = "";
 747 
 748     fe = panel_current_entry (panel);
 749     if (fe == NULL)
 750         return;
 751 
 752     // If 'on' then automatically fills name with current item name
 753     if (auto_fill_mkdir_name && !DIR_IS_DOTDOT (fe->fname->str))
 754         name = fe->fname->str;
 755 
 756     dir = input_expand_dialog (_ ("Create a new Directory"), _ ("Enter directory name:"),
 757                                MC_HISTORY_FM_MKDIR, name, INPUT_COMPLETE_FILENAMES);
 758 
 759     if (dir != NULL && *dir != '\0')
 760     {
 761         vfs_path_t *absdir;
 762 
 763         if (IS_PATH_SEP (dir[0]) || dir[0] == '~')
 764             absdir = vfs_path_from_str (dir);
 765         else
 766         {
 767             // possible escaped '~'
 768             // allow create directory with name '~'
 769             char *tmpdir = dir;
 770 
 771             if (dir[0] == '\\' && dir[1] == '~')
 772                 tmpdir = dir + 1;
 773 
 774             absdir = vfs_path_append_new (panel->cwd_vpath, tmpdir, (char *) NULL);
 775         }
 776 
 777         save_cwds_stat ();
 778 
 779         if (my_mkdir (absdir, 0777) != 0)
 780             message (D_ERROR, MSG_ERROR, "%s", unix_error_string (errno));
 781         else
 782         {
 783             update_panels (UP_OPTIMIZE, dir);
 784             repaint_screen ();
 785             select_item (panel);
 786         }
 787 
 788         vfs_path_free (absdir, TRUE);
 789     }
 790     g_free (dir);
 791 }
 792 
 793 /* --------------------------------------------------------------------------------------------- */
 794 
 795 void
 796 reread_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 797 {
 798     panel_update_flags_t flag = UP_ONLY_CURRENT;
 799 
 800     if (get_current_type () == view_listing && get_other_type () == view_listing
 801         && vfs_path_equal (current_panel->cwd_vpath, other_panel->cwd_vpath))
 802         flag = UP_OPTIMIZE;
 803 
 804     update_panels (UP_RELOAD | flag, UP_KEEPSEL);
 805     repaint_screen ();
 806 }
 807 
 808 /* --------------------------------------------------------------------------------------------- */
 809 
 810 void
 811 ext_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 812 {
 813     vfs_path_t *extdir_vpath;
 814     int dir = 0;
 815 
 816     if (geteuid () == 0)
 817         dir = query_dialog (_ ("Extension file edit"), _ ("Which extension file you want to edit?"),
 818                             D_NORMAL, 2, _ ("&User"), _ ("&System Wide"));
 819 
 820     extdir_vpath = vfs_path_build_filename (mc_global.sysconfig_dir, MC_EXT_FILE, (char *) NULL);
 821 
 822     if (dir == 0)
 823     {
 824         vfs_path_t *buffer_vpath;
 825 
 826         buffer_vpath = mc_config_get_full_vpath (MC_EXT_FILE);
 827         check_for_default (extdir_vpath, buffer_vpath);
 828         do_edit (buffer_vpath);
 829         vfs_path_free (buffer_vpath, TRUE);
 830     }
 831     else if (dir == 1)
 832     {
 833         if (!exist_file (vfs_path_get_last_path_str (extdir_vpath)))
 834         {
 835             vfs_path_free (extdir_vpath, TRUE);
 836             extdir_vpath =
 837                 vfs_path_build_filename (mc_global.share_data_dir, MC_EXT_FILE, (char *) NULL);
 838         }
 839         do_edit (extdir_vpath);
 840     }
 841 
 842     vfs_path_free (extdir_vpath, TRUE);
 843     flush_extension_file ();
 844 }
 845 
 846 /* --------------------------------------------------------------------------------------------- */
 847 /** edit file menu for mc */
 848 
 849 void
 850 edit_mc_menu_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 851 {
 852     vfs_path_t *buffer_vpath;
 853     vfs_path_t *menufile_vpath;
 854     int dir = 0;
 855 
 856     query_set_sel (1);
 857     dir = query_dialog (_ ("Menu edit"), _ ("Which menu file do you want to edit?"), D_NORMAL,
 858                         geteuid () ? 2 : 3, _ ("&Local"), _ ("&User"), _ ("&System Wide"));
 859 
 860     menufile_vpath =
 861         vfs_path_build_filename (mc_global.sysconfig_dir, MC_GLOBAL_MENU, (char *) NULL);
 862 
 863     if (!exist_file (vfs_path_get_last_path_str (menufile_vpath)))
 864     {
 865         vfs_path_free (menufile_vpath, TRUE);
 866         menufile_vpath =
 867             vfs_path_build_filename (mc_global.share_data_dir, MC_GLOBAL_MENU, (char *) NULL);
 868     }
 869 
 870     switch (dir)
 871     {
 872     case 0:
 873         buffer_vpath = vfs_path_from_str (MC_LOCAL_MENU);
 874         check_for_default (menufile_vpath, buffer_vpath);
 875         chmod (vfs_path_get_last_path_str (buffer_vpath), 0600);
 876         break;
 877 
 878     case 1:
 879         buffer_vpath = mc_config_get_full_vpath (MC_USERMENU_FILE);
 880         check_for_default (menufile_vpath, buffer_vpath);
 881         break;
 882 
 883     case 2:
 884         buffer_vpath =
 885             vfs_path_build_filename (mc_global.sysconfig_dir, MC_GLOBAL_MENU, (char *) NULL);
 886         if (!exist_file (vfs_path_get_last_path_str (buffer_vpath)))
 887         {
 888             vfs_path_free (buffer_vpath, TRUE);
 889             buffer_vpath =
 890                 vfs_path_build_filename (mc_global.share_data_dir, MC_GLOBAL_MENU, (char *) NULL);
 891         }
 892         break;
 893 
 894     default:
 895         vfs_path_free (menufile_vpath, TRUE);
 896         return;
 897     }
 898 
 899     do_edit (buffer_vpath);
 900 
 901     vfs_path_free (buffer_vpath, TRUE);
 902     vfs_path_free (menufile_vpath, TRUE);
 903 }
 904 
 905 /* --------------------------------------------------------------------------------------------- */
 906 
 907 void
 908 edit_fhl_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 909 {
 910     vfs_path_t *fhlfile_vpath = NULL;
 911     int dir = 0;
 912 
 913     if (geteuid () == 0)
 914         dir = query_dialog (_ ("Highlighting groups file edit"),
 915                             _ ("Which highlighting file you want to edit?"), D_NORMAL, 2,
 916                             _ ("&User"), _ ("&System Wide"));
 917 
 918     fhlfile_vpath =
 919         vfs_path_build_filename (mc_global.sysconfig_dir, MC_FHL_INI_FILE, (char *) NULL);
 920 
 921     if (dir == 0)
 922     {
 923         vfs_path_t *buffer_vpath;
 924 
 925         buffer_vpath = mc_config_get_full_vpath (MC_FHL_INI_FILE);
 926         check_for_default (fhlfile_vpath, buffer_vpath);
 927         do_edit (buffer_vpath);
 928         vfs_path_free (buffer_vpath, TRUE);
 929     }
 930     else if (dir == 1)
 931     {
 932         if (!exist_file (vfs_path_get_last_path_str (fhlfile_vpath)))
 933         {
 934             vfs_path_free (fhlfile_vpath, TRUE);
 935             fhlfile_vpath =
 936                 vfs_path_build_filename (mc_global.sysconfig_dir, MC_FHL_INI_FILE, (char *) NULL);
 937         }
 938         do_edit (fhlfile_vpath);
 939     }
 940 
 941     vfs_path_free (fhlfile_vpath, TRUE);
 942     // refresh highlighting rules
 943     mc_fhl_free (&mc_filehighlight);
 944     mc_filehighlight = mc_fhl_new (TRUE);
 945 }
 946 
 947 /* --------------------------------------------------------------------------------------------- */
 948 
 949 void
 950 hotlist_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 951 {
 952     char *target;
 953 
 954     target = hotlist_show (LIST_HOTLIST, panel);
 955     if (target == NULL)
 956         return;
 957 
 958     if (get_current_type () == view_tree)
 959     {
 960         vfs_path_t *vpath;
 961 
 962         vpath = vfs_path_from_str (target);
 963         tree_chdir (the_tree, vpath);
 964         vfs_path_free (vpath, TRUE);
 965     }
 966     else
 967     {
 968         vfs_path_t *deprecated_vpath;
 969         const char *deprecated_path;
 970 
 971         deprecated_vpath = vfs_path_from_str_flags (target, VPF_USE_DEPRECATED_PARSER);
 972         deprecated_path = vfs_path_as_str (deprecated_vpath);
 973         cd_to (deprecated_path);
 974         vfs_path_free (deprecated_vpath, TRUE);
 975     }
 976 
 977     g_free (target);
 978 }
 979 
 980 /* --------------------------------------------------------------------------------------------- */
 981 
 982 #ifdef ENABLE_VFS
 983 void
 984 vfs_list (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 985 {
 986     char *target;
 987     vfs_path_t *target_vpath;
 988 
 989     target = hotlist_show (LIST_VFSLIST, panel);
 990     if (target == NULL)
 991         return;
 992 
 993     target_vpath = vfs_path_from_str (target);
 994     if (!panel_cd (current_panel, target_vpath, cd_exact))
 995         cd_error_message (target);
 996     vfs_path_free (target_vpath, TRUE);
 997     g_free (target);
 998 }
 999 #endif
1000 
1001 /* --------------------------------------------------------------------------------------------- */
1002 
1003 void
1004 compare_dirs_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1005 {
1006     int choice;
1007     enum CompareMode thorough_flag;
1008 
1009     choice = query_dialog (_ ("Compare directories"), _ ("Select compare method:"), D_NORMAL, 4,
1010                            _ ("&Quick"), _ ("&Size only"), _ ("&Thorough"), _ ("&Cancel"));
1011 
1012     if (choice < 0 || choice > 2)
1013         return;
1014 
1015     thorough_flag = choice;
1016 
1017     if (get_current_type () == view_listing && get_other_type () == view_listing)
1018     {
1019         compare_dir (current_panel, other_panel, thorough_flag);
1020         compare_dir (other_panel, current_panel, thorough_flag);
1021     }
1022     else
1023         message (D_ERROR, MSG_ERROR,
1024                  _ ("Both panels should be in the listing mode\nto use this command"));
1025 }
1026 
1027 /* --------------------------------------------------------------------------------------------- */
1028 
1029 #ifdef USE_DIFF_VIEW
1030 void
1031 diff_view_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1032 {
1033     // both panels must be in the list mode
1034     if (get_current_type () == view_listing && get_other_type () == view_listing)
1035     {
1036         if (get_current_index () == 0)
1037             dview_diff_cmd (current_panel, other_panel);
1038         else
1039             dview_diff_cmd (other_panel, current_panel);
1040 
1041         if (mc_global.mc_run_mode == MC_RUN_FULL)
1042             update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1043 
1044         dialog_switch_process_pending ();
1045     }
1046 }
1047 #endif
1048 
1049 /* --------------------------------------------------------------------------------------------- */
1050 
1051 void
1052 swap_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1053 {
1054     swap_panels ();
1055     tty_touch_screen ();
1056     repaint_screen ();
1057 }
1058 
1059 /* --------------------------------------------------------------------------------------------- */
1060 
1061 void
1062 link_cmd (link_type_t link_type)
     /* [previous][next][first][last][top][bottom][index][help]  */
1063 {
1064     const file_entry_t *fe;
1065 
1066     fe = panel_current_entry (current_panel);
1067     if (fe != NULL)
1068         do_link (link_type, fe->fname->str);
1069 }
1070 
1071 /* --------------------------------------------------------------------------------------------- */
1072 
1073 void
1074 edit_symlink_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1075 {
1076     const file_entry_t *fe;
1077     const char *p;
1078 
1079     fe = panel_current_entry (current_panel);
1080     if (fe == NULL)
1081         return;
1082 
1083     p = fe->fname->str;
1084 
1085     if (!S_ISLNK (fe->st.st_mode))
1086         message (D_ERROR, MSG_ERROR, _ ("'%s' is not a symbolic link"), p);
1087     else
1088     {
1089         char buffer[MC_MAXPATHLEN];
1090         int i;
1091 
1092         i = readlink (p, buffer, sizeof (buffer) - 1);
1093         if (i > 0)
1094         {
1095             char *q, *dest;
1096 
1097             buffer[i] = '\0';
1098 
1099             q = g_strdup_printf (_ ("Symlink '%s\' points to:"), str_trunc (p, 32));
1100             dest = input_expand_dialog (_ ("Edit symlink"), q, MC_HISTORY_FM_EDIT_LINK, buffer,
1101                                         INPUT_COMPLETE_FILENAMES);
1102             g_free (q);
1103 
1104             if (dest != NULL && *dest != '\0' && strcmp (buffer, dest) != 0)
1105             {
1106                 vfs_path_t *p_vpath;
1107 
1108                 p_vpath = vfs_path_from_str (p);
1109 
1110                 save_cwds_stat ();
1111 
1112                 if (mc_unlink (p_vpath) == -1)
1113                     message (D_ERROR, MSG_ERROR, _ ("edit symlink, unable to remove %s: %s"), p,
1114                              unix_error_string (errno));
1115                 else
1116                 {
1117                     vfs_path_t *dest_vpath;
1118 
1119                     dest_vpath = vfs_path_from_str_flags (dest, VPF_NO_CANON);
1120                     if (mc_symlink (dest_vpath, p_vpath) == -1)
1121                         message (D_ERROR, MSG_ERROR, _ ("edit symlink: %s"),
1122                                  unix_error_string (errno));
1123                     vfs_path_free (dest_vpath, TRUE);
1124                 }
1125 
1126                 vfs_path_free (p_vpath, TRUE);
1127 
1128                 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1129                 repaint_screen ();
1130             }
1131 
1132             g_free (dest);
1133         }
1134     }
1135 }
1136 
1137 /* --------------------------------------------------------------------------------------------- */
1138 
1139 void
1140 help_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1141 {
1142     ev_help_t event_data = { NULL, NULL };
1143 
1144     if (current_panel->quick_search.active)
1145         event_data.node = "[Quick search]";
1146     else
1147         event_data.node = "[main]";
1148 
1149     mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
1150 }
1151 
1152 /* --------------------------------------------------------------------------------------------- */
1153 
1154 #ifdef ENABLE_VFS_FTP
1155 void
1156 ftplink_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1157 {
1158     nice_cd (_ ("FTP to machine"), _ (machine_str), "[FTP File System]",
1159              ":ftplink_cmd: FTP to machine ", "ftp://", 1, TRUE);
1160 }
1161 #endif
1162 
1163 /* --------------------------------------------------------------------------------------------- */
1164 
1165 #ifdef ENABLE_VFS_SFTP
1166 void
1167 sftplink_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1168 {
1169     nice_cd (_ ("SFTP to machine"), _ (machine_str),
1170              "[SFTP (SSH File Transfer Protocol) filesystem]", ":sftplink_cmd: SFTP to machine ",
1171              "sftp://", 1, TRUE);
1172 }
1173 #endif
1174 
1175 /* --------------------------------------------------------------------------------------------- */
1176 
1177 #ifdef ENABLE_VFS_SHELL
1178 void
1179 shelllink_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1180 {
1181     nice_cd (_ ("Shell link to machine"), _ (machine_str), "[FIle transfer over SHell filesystem]",
1182              ":fishlink_cmd: Shell link to machine ", "sh://", 1, TRUE);
1183 }
1184 #endif
1185 
1186 /* --------------------------------------------------------------------------------------------- */
1187 
1188 #ifdef ENABLE_VFS_UNDELFS
1189 void
1190 undelete_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1191 {
1192     nice_cd (_ ("Undelete files on an ext2 file system"),
1193              _ ("Enter device (without /dev/) to undelete\nfiles on: (F1 for details)"),
1194              "[Undelete File System]", ":undelete_cmd: Undel on ext2 fs ", "undel://", 0, FALSE);
1195 }
1196 #endif
1197 
1198 /* --------------------------------------------------------------------------------------------- */
1199 
1200 void
1201 quick_cd_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
1202 {
1203     char *p;
1204 
1205     p = cd_box (panel);
1206     if (p != NULL && *p != '\0')
1207         cd_to (p);
1208     g_free (p);
1209 }
1210 
1211 /* --------------------------------------------------------------------------------------------- */
1212 /*!
1213    \brief calculate dirs sizes
1214 
1215    calculate dirs sizes and resort panel:
1216    dirs_selected = show size for selected dirs,
1217    otherwise = show size for dir under cursor:
1218    dir under cursor ".." = show size for all dirs,
1219    otherwise = show size for dir under cursor
1220  */
1221 
1222 void
1223 smart_dirsize_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
1224 {
1225     const file_entry_t *entry;
1226 
1227     entry = panel_current_entry (panel);
1228     if ((entry != NULL && S_ISDIR (entry->st.st_mode) && DIR_IS_DOTDOT (entry->fname->str))
1229         || panel->dirs_marked)
1230         dirsizes_cmd (panel);
1231     else
1232         single_dirsize_cmd (panel);
1233 }
1234 
1235 /* --------------------------------------------------------------------------------------------- */
1236 
1237 void
1238 single_dirsize_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
1239 {
1240     file_entry_t *entry;
1241 
1242     entry = panel_current_entry (panel);
1243 
1244     if (entry != NULL && S_ISDIR (entry->st.st_mode) && !DIR_IS_DOTDOT (entry->fname->str))
1245     {
1246         size_t dir_count = 0;
1247         size_t count = 0;
1248         uintmax_t total = 0;
1249         dirsize_status_msg_t dsm;
1250         vfs_path_t *p;
1251 
1252         p = vfs_path_from_str (entry->fname->str);
1253 
1254         memset (&dsm, 0, sizeof (dsm));
1255         status_msg_init (STATUS_MSG (&dsm), _ ("Directory scanning"), 0, dirsize_status_init_cb,
1256                          dirsize_status_update_cb, dirsize_status_deinit_cb);
1257 
1258         if (compute_dir_size (p, &dsm, &dir_count, &count, &total, FALSE) == FILE_CONT)
1259         {
1260             entry->st.st_size = (off_t) total;
1261             entry->f.dir_size_computed = 1;
1262         }
1263 
1264         vfs_path_free (p, TRUE);
1265 
1266         status_msg_deinit (STATUS_MSG (&dsm));
1267     }
1268 
1269     if (panels_options.mark_moves_down)
1270         send_message (panel, NULL, MSG_ACTION, CK_Down, NULL);
1271 
1272     recalculate_panel_summary (panel);
1273 
1274     if (panel->sort_field->sort_routine == (GCompareFunc) sort_size)
1275         panel_re_sort (panel);
1276 
1277     panel->dirty = TRUE;
1278 }
1279 
1280 /* --------------------------------------------------------------------------------------------- */
1281 
1282 void
1283 dirsizes_cmd (WPanel *panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
1284 {
1285     int i;
1286     dirsize_status_msg_t dsm;
1287 
1288     memset (&dsm, 0, sizeof (dsm));
1289     status_msg_init (STATUS_MSG (&dsm), _ ("Directory scanning"), 0, dirsize_status_init_cb,
1290                      dirsize_status_update_cb, dirsize_status_deinit_cb);
1291 
1292     for (i = 0; i < panel->dir.len; i++)
1293         if (S_ISDIR (panel->dir.list[i].st.st_mode)
1294             && ((panel->dirs_marked != 0 && panel->dir.list[i].f.marked != 0)
1295                 || panel->dirs_marked == 0)
1296             && !DIR_IS_DOTDOT (panel->dir.list[i].fname->str))
1297         {
1298             vfs_path_t *p;
1299             size_t dir_count = 0;
1300             size_t count = 0;
1301             uintmax_t total = 0;
1302             gboolean ok;
1303 
1304             p = vfs_path_from_str (panel->dir.list[i].fname->str);
1305             ok = compute_dir_size (p, &dsm, &dir_count, &count, &total, FALSE) != FILE_CONT;
1306             vfs_path_free (p, TRUE);
1307             if (ok)
1308                 break;
1309 
1310             panel->dir.list[i].st.st_size = (off_t) total;
1311             panel->dir.list[i].f.dir_size_computed = 1;
1312         }
1313 
1314     status_msg_deinit (STATUS_MSG (&dsm));
1315 
1316     recalculate_panel_summary (panel);
1317 
1318     if (panel->sort_field->sort_routine == (GCompareFunc) sort_size)
1319         panel_re_sort (panel);
1320 
1321     panel->dirty = TRUE;
1322 }
1323 
1324 /* --------------------------------------------------------------------------------------------- */
1325 
1326 void
1327 save_setup_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1328 {
1329     vfs_path_t *vpath;
1330     const char *path;
1331 
1332     vpath = vfs_path_from_str_flags (mc_config_get_path (), VPF_STRIP_HOME);
1333     path = vfs_path_as_str (vpath);
1334 
1335     if (save_setup (TRUE, TRUE))
1336         message (D_NORMAL, _ ("Setup"), _ ("Setup saved to %s"), path);
1337     else
1338         message (D_ERROR, _ ("Setup"), _ ("Unable to save setup to %s"), path);
1339 
1340     vfs_path_free (vpath, TRUE);
1341 }
1342 
1343 /* --------------------------------------------------------------------------------------------- */
1344 
1345 void
1346 info_cmd_no_menu (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1347 {
1348     if (get_panel_type (0) == view_info)
1349         create_panel (0, view_listing);
1350     else if (get_panel_type (1) == view_info)
1351         create_panel (1, view_listing);
1352     else
1353         create_panel (current_panel == left_panel ? 1 : 0, view_info);
1354 }
1355 
1356 /* --------------------------------------------------------------------------------------------- */
1357 
1358 void
1359 quick_cmd_no_menu (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1360 {
1361     if (get_panel_type (0) == view_quick)
1362         create_panel (0, view_listing);
1363     else if (get_panel_type (1) == view_quick)
1364         create_panel (1, view_listing);
1365     else
1366         create_panel (current_panel == left_panel ? 1 : 0, view_quick);
1367 }
1368 
1369 /* --------------------------------------------------------------------------------------------- */
1370 
1371 void
1372 listing_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1373 {
1374     WPanel *p;
1375 
1376     switch_to_listing (MENU_PANEL_IDX);
1377 
1378     p = PANEL (get_panel_widget (MENU_PANEL_IDX));
1379 
1380     p->is_panelized = FALSE;
1381     panel_set_filter (p, NULL);  // including panel reload
1382 }
1383 
1384 /* --------------------------------------------------------------------------------------------- */
1385 
1386 void
1387 setup_listing_format_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1388 {
1389     int list_format;
1390     gboolean use_msformat;
1391     int brief_cols;
1392     char *user, *status;
1393     WPanel *p = NULL;
1394 
1395     if (SELECTED_IS_PANEL)
1396         p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1397 
1398     list_format = panel_listing_box (p, MENU_PANEL_IDX, &user, &status, &use_msformat, &brief_cols);
1399     if (list_format != -1)
1400     {
1401         switch_to_listing (MENU_PANEL_IDX);
1402         p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1403         configure_panel_listing (p, list_format, brief_cols, use_msformat, &user, &status);
1404         g_free (user);
1405         g_free (status);
1406     }
1407 }
1408 
1409 /* --------------------------------------------------------------------------------------------- */
1410 
1411 void
1412 panel_tree_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1413 {
1414     create_panel (MENU_PANEL_IDX, view_tree);
1415 }
1416 
1417 /* --------------------------------------------------------------------------------------------- */
1418 
1419 void
1420 info_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1421 {
1422     create_panel (MENU_PANEL_IDX, view_info);
1423 }
1424 
1425 /* --------------------------------------------------------------------------------------------- */
1426 
1427 void
1428 quick_view_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1429 {
1430     if (PANEL (get_panel_widget (MENU_PANEL_IDX)) == current_panel)
1431         (void) change_panel ();
1432     create_panel (MENU_PANEL_IDX, view_quick);
1433 }
1434 
1435 /* --------------------------------------------------------------------------------------------- */
1436 
1437 #ifdef HAVE_CHARSET
1438 void
1439 encoding_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1440 {
1441     if (SELECTED_IS_PANEL)
1442         panel_change_encoding (MENU_PANEL);
1443 }
1444 #endif
1445 
1446 /* --------------------------------------------------------------------------------------------- */

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