Updated italian translation
[midnight-commander.git] / src / cmd.c
blob59de42b17eb2b7723ff922c36bce9cc849738a04
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 <errno.h>
33 #ifdef USE_NETCODE
34 #include <netdb.h>
35 #endif
37 #ifdef HAVE_MMAP
38 # include <sys/mman.h>
39 #endif
41 #include "global.h"
42 #include "cmd.h" /* Our definitions */
43 #include "fileopctx.h" /* file_op_context_new() */
44 #include "file.h" /* copy_file_file() */
45 #include "find.h" /* do_find() */
46 #include "hotlist.h" /* hotlist_cmd() */
47 #include "tree.h" /* tree_chdir() */
48 #include "subshell.h" /* use_subshell */
49 #include "cons.saver.h" /* console_flag */
50 #include "tty.h" /* LINES */
51 #include "dialog.h" /* Widget */
52 #include "view.h" /* view() */
53 #include "wtools.h" /* message() */
54 #include "widget.h" /* push_history() */
55 #include "key.h" /* application_keypad_mode() */
56 #include "win.h" /* do_enter_ca_mode() */
57 #include "main.h" /* change_panel() */
58 #include "panel.h" /* current_panel */
59 #include "help.h" /* interactive_display() */
60 #include "user.h" /* MC_GLOBAL_MENU */
61 #include "command.h" /* cmdline */
62 #include "layout.h" /* get_current_type() */
63 #include "ext.h" /* regex_command() */
64 #include "boxes.h" /* cd_dialog() */
65 #include "setup.h" /* save_setup() */
66 #include "profile.h" /* PROFILE_NAME */
67 #include "execute.h" /* toggle_panels() */
69 #ifndef MAP_FILE
70 # define MAP_FILE 0
71 #endif
73 #ifdef USE_INTERNAL_EDIT
74 # include "../edit/edit.h"
75 #endif
77 /* If set and you don't have subshell support,then C-o will give you a shell */
78 int output_starts_shell = 0;
80 /* If set, use the builtin editor */
81 int use_internal_edit = 1;
84 int
85 view_file_at_line (char *filename, int plain_view, int internal,
86 int start_line)
88 static char *viewer = 0;
89 int move_dir = 0;
92 if (plain_view) {
93 int changed_hex_mode = 0;
94 int changed_nroff_flag = 0;
95 int changed_magic_flag = 0;
97 altered_hex_mode = 0;
98 altered_nroff_flag = 0;
99 altered_magic_flag = 0;
100 if (default_hex_mode)
101 changed_hex_mode = 1;
102 if (default_nroff_flag)
103 changed_nroff_flag = 1;
104 if (default_magic_flag)
105 changed_magic_flag = 1;
106 default_hex_mode = 0;
107 default_nroff_flag = 0;
108 default_magic_flag = 0;
109 view (0, filename, &move_dir, start_line);
110 if (changed_hex_mode && !altered_hex_mode)
111 default_hex_mode = 1;
112 if (changed_nroff_flag && !altered_nroff_flag)
113 default_nroff_flag = 1;
114 if (changed_magic_flag && !altered_magic_flag)
115 default_magic_flag = 1;
116 repaint_screen ();
117 return move_dir;
119 if (internal) {
120 char view_entry[BUF_TINY];
122 if (start_line != 0)
123 g_snprintf (view_entry, sizeof (view_entry), "View:%d",
124 start_line);
125 else
126 strcpy (view_entry, "View");
128 if (regex_command (filename, view_entry, &move_dir) == 0) {
129 view (0, filename, &move_dir, start_line);
130 repaint_screen ();
132 } else {
133 if (!viewer) {
134 viewer = getenv ("PAGER");
135 if (!viewer)
136 viewer = "view";
138 execute_with_vfs_arg (viewer, filename);
140 return move_dir;
143 /* view_file (filename, plain_view, internal)
145 * Inputs:
146 * filename: The file name to view
147 * plain_view: If set does not do any fancy pre-processing (no filtering) and
148 * always invokes the internal viewer.
149 * internal: If set uses the internal viewer, otherwise an external viewer.
152 view_file (char *filename, int plain_view, int internal)
154 return view_file_at_line (filename, plain_view, internal, 0);
157 /* scan_for_file (panel, idx, direction)
159 * Inputs:
160 * panel: pointer to the panel on which we operate
161 * idx: starting file.
162 * direction: 1, or -1
164 static int scan_for_file (WPanel *panel, int idx, int direction)
166 int i = idx + direction;
168 while (i != idx){
169 if (i < 0)
170 i = panel->count - 1;
171 if (i == panel->count)
172 i = 0;
173 if (!S_ISDIR (panel->dir.list [i].st.st_mode))
174 return i;
175 i += direction;
177 return i;
181 * Run viewer (internal or external) on the currently selected file.
182 * If normal is 1, force internal viewer and raw mode (used for F13).
184 static void
185 do_view_cmd (int normal)
187 int dir, file_idx;
189 /* Directories are viewed by changing to them */
190 if (S_ISDIR (selection (current_panel)->st.st_mode)
191 || link_isdir (selection (current_panel))) {
192 if (confirm_view_dir && (current_panel->marked || current_panel->dirs_marked)) {
193 if (query_dialog
194 (_(" Confirmation "), _("Files tagged, want to cd?"), 0, 2,
195 _("&Yes"), _("&No")) != 0) {
196 return;
199 if (!do_cd (selection (current_panel)->fname, cd_exact))
200 message (1, MSG_ERROR, _("Cannot change directory"));
202 return;
206 file_idx = current_panel->selected;
207 while (1) {
208 char *filename;
210 filename = current_panel->dir.list[file_idx].fname;
212 dir = view_file (filename, normal, use_internal_view);
213 if (dir == 0)
214 break;
215 file_idx = scan_for_file (current_panel, file_idx, dir);
219 /* Run user's preferred viewer on the currently selected file */
220 void
221 view_cmd (void)
223 do_view_cmd (0);
226 /* Ask for file and run user's preferred viewer on it */
227 void
228 view_file_cmd (void)
230 char *filename;
232 filename =
233 input_expand_dialog (_(" View file "), _(" Filename:"),
234 selection (current_panel)->fname);
235 if (!filename)
236 return;
238 view_file (filename, 0, use_internal_view);
239 g_free (filename);
242 /* Run plain internal viewer on the currently selected file */
243 void
244 view_simple_cmd (void)
246 do_view_cmd (1);
249 void
250 filtered_view_cmd (void)
252 char *command;
254 command =
255 input_dialog (_(" Filtered view "),
256 _(" Filter command and arguments:"),
257 selection (current_panel)->fname);
258 if (!command)
259 return;
261 view (command, "", 0, 0);
263 g_free (command);
266 void do_edit_at_line (const char *what, int start_line)
268 static char *editor = 0;
270 #ifdef USE_INTERNAL_EDIT
271 if (use_internal_edit){
272 edit (what, start_line);
273 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
274 repaint_screen ();
275 return;
277 #endif /* USE_INTERNAL_EDIT */
278 if (!editor){
279 editor = getenv ("EDITOR");
280 if (!editor)
281 editor = get_default_editor ();
283 execute_with_vfs_arg (editor, what);
284 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
285 repaint_screen ();
288 static void
289 do_edit (const char *what)
291 do_edit_at_line (what, 0);
294 void
295 edit_cmd (void)
297 if (regex_command (selection (current_panel)->fname, "Edit", 0) == 0)
298 do_edit (selection (current_panel)->fname);
301 void
302 edit_cmd_new (void)
304 do_edit (NULL);
307 /* Invoked by F5. Copy, default to the other panel. */
308 void
309 copy_cmd (void)
311 save_cwds_stat ();
312 if (panel_operate (current_panel, OP_COPY, 0)) {
313 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
314 repaint_screen ();
318 /* Invoked by F6. Move/rename, default to the other panel, ignore marks. */
319 void ren_cmd (void)
321 save_cwds_stat ();
322 if (panel_operate (current_panel, OP_MOVE, 0)){
323 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
324 repaint_screen ();
328 /* Invoked by F15. Copy, default to the same panel, ignore marks. */
329 void copy_cmd_local (void)
331 save_cwds_stat ();
332 if (panel_operate (current_panel, OP_COPY, 1)){
333 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
334 repaint_screen ();
338 /* Invoked by F16. Move/rename, default to the same panel. */
339 void ren_cmd_local (void)
341 save_cwds_stat ();
342 if (panel_operate (current_panel, OP_MOVE, 1)){
343 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
344 repaint_screen ();
348 void
349 mkdir_cmd (void)
351 char *tempdir;
352 char *dir;
354 dir =
355 input_expand_dialog (_("Create a new Directory"),
356 _(" Enter directory name:"), "");
358 if (!dir || !*dir)
359 return;
361 if (dir[0] == '/' || dir[0] == '~')
362 tempdir = g_strdup (dir);
363 else
364 tempdir = concat_dir_and_file (current_panel->cwd, dir);
365 g_free (dir);
367 save_cwds_stat ();
368 if (my_mkdir (tempdir, 0777) == 0) {
369 update_panels (UP_OPTIMIZE, tempdir);
370 repaint_screen ();
371 select_item (current_panel);
372 g_free (tempdir);
373 return;
375 g_free (tempdir);
376 message (1, MSG_ERROR, " %s ", unix_error_string (errno));
379 void delete_cmd (void)
381 save_cwds_stat ();
383 if (panel_operate (current_panel, OP_DELETE, 0)){
384 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
385 repaint_screen ();
389 /* Invoked by F18. Remove selected file, regardless of marked files. */
390 void delete_cmd_local (void)
392 save_cwds_stat ();
394 if (panel_operate (current_panel, OP_DELETE, 1)){
395 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
396 repaint_screen ();
400 void find_cmd (void)
402 do_find ();
405 static void
406 set_panel_filter_to (WPanel *p, char *allocated_filter_string)
408 if (p->filter){
409 g_free (p->filter);
410 p->filter = 0;
412 if (!(allocated_filter_string [0] == '*' && allocated_filter_string [1] == 0))
413 p->filter = allocated_filter_string;
414 else
415 g_free (allocated_filter_string);
416 reread_cmd ();
419 /* Set a given panel filter expression */
420 static void
421 set_panel_filter (WPanel *p)
423 char *reg_exp;
424 char *x;
426 x = p->filter ? p->filter : easy_patterns ? "*" : ".";
428 reg_exp = input_dialog_help (_(" Filter "),
429 _(" Set expression for filtering filenames"),
430 "[Filter...]", x);
431 if (!reg_exp)
432 return;
433 set_panel_filter_to (p, reg_exp);
436 /* Invoked from the left/right menus */
437 void filter_cmd (void)
439 WPanel *p;
441 if (!SELECTED_IS_PANEL)
442 return;
444 p = MENU_PANEL;
445 set_panel_filter (p);
448 void reread_cmd (void)
450 int flag;
452 if (get_current_type () == view_listing &&
453 get_other_type () == view_listing)
454 flag = strcmp (current_panel->cwd, other_panel->cwd) ? UP_ONLY_CURRENT : 0;
455 else
456 flag = UP_ONLY_CURRENT;
458 update_panels (UP_RELOAD|flag, UP_KEEPSEL);
459 repaint_screen ();
462 void reverse_selection_cmd (void)
464 file_entry *file;
465 int i;
467 for (i = 0; i < current_panel->count; i++){
468 file = &current_panel->dir.list [i];
469 if (S_ISDIR (file->st.st_mode))
470 continue;
471 do_file_mark (current_panel, i, !file->f.marked);
475 void select_cmd (void)
477 char *reg_exp, *reg_exp_t;
478 int i;
479 int c;
480 int dirflag = 0;
482 reg_exp = input_dialog (_(" Select "), "", easy_patterns ? "*" : ".");
483 if (!reg_exp)
484 return;
486 reg_exp_t = reg_exp;
488 /* Check if they specified a directory */
489 if (*reg_exp_t == PATH_SEP){
490 dirflag = 1;
491 reg_exp_t++;
493 if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
494 dirflag = 1;
495 reg_exp_t [strlen(reg_exp_t) - 1] = 0;
498 for (i = 0; i < current_panel->count; i++){
499 if (!strcmp (current_panel->dir.list [i].fname, ".."))
500 continue;
501 if (S_ISDIR (current_panel->dir.list [i].st.st_mode)){
502 if (!dirflag)
503 continue;
504 } else {
505 if (dirflag)
506 continue;
508 c = regexp_match (reg_exp_t, current_panel->dir.list [i].fname, match_file);
509 if (c == -1){
510 message (1, MSG_ERROR, _(" Malformed regular expression "));
511 g_free (reg_exp);
512 return;
514 if (c){
515 do_file_mark (current_panel, i, 1);
518 g_free (reg_exp);
521 void unselect_cmd (void)
523 char *reg_exp, *reg_exp_t;
524 int i;
525 int c;
526 int dirflag = 0;
528 reg_exp = input_dialog (_(" Unselect "),"", easy_patterns ? "*" : ".");
529 if (!reg_exp)
530 return;
532 reg_exp_t = reg_exp;
534 /* Check if they specified directory matching */
535 if (*reg_exp_t == PATH_SEP){
536 dirflag = 1;
537 reg_exp_t ++;
539 if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
540 dirflag = 1;
541 reg_exp_t [strlen(reg_exp_t) - 1] = 0;
543 for (i = 0; i < current_panel->count; i++){
544 if (!strcmp (current_panel->dir.list [i].fname, ".."))
545 continue;
546 if (S_ISDIR (current_panel->dir.list [i].st.st_mode)){
547 if (!dirflag)
548 continue;
549 } else {
550 if (dirflag)
551 continue;
553 c = regexp_match (reg_exp_t, current_panel->dir.list [i].fname, match_file);
554 if (c == -1){
555 message (1, MSG_ERROR, _(" Malformed regular expression "));
556 g_free (reg_exp);
557 return;
559 if (c){
560 do_file_mark (current_panel, i, 0);
563 g_free (reg_exp);
566 /* Check if the file exists */
567 /* If not copy the default */
568 static int
569 check_for_default(char *default_file, char *file)
571 struct stat s;
572 off_t count = 0;
573 double bytes = 0;
574 FileOpContext *ctx;
576 if (mc_stat (file, &s)){
577 if (mc_stat (default_file, &s)){
578 return -1;
580 ctx = file_op_context_new (OP_COPY);
581 file_op_context_create_ui (ctx, 0);
582 copy_file_file (ctx, default_file, file, 1, &count, &bytes, 1);
583 file_op_context_destroy (ctx);
585 return 0;
588 void ext_cmd (void)
590 char *buffer;
591 char *extdir;
592 int dir;
594 dir = 0;
595 if (geteuid () == 0){
596 dir = query_dialog (_("Extension file edit"),
597 _(" Which extension file you want to edit? "), 0, 2,
598 _("&User"), _("&System Wide"));
600 extdir = concat_dir_and_file (mc_home, MC_LIB_EXT);
602 if (dir == 0){
603 buffer = concat_dir_and_file (home_dir, MC_USER_EXT);
604 check_for_default (extdir, buffer);
605 do_edit (buffer);
606 g_free (buffer);
607 } else if (dir == 1)
608 do_edit (extdir);
610 g_free (extdir);
611 flush_extension_file ();
614 /* where = 0 - do edit file menu for mc */
615 /* where = 1 - do edit file menu for mcedit */
616 static void
617 menu_edit_cmd (int where)
619 char *buffer;
620 char *menufile;
621 int dir = 0;
623 dir = query_dialog (
624 _(" Menu edit "),
625 _(" Which menu file do you want to edit? "),
626 0, geteuid() ? 2 : 3,
627 _("&Local"), _("&Home"), _("&System Wide")
630 menufile = concat_dir_and_file (mc_home, where ? CEDIT_GLOBAL_MENU : MC_GLOBAL_MENU);
632 switch (dir) {
633 case 0:
634 buffer = g_strdup (where ? CEDIT_LOCAL_MENU : MC_LOCAL_MENU);
635 check_for_default (menufile, buffer);
636 break;
638 case 1:
639 buffer = concat_dir_and_file (home_dir, where ? CEDIT_HOME_MENU : MC_HOME_MENU);
640 check_for_default (menufile, buffer);
641 break;
643 case 2:
644 buffer = concat_dir_and_file (mc_home, where ? CEDIT_GLOBAL_MENU : MC_GLOBAL_MENU);
645 break;
647 default:
648 g_free (menufile);
649 return;
651 do_edit (buffer);
652 if (dir == 0)
653 chmod(buffer, 0600);
654 g_free (buffer);
655 g_free (menufile);
658 void quick_chdir_cmd (void)
660 char *target;
662 target = hotlist_cmd (LIST_HOTLIST);
663 if (!target)
664 return;
666 if (get_current_type () == view_tree)
667 tree_chdir (the_tree, target);
668 else
669 if (!do_cd (target, cd_exact))
670 message (1, MSG_ERROR, _("Cannot change directory") );
671 g_free (target);
674 /* edit file menu for mc */
675 void
676 edit_mc_menu_cmd (void)
678 menu_edit_cmd (0);
681 #ifdef USE_INTERNAL_EDIT
682 /* edit file menu for mcedit */
683 void
684 edit_user_menu_cmd (void)
686 menu_edit_cmd (1);
689 /* edit syntax file for mcedit */
690 void
691 edit_syntax_cmd (void)
693 char *buffer;
694 char *extdir;
695 int dir = 0;
697 if (geteuid () == 0) {
698 dir =
699 query_dialog (_("Syntax file edit"),
700 _(" Which syntax file you want to edit? "), 0, 2,
701 _("&User"), _("&System Wide"));
703 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
705 if (dir == 0) {
706 buffer = concat_dir_and_file (home_dir, SYNTAX_FILE);
707 check_for_default (extdir, buffer);
708 do_edit (buffer);
709 g_free (buffer);
710 } else if (dir == 1)
711 do_edit (extdir);
713 g_free (extdir);
715 #endif
717 #ifdef USE_VFS
718 void reselect_vfs (void)
720 char *target;
722 target = hotlist_cmd (LIST_VFSLIST);
723 if (!target)
724 return;
726 if (!do_cd (target, cd_exact))
727 message (1, MSG_ERROR, _("Cannot change directory") );
728 g_free (target);
730 #endif /* USE_VFS */
732 static int compare_files (char *name1, char *name2, off_t size)
734 int file1, file2;
735 int result = -1; /* Different by default */
737 file1 = open (name1, O_RDONLY);
738 if (file1 >= 0){
739 file2 = open (name2, O_RDONLY);
740 if (file2 >= 0){
741 #ifdef HAVE_MMAP
742 char *data1, *data2;
743 /* Ugly if jungle */
744 data1 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file1, 0);
745 if (data1 != (char*) -1){
746 data2 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file2, 0);
747 if (data2 != (char*) -1){
748 rotate_dash ();
749 result = memcmp (data1, data2, size);
750 munmap (data2, size);
752 munmap (data1, size);
754 #else
755 /* Don't have mmap() :( Even more ugly :) */
756 char buf1[BUFSIZ], buf2[BUFSIZ];
757 int n1, n2;
758 rotate_dash ();
761 while((n1 = read(file1,buf1,BUFSIZ)) == -1 && errno == EINTR);
762 while((n2 = read(file2,buf2,BUFSIZ)) == -1 && errno == EINTR);
763 } while (n1 == n2 && n1 == BUFSIZ && !memcmp(buf1,buf2,BUFSIZ));
764 result = (n1 != n2) || memcmp(buf1,buf2,n1);
765 #endif /* !HAVE_MMAP */
766 close (file2);
768 close (file1);
770 return result;
773 enum CompareMode {
774 compare_quick, compare_size_only, compare_thourough
777 static void
778 compare_dir (WPanel *panel, WPanel *other, enum CompareMode mode)
780 int i, j;
781 char *src_name, *dst_name;
783 /* No marks by default */
784 panel->marked = 0;
785 panel->total = 0;
786 panel->dirs_marked = 0;
788 /* Handle all files in the panel */
789 for (i = 0; i < panel->count; i++){
790 file_entry *source = &panel->dir.list[i];
792 /* Default: unmarked */
793 file_mark (panel, i, 0);
795 /* Skip directories */
796 if (S_ISDIR (source->st.st_mode))
797 continue;
799 /* Search the corresponding entry from the other panel */
800 for (j = 0; j < other->count; j++){
801 if (strcmp (source->fname,
802 other->dir.list[j].fname) == 0)
803 break;
805 if (j >= other->count)
806 /* Not found -> mark */
807 do_file_mark (panel, i, 1);
808 else {
809 /* Found */
810 file_entry *target = &other->dir.list[j];
812 if (mode != compare_size_only){
813 /* Older version is not marked */
814 if (source->st.st_mtime < target->st.st_mtime)
815 continue;
818 /* Newer version with different size is marked */
819 if (source->st.st_size != target->st.st_size){
820 do_file_mark (panel, i, 1);
821 continue;
824 if (mode == compare_size_only)
825 continue;
827 if (mode == compare_quick){
828 /* Thorough compare off, compare only time stamps */
829 /* Mark newer version, don't mark version with the same date */
830 if (source->st.st_mtime > target->st.st_mtime){
831 do_file_mark (panel, i, 1);
833 continue;
836 /* Thorough compare on, do byte-by-byte comparison */
837 src_name = concat_dir_and_file (panel->cwd, source->fname);
838 dst_name = concat_dir_and_file (other->cwd, target->fname);
839 if (compare_files (src_name, dst_name, source->st.st_size))
840 do_file_mark (panel, i, 1);
841 g_free (src_name);
842 g_free (dst_name);
844 } /* for (i ...) */
847 void
848 compare_dirs_cmd (void)
850 int choice;
851 enum CompareMode thorough_flag;
853 choice =
854 query_dialog (_(" Compare directories "),
855 _(" Select compare method: "), 0, 3, _("&Quick"),
856 _("&Size only"), _("&Thorough"), _("&Cancel"));
858 if (choice < 0 || choice > 2)
859 return;
860 else
861 thorough_flag = choice;
863 if (get_current_type () == view_listing
864 && get_other_type () == view_listing) {
865 compare_dir (current_panel, other_panel, thorough_flag);
866 compare_dir (other_panel, current_panel, thorough_flag);
867 } else {
868 message (1, MSG_ERROR,
869 _(" Both panels should be in the "
870 "listing mode to use this command "));
874 void
875 history_cmd (void)
877 Listbox *listbox;
878 GList *current;
880 if (cmdline->need_push) {
881 if (push_history (cmdline, cmdline->buffer) == 2)
882 cmdline->need_push = 0;
884 if (!cmdline->history) {
885 message (1, MSG_ERROR, _(" The command history is empty "));
886 return;
888 current = g_list_first (cmdline->history);
889 listbox = create_listbox_window (60, 10, _(" Command history "),
890 "[Command Menu]");
891 while (current) {
892 LISTBOX_APPEND_TEXT (listbox, 0, (char *) current->data, current);
893 current = g_list_next(current);
895 run_dlg (listbox->dlg);
896 if (listbox->dlg->ret_value == B_CANCEL)
897 current = NULL;
898 else
899 current = listbox->list->current->data;
900 destroy_dlg (listbox->dlg);
901 g_free (listbox);
903 if (!current)
904 return;
905 cmdline->history = current;
906 assign_text (cmdline, (char *) current->data);
907 update_input (cmdline, 1);
910 void swap_cmd (void)
912 swap_panels ();
913 touchwin (stdscr);
914 repaint_screen ();
917 void
918 view_other_cmd (void)
920 static int message_flag = TRUE;
922 if (!xterm_flag && !console_flag && !use_subshell) {
923 if (message_flag)
924 message (1, MSG_ERROR,
925 _(" Not an xterm or Linux console; \n"
926 " the panels cannot be toggled. "));
927 message_flag = FALSE;
928 } else {
929 toggle_panels ();
933 static void
934 do_link (int symbolic_link, char *fname)
936 char *dest, *src;
938 if (!symbolic_link) {
939 src = g_strdup_printf (_("Link %s to:"), name_trunc (fname, 46));
940 dest = input_expand_dialog (_(" Link "), src, "");
941 g_free (src);
942 if (!dest)
943 return;
944 if (!*dest) {
945 g_free (dest);
946 return;
948 save_cwds_stat ();
949 if (-1 == mc_link (fname, dest))
950 message (1, MSG_ERROR, _(" link: %s "),
951 unix_error_string (errno));
952 } else {
953 char *s;
954 char *d;
956 /* suggest the full path for symlink */
957 s = concat_dir_and_file (current_panel->cwd, fname);
959 if (get_other_type () == view_listing) {
960 d = concat_dir_and_file (other_panel->cwd, fname);
961 } else {
962 d = g_strdup (fname);
965 symlink_dialog (s, d, &dest, &src);
966 g_free (d);
967 g_free (s);
969 if (!dest || !*dest || !src || !*src) {
970 if (src)
971 g_free (src);
972 if (dest)
973 g_free (dest);
974 return;
976 save_cwds_stat ();
977 if (-1 == mc_symlink (dest, src))
978 message (1, MSG_ERROR, _(" symlink: %s "),
979 unix_error_string (errno));
980 g_free (src);
982 g_free (dest);
983 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
984 repaint_screen ();
987 void link_cmd (void)
989 do_link (0, selection (current_panel)->fname);
992 void symlink_cmd (void)
994 char *filename = NULL;
995 filename = selection (current_panel)->fname;
997 if (filename) {
998 do_link (1, filename);
1002 void edit_symlink_cmd (void)
1004 if (S_ISLNK (selection (current_panel)->st.st_mode)) {
1005 char buffer [MC_MAXPATHLEN];
1006 char *p = NULL;
1007 int i;
1008 char *dest, *q;
1010 p = selection (current_panel)->fname;
1012 q = g_strdup_printf (_(" Symlink `%s\' points to: "), name_trunc (p, 32));
1014 i = readlink (p, buffer, MC_MAXPATHLEN - 1);
1015 if (i > 0) {
1016 buffer [i] = 0;
1017 dest = input_expand_dialog (_(" Edit symlink "), q, buffer);
1018 if (dest) {
1019 if (*dest && strcmp (buffer, dest)) {
1020 save_cwds_stat ();
1021 if (-1 == mc_unlink (p)){
1022 message (1, MSG_ERROR, _(" edit symlink, unable to remove %s: %s "),
1023 p, unix_error_string (errno));
1024 } else {
1025 if (-1 == mc_symlink (dest, p))
1026 message (1, MSG_ERROR, _(" edit symlink: %s "),
1027 unix_error_string (errno));
1029 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1030 repaint_screen ();
1032 g_free (dest);
1035 g_free (q);
1036 } else {
1037 message (1, MSG_ERROR, _("`%s' is not a symbolic link"),
1038 selection (current_panel)->fname);
1042 void help_cmd (void)
1044 interactive_display (NULL, "[main]");
1047 void
1048 user_file_menu_cmd (void)
1050 user_menu_cmd (NULL);
1053 /* partly taken from dcigettext.c, returns "" for default locale */
1054 /* value should be freed by calling function g_free() */
1055 char *guess_message_value (void)
1057 static const char * const var[] = {
1058 /* The highest priority value is the `LANGUAGE' environment
1059 variable. This is a GNU extension. */
1060 "LANGUAGE",
1061 /* Setting of LC_ALL overwrites all other. */
1062 "LC_ALL",
1063 /* Next comes the name of the desired category. */
1064 "LC_MESSAGES",
1065 /* Last possibility is the LANG environment variable. */
1066 "LANG",
1067 /* NULL exit loops */
1068 NULL
1071 unsigned i = 0;
1072 char *locale = NULL;
1074 while (var[i] != NULL) {
1075 locale = getenv (var[i]);
1076 if (locale != NULL && locale[0] != '\0')
1077 break;
1078 i++;
1081 if (locale == NULL)
1082 locale = "";
1084 return g_strdup (locale);
1088 * Return a random hint. If force is not 0, ignore the timeout.
1090 char *
1091 get_random_hint (int force)
1093 char *data, *result, *eol;
1094 int len;
1095 int start;
1096 static int last_sec;
1097 static struct timeval tv;
1099 /* Do not change hints more often than one minute */
1100 gettimeofday (&tv, NULL);
1101 if (!force && !(tv.tv_sec > last_sec + 60))
1102 return g_strdup ("");
1103 last_sec = tv.tv_sec;
1105 data = load_mc_home_file (MC_HINT, NULL);
1106 if (!data)
1107 return 0;
1109 /* get a random entry */
1110 srand (tv.tv_sec);
1111 len = strlen (data);
1112 start = rand () % len;
1114 for (; start; start--) {
1115 if (data[start] == '\n') {
1116 start++;
1117 break;
1120 eol = strchr (&data[start], '\n');
1121 if (eol)
1122 *eol = 0;
1123 result = g_strdup (&data[start]);
1124 g_free (data);
1125 return result;
1128 #if defined(USE_NETCODE) || defined(USE_EXT2FSLIB)
1129 static void
1130 nice_cd (char *text, char *xtext, char *help, char *prefix, int to_home)
1132 char *machine;
1133 char *cd_path;
1135 if (!SELECTED_IS_PANEL)
1136 return;
1138 machine = input_dialog_help (text,
1139 xtext,
1140 help, "");
1141 if (!machine)
1142 return;
1144 to_home = 0; /* FIXME: how to solve going to home nicely? /~/ is
1145 ugly as hell and leads to problems in vfs layer */
1147 if (strncmp (prefix, machine, strlen (prefix)) == 0)
1148 cd_path = g_strconcat (machine, to_home ? "/~/" : NULL, NULL);
1149 else
1150 cd_path = g_strconcat (prefix, machine, to_home ? "/~/" : NULL, NULL);
1152 if (do_panel_cd (MENU_PANEL, cd_path, 0))
1153 directory_history_add (MENU_PANEL, (MENU_PANEL)->cwd);
1154 else
1155 message (1, MSG_ERROR, _(" Cannot chdir to %s "), cd_path);
1156 g_free (cd_path);
1157 g_free (machine);
1159 #endif /* USE_NETCODE || USE_EXT2FSLIB */
1162 #ifdef USE_NETCODE
1164 static char *machine_str = N_(" Enter machine name (F1 for details): ");
1166 #ifdef WITH_MCFS
1167 void netlink_cmd (void)
1169 nice_cd (_(" Link to a remote machine "), _(machine_str),
1170 "[Network File System]", "/#mc:", 1);
1172 #endif /* WITH_MCFS */
1174 void ftplink_cmd (void)
1176 nice_cd (_(" FTP to machine "), _(machine_str),
1177 "[FTP File System]", "/#ftp:", 1);
1180 void fishlink_cmd (void)
1182 nice_cd (_(" Shell link to machine "), _(machine_str),
1183 "[FIle transfer over SHell filesystem]", "/#sh:", 1);
1186 #ifdef WITH_SMBFS
1187 void smblink_cmd (void)
1189 nice_cd (_(" SMB link to machine "), _(machine_str),
1190 "[SMB File System]", "/#smb:", 0);
1192 #endif /* WITH_SMBFS */
1193 #endif /* USE_NETCODE */
1195 #ifdef USE_EXT2FSLIB
1196 void undelete_cmd (void)
1198 nice_cd (_(" Undelete files on an ext2 file system "),
1199 _(" Enter device (without /dev/) to undelete\n "
1200 " files on: (F1 for details)"),
1201 "[Undelete File System]", "/#undel:", 0);
1203 #endif /* USE_EXT2FSLIB */
1205 void quick_cd_cmd (void)
1207 char *p = cd_dialog ();
1209 if (p && *p) {
1210 char *q = g_strconcat ("cd ", p, NULL);
1212 do_cd_command (q);
1213 g_free (q);
1215 if (p)
1216 g_free (p);
1219 void
1220 dirsizes_cmd (void)
1222 WPanel *panel = current_panel;
1223 int i;
1224 off_t marked;
1225 double total;
1227 for (i = 0; i < panel->count; i++)
1228 if (S_ISDIR (panel->dir.list [i].st.st_mode) &&
1229 ((panel->dirs_marked && panel->dir.list [i].f.marked) ||
1230 !panel->dirs_marked) &&
1231 strcmp (panel->dir.list [i].fname, "..") != 0) {
1232 total = 0.0l;
1233 compute_dir_size (panel->dir.list [i].fname, &marked, &total);
1234 panel->dir.list [i].st.st_size = (off_t) total;
1235 panel->dir.list [i].f.dir_size_computed = 1;
1238 recalculate_panel_summary (panel);
1239 panel->dirty = 1;
1242 void
1243 save_setup_cmd (void)
1245 char *str;
1247 save_setup ();
1248 sync_profiles ();
1249 str = g_strconcat ( _(" Setup saved to ~/"), PROFILE_NAME, NULL);
1251 message (0, _(" Setup "), str);
1252 g_free (str);
1255 static void
1256 configure_panel_listing (WPanel *p, int view_type, int use_msformat, char *user, char *status)
1258 p->user_mini_status = use_msformat;
1259 p->list_type = view_type;
1261 if (view_type == list_user || use_msformat){
1262 g_free (p->user_format);
1263 p->user_format = user;
1265 g_free (p->user_status_format [view_type]);
1266 p->user_status_format [view_type] = status;
1268 set_panel_formats (p);
1270 else {
1271 g_free (user);
1272 g_free (status);
1275 set_panel_formats (p);
1276 do_refresh ();
1279 void
1280 info_cmd_no_menu (void)
1282 if (get_display_type (0) == view_info)
1283 set_display_type (0, view_listing);
1284 else if (get_display_type (1) == view_info)
1285 set_display_type (1, view_listing);
1286 else
1287 set_display_type (current_panel == left_panel ? 1 : 0, view_info);
1290 void
1291 quick_cmd_no_menu (void)
1293 if (get_display_type (0) == view_quick)
1294 set_display_type (0, view_listing);
1295 else if (get_display_type (1) == view_quick)
1296 set_display_type (1, view_listing);
1297 else
1298 set_display_type (current_panel == left_panel ? 1 : 0, view_quick);
1301 static void
1302 switch_to_listing (int panel_index)
1304 if (get_display_type (panel_index) != view_listing)
1305 set_display_type (panel_index, view_listing);
1308 void
1309 listing_cmd (void)
1311 int view_type, use_msformat;
1312 char *user, *status;
1313 WPanel *p;
1314 int display_type;
1316 display_type = get_display_type (MENU_PANEL_IDX);
1317 if (display_type == view_listing)
1318 p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1319 else
1320 p = 0;
1322 view_type = display_box (p, &user, &status, &use_msformat, MENU_PANEL_IDX);
1324 if (view_type == -1)
1325 return;
1327 switch_to_listing (MENU_PANEL_IDX);
1329 p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1331 configure_panel_listing (p, view_type, use_msformat, user, status);
1334 void
1335 tree_cmd (void)
1337 set_display_type (MENU_PANEL_IDX, view_tree);
1340 void
1341 info_cmd (void)
1343 set_display_type (MENU_PANEL_IDX, view_info);
1346 void
1347 quick_view_cmd (void)
1349 if ((WPanel *) get_panel_widget (MENU_PANEL_IDX) == current_panel)
1350 change_panel ();
1351 set_display_type (MENU_PANEL_IDX, view_quick);
1354 /* Handle the tree internal listing modes switching */
1355 static int
1356 set_basic_panel_listing_to (int panel_index, int listing_mode)
1358 WPanel *p = (WPanel *) get_panel_widget (panel_index);
1360 switch_to_listing (panel_index);
1361 p->list_type = listing_mode;
1362 if (set_panel_formats (p))
1363 return 0;
1365 do_refresh ();
1366 return 1;
1369 void
1370 toggle_listing_cmd (void)
1372 int current = get_current_index ();
1373 WPanel *p = (WPanel *) get_panel_widget (current);
1374 int list_mode = p->list_type;
1375 int m;
1377 switch (list_mode){
1378 case list_full:
1379 case list_brief:
1380 m = list_long;
1381 break;
1382 case list_long:
1383 m = list_user;
1384 break;
1385 default:
1386 m = list_full;
1388 if (set_basic_panel_listing_to (current, m))
1389 return;
1390 set_basic_panel_listing_to (current, list_full);