Added cs to the list of languages
[midnight-commander.git] / src / cmd.c
blobd25a4d058ec1d1a9b02f3b8cc2f668b68d44ac69
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
21 #include <config.h>
22 #ifdef __os2__
23 # define INCL_DOSFILEMGR
24 # define INCL_DOSMISC
25 # define INCL_DOSERROR
26 #endif
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include "tty.h"
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/stat.h>
35 #include <sys/time.h>
36 #include <string.h>
37 #include <fcntl.h> /* open, O_RDWR */
38 #include <errno.h>
40 #ifdef NEEDS_IO_H
41 # include <io.h>
42 #endif
44 #ifdef USE_NETCODE
45 #include <netdb.h>
46 #endif
48 #ifdef HAVE_MMAP
49 # include <sys/mman.h>
50 #endif
51 #include "global.h"
52 #include "dir.h"
53 #include "panel.h"
54 #include "cmd.h" /* Our definitions */
55 #include "view.h" /* view() */
56 #include "dialog.h" /* query_dialog, message */
57 #include "file.h" /* the file operations */
58 #include "fileopctx.h"
59 #include "find.h" /* do_find */
60 #include "hotlist.h"
61 #include "tree.h"
62 #include "subshell.h" /* use_subshell */
63 #include "cons.saver.h"
64 #include "dlg.h" /* required by wtools.h */
65 #include "widget.h" /* required by wtools.h */
66 #include "wtools.h" /* listbox */
67 #include "command.h" /* for input_w */
68 #include "win.h" /* do_exit_ca_mode */
69 #include "layout.h" /* get_current/other_type */
70 #include "ext.h" /* regex_command */
71 #include "view.h" /* view */
72 #include "key.h" /* get_key_code */
73 #include "help.h" /* interactive_display */
74 #include "boxes.h" /* cd_dialog */
75 #include "color.h"
76 #include "user.h"
77 #include "setup.h"
78 #include "x.h"
79 #include "profile.h"
81 #define MIDNIGHT
82 #ifdef USE_INTERNAL_EDIT
83 extern int edit (const char *file, int line);
84 #endif
85 #include "../vfs/vfs.h"
86 #define WANT_WIDGETS
87 #include "main.h" /* global variables, global functions */
88 #ifndef MAP_FILE
89 # define MAP_FILE 0
90 #endif
92 #ifdef HAVE_TK
93 # include "tkscreen.h"
94 #endif
96 /* If set and you don't have subshell support,then C-o will give you a shell */
97 int output_starts_shell = 0;
99 /* Source routing destination */
100 int source_route = 0;
102 /* If set, use the builtin editor */
103 int use_internal_edit = 1;
105 /* Ugly hack in order to distinguish between left and right panel in menubar */
106 int is_right;
107 #define MENU_PANEL_IDX (is_right ? 1 : 0)
110 #ifndef PORT_HAS_FILTER_CHANGED
111 # define x_filter_changed(p)
112 #endif
114 /* This is used since the parameter panel on some of the commands */
115 /* defined in this file may receive a 0 parameter if they are invoked */
116 /* The drop down menu */
118 static WPanel *
119 get_a_panel (WPanel *panel)
121 if (panel)
122 return panel;
123 if (get_current_type () == view_listing){
124 return cpanel;
125 } else
126 return other_panel;
129 /* view_file (filename, normal, internal)
131 * Inputs:
132 * filename: The file name to view
133 * plain_view: If set does not do any fancy pre-processing (no filtering) and
134 * always invokes the internal viewer.
135 * internal: If set uses the internal viewer, otherwise an external viewer.
137 int view_file_at_line (char *filename, int plain_view, int internal, int start_line)
139 static char *viewer = 0;
140 int move_dir = 0;
143 if (plain_view) {
144 int changed_hex_mode = 0;
145 int changed_nroff_flag = 0;
146 int changed_magic_flag = 0;
148 altered_hex_mode = 0;
149 altered_nroff_flag = 0;
150 altered_magic_flag = 0;
151 if (default_hex_mode)
152 changed_hex_mode = 1;
153 if (default_nroff_flag)
154 changed_nroff_flag = 1;
155 if (default_magic_flag)
156 changed_magic_flag = 1;
157 default_hex_mode = 0;
158 default_nroff_flag = 0;
159 default_magic_flag = 0;
160 view (0, filename, &move_dir, start_line);
161 if (changed_hex_mode && !altered_hex_mode)
162 default_hex_mode = 1;
163 if (changed_nroff_flag && !altered_nroff_flag)
164 default_nroff_flag = 1;
165 if (changed_magic_flag && !altered_magic_flag)
166 default_magic_flag = 1;
167 repaint_screen ();
168 return move_dir;
170 if (internal){
171 char view_entry [BUF_TINY];
173 #ifdef HAVE_GNOME
174 if (!gmc_view (filename, start_line)){
175 view (0, filename, &move_dir, start_line);
177 #else
178 if (start_line != 0)
179 g_snprintf (view_entry, sizeof (view_entry), "View:%d", start_line);
180 else
181 strcpy (view_entry, "View");
183 if (!regex_command (filename, view_entry, NULL, &move_dir)){
184 view (0, filename, &move_dir, start_line);
185 repaint_screen ();
187 #endif
188 } else {
189 char *localcopy;
191 if (!viewer){
192 viewer = getenv ("PAGER");
193 if (!viewer)
194 viewer = "view";
196 /* The file may be a non local file, get a copy */
197 if (!vfs_file_is_local (filename)){
198 localcopy = mc_getlocalcopy (filename);
199 if (localcopy == NULL){
200 message (1, MSG_ERROR, _(" Can not fetch a local copy of %s "), filename);
201 return 0;
203 execute_internal (viewer, localcopy);
204 mc_ungetlocalcopy (filename, localcopy, 0);
205 } else
206 execute_internal (viewer, filename);
208 return move_dir;
212 view_file (char *filename, int plain_view, int internal)
214 return view_file_at_line (filename, plain_view, internal, 0);
217 /* scan_for_file (panel, idx, direction)
219 * Inputs:
220 * panel: pointer to the panel on which we operate
221 * idx: starting file.
222 * direction: 1, or -1
224 static int scan_for_file (WPanel *panel, int idx, int direction)
226 int i = idx + direction;
228 while (i != idx){
229 if (i < 0)
230 i = panel->count - 1;
231 if (i == panel->count)
232 i = 0;
233 if (!S_ISDIR (panel->dir.list [i].buf.st_mode))
234 return i;
235 i += direction;
237 return i;
240 /* do_view: Invoked as the F3/F13 key. */
241 static void do_view_cmd (WPanel *panel, int normal)
243 int dir, file_idx;
244 panel = get_a_panel (panel);
246 /* Directories are viewed by changing to them */
247 if (S_ISDIR (selection (panel)->buf.st_mode) ||
248 link_isdir (selection (panel))) {
249 if (confirm_view_dir && (panel->marked || panel->dirs_marked)){
250 if (query_dialog (_(" CD "), _("Files tagged, want to cd?"),
251 0, 2, _("&Yes"), _("&No")) == 1){
252 return;
255 if (!do_cd (selection (panel)->fname, cd_exact))
256 message (1, MSG_ERROR, _("Could not change directory") );
258 return;
262 file_idx = panel->selected;
263 while (1) {
264 char *filename;
266 filename = panel->dir.list [file_idx].fname;
268 dir = view_file (filename, normal, use_internal_view);
269 if (dir == 0)
270 break;
271 file_idx = scan_for_file (panel, file_idx, dir);
275 void view_cmd (WPanel *panel)
277 do_view_cmd (panel, 0);
280 void view_file_cmd (WPanel *panel)
282 char *filename;
284 panel = get_a_panel (panel);
285 filename = input_dialog (_(" View file "), _(" Filename:"), selection (panel)->fname);
286 if (!filename) return;
288 view_file (filename, 0, use_internal_view);
289 g_free (filename);
292 void view_simple_cmd (WPanel *panel)
294 do_view_cmd (panel, 1);
297 void filtered_view_cmd (WPanel *panel)
299 char *command;
301 panel = get_a_panel (panel);
302 command = input_dialog (_(" Filtered view "), _(" Filter command and arguments:"),
303 selection (panel)->fname);
304 if (!command)
305 return;
307 view (command, "", 0, 0);
309 g_free (command);
312 void filtered_view_cmd_cpanel (void)
314 filtered_view_cmd (cpanel);
317 void do_edit_at_line (const char *what, int start_line)
319 static char *editor = 0;
321 #ifdef USE_INTERNAL_EDIT
322 if (use_internal_edit){
323 edit (what, start_line);
324 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
325 repaint_screen ();
326 return;
328 #endif
329 if (!editor){
330 editor = getenv ("EDITOR");
331 if (!editor)
332 editor = get_default_editor ();
334 execute_internal (editor, what);
335 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
336 repaint_screen ();
339 void
340 do_edit (const char *what)
342 do_edit_at_line (what, 1);
345 void edit_cmd (WPanel *panel)
347 panel = get_a_panel(panel);
348 if (!regex_command (selection (panel)->fname, "Edit", NULL, 0))
349 do_edit (selection (panel)->fname);
352 void edit_cmd_new (WPanel *panel)
354 do_edit ("");
357 void copy_cmd (void)
359 save_cwds_stat ();
360 if (panel_operate (cpanel, OP_COPY, NULL, TRUE)){
361 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
362 repaint_screen ();
366 void ren_cmd (void)
368 save_cwds_stat ();
369 if (panel_operate (cpanel, OP_MOVE, NULL, TRUE)){
370 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
371 repaint_screen ();
375 void copymove_cmd_with_default (int copy, char *thedefault)
377 save_cwds_stat ();
378 if (panel_operate (cpanel, copy ? OP_COPY : OP_MOVE, thedefault, TRUE)){
379 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
380 repaint_screen ();
384 void mkdir_cmd (WPanel *panel)
386 char *tempdir;
387 char *dir;
389 panel = get_a_panel (panel);
390 dir = input_expand_dialog (_("Create a new Directory"), _(" Enter directory name:") , "");
392 if (!dir)
393 return;
395 if (dir [0] && (dir [0] == '/' || dir [0] == '~'))
396 tempdir = g_strdup (dir);
397 else
398 tempdir = concat_dir_and_file (panel->cwd, dir);
399 g_free (dir);
401 save_cwds_stat ();
402 if (my_mkdir (tempdir, 0777) == 0){
403 update_panels (UP_OPTIMIZE, tempdir);
404 repaint_screen ();
405 select_item (cpanel);
406 g_free (tempdir);
407 return;
409 g_free (tempdir);
410 message (1, MSG_ERROR, " %s ", unix_error_string (errno));
413 void delete_cmd (void)
415 save_cwds_stat ();
417 if (panel_operate (cpanel, OP_DELETE, NULL, TRUE)){
418 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
419 repaint_screen ();
423 void find_cmd (void)
425 do_find ();
428 void
429 set_panel_filter_to (WPanel *p, char *allocated_filter_string)
431 if (p->filter){
432 g_free (p->filter);
433 p->filter = 0;
435 if (!(allocated_filter_string [0] == '*' && allocated_filter_string [1] == 0))
436 p->filter = allocated_filter_string;
437 else
438 g_free (allocated_filter_string);
439 reread_cmd ();
440 x_filter_changed (p);
443 /* Set a given panel filter expression */
444 void set_panel_filter (WPanel *p)
446 char *reg_exp;
447 char *x;
449 x = p->filter ? p->filter : easy_patterns ? "*" : ".";
451 reg_exp = input_dialog (_(" Filter "), _(" Set expression for filtering filenames"), x);
452 if (!reg_exp)
453 return;
454 set_panel_filter_to (p, reg_exp);
457 /* Invoked from the left/right menus */
458 void filter_cmd (void)
460 WPanel *p;
462 if (!SELECTED_IS_PANEL)
463 return;
465 p = MENU_PANEL;
466 set_panel_filter (p);
469 void reread_cmd (void)
471 int flag;
473 mad_check (__FILE__, __LINE__);
474 if (get_current_type () == view_listing &&
475 get_other_type () == view_listing)
476 flag = strcmp (cpanel->cwd, opanel->cwd) ? UP_ONLY_CURRENT : 0;
477 else
478 flag = UP_ONLY_CURRENT;
480 update_panels (UP_RELOAD|flag, UP_KEEPSEL);
481 repaint_screen ();
484 /* Panel sorting related routines */
485 void do_re_sort (WPanel *panel)
487 panel = get_a_panel (panel);
488 panel_re_sort (panel);
491 void reverse_selection_cmd_panel (WPanel *panel)
493 file_entry *file;
494 int i;
496 for (i = 0; i < panel->count; i++){
497 file = &panel->dir.list [i];
498 if (S_ISDIR (file->buf.st_mode))
499 continue;
500 do_file_mark (panel, i, !file->f.marked);
502 paint_panel (panel);
505 void reverse_selection_cmd (void)
507 reverse_selection_cmd_panel (cpanel);
510 void select_cmd_panel (WPanel *panel)
512 char *reg_exp, *reg_exp_t;
513 int i;
514 int c;
515 int dirflag = 0;
517 reg_exp = input_dialog (_(" Select "), "", easy_patterns ? "*" : ".");
518 if (!reg_exp)
519 return;
521 reg_exp_t = reg_exp;
523 /* Check if they specified a directory */
524 if (*reg_exp_t == PATH_SEP){
525 dirflag = 1;
526 reg_exp_t++;
528 if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
529 dirflag = 1;
530 reg_exp_t [strlen(reg_exp_t) - 1] = 0;
533 for (i = 0; i < panel->count; i++){
534 if (!strcmp (panel->dir.list [i].fname, ".."))
535 continue;
536 if (S_ISDIR (panel->dir.list [i].buf.st_mode)){
537 if (!dirflag)
538 continue;
539 } else {
540 if (dirflag)
541 continue;
543 c = regexp_match (reg_exp_t, panel->dir.list [i].fname, match_file);
544 if (c == -1){
545 message (1, MSG_ERROR, _(" Malformed regular expression "));
546 g_free (reg_exp);
547 return;
549 if (c){
550 do_file_mark (panel, i, 1);
553 paint_panel (panel);
554 g_free (reg_exp);
557 void select_cmd (void)
559 select_cmd_panel (cpanel);
562 void unselect_cmd_panel (WPanel *panel)
564 char *reg_exp, *reg_exp_t;
565 int i;
566 int c;
567 int dirflag = 0;
569 reg_exp = input_dialog (_(" Unselect "),"", easy_patterns ? "*" : ".");
570 if (!reg_exp)
571 return;
573 reg_exp_t = reg_exp;
575 /* Check if they specified directory matching */
576 if (*reg_exp_t == PATH_SEP){
577 dirflag = 1;
578 reg_exp_t ++;
580 if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
581 dirflag = 1;
582 reg_exp_t [strlen(reg_exp_t) - 1] = 0;
584 for (i = 0; i < panel->count; i++){
585 if (!strcmp (panel->dir.list [i].fname, ".."))
586 continue;
587 if (S_ISDIR (panel->dir.list [i].buf.st_mode)){
588 if (!dirflag)
589 continue;
590 } else {
591 if (dirflag)
592 continue;
594 c = regexp_match (reg_exp_t, panel->dir.list [i].fname, match_file);
595 if (c == -1){
596 message (1, MSG_ERROR, _(" Malformed regular expression "));
597 g_free (reg_exp);
598 return;
600 if (c){
601 do_file_mark (panel, i, 0);
604 paint_panel (panel);
605 g_free (reg_exp);
608 void unselect_cmd (void)
610 unselect_cmd_panel (cpanel);
613 /* Check if the file exists */
614 /* If not copy the default */
615 static int check_for_default(char *default_file, char *file)
617 struct stat s;
618 long count = 0;
619 double bytes = 0;
620 FileOpContext *ctx;
622 if (mc_stat (file, &s)){
623 if (mc_stat (default_file, &s)){
624 return -1;
626 ctx = file_op_context_new ();
627 file_op_context_create_ui (ctx, OP_COPY, 0);
628 copy_file_file (ctx, default_file, file, 1, &count, &bytes, 1);
629 file_op_context_destroy (ctx);
631 return 0;
634 void ext_cmd (void)
636 char *buffer;
637 char *extdir;
638 int dir;
640 dir = 0;
641 if (geteuid () == 0){
642 dir = query_dialog (_("Extension file edit"),
643 _(" Which extension file you want to edit? "), 0, 2,
644 _("&User"), _("&System Wide"));
646 extdir = concat_dir_and_file (mc_home, MC_LIB_EXT);
648 if (dir == 0){
649 buffer = concat_dir_and_file (home_dir, MC_USER_EXT);
650 check_for_default (extdir, buffer);
651 do_edit (buffer);
652 g_free (buffer);
653 } else if (dir == 1)
654 do_edit (extdir);
656 g_free (extdir);
657 flush_extension_file ();
660 void menu_edit_cmd (void)
662 char *buffer;
663 char *menufile;
664 int dir = 0;
666 dir = query_dialog (
667 _("Menu file edit"),
668 _(" Which menu file will you edit? "),
669 0, geteuid() ? 2 : 3,
670 _("&Local"), _("&Home"), _("&System Wide")
673 menufile = concat_dir_and_file(mc_home, MC_GLOBAL_MENU);
675 switch (dir){
676 case 0:
677 buffer = g_strdup (MC_LOCAL_MENU);
678 check_for_default (menufile, buffer);
679 break;
681 case 1:
682 buffer = concat_dir_and_file (home_dir, MC_HOME_MENU);
683 check_for_default (menufile, buffer);
684 break;
686 case 2:
687 buffer = concat_dir_and_file (mc_home, MC_GLOBAL_MENU);
688 break;
690 default:
691 g_free (menufile);
692 return;
694 do_edit (buffer);
695 if (dir == 0)
696 chmod(buffer, 0600);
697 g_free (buffer);
698 g_free (menufile);
701 void quick_chdir_cmd (void)
703 char *target;
705 target = hotlist_cmd (LIST_HOTLIST);
706 if (!target)
707 return;
709 #ifndef HAVE_GNOME
710 if (get_current_type () == view_tree)
711 tree_chdir (the_tree, target);
712 else
713 #endif
714 if (!do_cd (target, cd_exact))
715 message (1, MSG_ERROR, _("Could not change directory") );
716 g_free (target);
719 #ifdef USE_VFS
720 void reselect_vfs (void)
722 char *target;
724 target = hotlist_cmd (LIST_VFSLIST);
725 if (!target)
726 return;
728 if (!do_cd (target, cd_exact))
729 message (1, MSG_ERROR, _("Could not change directory") );
730 g_free (target);
732 #endif
734 static int compare_files (char *name1, char *name2, long size)
736 int file1, file2;
737 char *data1, *data2;
738 int result = -1; /* Different by default */
740 file1 = open (name1, O_RDONLY);
741 if (file1 >= 0){
742 file2 = open (name2, O_RDONLY);
743 if (file2 >= 0){
744 #ifdef HAVE_MMAP
745 /* Ugly if jungle */
746 data1 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file1, 0);
747 if (data1 != (char*) -1){
748 data2 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file2, 0);
749 if (data2 != (char*) -1){
750 rotate_dash ();
751 result = memcmp (data1, data2, size);
752 munmap (data2, size);
754 munmap (data1, size);
756 #else
757 /* Don't have mmap() :( Even more ugly :) */
758 char buf1[BUFSIZ], buf2[BUFSIZ];
759 int n1, n2;
760 rotate_dash ();
763 while((n1 = read(file1,buf1,BUFSIZ)) == -1 && errno == EINTR);
764 while((n2 = read(file2,buf2,BUFSIZ)) == -1 && errno == EINTR);
765 } while (n1 == n2 && n1 == BUFSIZ && !memcmp(buf1,buf2,BUFSIZ));
766 result = (n1 != n2) || memcmp(buf1,buf2,n1);
767 #endif
768 close (file2);
770 close (file1);
772 return result;
775 enum CompareMode {
776 compare_quick, compare_size_only, compare_thourough
779 static void
780 compare_dir (WPanel *panel, WPanel *other, enum CompareMode mode)
782 int i, j;
783 char *src_name, *dst_name;
785 panel = get_a_panel (panel);
787 /* No marks by default */
788 panel->marked = 0;
789 panel->total = 0;
790 panel->dirs_marked = 0;
792 /* Handle all files in the panel */
793 for (i = 0; i < panel->count; i++){
794 file_entry *source = &panel->dir.list[i];
796 /* Default: unmarked */
797 file_mark (panel, i, 0);
799 /* Skip directories */
800 if (S_ISDIR (source->buf.st_mode))
801 continue;
803 /* Search the corresponding entry from the other panel */
804 for (j = 0; j < other->count; j++){
805 if (strcmp (source->fname,
806 other->dir.list[j].fname) == 0)
807 break;
809 if (j >= other->count)
810 /* Not found -> mark */
811 do_file_mark (panel, i, 1);
812 else {
813 /* Found */
814 file_entry *target = &other->dir.list[j];
816 if (mode != compare_size_only){
817 /* Older version is not marked */
818 if (source->buf.st_mtime < target->buf.st_mtime)
819 continue;
822 /* Newer version with different size is marked */
823 if (source->buf.st_size != target->buf.st_size){
824 do_file_mark (panel, i, 1);
825 continue;
828 if (mode == compare_size_only)
829 continue;
831 if (mode == compare_quick){
832 /* Thorough compare off, compare only time stamps */
833 /* Mark newer version, don't mark version with the same date */
834 if (source->buf.st_mtime > target->buf.st_mtime){
835 do_file_mark (panel, i, 1);
837 continue;
840 /* Thorough compare on, do byte-by-byte comparison */
841 src_name = concat_dir_and_file (panel->cwd, source->fname);
842 dst_name = concat_dir_and_file (other->cwd, target->fname);
843 if (compare_files (src_name, dst_name, source->buf.st_size))
844 do_file_mark (panel, i, 1);
845 g_free (src_name);
846 g_free (dst_name);
848 } /* for (i ...) */
851 void compare_dirs_cmd (void)
853 enum CompareMode thorough_flag = compare_quick;
855 thorough_flag = query_dialog (_(" Compare directories "), _(" Select compare method: "),
856 0, 3, _("&Quick"), _("&Size only"), _("&Thorough"), _("&Cancel"));
857 if (thorough_flag < 0 || thorough_flag > 2)
858 return;
859 if (get_current_type () == view_listing &&
860 get_other_type () == view_listing){
861 compare_dir (cpanel, opanel, thorough_flag);
862 compare_dir (opanel, cpanel, thorough_flag);
863 paint_panel (cpanel);
864 paint_panel (opanel);
865 } else {
866 message (1, MSG_ERROR, _(" Both panels should be on the listing view mode to use this command "));
870 void history_cmd (void)
872 Listbox *listbox;
873 Hist *current;
875 if (input_w (cmdline)->need_push){
876 if (push_history (input_w (cmdline), input_w (cmdline)->buffer) == 2)
877 input_w (cmdline)->need_push = 0;
879 if (!input_w (cmdline)->history){
880 message (1, MSG_ERROR, _(" The command history is empty "));
881 return;
883 current = input_w (cmdline)->history;
884 while (current->prev)
885 current = current->prev;
886 listbox = create_listbox_window (60, 10, _(" Command history "),
887 "[Command Menu]");
888 while (current){
889 LISTBOX_APPEND_TEXT (listbox, 0, current->text,
890 current);
891 current = current->next;
893 run_dlg (listbox->dlg);
894 if (listbox->dlg->ret_value == B_CANCEL)
895 current = NULL;
896 else
897 current = listbox->list->current->data;
898 destroy_dlg (listbox->dlg);
899 g_free (listbox);
901 if (!current)
902 return;
903 input_w (cmdline)->history = current;
904 assign_text (input_w (cmdline), input_w (cmdline)->history->text);
905 update_input (input_w (cmdline), 1);
908 #if !defined(HAVE_XVIEW) && !defined(HAVE_GNOME)
909 void swap_cmd (void)
911 swap_panels ();
912 touchwin (stdscr);
913 repaint_screen ();
915 #endif
917 void
918 view_other_cmd (void)
920 static int message_flag = TRUE;
921 #ifdef HAVE_SUBSHELL_SUPPORT
922 char *new_dir = NULL;
923 char **new_dir_p;
924 #endif
926 if (!xterm_flag && !console_flag && !use_subshell){
927 if (message_flag)
928 message (1, MSG_ERROR, _(" Not an xterm or Linux console; \n"
929 " the panels cannot be toggled. "));
930 message_flag = FALSE;
931 } else {
932 #ifndef HAVE_X
933 if (use_mouse_p)
934 shut_mouse ();
935 if (clear_before_exec)
936 clr_scr ();
937 if (alternate_plus_minus)
938 numeric_keypad_mode ();
939 #endif
940 #ifndef HAVE_SLANG
941 /* With slang we don't want any of this, since there
942 * is no mc_raw_mode supported
944 reset_shell_mode ();
945 noecho ();
946 #endif
947 #ifndef HAVE_X
948 keypad(stdscr, FALSE);
949 endwin ();
950 #endif
951 if (!status_using_ncurses)
952 do_exit_ca_mode ();
953 mc_raw_mode ();
954 if (console_flag)
955 restore_console ();
957 #ifdef HAVE_SUBSHELL_SUPPORT
958 if (use_subshell){
959 new_dir_p = vfs_current_is_local () ? &new_dir : NULL;
960 if (invoke_subshell (NULL, VISIBLY, new_dir_p))
961 quiet_quit_cmd(); /* User did `exit' or `logout': quit MC quietly */
962 } else
963 #endif
965 if (output_starts_shell){
966 fprintf (stderr,
967 _("Type `exit' to return to the Midnight Commander"));
968 fprintf (stderr, "\n\r\n\r");
970 my_system (EXECUTE_AS_SHELL, shell, NULL);
971 } else
972 get_key_code (0);
974 if (console_flag)
975 handle_console (CONSOLE_SAVE);
977 if (!status_using_ncurses)
978 do_enter_ca_mode ();
980 #ifndef HAVE_X
981 reset_prog_mode ();
982 keypad(stdscr, TRUE);
983 if (use_mouse_p)
984 init_mouse ();
985 if (alternate_plus_minus)
986 application_keypad_mode ();
987 #endif
989 #ifdef HAVE_SUBSHELL_SUPPORT
990 if (use_subshell){
991 load_prompt (0, 0);
992 if (new_dir)
993 do_possible_cd (new_dir);
994 if (console_flag && output_lines)
995 show_console_contents (output_start_y,
996 LINES-keybar_visible-output_lines-1,
997 LINES-keybar_visible-1);
999 #endif
1000 #ifndef HAVE_X
1001 touchwin (stdscr);
1002 #endif
1004 /* prevent screen flash when user did 'exit' or 'logout' within
1005 subshell */
1006 if (!quit)
1007 repaint_screen ();
1011 #ifndef OS2_NT
1012 static void
1013 do_link (int symbolic_link, char *fname)
1015 struct stat s;
1016 char *dest, *src;
1017 int stat_r;
1019 if (!symbolic_link){
1020 stat_r = mc_stat (fname, &s);
1021 if (stat_r != 0){
1022 message (1, MSG_ERROR, _(" Couldn't stat %s \n %s "),
1023 fname, unix_error_string (errno));
1024 return;
1026 if (!S_ISREG (s.st_mode))
1027 return;
1030 if (!symbolic_link){
1031 src = g_strconcat (_(" Link "), name_trunc (fname, 46),
1032 _(" to:"), NULL);
1033 dest = input_expand_dialog (_(" Link "), src, "");
1034 g_free (src);
1035 if (!dest)
1036 return;
1037 if (!*dest) {
1038 g_free (dest);
1039 return;
1041 save_cwds_stat ();
1042 if (-1 == mc_link (fname, dest))
1043 message (1, MSG_ERROR, _(" link: %s "), unix_error_string (errno));
1044 } else {
1045 #ifdef OLD_SYMLINK_VERSION
1046 symlink_dialog (fname, "", &dest, &src);
1047 #else
1048 /* suggest the full path for symlink */
1049 char s[MC_MAXPATHLEN];
1050 char d[MC_MAXPATHLEN];
1052 strcpy(s, cpanel->cwd);
1053 if ( ! ((s[0] == '/') && (s[1] == 0)))
1054 strcat(s, "/");
1055 strcat(s, fname);
1056 if (get_other_type () == view_listing)
1057 strcpy(d, opanel->cwd);
1058 else
1059 strcpy (d,"");
1061 if ( ! ((d[0] == '/') && (d[1] == 0)))
1062 strcat(d, "/");
1063 symlink_dialog (s, d, &dest, &src);
1064 #endif
1065 if (!dest || !*dest) {
1066 if (src)
1067 g_free (src);
1068 if (dest)
1069 g_free (dest);
1070 return;
1072 if (src){
1073 if (*src) {
1074 save_cwds_stat ();
1075 if (-1 == mc_symlink (dest, src))
1076 message (1, MSG_ERROR, _(" symlink: %s "),
1077 unix_error_string (errno));
1079 g_free (src);
1082 g_free (dest);
1083 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1084 repaint_screen ();
1087 void link_cmd (void)
1089 do_link (0, selection (cpanel)->fname);
1092 void symlink_cmd (void)
1094 do_link (1, selection (cpanel)->fname);
1097 void edit_symlink_cmd (void)
1099 if (S_ISLNK (selection (cpanel)->buf.st_mode)) {
1100 char buffer [MC_MAXPATHLEN], *p = selection (cpanel)->fname;
1101 int i;
1102 char *dest, *q = g_strconcat (_(" Symlink "), name_trunc (p, 32), _(" points to:"), NULL);
1104 i = readlink (p, buffer, MC_MAXPATHLEN);
1105 if (i > 0) {
1106 buffer [i] = 0;
1107 dest = input_expand_dialog (_(" Edit symlink "), q, buffer);
1108 if (dest) {
1109 if (*dest && strcmp (buffer, dest)) {
1110 save_cwds_stat ();
1111 mc_unlink (p);
1112 if (-1 == mc_symlink (dest, p))
1113 message (1, MSG_ERROR, _(" edit symlink: %s "),
1114 unix_error_string (errno));
1115 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1116 repaint_screen ();
1118 g_free (dest);
1121 g_free (q);
1125 void other_symlink_cmd (void)
1127 char *dest, *q, *p, *r, *s, *t;
1129 if (get_other_type () != view_listing)
1130 return;
1132 if (!strcmp (selection (opanel)->fname, ".."))
1133 return;
1134 p = concat_dir_and_file (cpanel->cwd, selection (cpanel)->fname);
1135 r = concat_dir_and_file (opanel->cwd, selection (cpanel)->fname);
1137 q = g_strconcat (_(" Link symbolically "), name_trunc (p, 32), _(" to:"), NULL);
1138 dest = input_expand_dialog (_(" Relative symlink "), q, r);
1139 if (dest) {
1140 if (*dest) {
1141 t = strrchr (dest, PATH_SEP);
1142 if (t) {
1143 t[1] = 0;
1144 s = diff_two_paths (dest, p);
1145 t[1] = PATH_SEP;
1146 if (s) {
1147 save_cwds_stat ();
1148 if (-1 == mc_symlink (dest, s))
1149 message (1, MSG_ERROR, _(" relative symlink: %s "),
1150 unix_error_string (errno));
1151 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1152 repaint_screen ();
1153 g_free (s);
1157 g_free (dest);
1159 g_free (q);
1160 g_free (p);
1161 g_free (r);
1163 #endif
1165 void help_cmd (void)
1167 char *hlpfile = concat_dir_and_file (mc_home, "mc.hlp");
1168 interactive_display (hlpfile, "[main]");
1169 g_free (hlpfile);
1172 void view_panel_cmd (void)
1174 view_cmd (cpanel);
1177 void edit_panel_cmd (void)
1179 edit_cmd (cpanel);
1182 void mkdir_panel_cmd (void)
1184 mkdir_cmd (cpanel);
1187 /* Returns a random hint */
1188 char *get_random_hint (void)
1190 char *data, *result, *eol;
1191 char *hintfile;
1192 int len;
1193 int start;
1195 /* Do not change hints more often than one minute */
1197 #ifdef SCO_FLAVOR
1198 static time_t last;
1199 time_t now;
1201 time (&now);
1202 if ((now - last) < 60)
1203 return g_strdup ("");
1204 last = now;
1205 #else
1206 static int last_sec;
1207 static struct timeval tv;
1209 gettimeofday (&tv, NULL);
1210 if (!(tv.tv_sec> last_sec+60))
1211 return g_strdup ("");
1212 last_sec = tv.tv_sec;
1213 #endif
1215 hintfile = concat_dir_and_file (mc_home, MC_HINT);
1216 data = load_file (hintfile);
1217 g_free (hintfile);
1218 if (!data)
1219 return 0;
1221 #ifdef SCO_FLAVOR
1222 srand ((short) now);
1223 #else
1224 srand (tv.tv_sec);
1225 #endif
1226 /* get a random entry */
1227 len = strlen (data);
1228 start = rand () % len;
1230 for (;start; start--){
1231 if (data [start] == '\n'){
1232 start++;
1233 break;
1236 eol = strchr (&data [start], '\n');
1237 if (eol)
1238 *eol = 0;
1239 result = g_strdup (&data [start]);
1240 g_free (data);
1241 return result;
1244 #ifndef USE_VFS
1245 #ifdef USE_NETCODE
1246 #undef USE_NETCODE
1247 #endif
1248 #endif
1250 #ifdef USE_NETCODE
1252 static char *machine_str = N_(" Enter machine name (F1 for details): ");
1254 static void nice_cd (char *text, char *xtext, char *help, char *prefix, int to_home)
1256 char *machine;
1257 char *cd_path;
1259 if (!SELECTED_IS_PANEL)
1260 return;
1262 machine = input_dialog_help (text,
1263 xtext,
1264 help, "");
1265 if (!machine)
1266 return;
1268 if (strncmp (prefix, machine, strlen (prefix)) == 0)
1269 cd_path = g_strconcat (machine, to_home ? "/~/" : NULL, NULL);
1270 else
1271 cd_path = g_strconcat (prefix, machine, to_home ? "/~/" : NULL, NULL);
1273 if (do_panel_cd (MENU_PANEL, cd_path, 0))
1274 directory_history_add (MENU_PANEL, (MENU_PANEL)->cwd);
1275 else
1276 message (1, MSG_ERROR, N_(" Could not chdir to %s "), cd_path);
1277 g_free (cd_path);
1278 g_free (machine);
1281 void netlink_cmd (void)
1283 nice_cd (_(" Link to a remote machine "), _(machine_str),
1284 "[Network File System]", "/#mc:", 1);
1287 void ftplink_cmd (void)
1289 nice_cd (_(" FTP to machine "), _(machine_str),
1290 "[FTP File System]", "/#ftp:", 1);
1293 #ifdef HAVE_SETSOCKOPT
1294 void source_routing (void)
1296 char *source;
1297 struct hostent *hp;
1299 source = input_dialog (_(" Socket source routing setup "),
1300 _(" Enter host name to use as a source routing hop: ")n,
1301 "");
1302 if (!source)
1303 return;
1305 hp = gethostbyname (source);
1306 if (!hp){
1307 message (1, _(" Host name "), _(" Error while looking up IP address "));
1308 return;
1310 source_route = *((int *)hp->h_addr);
1312 #endif /* HAVE_SETSOCKOPT */
1313 #endif /* USE_NETCODE */
1315 #ifdef USE_EXT2FSLIB
1316 void undelete_cmd (void)
1318 nice_cd (_(" Undelete files on an ext2 file system "),
1319 _(" Enter device (without /dev/) to undelete\n "
1320 " files on: (F1 for details)"),
1321 "[Undelete File System]", "/#undel:", 0);
1323 #endif
1325 void quick_cd_cmd (void)
1327 char *p = cd_dialog ();
1329 if (p && *p) {
1330 char *q = g_strconcat ("cd ", p, NULL);
1332 do_cd_command (q);
1333 g_free (q);
1335 if (p)
1336 g_free (p);
1339 void
1340 dirsizes_cmd (void)
1342 WPanel *panel = cpanel;
1343 int i;
1344 long marked;
1345 double total;
1347 for (i = 0; i < panel->count; i++)
1348 if (S_ISDIR (panel->dir.list [i].buf.st_mode) &&
1349 ((panel->dirs_marked && panel->dir.list [i].f.marked) ||
1350 !panel->dirs_marked) &&
1351 strcmp (panel->dir.list [i].fname, "..") != 0) {
1352 total = 0.0l;
1353 compute_dir_size (panel->dir.list [i].fname, &marked, &total);
1354 panel->dir.list [i].buf.st_size = (long)total;
1355 panel->dir.list [i].f.dir_size_computed = 1;
1358 recalculate_panel_summary (panel);
1359 paint_panel (panel);
1362 void
1363 save_setup_cmd (void)
1365 char *str;
1367 save_setup ();
1368 sync_profiles ();
1369 str = g_strconcat ( _(" Setup saved to ~/"), PROFILE_NAME, NULL);
1371 #ifdef HAVE_GNOME
1372 set_hintbar (str);
1373 #else
1374 message (0, _(" Setup "), str);
1375 #endif
1376 g_free (str);
1379 void
1380 configure_panel_listing (WPanel *p, int view_type, int use_msformat, char *user, char *status)
1382 int err;
1384 p->user_mini_status = use_msformat;
1385 p->list_type = view_type;
1387 if (view_type == list_user || use_msformat){
1388 g_free (p->user_format);
1389 p->user_format = user;
1391 g_free (p->user_status_format [view_type]);
1392 p->user_status_format [view_type] = status;
1394 err = set_panel_formats (p);
1396 if (err){
1397 if (err & 0x01){
1398 g_free (p->user_format);
1399 p->user_format = g_strdup (DEFAULT_USER_FORMAT);
1402 if (err & 0x02){
1403 g_free (p->user_status_format [view_type]);
1404 p->user_status_format [view_type] = g_strdup (DEFAULT_USER_FORMAT);
1408 else {
1409 g_free (user);
1410 g_free (status);
1413 set_panel_formats (p);
1414 paint_panel (p);
1416 do_refresh ();
1419 #ifndef HAVE_GNOME
1420 void
1421 info_cmd_no_menu (void)
1423 set_display_type (cpanel == left_panel ? 1 : 0, view_info);
1426 void
1427 quick_cmd_no_menu (void)
1429 set_display_type (cpanel == left_panel ? 1 : 0, view_quick);
1432 void
1433 switch_to_listing (int panel_index)
1435 if (get_display_type (panel_index) != view_listing)
1436 set_display_type (panel_index, view_listing);
1439 void
1440 listing_cmd (void)
1442 int view_type, use_msformat;
1443 char *user, *status;
1444 WPanel *p;
1445 int display_type;
1447 display_type = get_display_type (MENU_PANEL_IDX);
1448 if (display_type == view_listing)
1449 p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1450 else
1451 p = 0;
1453 view_type = display_box (p, &user, &status, &use_msformat, MENU_PANEL_IDX);
1455 if (view_type == -1)
1456 return;
1458 switch_to_listing (MENU_PANEL_IDX);
1460 p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1462 configure_panel_listing (p, view_type, use_msformat, user, status);
1465 void
1466 tree_cmd (void)
1468 set_display_type (MENU_PANEL_IDX, view_tree);
1471 void
1472 info_cmd (void)
1474 set_display_type (MENU_PANEL_IDX, view_info);
1477 void
1478 quick_view_cmd (void)
1480 set_display_type (MENU_PANEL_IDX, view_quick);
1482 #endif
1484 /* Handle the tree internal listing modes switching */
1485 static int
1486 set_basic_panel_listing_to (int panel_index, int listing_mode)
1488 WPanel *p = (WPanel *) get_panel_widget (panel_index);
1490 #ifndef HAVE_GNOME
1491 switch_to_listing (panel_index);
1492 #endif
1493 p->list_type = listing_mode;
1494 if (set_panel_formats (p))
1495 return 0;
1497 paint_panel (p);
1498 do_refresh ();
1499 return 1;
1502 void
1503 toggle_listing_cmd (void)
1505 int current = get_current_index ();
1506 WPanel *p = (WPanel *) get_panel_widget (current);
1507 int list_mode = p->list_type;
1508 int m;
1510 switch (list_mode){
1511 case list_full:
1512 case list_brief:
1513 m = list_long;
1514 break;
1515 case list_long:
1516 m = list_user;
1517 break;
1518 default:
1519 m = list_full;
1521 if (set_basic_panel_listing_to (current, m))
1522 return;
1523 set_basic_panel_listing_to (current, list_full);