Manual pages: mc • mcdiff • mcedit • mcview

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

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