*** empty log message ***
[midnight-commander.git] / src / cmd.c
blob444fb0c6636ee4c0bf56372cbea55f2d5276c497
1 /* Routines invoked by a function key
2 They normally operate on the current panel.
4 Copyright (C) 1994, 1995 Miguel de Icaza
5 Copyright (C) 1994, 1995 Janne Kukonlehto
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21 #include <config.h>
23 #ifdef HAVE_UNISTD_H
24 # include <unistd.h>
25 #endif
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <string.h>
31 #include <fcntl.h> /* open, O_RDWR */
32 #include <errno.h>
34 #ifdef USE_NETCODE
35 #include <netdb.h>
36 #endif
38 #ifdef HAVE_MMAP
39 # include <sys/mman.h>
40 #endif
42 #include "global.h"
43 #include "tty.h"
44 #include "dir.h"
45 #include "panel.h"
46 #include "cmd.h" /* Our definitions */
47 #include "view.h" /* view() */
48 #include "dialog.h" /* query_dialog, message */
49 #include "file.h" /* the file operations */
50 #include "fileopctx.h"
51 #include "find.h" /* do_find */
52 #include "hotlist.h"
53 #include "tree.h"
54 #include "subshell.h" /* use_subshell */
55 #include "cons.saver.h"
56 #include "dlg.h" /* required by wtools.h */
57 #include "widget.h" /* required by wtools.h */
58 #include "wtools.h" /* listbox */
59 #include "command.h" /* for input_w */
60 #include "win.h" /* do_exit_ca_mode */
61 #include "layout.h" /* get_current/other_type */
62 #include "ext.h" /* regex_command */
63 #include "key.h" /* get_key_code */
64 #include "help.h" /* interactive_display */
65 #include "boxes.h" /* cd_dialog */
66 #include "color.h"
67 #include "user.h"
68 #include "setup.h"
69 #include "profile.h"
71 #include "vfs/vfs.h"
72 #define WANT_WIDGETS
73 #include "main.h" /* global variables, global functions */
74 #ifndef MAP_FILE
75 # define MAP_FILE 0
76 #endif
78 /* If set and you don't have subshell support,then C-o will give you a shell */
79 int output_starts_shell = 0;
81 /* Source routing destination */
82 int source_route = 0;
84 /* If set, use the builtin editor */
85 int use_internal_edit = 1;
87 /* Ugly hack in order to distinguish between left and right panel in menubar */
88 int is_right;
89 #define MENU_PANEL_IDX (is_right ? 1 : 0)
92 /* This is used since the parameter panel on some of the commands */
93 /* defined in this file may receive a 0 parameter if they are invoked */
94 /* The drop down menu */
96 static WPanel *
97 get_a_panel (WPanel *panel)
99 if (panel)
100 return panel;
101 if (get_current_type () == view_listing){
102 return cpanel;
103 } else
104 return other_panel;
107 /* view_file (filename, normal, internal)
109 * Inputs:
110 * filename: The file name to view
111 * plain_view: If set does not do any fancy pre-processing (no filtering) and
112 * always invokes the internal viewer.
113 * internal: If set uses the internal viewer, otherwise an external viewer.
115 int view_file_at_line (char *filename, int plain_view, int internal, int start_line)
117 static char *viewer = 0;
118 int move_dir = 0;
121 if (plain_view) {
122 int changed_hex_mode = 0;
123 int changed_nroff_flag = 0;
124 int changed_magic_flag = 0;
126 altered_hex_mode = 0;
127 altered_nroff_flag = 0;
128 altered_magic_flag = 0;
129 if (default_hex_mode)
130 changed_hex_mode = 1;
131 if (default_nroff_flag)
132 changed_nroff_flag = 1;
133 if (default_magic_flag)
134 changed_magic_flag = 1;
135 default_hex_mode = 0;
136 default_nroff_flag = 0;
137 default_magic_flag = 0;
138 view (0, filename, &move_dir, start_line);
139 if (changed_hex_mode && !altered_hex_mode)
140 default_hex_mode = 1;
141 if (changed_nroff_flag && !altered_nroff_flag)
142 default_nroff_flag = 1;
143 if (changed_magic_flag && !altered_magic_flag)
144 default_magic_flag = 1;
145 repaint_screen ();
146 return move_dir;
148 if (internal){
149 char view_entry [BUF_TINY];
151 if (start_line != 0)
152 g_snprintf (view_entry, sizeof (view_entry), "View:%d", start_line);
153 else
154 strcpy (view_entry, "View");
156 if (!regex_command (filename, view_entry, &move_dir)){
157 view (0, filename, &move_dir, start_line);
158 repaint_screen ();
160 } else {
161 char *localcopy;
163 if (!viewer){
164 viewer = getenv ("PAGER");
165 if (!viewer)
166 viewer = "view";
168 /* The file may be a non local file, get a copy */
169 if (!vfs_file_is_local (filename)){
170 localcopy = mc_getlocalcopy (filename);
171 if (localcopy == NULL){
172 message (1, MSG_ERROR, _(" Can not fetch a local copy of %s "), filename);
173 return 0;
175 execute_internal (viewer, localcopy);
176 mc_ungetlocalcopy (filename, localcopy, 0);
177 } else
178 execute_internal (viewer, filename);
180 return move_dir;
184 view_file (char *filename, int plain_view, int internal)
186 return view_file_at_line (filename, plain_view, internal, 0);
189 /* scan_for_file (panel, idx, direction)
191 * Inputs:
192 * panel: pointer to the panel on which we operate
193 * idx: starting file.
194 * direction: 1, or -1
196 static int scan_for_file (WPanel *panel, int idx, int direction)
198 int i = idx + direction;
200 while (i != idx){
201 if (i < 0)
202 i = panel->count - 1;
203 if (i == panel->count)
204 i = 0;
205 if (!S_ISDIR (panel->dir.list [i].buf.st_mode))
206 return i;
207 i += direction;
209 return i;
212 /* do_view: Invoked as the F3/F13 key. */
213 static void do_view_cmd (WPanel *panel, int normal)
215 int dir, file_idx;
216 panel = get_a_panel (panel);
218 /* Directories are viewed by changing to them */
219 if (S_ISDIR (selection (panel)->buf.st_mode) ||
220 link_isdir (selection (panel))) {
221 if (confirm_view_dir && (panel->marked || panel->dirs_marked)){
222 if (query_dialog (_(" CD "), _("Files tagged, want to cd?"),
223 0, 2, _("&Yes"), _("&No")) == 1){
224 return;
227 if (!do_cd (selection (panel)->fname, cd_exact))
228 message (1, MSG_ERROR, _("Could not change directory") );
230 return;
234 file_idx = panel->selected;
235 while (1) {
236 char *filename;
238 filename = panel->dir.list [file_idx].fname;
240 dir = view_file (filename, normal, use_internal_view);
241 if (dir == 0)
242 break;
243 file_idx = scan_for_file (panel, file_idx, dir);
247 void view_cmd (WPanel *panel)
249 do_view_cmd (panel, 0);
252 void view_file_cmd (WPanel *panel)
254 char *filename;
256 panel = get_a_panel (panel);
257 filename = input_dialog (_(" View file "), _(" Filename:"), selection (panel)->fname);
258 if (!filename) return;
260 view_file (filename, 0, use_internal_view);
261 g_free (filename);
264 void view_simple_cmd (WPanel *panel)
266 do_view_cmd (panel, 1);
269 void filtered_view_cmd (WPanel *panel)
271 char *command;
273 panel = get_a_panel (panel);
274 command = input_dialog (_(" Filtered view "), _(" Filter command and arguments:"),
275 selection (panel)->fname);
276 if (!command)
277 return;
279 view (command, "", 0, 0);
281 g_free (command);
284 void filtered_view_cmd_cpanel (void)
286 filtered_view_cmd (cpanel);
289 void do_edit_at_line (const char *what, int start_line)
291 static char *editor = 0;
293 #ifdef USE_INTERNAL_EDIT
294 if (use_internal_edit){
295 edit (what, start_line);
296 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
297 repaint_screen ();
298 return;
300 #endif /* USE_INTERNAL_EDIT */
301 if (!editor){
302 editor = getenv ("EDITOR");
303 if (!editor)
304 editor = get_default_editor ();
306 execute_internal (editor, what);
307 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
308 repaint_screen ();
311 void
312 do_edit (const char *what)
314 do_edit_at_line (what, 1);
317 void edit_cmd (WPanel *panel)
319 panel = get_a_panel(panel);
320 if (!regex_command (selection (panel)->fname, "Edit", 0))
321 do_edit (selection (panel)->fname);
324 void edit_cmd_new (WPanel *panel)
326 do_edit ("");
329 /* Invoked by F5. Copy, default to the other panel. */
330 void copy_cmd (void)
332 save_cwds_stat ();
333 if (panel_operate (cpanel, OP_COPY, NULL, TRUE)){
334 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
335 repaint_screen ();
339 /* Invoked by F6. Move/rename, default to the other panel. */
340 void ren_cmd (void)
342 save_cwds_stat ();
343 if (panel_operate (cpanel, OP_MOVE, NULL, TRUE)){
344 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
345 repaint_screen ();
349 /* Invoked by F15. Copy, default to the same panel. */
350 void copy_cmd_local (void)
352 save_cwds_stat ();
353 if (panel_operate (cpanel, OP_COPY, selection (cpanel)->fname, TRUE)){
354 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
355 repaint_screen ();
359 /* Invoked by F16. Move/rename, default to the same panel. */
360 void ren_cmd_local (void)
362 save_cwds_stat ();
363 if (panel_operate (cpanel, OP_MOVE, selection (cpanel)->fname, TRUE)){
364 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
365 repaint_screen ();
369 void mkdir_cmd (WPanel *panel)
371 char *tempdir;
372 char *dir;
374 panel = get_a_panel (panel);
375 dir = input_expand_dialog (_("Create a new Directory"), _(" Enter directory name:") , "");
377 if (!dir)
378 return;
380 if (dir [0] && (dir [0] == '/' || dir [0] == '~'))
381 tempdir = g_strdup (dir);
382 else
383 tempdir = concat_dir_and_file (panel->cwd, dir);
384 g_free (dir);
386 save_cwds_stat ();
387 if (my_mkdir (tempdir, 0777) == 0){
388 update_panels (UP_OPTIMIZE, tempdir);
389 repaint_screen ();
390 select_item (cpanel);
391 g_free (tempdir);
392 return;
394 g_free (tempdir);
395 message (1, MSG_ERROR, " %s ", unix_error_string (errno));
398 void delete_cmd (void)
400 save_cwds_stat ();
402 if (panel_operate (cpanel, OP_DELETE, NULL, TRUE)){
403 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
404 repaint_screen ();
408 void find_cmd (void)
410 do_find ();
413 void
414 set_panel_filter_to (WPanel *p, char *allocated_filter_string)
416 if (p->filter){
417 g_free (p->filter);
418 p->filter = 0;
420 if (!(allocated_filter_string [0] == '*' && allocated_filter_string [1] == 0))
421 p->filter = allocated_filter_string;
422 else
423 g_free (allocated_filter_string);
424 reread_cmd ();
427 /* Set a given panel filter expression */
428 void set_panel_filter (WPanel *p)
430 char *reg_exp;
431 char *x;
433 x = p->filter ? p->filter : easy_patterns ? "*" : ".";
435 reg_exp = input_dialog_help (_(" Filter "),
436 _(" Set expression for filtering filenames"),
437 "[Filter...]", x);
438 if (!reg_exp)
439 return;
440 set_panel_filter_to (p, reg_exp);
443 /* Invoked from the left/right menus */
444 void filter_cmd (void)
446 WPanel *p;
448 if (!SELECTED_IS_PANEL)
449 return;
451 p = MENU_PANEL;
452 set_panel_filter (p);
455 void reread_cmd (void)
457 int flag;
459 if (get_current_type () == view_listing &&
460 get_other_type () == view_listing)
461 flag = strcmp (cpanel->cwd, opanel->cwd) ? UP_ONLY_CURRENT : 0;
462 else
463 flag = UP_ONLY_CURRENT;
465 update_panels (UP_RELOAD|flag, UP_KEEPSEL);
466 repaint_screen ();
469 /* Panel sorting related routines */
470 void do_re_sort (WPanel *panel)
472 panel = get_a_panel (panel);
473 panel_re_sort (panel);
476 void reverse_selection_cmd_panel (WPanel *panel)
478 file_entry *file;
479 int i;
481 for (i = 0; i < panel->count; i++){
482 file = &panel->dir.list [i];
483 if (S_ISDIR (file->buf.st_mode))
484 continue;
485 do_file_mark (panel, i, !file->f.marked);
487 paint_panel (panel);
490 void reverse_selection_cmd (void)
492 reverse_selection_cmd_panel (cpanel);
495 void select_cmd_panel (WPanel *panel)
497 char *reg_exp, *reg_exp_t;
498 int i;
499 int c;
500 int dirflag = 0;
502 reg_exp = input_dialog (_(" Select "), "", easy_patterns ? "*" : ".");
503 if (!reg_exp)
504 return;
506 reg_exp_t = reg_exp;
508 /* Check if they specified a directory */
509 if (*reg_exp_t == PATH_SEP){
510 dirflag = 1;
511 reg_exp_t++;
513 if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
514 dirflag = 1;
515 reg_exp_t [strlen(reg_exp_t) - 1] = 0;
518 for (i = 0; i < panel->count; i++){
519 if (!strcmp (panel->dir.list [i].fname, ".."))
520 continue;
521 if (S_ISDIR (panel->dir.list [i].buf.st_mode)){
522 if (!dirflag)
523 continue;
524 } else {
525 if (dirflag)
526 continue;
528 c = regexp_match (reg_exp_t, panel->dir.list [i].fname, match_file);
529 if (c == -1){
530 message (1, MSG_ERROR, _(" Malformed regular expression "));
531 g_free (reg_exp);
532 return;
534 if (c){
535 do_file_mark (panel, i, 1);
538 paint_panel (panel);
539 g_free (reg_exp);
542 void select_cmd (void)
544 select_cmd_panel (cpanel);
547 void unselect_cmd_panel (WPanel *panel)
549 char *reg_exp, *reg_exp_t;
550 int i;
551 int c;
552 int dirflag = 0;
554 reg_exp = input_dialog (_(" Unselect "),"", easy_patterns ? "*" : ".");
555 if (!reg_exp)
556 return;
558 reg_exp_t = reg_exp;
560 /* Check if they specified directory matching */
561 if (*reg_exp_t == PATH_SEP){
562 dirflag = 1;
563 reg_exp_t ++;
565 if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
566 dirflag = 1;
567 reg_exp_t [strlen(reg_exp_t) - 1] = 0;
569 for (i = 0; i < panel->count; i++){
570 if (!strcmp (panel->dir.list [i].fname, ".."))
571 continue;
572 if (S_ISDIR (panel->dir.list [i].buf.st_mode)){
573 if (!dirflag)
574 continue;
575 } else {
576 if (dirflag)
577 continue;
579 c = regexp_match (reg_exp_t, panel->dir.list [i].fname, match_file);
580 if (c == -1){
581 message (1, MSG_ERROR, _(" Malformed regular expression "));
582 g_free (reg_exp);
583 return;
585 if (c){
586 do_file_mark (panel, i, 0);
589 paint_panel (panel);
590 g_free (reg_exp);
593 void unselect_cmd (void)
595 unselect_cmd_panel (cpanel);
598 /* Check if the file exists */
599 /* If not copy the default */
600 int check_for_default(char *default_file, char *file)
602 struct stat s;
603 off_t count = 0;
604 double bytes = 0;
605 FileOpContext *ctx;
607 if (mc_stat (file, &s)){
608 if (mc_stat (default_file, &s)){
609 return -1;
611 ctx = file_op_context_new ();
612 file_op_context_create_ui (ctx, OP_COPY, 0);
613 copy_file_file (ctx, default_file, file, 1, &count, &bytes, 1);
614 file_op_context_destroy (ctx);
616 return 0;
619 void ext_cmd (void)
621 char *buffer;
622 char *extdir;
623 int dir;
625 dir = 0;
626 if (geteuid () == 0){
627 dir = query_dialog (_("Extension file edit"),
628 _(" Which extension file you want to edit? "), 0, 2,
629 _("&User"), _("&System Wide"));
631 extdir = concat_dir_and_file (mc_home, MC_LIB_EXT);
633 if (dir == 0){
634 buffer = concat_dir_and_file (home_dir, MC_USER_EXT);
635 check_for_default (extdir, buffer);
636 do_edit (buffer);
637 g_free (buffer);
638 } else if (dir == 1)
639 do_edit (extdir);
641 g_free (extdir);
642 flush_extension_file ();
645 #ifdef USE_INTERNAL_EDIT
646 void edit_syntax_cmd (void)
648 char *buffer;
649 char *extdir;
650 int dir = 0;
652 if (geteuid () == 0){
653 dir = query_dialog (_("Syntax file edit"),
654 _(" Which syntax file you want to edit? "), 0, 2,
655 _("&User"), _("&System Wide"));
657 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
659 if (dir == 0){
660 buffer = concat_dir_and_file (home_dir, SYNTAX_FILE);
661 check_for_default (extdir, buffer);
662 do_edit (buffer);
663 g_free (buffer);
664 } else if (dir == 1)
665 do_edit (extdir);
667 g_free (extdir);
669 #endif
671 /* where = 0 - do edit a file menu for mc */
672 /* where = 1 - do edit a file menu for cool edit */
673 void menu_edit_cmd (int where)
675 char *buffer;
676 char *menufile;
677 int dir = 0;
679 dir = query_dialog (
680 _(" Menu edit "),
681 _(" Which menu file will you edit ? "),
682 0, geteuid() ? 2 : 3,
683 _("&Local"), _("&Home"), _("&System Wide")
686 menufile = concat_dir_and_file (mc_home, where ? CEDIT_GLOBAL_MENU : MC_GLOBAL_MENU);
688 switch (dir) {
689 case 0:
690 buffer = g_strdup (where ? CEDIT_LOCAL_MENU : MC_LOCAL_MENU);
691 check_for_default (menufile, buffer);
692 break;
694 case 1:
695 buffer = concat_dir_and_file (home_dir, where ? CEDIT_HOME_MENU : MC_HOME_MENU);
696 check_for_default (menufile, buffer);
697 break;
699 case 2:
700 buffer = concat_dir_and_file (mc_home, where ? CEDIT_GLOBAL_MENU : MC_GLOBAL_MENU);
701 break;
703 default:
704 g_free (menufile);
705 return;
707 do_edit (buffer);
708 if (dir == 0)
709 chmod(buffer, 0600);
710 g_free (buffer);
711 g_free (menufile);
714 void quick_chdir_cmd (void)
716 char *target;
718 target = hotlist_cmd (LIST_HOTLIST);
719 if (!target)
720 return;
722 if (get_current_type () == view_tree)
723 tree_chdir (the_tree, target);
724 else
725 if (!do_cd (target, cd_exact))
726 message (1, MSG_ERROR, _("Could not change directory") );
727 g_free (target);
730 #ifdef USE_VFS
731 void free_vfs_now (void)
733 vfs_expire (1);
736 void reselect_vfs (void)
738 char *target;
740 target = hotlist_cmd (LIST_VFSLIST);
741 if (!target)
742 return;
744 if (!do_cd (target, cd_exact))
745 message (1, MSG_ERROR, _("Could not change directory") );
746 g_free (target);
748 #endif /* USE_VFS */
750 static int compare_files (char *name1, char *name2, off_t size)
752 int file1, file2;
753 int result = -1; /* Different by default */
755 file1 = open (name1, O_RDONLY);
756 if (file1 >= 0){
757 file2 = open (name2, O_RDONLY);
758 if (file2 >= 0){
759 #ifdef HAVE_MMAP
760 char *data1, *data2;
761 /* Ugly if jungle */
762 data1 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file1, 0);
763 if (data1 != (char*) -1){
764 data2 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file2, 0);
765 if (data2 != (char*) -1){
766 rotate_dash ();
767 result = memcmp (data1, data2, size);
768 munmap (data2, size);
770 munmap (data1, size);
772 #else
773 /* Don't have mmap() :( Even more ugly :) */
774 char buf1[BUFSIZ], buf2[BUFSIZ];
775 int n1, n2;
776 rotate_dash ();
779 while((n1 = read(file1,buf1,BUFSIZ)) == -1 && errno == EINTR);
780 while((n2 = read(file2,buf2,BUFSIZ)) == -1 && errno == EINTR);
781 } while (n1 == n2 && n1 == BUFSIZ && !memcmp(buf1,buf2,BUFSIZ));
782 result = (n1 != n2) || memcmp(buf1,buf2,n1);
783 #endif /* !HAVE_MMAP */
784 close (file2);
786 close (file1);
788 return result;
791 enum CompareMode {
792 compare_quick, compare_size_only, compare_thourough
795 static void
796 compare_dir (WPanel *panel, WPanel *other, enum CompareMode mode)
798 int i, j;
799 char *src_name, *dst_name;
801 panel = get_a_panel (panel);
803 /* No marks by default */
804 panel->marked = 0;
805 panel->total = 0;
806 panel->dirs_marked = 0;
808 /* Handle all files in the panel */
809 for (i = 0; i < panel->count; i++){
810 file_entry *source = &panel->dir.list[i];
812 /* Default: unmarked */
813 file_mark (panel, i, 0);
815 /* Skip directories */
816 if (S_ISDIR (source->buf.st_mode))
817 continue;
819 /* Search the corresponding entry from the other panel */
820 for (j = 0; j < other->count; j++){
821 if (strcmp (source->fname,
822 other->dir.list[j].fname) == 0)
823 break;
825 if (j >= other->count)
826 /* Not found -> mark */
827 do_file_mark (panel, i, 1);
828 else {
829 /* Found */
830 file_entry *target = &other->dir.list[j];
832 if (mode != compare_size_only){
833 /* Older version is not marked */
834 if (source->buf.st_mtime < target->buf.st_mtime)
835 continue;
838 /* Newer version with different size is marked */
839 if (source->buf.st_size != target->buf.st_size){
840 do_file_mark (panel, i, 1);
841 continue;
844 if (mode == compare_size_only)
845 continue;
847 if (mode == compare_quick){
848 /* Thorough compare off, compare only time stamps */
849 /* Mark newer version, don't mark version with the same date */
850 if (source->buf.st_mtime > target->buf.st_mtime){
851 do_file_mark (panel, i, 1);
853 continue;
856 /* Thorough compare on, do byte-by-byte comparison */
857 src_name = concat_dir_and_file (panel->cwd, source->fname);
858 dst_name = concat_dir_and_file (other->cwd, target->fname);
859 if (compare_files (src_name, dst_name, source->buf.st_size))
860 do_file_mark (panel, i, 1);
861 g_free (src_name);
862 g_free (dst_name);
864 } /* for (i ...) */
867 void compare_dirs_cmd (void)
869 enum CompareMode thorough_flag = compare_quick;
871 thorough_flag = query_dialog (_(" Compare directories "), _(" Select compare method: "),
872 0, 3, _("&Quick"), _("&Size only"), _("&Thorough"), _("&Cancel"));
873 if (thorough_flag < 0 || thorough_flag > 2)
874 return;
875 if (get_current_type () == view_listing &&
876 get_other_type () == view_listing){
877 compare_dir (cpanel, opanel, thorough_flag);
878 compare_dir (opanel, cpanel, thorough_flag);
879 paint_panel (cpanel);
880 paint_panel (opanel);
881 } else {
882 message (1, MSG_ERROR, _(" Both panels should be on the listing view mode to use this command "));
886 void history_cmd (void)
888 Listbox *listbox;
889 Hist *current;
891 if (input_w (cmdline)->need_push){
892 if (push_history (input_w (cmdline), input_w (cmdline)->buffer) == 2)
893 input_w (cmdline)->need_push = 0;
895 if (!input_w (cmdline)->history){
896 message (1, MSG_ERROR, _(" The command history is empty "));
897 return;
899 current = input_w (cmdline)->history;
900 while (current->prev)
901 current = current->prev;
902 listbox = create_listbox_window (60, 10, _(" Command history "),
903 "[Command Menu]");
904 while (current){
905 LISTBOX_APPEND_TEXT (listbox, 0, current->text,
906 current);
907 current = current->next;
909 run_dlg (listbox->dlg);
910 if (listbox->dlg->ret_value == B_CANCEL)
911 current = NULL;
912 else
913 current = listbox->list->current->data;
914 destroy_dlg (listbox->dlg);
915 g_free (listbox);
917 if (!current)
918 return;
919 input_w (cmdline)->history = current;
920 assign_text (input_w (cmdline), input_w (cmdline)->history->text);
921 update_input (input_w (cmdline), 1);
924 void swap_cmd (void)
926 swap_panels ();
927 touchwin (stdscr);
928 repaint_screen ();
931 void
932 view_other_cmd (void)
934 static int message_flag = TRUE;
935 #ifdef HAVE_SUBSHELL_SUPPORT
936 char *new_dir = NULL;
937 char **new_dir_p;
938 #endif /* HAVE_SUBSHELL_SUPPORT */
940 if (!xterm_flag && !console_flag && !use_subshell){
941 if (message_flag)
942 message (1, MSG_ERROR, _(" Not an xterm or Linux console; \n"
943 " the panels cannot be toggled. "));
944 message_flag = FALSE;
945 } else {
946 channels_down ();
947 disable_mouse ();
948 if (clear_before_exec)
949 clr_scr ();
950 if (alternate_plus_minus)
951 numeric_keypad_mode ();
952 #ifndef HAVE_SLANG
953 /* With slang we don't want any of this, since there
954 * is no mc_raw_mode supported
956 reset_shell_mode ();
957 noecho ();
958 #endif /* !HAVE_SLANG */
959 keypad(stdscr, FALSE);
960 endwin ();
961 do_exit_ca_mode ();
962 mc_raw_mode ();
963 if (console_flag)
964 restore_console ();
966 #ifdef HAVE_SUBSHELL_SUPPORT
967 if (use_subshell){
968 new_dir_p = vfs_current_is_local () ? &new_dir : NULL;
969 if (invoke_subshell (NULL, VISIBLY, new_dir_p))
970 quiet_quit_cmd(); /* User did `exit' or `logout': quit MC quietly */
971 } else
972 #endif /* HAVE_SUBSHELL_SUPPORT */
974 if (output_starts_shell){
975 fprintf (stderr,
976 _("Type `exit' to return to the Midnight Commander"));
977 fprintf (stderr, "\n\r\n\r");
979 my_system (EXECUTE_AS_SHELL, shell, NULL);
980 } else
981 get_key_code (0);
983 if (console_flag)
984 handle_console (CONSOLE_SAVE);
986 do_enter_ca_mode ();
988 reset_prog_mode ();
989 keypad(stdscr, TRUE);
991 /* Prevent screen flash when user did 'exit' or 'logout' within
992 subshell */
993 if (quit)
994 return;
996 enable_mouse ();
997 channels_up ();
998 if (alternate_plus_minus)
999 application_keypad_mode ();
1001 #ifdef HAVE_SUBSHELL_SUPPORT
1002 if (use_subshell){
1003 load_prompt (0, 0);
1004 if (new_dir)
1005 do_possible_cd (new_dir);
1006 if (console_flag && output_lines)
1007 show_console_contents (output_start_y,
1008 LINES-keybar_visible-output_lines-1,
1009 LINES-keybar_visible-1);
1011 #endif /* HAVE_SUBSHELL_SUPPORT */
1012 touchwin (stdscr);
1014 repaint_screen ();
1018 #ifndef OS2_NT
1019 static void
1020 do_link (int symbolic_link, char *fname)
1022 char *dest, *src;
1024 if (!symbolic_link){
1025 src = g_strconcat (_(" Link "), name_trunc (fname, 46),
1026 _(" to:"), NULL);
1027 dest = input_expand_dialog (_(" Link "), src, "");
1028 g_free (src);
1029 if (!dest)
1030 return;
1031 if (!*dest) {
1032 g_free (dest);
1033 return;
1035 save_cwds_stat ();
1036 if (-1 == mc_link (fname, dest))
1037 message (1, MSG_ERROR, _(" link: %s "), unix_error_string (errno));
1038 } else {
1039 char *s;
1040 char *d;
1042 /* suggest the full path for symlink */
1043 s = concat_dir_and_file (cpanel->cwd, fname);
1045 if (get_other_type () == view_listing) {
1046 d = concat_dir_and_file (opanel->cwd, fname);
1047 } else {
1048 d = g_strdup (fname);
1051 symlink_dialog (s, d, &dest, &src);
1052 g_free (d);
1053 g_free (s);
1055 if (!dest || !*dest || !src || !*src) {
1056 if (src)
1057 g_free (src);
1058 if (dest)
1059 g_free (dest);
1060 return;
1062 save_cwds_stat ();
1063 if (-1 == mc_symlink (dest, src))
1064 message (1, MSG_ERROR, _(" symlink: %s "),
1065 unix_error_string (errno));
1066 g_free (src);
1068 g_free (dest);
1069 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1070 repaint_screen ();
1073 void link_cmd (void)
1075 do_link (0, selection (cpanel)->fname);
1078 void symlink_cmd (void)
1080 char *filename = NULL;
1081 filename = selection (cpanel)->fname;
1083 if (filename) {
1084 do_link (1, filename);
1088 void edit_symlink_cmd (void)
1090 if (S_ISLNK (selection (cpanel)->buf.st_mode)) {
1091 char buffer [MC_MAXPATHLEN];
1092 char *p = NULL;
1093 int i;
1094 char *dest, *q;
1096 p = selection (cpanel)->fname;
1098 q = g_strdup_printf (_(" Symlink `%s\' points to: "), name_trunc (p, 32));
1100 i = readlink (p, buffer, MC_MAXPATHLEN);
1101 if (i > 0) {
1102 buffer [i] = 0;
1103 dest = input_expand_dialog (_(" Edit symlink "), q, buffer);
1104 if (dest) {
1105 if (*dest && strcmp (buffer, dest)) {
1106 save_cwds_stat ();
1107 if (-1 == mc_unlink (p)){
1108 message (1, MSG_ERROR, _(" edit symlink, unable to remove %s: %s "),
1109 p, unix_error_string (errno));
1110 } else {
1111 if (-1 == mc_symlink (dest, p))
1112 message (1, MSG_ERROR, _(" edit symlink: %s "),
1113 unix_error_string (errno));
1115 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1116 repaint_screen ();
1118 g_free (dest);
1121 g_free (q);
1122 } else {
1123 message (1, MSG_ERROR, _("`%s' is not a symbolic link"),
1124 selection (cpanel)->fname);
1128 void other_symlink_cmd (void)
1130 char *dest, *q, *p, *r, *s, *t;
1132 if (get_other_type () != view_listing)
1133 return;
1135 if (!strcmp (selection (opanel)->fname, ".."))
1136 return;
1137 p = concat_dir_and_file (cpanel->cwd, selection (cpanel)->fname);
1138 r = concat_dir_and_file (opanel->cwd, selection (cpanel)->fname);
1140 q = g_strconcat (_(" Link symbolically "), name_trunc (p, 32), _(" to:"), NULL);
1141 dest = input_expand_dialog (_(" Relative symlink "), q, r);
1142 if (dest) {
1143 if (*dest) {
1144 t = strrchr (dest, PATH_SEP);
1145 if (t) {
1146 t[1] = 0;
1147 s = diff_two_paths (dest, p);
1148 t[1] = PATH_SEP;
1149 if (s) {
1150 save_cwds_stat ();
1151 if (-1 == mc_symlink (dest, s))
1152 message (1, MSG_ERROR, _(" relative symlink: %s "),
1153 unix_error_string (errno));
1154 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1155 repaint_screen ();
1156 g_free (s);
1160 g_free (dest);
1162 g_free (q);
1163 g_free (p);
1164 g_free (r);
1166 #endif /* !OS2_NT */
1168 void help_cmd (void)
1170 interactive_display (NULL, "[main]");
1173 void view_panel_cmd (void)
1175 view_cmd (cpanel);
1178 void edit_panel_cmd (void)
1180 edit_cmd (cpanel);
1183 void mkdir_panel_cmd (void)
1185 mkdir_cmd (cpanel);
1188 /* partly taken from dcigettext.c, returns "" for default locale */
1189 /* value should be freed by calling function g_free() */
1190 char *guess_message_value (void)
1192 static const char * const var[] = {
1193 /* The highest priority value is the `LANGUAGE' environment
1194 variable. This is a GNU extension. */
1195 "LANGUAGE",
1196 /* Setting of LC_ALL overwrites all other. */
1197 "LC_ALL",
1198 /* Next comes the name of the desired category. */
1199 "LC_MESSAGES",
1200 /* Last possibility is the LANG environment variable. */
1201 "LANG",
1202 /* NULL exit loops */
1203 NULL
1206 unsigned i = 0;
1207 char *locale = NULL;
1209 while (var[i] != NULL) {
1210 locale = getenv (var[i]);
1211 if (locale != NULL && locale[0] != '\0')
1212 break;
1213 i++;
1216 if (locale == NULL)
1217 locale = "";
1219 return g_strdup (locale);
1222 /* Returns a random hint */
1223 char *get_random_hint (void)
1225 char *data, *result, *eol;
1226 int len;
1227 int start;
1229 /* Do not change hints more often than one minute */
1231 #ifdef SCO_FLAVOR
1232 static time_t last;
1233 time_t now;
1235 time (&now);
1236 if ((now - last) < 60)
1237 return g_strdup ("");
1238 last = now;
1239 #else
1240 static int last_sec;
1241 static struct timeval tv;
1243 gettimeofday (&tv, NULL);
1244 if (!(tv.tv_sec> last_sec+60))
1245 return g_strdup ("");
1246 last_sec = tv.tv_sec;
1247 #endif /* !SCO_FLAVOR */
1249 data = load_mc_home_file (MC_HINT, NULL);
1250 if (!data)
1251 return 0;
1253 #ifdef SCO_FLAVOR
1254 srand ((short) now);
1255 #else
1256 srand (tv.tv_sec);
1257 #endif /* !SCO_FLAVOR */
1258 /* get a random entry */
1259 len = strlen (data);
1260 start = rand () % len;
1262 for (;start; start--){
1263 if (data [start] == '\n'){
1264 start++;
1265 break;
1268 eol = strchr (&data [start], '\n');
1269 if (eol)
1270 *eol = 0;
1271 result = g_strdup (&data [start]);
1272 g_free (data);
1273 return result;
1276 #ifdef USE_NETCODE
1278 static char *machine_str = N_(" Enter machine name (F1 for details): ");
1280 static void nice_cd (char *text, char *xtext, char *help, char *prefix, int to_home)
1282 char *machine;
1283 char *cd_path;
1285 if (!SELECTED_IS_PANEL)
1286 return;
1288 machine = input_dialog_help (text,
1289 xtext,
1290 help, "");
1291 if (!machine)
1292 return;
1294 to_home = 0; /* FIXME: how to solve going to home nicely? /~/ is
1295 ugly as hell and leads to problems in vfs layer */
1297 if (strncmp (prefix, machine, strlen (prefix)) == 0)
1298 cd_path = g_strconcat (machine, to_home ? "/~/" : NULL, NULL);
1299 else
1300 cd_path = g_strconcat (prefix, machine, to_home ? "/~/" : NULL, NULL);
1302 if (do_panel_cd (MENU_PANEL, cd_path, 0))
1303 directory_history_add (MENU_PANEL, (MENU_PANEL)->cwd);
1304 else
1305 message (1, MSG_ERROR, _(" Could not chdir to %s "), cd_path);
1306 g_free (cd_path);
1307 g_free (machine);
1309 #ifdef WITH_MCFS
1310 void netlink_cmd (void)
1312 nice_cd (_(" Link to a remote machine "), _(machine_str),
1313 "[Network File System]", "/#mc:", 1);
1315 #endif
1316 void ftplink_cmd (void)
1318 nice_cd (_(" FTP to machine "), _(machine_str),
1319 "[FTP File System]", "/#ftp:", 1);
1321 void fishlink_cmd (void)
1323 nice_cd (_(" Shell link to machine "), _(machine_str),
1324 "[FIle transfer over SHell filesystem]", "/#sh:", 1);
1326 #ifdef WITH_SMBFS
1327 void smblink_cmd (void)
1329 nice_cd (_(" SMB link to machine "), _(machine_str),
1330 "[SMB File System]", "/#smb:", 0);
1332 #endif
1333 #ifdef HAVE_SETSOCKOPT
1334 void source_routing (void)
1336 char *source;
1337 struct hostent *hp;
1339 source = input_dialog (_(" Socket source routing setup "),
1340 _(" Enter host name to use as a source routing hop: "),
1341 "");
1342 if (!source)
1343 return;
1345 hp = gethostbyname (source);
1346 g_free (source);
1347 if (!hp){
1348 message (1, _(" Host name "), _(" Error while looking up IP address "));
1349 return;
1351 source_route = *((int *)hp->h_addr);
1353 #endif /* HAVE_SETSOCKOPT */
1354 #endif /* USE_NETCODE */
1356 #ifdef USE_EXT2FSLIB
1357 void undelete_cmd (void)
1359 nice_cd (_(" Undelete files on an ext2 file system "),
1360 _(" Enter device (without /dev/) to undelete\n "
1361 " files on: (F1 for details)"),
1362 "[Undelete File System]", "/#undel:", 0);
1364 #endif /* USE_EXT2FSLIB */
1366 void quick_cd_cmd (void)
1368 char *p = cd_dialog ();
1370 if (p && *p) {
1371 char *q = g_strconcat ("cd ", p, NULL);
1373 do_cd_command (q);
1374 g_free (q);
1376 if (p)
1377 g_free (p);
1380 void
1381 dirsizes_cmd (void)
1383 WPanel *panel = cpanel;
1384 int i;
1385 off_t marked;
1386 double total;
1388 for (i = 0; i < panel->count; i++)
1389 if (S_ISDIR (panel->dir.list [i].buf.st_mode) &&
1390 ((panel->dirs_marked && panel->dir.list [i].f.marked) ||
1391 !panel->dirs_marked) &&
1392 strcmp (panel->dir.list [i].fname, "..") != 0) {
1393 total = 0.0l;
1394 compute_dir_size (panel->dir.list [i].fname, &marked, &total);
1395 panel->dir.list [i].buf.st_size = (off_t) total;
1396 panel->dir.list [i].f.dir_size_computed = 1;
1399 recalculate_panel_summary (panel);
1400 paint_panel (panel);
1403 void
1404 save_setup_cmd (void)
1406 char *str;
1408 save_setup ();
1409 sync_profiles ();
1410 str = g_strconcat ( _(" Setup saved to ~/"), PROFILE_NAME, NULL);
1412 message (0, _(" Setup "), str);
1413 g_free (str);
1416 void
1417 configure_panel_listing (WPanel *p, int view_type, int use_msformat, char *user, char *status)
1419 p->user_mini_status = use_msformat;
1420 p->list_type = view_type;
1422 if (view_type == list_user || use_msformat){
1423 g_free (p->user_format);
1424 p->user_format = user;
1426 g_free (p->user_status_format [view_type]);
1427 p->user_status_format [view_type] = status;
1429 set_panel_formats (p);
1431 else {
1432 g_free (user);
1433 g_free (status);
1436 set_panel_formats (p);
1437 paint_panel (p);
1439 do_refresh ();
1442 void
1443 info_cmd_no_menu (void)
1445 if (get_display_type (0) == view_info)
1446 set_display_type (0, view_listing);
1447 else if (get_display_type (1) == view_info)
1448 set_display_type (1, view_listing);
1449 else
1450 set_display_type (cpanel == left_panel ? 1 : 0, view_info);
1453 void
1454 quick_cmd_no_menu (void)
1456 if (get_display_type (0) == view_quick)
1457 set_display_type (0, view_listing);
1458 else if (get_display_type (1) == view_quick)
1459 set_display_type (1, view_listing);
1460 else
1461 set_display_type (cpanel == left_panel ? 1 : 0, view_quick);
1464 void
1465 switch_to_listing (int panel_index)
1467 if (get_display_type (panel_index) != view_listing)
1468 set_display_type (panel_index, view_listing);
1471 void
1472 listing_cmd (void)
1474 int view_type, use_msformat;
1475 char *user, *status;
1476 WPanel *p;
1477 int display_type;
1479 display_type = get_display_type (MENU_PANEL_IDX);
1480 if (display_type == view_listing)
1481 p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1482 else
1483 p = 0;
1485 view_type = display_box (p, &user, &status, &use_msformat, MENU_PANEL_IDX);
1487 if (view_type == -1)
1488 return;
1490 switch_to_listing (MENU_PANEL_IDX);
1492 p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1494 configure_panel_listing (p, view_type, use_msformat, user, status);
1497 void
1498 tree_cmd (void)
1500 set_display_type (MENU_PANEL_IDX, view_tree);
1503 void
1504 info_cmd (void)
1506 set_display_type (MENU_PANEL_IDX, view_info);
1509 void
1510 quick_view_cmd (void)
1512 if ((WPanel *) get_panel_widget (MENU_PANEL_IDX) == cpanel)
1513 change_panel ();
1514 set_display_type (MENU_PANEL_IDX, view_quick);
1517 /* Handle the tree internal listing modes switching */
1518 static int
1519 set_basic_panel_listing_to (int panel_index, int listing_mode)
1521 WPanel *p = (WPanel *) get_panel_widget (panel_index);
1523 switch_to_listing (panel_index);
1524 p->list_type = listing_mode;
1525 if (set_panel_formats (p))
1526 return 0;
1528 paint_panel (p);
1529 do_refresh ();
1530 return 1;
1533 void
1534 toggle_listing_cmd (void)
1536 int current = get_current_index ();
1537 WPanel *p = (WPanel *) get_panel_widget (current);
1538 int list_mode = p->list_type;
1539 int m;
1541 switch (list_mode){
1542 case list_full:
1543 case list_brief:
1544 m = list_long;
1545 break;
1546 case list_long:
1547 m = list_user;
1548 break;
1549 default:
1550 m = list_full;
1552 if (set_basic_panel_listing_to (current, m))
1553 return;
1554 set_basic_panel_listing_to (current, list_full);