reactos/rosapps/mc/src/cmd.c
Steven Edwards e5c0c7185e Midnight Commander for Win32
svn path=/trunk/; revision=2456
2001-12-30 10:02:14 +00:00

1573 lines
35 KiB
C

/* Routines invoked by a function key
They normally operate on the current panel.
Copyright (C) 1994, 1995 Miguel de Icaza
Copyright (C) 1994, 1995 Janne Kukonlehto
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <config.h>
#ifdef __os2__
# define INCL_DOSFILEMGR
# define INCL_DOSMISC
# define INCL_DOSERROR
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "tty.h"
#include <stdio.h>
#include <stdlib.h> /* getenv (), rand */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#if defined (__MINGW32__) || defined(_MSC_VER)
#include <sys/time.h___>
#else
#include <time.h>
#endif
#include <malloc.h>
#include <string.h>
#include <fcntl.h> /* open, O_RDWR */
#include <errno.h>
#ifdef OS2_NT
# include <io.h>
#endif
#ifdef USE_NETCODE
#include <netdb.h>
#endif
#ifdef HAVE_MMAP
# include <sys/mman.h>
#endif
#include "mad.h"
#include "dir.h"
#include "util.h"
#include "panel.h"
#include "cmd.h" /* Our definitions */
#include "view.h" /* view() */
#include "dialog.h" /* query_dialog, message */
#include "file.h" /* the file operations */
#include "find.h" /* do_find */
#include "hotlist.h"
#include "tree.h"
#include "subshell.h" /* use_subshell */
#include "cons.saver.h"
#include "global.h"
#include "dlg.h" /* required by wtools.h */
#include "widget.h" /* required by wtools.h */
#include "wtools.h" /* listbox */
#include "command.h" /* for input_w */
#include "win.h" /* do_exit_ca_mode */
#include "layout.h" /* get_current/other_type */
#include "ext.h" /* regex_command */
#include "view.h" /* view */
#include "key.h" /* get_key_code */
#include "help.h" /* interactive_display */
#include "fs.h"
#include "boxes.h" /* cd_dialog */
#include "color.h"
#include "user.h"
#include "setup.h"
#include "x.h"
#include "profile.h"
#define MIDNIGHT
#ifdef USE_INTERNAL_EDIT
extern int edit (const char *file, int line);
#endif
#include "../vfs/vfs.h"
#define WANT_WIDGETS
#include "main.h" /* global variables, global functions */
#ifndef MAP_FILE
# define MAP_FILE 0
#endif
#ifdef HAVE_TK
# include "tkscreen.h"
#endif
/* If set and you don't have subshell support,then C-o will give you a shell */
int output_starts_shell = 0;
/* Source routing destination */
int source_route = 0;
/* If set, use the builtin editor */
int use_internal_edit = 1;
/* Ugly hack in order to distinguish between left and right panel in menubar */
int is_right;
#define MENU_PANEL_IDX (is_right ? 1 : 0)
#ifndef PORT_HAS_FILTER_CHANGED
# define x_filter_changed(p)
#endif
/* This is used since the parameter panel on some of the commands */
/* defined in this file may receive a 0 parameter if they are invoked */
/* The drop down menu */
WPanel *get_a_panel (WPanel *panel)
{
if (panel)
return panel;
if (get_current_type () == view_listing){
return cpanel;
} else
return other_panel;
}
/* view_file (filename, normal, internal)
*
* Inputs:
* filename: The file name to view
* plain_view: If set does not do any fancy pre-processing (no filtering) and
* always invokes the internal viewer.
* internal: If set uses the internal viewer, otherwise an external viewer.
*/
int view_file_at_line (char *filename, int plain_view, int internal, int start_line)
{
static char *viewer = 0;
int move_dir = 0;
if (plain_view) {
int changed_hex_mode = 0;
int changed_nroff_flag = 0;
int changed_magic_flag = 0;
altered_hex_mode = 0;
altered_nroff_flag = 0;
altered_magic_flag = 0;
if (default_hex_mode)
changed_hex_mode = 1;
if (default_nroff_flag)
changed_nroff_flag = 1;
if (default_magic_flag)
changed_magic_flag = 1;
default_hex_mode = 0;
default_nroff_flag = 0;
default_magic_flag = 0;
view (0, filename, &move_dir, start_line);
if (changed_hex_mode && !altered_hex_mode)
default_hex_mode = 1;
if (changed_nroff_flag && !altered_nroff_flag)
default_nroff_flag = 1;
if (changed_magic_flag && !altered_magic_flag)
default_magic_flag = 1;
repaint_screen ();
return move_dir;
}
if (internal){
char view_entry [32];
if (start_line != 0)
sprintf (view_entry, "View:%d", start_line);
else
strcpy (view_entry, "View");
if (!regex_command (filename, view_entry, NULL, &move_dir)){
view (0, filename, &move_dir, start_line);
repaint_screen ();
}
} else {
char *localcopy;
if (!viewer){
viewer = getenv ("PAGER");
if (!viewer)
viewer = "view";
}
/* The file may be a non local file, get a copy */
if (!vfs_file_is_local (filename)){
localcopy = mc_getlocalcopy (filename);
if (localcopy == NULL){
message (1, MSG_ERROR, _(" Can not fetch a local copy of %s "), filename);
return 0;
}
execute_internal (viewer, localcopy);
mc_ungetlocalcopy (filename, localcopy, 0);
} else
execute_internal (viewer, filename);
}
return move_dir;
}
int
view_file (char *filename, int plain_view, int internal)
{
return view_file_at_line (filename, plain_view, internal, 0);
}
/* scan_for_file (panel, idx, direction)
*
* Inputs:
* panel: pointer to the panel on which we operate
* idx: starting file.
* direction: 1, or -1
*/
static int scan_for_file (WPanel *panel, int idx, int direction)
{
int i = idx + direction;
while (i != idx){
if (i < 0)
i = panel->count - 1;
if (i == panel->count)
i = 0;
if (!S_ISDIR (panel->dir.list [i].buf.st_mode))
return i;
i += direction;
}
return i;
}
/* do_view: Invoked as the F3/F13 key. */
static void do_view_cmd (WPanel *panel, int normal)
{
int dir, file_idx;
panel = get_a_panel (panel);
/* Directories are viewed by changing to them */
if (S_ISDIR (selection (panel)->buf.st_mode) ||
link_isdir (selection (panel))){
if (confirm_view_dir && (panel->marked || panel->dirs_marked)){
if (query_dialog (_(" CD "), _("Files tagged, want to cd?"),
0, 2, _("&Yes"), _("&No")) == 1){
return;
}
}
do_cd (selection (panel)->fname, cd_exact);
return;
}
file_idx = panel->selected;
while (1) {
char *filename;
filename = panel->dir.list [file_idx].fname;
dir = view_file (filename, normal, use_internal_view);
if (dir == 0)
break;
file_idx = scan_for_file (panel, file_idx, dir);
}
}
void view_cmd (WPanel *panel)
{
do_view_cmd (panel, 0);
}
void view_simple_cmd (WPanel *panel)
{
do_view_cmd (panel, 1);
}
void filtered_view_cmd (WPanel *panel)
{
char *command;
panel = get_a_panel (panel);
command = input_dialog (_(" Filtered view "), _(" Filter command and arguments:"),
selection (panel)->fname);
if (!command)
return;
view (command, "", 0, 0);
free (command);
}
void filtered_view_cmd_cpanel (void)
{
filtered_view_cmd (cpanel);
}
void do_edit_at_line (const char *what, int start_line)
{
static char *editor = 0;
#ifdef USE_INTERNAL_EDIT
if (use_internal_edit){
edit (what, start_line);
reread_cmd ();
return;
}
#endif
if (!editor){
editor = getenv ("EDITOR");
if (!editor)
editor = get_default_editor ();
}
execute_internal (editor, what);
reread_cmd ();
}
void
do_edit (const char *what)
{
do_edit_at_line (what, 1);
}
void edit_cmd (WPanel *panel)
{
panel = get_a_panel(panel);
if (!regex_command (selection (panel)->fname, "Edit", NULL, 0))
do_edit (selection (panel)->fname);
}
void edit_cmd_new (WPanel *panel)
{
do_edit ("");
}
void copy_cmd (void)
{
save_cwds_stat ();
if (panel_operate (cpanel, OP_COPY, NULL)){
update_panels (UP_OPTIMIZE, UP_KEEPSEL);
repaint_screen ();
}
}
void ren_cmd (void)
{
save_cwds_stat ();
if (panel_operate (cpanel, OP_MOVE, NULL)){
update_panels (UP_OPTIMIZE, UP_KEEPSEL);
repaint_screen ();
}
}
void copymove_cmd_with_default (int copy, char *thedefault)
{
save_cwds_stat ();
if (panel_operate (cpanel, copy ? OP_COPY : OP_MOVE, thedefault)){
update_panels (UP_OPTIMIZE, UP_KEEPSEL);
repaint_screen ();
}
}
void mkdir_cmd (WPanel *panel)
{
char *dir;
panel = get_a_panel (panel);
dir = input_expand_dialog (_(" Mkdir "), _(" Enter directory name:") , "");
if (!dir)
return;
save_cwds_stat ();
if (my_mkdir (dir, 0777) == 0){
update_panels (UP_OPTIMIZE, dir);
repaint_screen ();
select_item (cpanel);
free (dir);
return;
}
free (dir);
message (1, MSG_ERROR, " %s ", unix_error_string (errno));
}
void delete_cmd (void)
{
save_cwds_stat ();
if (panel_operate (cpanel, OP_DELETE, NULL)){
update_panels (UP_OPTIMIZE, UP_KEEPSEL);
repaint_screen ();
}
}
void find_cmd (void)
{
do_find ();
}
void
set_panel_filter_to (WPanel *p, char *allocated_filter_string)
{
if (p->filter){
free (p->filter);
p->filter = 0;
}
if (!(allocated_filter_string [0] == '*' && allocated_filter_string [1] == 0))
p->filter = allocated_filter_string;
else
free (allocated_filter_string);
reread_cmd ();
x_filter_changed (p);
}
/* Set a given panel filter expression */
void set_panel_filter (WPanel *p)
{
char *reg_exp;
char *x;
x = p->filter ? p->filter : easy_patterns ? "*" : ".";
reg_exp = input_dialog (_(" Filter "), _(" Set expression for filtering filenames"), x);
if (!reg_exp)
return;
set_panel_filter_to (p, reg_exp);
}
/* Invoked from the left/right menus */
void filter_cmd (void)
{
WPanel *p;
if (!SELECTED_IS_PANEL)
return;
p = MENU_PANEL;
set_panel_filter (p);
}
void reread_cmd (void)
{
int flag;
mad_check (__FILE__, __LINE__);
if (get_current_type () == view_listing &&
get_other_type () == view_listing)
flag = strcmp (cpanel->cwd, opanel->cwd) ? UP_ONLY_CURRENT : 0;
else
flag = UP_ONLY_CURRENT;
update_panels (UP_RELOAD|flag, UP_KEEPSEL);
repaint_screen ();
}
/* Panel sorting related routines */
void do_re_sort (WPanel *panel)
{
char *filename;
int i;
panel = get_a_panel (panel);
filename = strdup (selection (cpanel)->fname);
unselect_item (panel);
do_sort (&panel->dir, panel->sort_type, panel->count-1, panel->reverse, panel->case_sensitive);
panel->selected = -1;
for (i = panel->count; i; i--){
if (!strcmp (panel->dir.list [i-1].fname, filename)){
panel->selected = i-1;
break;
}
}
free (filename);
cpanel->top_file = cpanel->selected - ITEMS (cpanel)/2;
if (cpanel->top_file < 0)
cpanel->top_file = 0;
select_item (panel);
panel_update_contents (panel);
}
void reverse_selection_cmd_panel (WPanel *panel)
{
file_entry *file;
int i;
for (i = 0; i < panel->count; i++){
file = &panel->dir.list [i];
if (S_ISDIR (file->buf.st_mode))
continue;
do_file_mark (panel, i, !file->f.marked);
}
paint_panel (panel);
}
void reverse_selection_cmd (void)
{
reverse_selection_cmd_panel (cpanel);
}
void select_cmd_panel (WPanel *panel)
{
char *reg_exp, *reg_exp_t;
int i;
int c;
int dirflag = 0;
reg_exp = input_dialog (_(" Select "), "", easy_patterns ? "*" : ".");
if (!reg_exp)
return;
reg_exp_t = reg_exp;
/* Check if they specified a directory */
if (*reg_exp_t == PATH_SEP){
dirflag = 1;
reg_exp_t++;
}
if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
dirflag = 1;
reg_exp_t [strlen(reg_exp_t) - 1] = 0;
}
for (i = 0; i < panel->count; i++){
if (!strcmp (panel->dir.list [i].fname, ".."))
continue;
if (S_ISDIR (panel->dir.list [i].buf.st_mode)){
if (!dirflag)
continue;
} else {
if (dirflag)
continue;
}
c = regexp_match (reg_exp_t, panel->dir.list [i].fname, match_file);
if (c == -1){
message (1, MSG_ERROR, _(" Malformed regular expression "));
free (reg_exp);
return;
}
if (c){
do_file_mark (panel, i, 1);
}
}
paint_panel (panel);
free (reg_exp);
}
void select_cmd (void)
{
select_cmd_panel (cpanel);
}
void unselect_cmd_panel (WPanel *panel)
{
char *reg_exp, *reg_exp_t;
int i;
int c;
int dirflag = 0;
reg_exp = input_dialog (_(" Unselect "),"", easy_patterns ? "*" : ".");
if (!reg_exp)
return;
reg_exp_t = reg_exp;
/* Check if they specified directory matching */
if (*reg_exp_t == PATH_SEP){
dirflag = 1;
reg_exp_t ++;
}
if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
dirflag = 1;
reg_exp_t [strlen(reg_exp_t) - 1] = 0;
}
for (i = 0; i < panel->count; i++){
if (!strcmp (panel->dir.list [i].fname, ".."))
continue;
if (S_ISDIR (panel->dir.list [i].buf.st_mode)){
if (!dirflag)
continue;
} else {
if (dirflag)
continue;
}
c = regexp_match (reg_exp_t, panel->dir.list [i].fname, match_file);
if (c == -1){
message (1, MSG_ERROR, _(" Malformed regular expression "));
free (reg_exp);
return;
}
if (c){
do_file_mark (panel, i, 0);
}
}
paint_panel (panel);
free (reg_exp);
}
void unselect_cmd (void)
{
unselect_cmd_panel (cpanel);
}
/* Check if the file exists */
/* If not copy the default */
static int check_for_default(char *default_file, char *file)
{
struct stat s;
if (mc_stat (file, &s)){
if (mc_stat (default_file, &s)){
return -1;
}
create_op_win (OP_COPY, 0);
file_mask_defaults ();
copy_file_file (default_file, file, 1);
destroy_op_win ();
}
return 0;
}
void ext_cmd (void)
{
char *buffer;
char *extdir;
int dir;
dir = 0;
if (geteuid () == 0){
dir = query_dialog (_("Extension file edit"),
_(" Which extension file you want to edit? "), 0, 2,
_("&User"), _("&System Wide"));
}
extdir = concat_dir_and_file (mc_home, MC_LIB_EXT);
if (dir == 0){
buffer = concat_dir_and_file (home_dir, MC_USER_EXT);
check_for_default (extdir, buffer);
do_edit (buffer);
free (buffer);
} else if (dir == 1)
do_edit (extdir);
free (extdir);
flush_extension_file ();
}
void menu_edit_cmd (void)
{
char *buffer;
char *menufile;
int dir = 0;
dir = query_dialog (
_("Menu file edit"),
_(" Which menu file will you edit? "),
0, geteuid() ? 2 : 3,
_("&Local"), _("&Home"), _("&System Wide")
);
menufile = concat_dir_and_file(mc_home, MC_GLOBAL_MENU);
switch (dir){
case 0:
buffer = strdup (MC_LOCAL_MENU);
check_for_default (menufile, buffer);
break;
case 1:
buffer = concat_dir_and_file (home_dir, MC_HOME_MENU);
check_for_default (menufile, buffer);
break;
case 2:
buffer = concat_dir_and_file (mc_home, MC_GLOBAL_MENU);
break;
default:
free (menufile);
return;
}
do_edit (buffer);
if (dir == 0)
chmod(buffer, 0600);
free (buffer);
free (menufile);
}
void quick_chdir_cmd (void)
{
char *target;
target = hotlist_cmd (LIST_HOTLIST);
if (!target)
return;
if (get_current_type () == view_tree)
tree_chdir (the_tree, target);
else
do_cd (target, cd_exact);
free (target);
}
#ifdef USE_VFS
void reselect_vfs (void)
{
char *target;
target = hotlist_cmd (LIST_VFSLIST);
if (!target)
return;
do_cd (target, cd_exact);
free (target);
}
#endif
static int compare_files (char *name1, char *name2, long size)
{
int file1, file2;
char *data1, *data2;
int result = -1; /* Different by default */
file1 = open (name1, O_RDONLY);
if (file1 >= 0){
file2 = open (name2, O_RDONLY);
if (file2 >= 0){
#ifdef HAVE_MMAP
/* Ugly if jungle */
data1 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file1, 0);
if (data1 != (char*) -1){
data2 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file2, 0);
if (data2 != (char*) -1){
rotate_dash ();
result = memcmp (data1, data2, size);
munmap (data2, size);
}
munmap (data1, size);
}
#else
/* Don't have mmap() :( Even more ugly :) */
char buf1[BUFSIZ], buf2[BUFSIZ];
int n1, n2;
rotate_dash ();
do
{
while((n1 = read(file1,buf1,BUFSIZ)) == -1 && errno == EINTR);
while((n2 = read(file2,buf2,BUFSIZ)) == -1 && errno == EINTR);
} while (n1 == n2 && n1 == BUFSIZ && !memcmp(buf1,buf2,BUFSIZ));
result = (n1 != n2) || memcmp(buf1,buf2,n1);
#endif
close (file2);
}
close (file1);
}
return result;
}
enum CompareMode {
compare_quick, compare_size_only, compare_thourough
};
static void
compare_dir (WPanel *panel, WPanel *other, enum CompareMode mode)
{
int i, j;
char *src_name, *dst_name;
panel = get_a_panel (panel);
/* No marks by default */
panel->marked = 0;
panel->total = 0;
panel->dirs_marked = 0;
/* Handle all files in the panel */
for (i = 0; i < panel->count; i++){
file_entry *source = &panel->dir.list[i];
/* Default: unmarked */
file_mark (panel, i, 0);
/* Skip directories */
if (S_ISDIR (source->buf.st_mode))
continue;
/* Search the corresponding entry from the other panel */
for (j = 0; j < other->count; j++){
if (strcmp (source->fname,
other->dir.list[j].fname) == 0)
break;
}
if (j >= other->count)
/* Not found -> mark */
do_file_mark (panel, i, 1);
else {
/* Found */
file_entry *target = &other->dir.list[j];
if (mode != compare_size_only){
/* Older version is not marked */
if (source->buf.st_mtime < target->buf.st_mtime)
continue;
}
/* Newer version with different size is marked */
if (source->buf.st_size != target->buf.st_size){
do_file_mark (panel, i, 1);
continue;
}
if (mode == compare_size_only)
continue;
if (mode == compare_quick){
/* Thorough compare off, compare only time stamps */
/* Mark newer version, don't mark version with the same date */
if (source->buf.st_mtime > target->buf.st_mtime){
do_file_mark (panel, i, 1);
}
continue;
}
/* Thorough compare on, do byte-by-byte comparison */
src_name = get_full_name (panel->cwd, source->fname);
dst_name = get_full_name (other->cwd, target->fname);
if (compare_files (src_name, dst_name, source->buf.st_size))
do_file_mark (panel, i, 1);
free (src_name);
free (dst_name);
}
} /* for (i ...) */
}
void compare_dirs_cmd (void)
{
enum CompareMode thorough_flag = compare_quick;
thorough_flag = query_dialog (_(" Compare directories "), _(" Select compare method: "),
0, 3, _("&Quick"), _("&Size only"), _("&Thorough"), _("&Cancel"));
if (thorough_flag < 0 || thorough_flag > 2)
return;
if (get_current_type () == view_listing &&
get_other_type () == view_listing){
compare_dir (cpanel, opanel, thorough_flag);
compare_dir (opanel, cpanel, thorough_flag);
paint_panel (cpanel);
paint_panel (opanel);
} else {
message (1, MSG_ERROR, _(" Both panels should be on the listing view mode to use this command "));
}
}
void history_cmd (void)
{
Listbox *listbox;
Hist *current;
if (input_w (cmdline)->need_push){
if (push_history (input_w (cmdline), input_w (cmdline)->buffer) == 2)
input_w (cmdline)->need_push = 0;
}
if (!input_w (cmdline)->history){
message (1, MSG_ERROR, _(" The command history is empty "));
return;
}
current = input_w (cmdline)->history;
while (current->prev)
current = current->prev;
listbox = create_listbox_window (60, 10, _(" Command history "),
"[Command Menu]");
while (current){
LISTBOX_APPEND_TEXT (listbox, 0, current->text,
current);
current = current->next;
}
run_dlg (listbox->dlg);
if (listbox->dlg->ret_value == B_CANCEL)
current = NULL;
else
current = listbox->list->current->data;
destroy_dlg (listbox->dlg);
free (listbox);
if (!current)
return;
input_w (cmdline)->history = current;
assign_text (input_w (cmdline), input_w (cmdline)->history->text);
update_input (input_w (cmdline), 1);
}
#if !defined(HAVE_XVIEW) && !defined(HAVE_GNOME)
void swap_cmd (void)
{
swap_panels ();
touchwin (stdscr);
repaint_screen ();
}
#endif
void
view_other_cmd (void)
{
static int message_flag = TRUE;
#ifdef HAVE_SUBSHELL_SUPPORT
char *new_dir = NULL;
char **new_dir_p;
#endif
if (!xterm_flag && !console_flag && !use_subshell){
if (message_flag)
message (1, MSG_ERROR, _(" Not an xterm or Linux console; \n"
" the panels cannot be toggled. "));
message_flag = FALSE;
} else {
#ifndef HAVE_X
if (use_mouse_p)
shut_mouse ();
if (clear_before_exec)
clr_scr ();
if (alternate_plus_minus)
numeric_keypad_mode ();
#endif
#ifndef HAVE_SLANG
/* With slang we don't want any of this, since there
* is no mc_raw_mode supported
*/
reset_shell_mode ();
noecho ();
#endif
keypad(stdscr, FALSE);
endwin ();
if (!status_using_ncurses)
do_exit_ca_mode ();
mc_raw_mode ();
if (console_flag)
restore_console ();
#ifdef HAVE_SUBSHELL_SUPPORT
if (use_subshell){
new_dir_p = vfs_current_is_local () ? &new_dir : NULL;
if (invoke_subshell (NULL, VISIBLY, new_dir_p))
quiet_quit_cmd(); /* User did `exit' or `logout': quit MC quietly */
} else
#endif
{
if (output_starts_shell){
fprintf (stderr,
_("Type `exit' to return to the Midnight Commander\n\r\n\r"));
my_system (EXECUTE_AS_SHELL, shell, NULL);
} else
get_key_code (0);
}
if (console_flag)
handle_console (CONSOLE_SAVE);
if (!status_using_ncurses)
do_enter_ca_mode ();
reset_prog_mode ();
keypad(stdscr, TRUE);
#ifndef HAVE_X
if (use_mouse_p)
init_mouse ();
if (alternate_plus_minus)
application_keypad_mode ();
#endif
#ifdef HAVE_SUBSHELL_SUPPORT
if (use_subshell){
load_prompt (0, 0);
if (new_dir)
do_possible_cd (new_dir);
if (console_flag && output_lines)
show_console_contents (output_start_y,
LINES-keybar_visible-output_lines-1,
LINES-keybar_visible-1);
}
#endif
touchwin (stdscr);
/* prevent screen flash when user did 'exit' or 'logout' within
subshell */
if (!quit)
repaint_screen ();
}
}
#ifndef OS2_NT
static void
do_link (int symbolic_link, char *fname)
{
struct stat s;
char *dest, *src;
int stat_r;
if (!symbolic_link){
stat_r = mc_stat (fname, &s);
if (stat_r != 0){
message (1, MSG_ERROR, _(" Couldn't stat %s \n %s "),
fname, unix_error_string (errno));
return;
}
if (!S_ISREG (s.st_mode))
return;
}
if (!symbolic_link){
src = copy_strings (_(" Link "), name_trunc (fname, 46),
_(" to:"), NULL);
dest = input_expand_dialog (_(" Link "), src, "");
free (src);
if (!dest)
return;
if (!*dest) {
free (dest);
return;
}
save_cwds_stat ();
if (-1 == mc_link (fname, dest))
message (1, MSG_ERROR, _(" link: %s "), unix_error_string (errno));
} else {
#ifdef OLD_SYMLINK_VERSION
symlink_dialog (fname, "", &dest, &src);
#else
/* suggest the full path for symlink */
char s[MC_MAXPATHLEN];
char d[MC_MAXPATHLEN];
strcpy(s, cpanel->cwd);
if ( ! ((s[0] == '/') && (s[1] == 0)))
strcat(s, "/");
strcat(s, fname);
if (get_other_type () == view_listing)
strcpy(d, opanel->cwd);
else
strcpy (d,"");
if ( ! ((d[0] == '/') && (d[1] == 0)))
strcat(d, "/");
symlink_dialog (s, d, &dest, &src);
#endif
if (!dest || !*dest) {
if (src)
free (src);
if (dest)
free (dest);
return;
}
if (src){
if (*src) {
save_cwds_stat ();
if (-1 == mc_symlink (dest, src))
message (1, MSG_ERROR, _(" symlink: %s "),
unix_error_string (errno));
}
free (src);
}
}
free (dest);
update_panels (UP_OPTIMIZE, UP_KEEPSEL);
repaint_screen ();
}
void link_cmd (void)
{
do_link (0, selection (cpanel)->fname);
}
void symlink_cmd (void)
{
do_link (1, selection (cpanel)->fname);
}
void edit_symlink_cmd (void)
{
if (S_ISLNK (selection (cpanel)->buf.st_mode)) {
char buffer [MC_MAXPATHLEN], *p = selection (cpanel)->fname;
int i;
char *dest, *q = copy_strings (_(" Symlink "), name_trunc (p, 32), _(" points to:"), NULL);
i = readlink (p, buffer, MC_MAXPATHLEN);
if (i > 0) {
buffer [i] = 0;
dest = input_expand_dialog (_(" Edit symlink "), q, buffer);
if (dest) {
if (*dest && strcmp (buffer, dest)) {
save_cwds_stat ();
mc_unlink (p);
if (-1 == mc_symlink (dest, p))
message (1, MSG_ERROR, _(" edit symlink: %s "),
unix_error_string (errno));
update_panels (UP_OPTIMIZE, UP_KEEPSEL);
repaint_screen ();
}
free (dest);
}
}
free (q);
}
}
void other_symlink_cmd (void)
{
char *dest, *q, *p, *r, *s, *t;
if (get_other_type () != view_listing)
return;
if (!strcmp (selection (opanel)->fname, ".."))
return;
p = concat_dir_and_file (cpanel->cwd, selection (cpanel)->fname);
r = concat_dir_and_file (opanel->cwd, selection (cpanel)->fname);
q = copy_strings (_(" Link symbolically "), name_trunc (p, 32), _(" to:"), NULL);
dest = input_expand_dialog (_(" Relative symlink "), q, r);
if (dest) {
if (*dest) {
t = strrchr (dest, PATH_SEP);
if (t) {
t[1] = 0;
s = diff_two_paths (dest, p);
t[1] = PATH_SEP;
if (s) {
save_cwds_stat ();
if (-1 == mc_symlink (dest, s))
message (1, MSG_ERROR, _(" relative symlink: %s "),
unix_error_string (errno));
update_panels (UP_OPTIMIZE, UP_KEEPSEL);
repaint_screen ();
free (s);
}
}
}
free (dest);
}
free (q);
free (p);
free (r);
}
#endif
void help_cmd (void)
{
char *hlpfile = concat_dir_and_file (mc_home, "mc.hlp");
interactive_display (hlpfile, "[main]");
free (hlpfile);
}
void view_panel_cmd (void)
{
view_cmd (cpanel);
}
void edit_panel_cmd (void)
{
edit_cmd (cpanel);
}
void mkdir_panel_cmd (void)
{
mkdir_cmd (cpanel);
}
/* Returns a random hint */
char *get_random_hint (void)
{
char *data, *result, *eol;
char *hintfile;
int len;
int start;
/* Do not change hints more often than one minute */
#ifdef SCO_FLAVOR
static time_t last;
time_t now;
time (&now);
if ((now - last) < 60)
return strdup ("");
last = now;
#else
static int last_sec;
static struct timeval tv;
gettimeofday (&tv, NULL);
if (!(tv.tv_sec> last_sec+60))
return strdup ("");
last_sec = tv.tv_sec;
#endif
hintfile = concat_dir_and_file (mc_home, MC_HINT);
data = load_file (hintfile);
free (hintfile);
if (!data)
return 0;
#ifdef SCO_FLAVOR
srand ((short) now);
#else
srand (tv.tv_sec);
#endif
/* get a random entry */
len = strlen (data);
start = rand () % len;
for (;start; start--){
if (data [start] == '\n'){
start++;
break;
}
}
eol = strchr (&data [start], '\n');
if (eol)
*eol = 0;
result = strdup (&data [start]);
free (data);
return result;
}
#ifndef USE_VFS
#ifdef USE_NETCODE
#undef USE_NETCODE
#endif
#endif
#ifdef USE_NETCODE
static char *machine_str = N_(" Enter machine name (F1 for details): ");
static void nice_cd (char *text, char *xtext, char *help, char *prefix, int to_home)
{
char *machine;
char *cd_path;
if (!SELECTED_IS_PANEL)
return;
machine = input_dialog_help (text,
xtext,
help, "");
if (!machine)
return;
if (strncmp (prefix, machine, strlen (prefix)) == 0)
cd_path = copy_strings (machine, to_home ? "/~/" : NULL, NULL);
else
cd_path = copy_strings (prefix, machine, to_home ? "/~/" : NULL, NULL);
if (do_panel_cd (MENU_PANEL, cd_path, 0))
directory_history_add (MENU_PANEL, (MENU_PANEL)->cwd);
else
message (1, MSG_ERROR, N_(" Could not chdir to %s "), cd_path);
free (cd_path);
free (machine);
}
void netlink_cmd (void)
{
nice_cd (_(" Link to a remote machine "), _(machine_str),
"[Network File System]", "mc:", 1);
}
void ftplink_cmd (void)
{
nice_cd (_(" FTP to machine "), _(machine_str),
"[FTP File System]", "ftp://", 1);
}
#ifdef HAVE_SETSOCKOPT
void source_routing (void)
{
char *source;
struct hostent *hp;
source = input_dialog (_(" Socket source routing setup "),
_(" Enter host name to use as a source routing hop: ")n,
"");
if (!source)
return;
hp = gethostbyname (source);
if (!hp){
message (1, _(" Host name "), _(" Error while looking up IP address "));
return;
}
source_route = *((int *)hp->h_addr);
}
#endif /* HAVE_SETSOCKOPT */
#endif /* USE_NETCODE */
#ifdef USE_EXT2FSLIB
void undelete_cmd (void)
{
nice_cd (_(" Undelete files on an ext2 file system "),
_(" Enter the file system name where you want to run the\n "
" undelete file system on: (F1 for details)"),
"[Undelete File System]", "undel:", 0);
}
#endif
void quick_cd_cmd (void)
{
char *p = cd_dialog ();
if (p && *p) {
char *q = copy_strings ("cd ", p, NULL);
do_cd_command (q);
free (q);
}
if (p)
free (p);
}
#ifdef SCO_FLAVOR
#undef DUSUM_USEB
#undef DUSUM_FACTOR
#endif /* SCO_FLAVOR */
#ifdef HAVE_DUSUM
void dirsizes_cmd (void)
{
WPanel *panel = cpanel;
int i, j = 0;
char *cmd, *p, *q, *r;
FILE *f;
#ifdef DUSUM_USEB
# define dirsizes_command "du -s -b "
#else
# define dirsizes_command "du -s "
#endif
#ifndef DUSUM_FACTOR
# define DUSUM_FACTOR 512
#endif
if (!vfs_current_is_local ())
return;
for (i = 0; i < panel->count; i++)
if (S_ISDIR (panel->dir.list [i].buf.st_mode))
j += strlen (panel->dir.list [i].fname) + 1;
if (!j)
return;
cmd = xmalloc (strlen (dirsizes_command) + j + 1, "dirsizes_cmd");
strcpy (cmd, dirsizes_command);
p = strchr (cmd, 0);
for (i = 0; i < panel->count; i++)
if (S_ISDIR (panel->dir.list [i].buf.st_mode) &&
strcmp (panel->dir.list [i].fname, "..")) {
strcpy (p, panel->dir.list [i].fname);
p = strchr (p, 0);
*(p++) = ' ';
}
*(--p) = 0;
open_error_pipe ();
f = popen (cmd, "r");
free (cmd);
if (f != NULL) {
/* Assume that du will display the directories in the order
* I've passed to it :(
*/
i = 0;
p = xmalloc (1024, "dirsizes_cmd");
while (fgets (p, 1024, f)) {
j = atoi (p) * DUSUM_FACTOR;
for (q = p; *q && *q != ' ' && *q != '\t'; q++);
while (*q == ' ' || *q == '\t')
q++;
r = strchr (q, '\n');
if (r == NULL)
r = strchr (q, 0);
for (; i < panel->count; i++)
if (S_ISDIR (panel->dir.list [i].buf.st_mode))
if (!strncmp (q, panel->dir.list [i].fname,
r - q)) {
if (panel->dir.list [i].f.marked)
panel->total += j -
((panel->has_dir_sizes) ? panel->dir.list [i].buf.st_size : 0);
panel->dir.list [i].buf.st_size = j;
break;
}
if (i == panel->count)
break;
}
free (p);
if (pclose (f) < 0)
#ifndef SCO_FLAVOR
message (0, _("Show directory sizes"), _("Pipe close failed"));
else
#else /* SCO_FLAVOR */
/*
** SCO reports about error while all seems to be ok. Just ignore it...
** (alex@bcs.zaporizhzhe.ua)
*/
;
#endif /* SCO_FLAVOR */
panel->has_dir_sizes = 1;
close_error_pipe (0, 0);
paint_panel (panel);
} else
close_error_pipe (1, _("Cannot invoke du command."));
}
#endif
void
save_setup_cmd (void)
{
char *str;
save_setup ();
sync_profiles ();
str = copy_strings ( _(" Setup saved to ~/"), PROFILE_NAME, NULL);
#ifdef HAVE_GNOME
set_hintbar (str);
#else
message (0, _(" Setup "), str);
#endif
free (str);
}
void
configure_panel_listing (WPanel *p, int view_type, int use_msformat, char *user, char *status)
{
int err;
p->user_mini_status = use_msformat;
p->list_type = view_type;
if (view_type == list_user || use_msformat){
free (p->user_format);
p->user_format = user;
free (p->user_status_format [view_type]);
p->user_status_format [view_type] = status;
err = set_panel_formats (p);
if (err){
if (err & 0x01){
free (p->user_format);
p->user_format = strdup (DEFAULT_USER_FORMAT);
}
if (err & 0x02){
free (p->user_status_format [view_type]);
p->user_status_format [view_type] = strdup (DEFAULT_USER_FORMAT);
}
}
}
else {
free (user);
free (status);
}
set_panel_formats (p);
paint_panel (p);
do_refresh ();
}
#ifndef HAVE_GNOME
void
info_cmd_no_menu (void)
{
set_display_type (cpanel == left_panel ? 1 : 0, view_info);
}
void
quick_cmd_no_menu (void)
{
set_display_type (cpanel == left_panel ? 1 : 0, view_quick);
}
void
switch_to_listing (int panel_index)
{
if (get_display_type (panel_index) != view_listing)
set_display_type (panel_index, view_listing);
}
void
listing_cmd (void)
{
int view_type, use_msformat;
char *user, *status;
WPanel *p;
int display_type;
display_type = get_display_type (MENU_PANEL_IDX);
if (display_type == view_listing)
p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
else
p = 0;
view_type = display_box (p, &user, &status, &use_msformat, MENU_PANEL_IDX);
if (view_type == -1)
return;
switch_to_listing (MENU_PANEL_IDX);
p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
configure_panel_listing (p, view_type, use_msformat, user, status);
}
void
tree_cmd (void)
{
set_display_type (MENU_PANEL_IDX, view_tree);
}
void
info_cmd (void)
{
set_display_type (MENU_PANEL_IDX, view_info);
}
void
quick_view_cmd (void)
{
set_display_type (MENU_PANEL_IDX, view_quick);
}
#endif
/* Handle the tree internal listing modes switching */
static int
set_basic_panel_listing_to (int panel_index, int listing_mode)
{
WPanel *p = (WPanel *) get_panel_widget (panel_index);
#ifndef HAVE_GNOME
switch_to_listing (panel_index);
#endif
p->list_type = listing_mode;
if (set_panel_formats (p))
return 0;
paint_panel (p);
do_refresh ();
return 1;
}
void
toggle_listing_cmd (void)
{
int current = get_current_index ();
WPanel *p = (WPanel *) get_panel_widget (current);
int list_mode = p->list_type;
int m;
switch (list_mode){
case list_full:
case list_brief:
m = list_long;
break;
case list_long:
m = list_user;
break;
default:
m = list_full;
}
if (set_basic_panel_listing_to (current, m))
return;
set_basic_panel_listing_to (current, list_full);
}