Ticket #1369 (Update *.hlp files and other docs)
[midnight-commander.git] / src / main.c
blobe9c08302d5310d231c9dd5ffaf7a50aa933f8426
1 /* Main program for the Midnight Commander
2 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
3 2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
5 Written by: 1994, 1995, 1996, 1997 Miguel de Icaza
6 1994, 1995 Janne Kukonlehto
7 1997 Norbert Warmuth
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
23 /** \file main.c
24 * \brief Source: this is a main module
27 #include <config.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #include <locale.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <fcntl.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/wait.h>
40 #include <unistd.h>
41 #include <pwd.h>
43 #include "global.h"
44 #include "tty.h"
45 #include "dir.h"
46 #include "color.h"
47 #include "dialog.h"
48 #include "menu.h"
49 #include "panel.h"
50 #include "main.h"
51 #include "win.h"
52 #include "mouse.h"
53 #include "option.h"
54 #include "tree.h"
55 #include "treestore.h"
56 #include "cons.saver.h"
57 #include "subshell.h"
58 #include "key.h" /* For init_key() and mi_getch() */
59 #include "setup.h" /* save_setup() */
60 #include "../src/mcconfig/mcconfig.h"
61 #include "boxes.h" /* sort_box() */
62 #include "layout.h"
63 #include "cmd.h" /* Normal commands */
64 #include "hotlist.h"
65 #include "panelize.h"
66 #include "learn.h" /* learn_keys() */
67 #include "listmode.h"
68 #include "execute.h"
69 #include "ext.h" /* For flush_extension_file() */
70 #include "strutil.h"
71 #include <pwd.h> /* for username in xterm title */
73 /* Listbox for the command history feature */
74 #include "widget.h"
75 #include "command.h"
76 #include "wtools.h"
78 #include "chmod.h"
79 #include "chown.h"
80 #include "achown.h"
82 #ifdef WITH_SMBFS
83 #include "../vfs/smbfs.h" /* smbfs_set_debug() */
84 #endif
86 #ifdef USE_INTERNAL_EDIT
87 # include "../edit/edit.h"
88 #endif
90 #ifdef HAVE_CHARSET
91 #include "charsets.h"
92 #endif /* HAVE_CHARSET */
94 #ifdef USE_VFS
95 #include "../vfs/gc.h"
96 #endif
98 #include "popt.h"
100 /* When the modes are active, left_panel, right_panel and tree_panel */
101 /* Point to a proper data structure. You should check with the functions */
102 /* get_current_type and get_other_type the types of the panels before using */
103 /* This pointer variables */
105 /* The structures for the panels */
106 WPanel *left_panel = NULL;
107 WPanel *right_panel = NULL;
109 /* The pointer to the tree */
110 WTree *the_tree = NULL;
112 /* The Menubar */
113 struct WMenu *the_menubar = NULL;
115 /* Pointers to the selected and unselected panel */
116 WPanel *current_panel = NULL;
118 /* Set if the command is being run from the "Right" menu */
119 int is_right = 0;
121 /* Set when main loop should be terminated */
122 volatile int quit = 0;
124 /* Set if you want the possible completions dialog for the first time */
125 int show_all_if_ambiguous = 0;
127 /* Set when cd symlink following is desirable (bash mode) */
128 int cd_symlinks = 1;
130 /* If set then dialogs just clean the screen when refreshing, else */
131 /* they do a complete refresh, refreshing all the parts of the program */
132 int fast_refresh = 0;
134 /* If true, marking a files moves the cursor down */
135 int mark_moves_down = 1;
137 /* If true, at startup the user-menu is invoked */
138 int auto_menu = 0;
140 /* If true, use + and \ keys normally and select/unselect do if M-+ / M-\
141 and M-- and keypad + / - */
142 int alternate_plus_minus = 0;
144 /* If true, then the +, - and \ keys have their special meaning only if the
145 * command line is emtpy, otherwise they behave like regular letters
147 int only_leading_plus_minus = 1;
149 int pause_after_run = pause_on_dumb_terminals;
151 /* It true saves the setup when quitting */
152 int auto_save_setup = 1;
154 #ifndef HAVE_CHARSET
155 /* If true, allow characters in the range 160-255 */
156 int eight_bit_clean = 1;
159 * If true, also allow characters in the range 128-159.
160 * This is reported to break on many terminals (xterm, qansi-m).
162 int full_eight_bits = 0;
164 #endif /* !HAVE_CHARSET */
167 * If utf-8 terminal utf8_display = 1
168 * Display bits set UTF-8
171 int utf8_display = 0;
173 /* If true use the internal viewer */
174 int use_internal_view = 1;
176 /* Have we shown the fast-reload warning in the past? */
177 int fast_reload_w = 0;
179 /* Move page/item? When clicking on the top or bottom of a panel */
180 int mouse_move_pages = 1;
182 /* If true: l&r arrows are used to chdir if the input line is empty */
183 int navigate_with_arrows = 0;
185 /* If true use +, -, | for line drawing */
186 int force_ugly_line_drawing = 0;
188 /* If true program softkeys (HP terminals only) on startup and after every
189 command ran in the subshell to the description found in the termcap/terminfo
190 database */
191 int reset_hp_softkeys = 0;
193 /* The prompt */
194 const char *prompt = NULL;
196 /* The widget where we draw the prompt */
197 WLabel *the_prompt;
199 /* The hint bar */
200 WLabel *the_hint;
202 /* The button bar */
203 WButtonBar *the_bar;
205 /* For slow terminals */
206 int slow_terminal = 0;
208 /* Mouse type: GPM, xterm or none */
209 Mouse_Type use_mouse_p = MOUSE_NONE;
211 /* If true, assume we are running on an xterm terminal */
212 static int force_xterm = 0;
214 /* If on, default for "No" in delete operations */
215 int safe_delete = 0;
217 /* Controls screen clearing before an exec */
218 int clear_before_exec = 1;
220 /* Asks for confirmation before deleting a file */
221 int confirm_delete = 1;
223 /* Asks for confirmation before deleting a hotlist entry */
224 int confirm_directory_hotlist_delete = 1;
226 /* Asks for confirmation before overwriting a file */
227 int confirm_overwrite = 1;
229 /* Asks for confirmation before executing a program by pressing enter */
230 int confirm_execute = 0;
232 /* Asks for confirmation before leaving the program */
233 int confirm_exit = 1;
235 /* Asks for confirmation when using F3 to view a directory and there
236 are tagged files */
237 int confirm_view_dir = 0;
239 /* This flag indicates if the pull down menus by default drop down */
240 int drop_menus = 0;
242 /* if skip_check_codeset = 1 do not show warning about
243 * system and display codeset is different
245 int skip_check_codeset = 0;
247 /* The dialog handle for the main program */
248 Dlg_head *midnight_dlg = NULL;
250 /* Subshell: if set, then the prompt was not saved on CONSOLE_SAVE */
251 /* We need to paint it after CONSOLE_RESTORE, see: load_prompt */
252 int update_prompt = 0;
254 /* The home directory */
255 const char *home_dir = NULL;
257 /* The value of the other directory, only used when loading the setup */
258 char *other_dir = NULL;
260 /* Only used at program boot */
261 int boot_current_is_left = 1;
263 static char *this_dir = NULL;
265 /* If this is true, then when browsing the tree the other window will
266 * automatically reload it's directory with the contents of the currently
267 * selected directory.
269 int xtree_mode = 0;
271 /* If set, then print to the given file the last directory we were at */
272 static char *last_wd_file = NULL;
273 static char *last_wd_string = NULL;
274 /* Set to 1 to suppress printing the last directory */
275 static int print_last_revert = 0;
277 /* Force colors, only used by Slang */
278 int force_colors = 0;
280 /* colors specified on the command line: they override any other setting */
281 char *command_line_colors = NULL;
283 /* File name to view if argument was supplied */
284 static const char *view_one_file = NULL;
286 /* File name to edit if argument was supplied */
287 const char *edit_one_file = NULL;
289 /* Line to start the editor on */
290 static int edit_one_file_start_line = 0;
292 /* Used so that widgets know if they are being destroyed or
293 shut down */
294 int midnight_shutdown = 0;
296 /* The user's shell */
297 const char *shell = NULL;
299 /* mc_home: The home of MC - /etc/mc or defined by MC_DATADIR */
300 char *mc_home = NULL;
302 /* mc_home_alt: Alternative home of MC - deprecated /usr/share/mc */
303 char *mc_home_alt = NULL;
305 char cmd_buf[512];
307 static void
308 reload_panelized (WPanel *panel)
310 int i, j;
311 dir_list *list = &panel->dir;
313 if (panel != current_panel)
314 mc_chdir (panel->cwd);
316 for (i = 0, j = 0; i < panel->count; i++) {
317 if (list->list[i].f.marked) {
318 /* Unmark the file in advance. In case the following mc_lstat
319 * fails we are done, else we have to mark the file again
320 * (Note: do_file_mark depends on a valid "list->list [i].buf").
321 * IMO that's the best way to update the panel's summary status
322 * -- Norbert
324 do_file_mark (panel, i, 0);
326 if (mc_lstat (list->list[i].fname, &list->list[i].st)) {
327 g_free (list->list[i].fname);
328 continue;
330 if (list->list[i].f.marked)
331 do_file_mark (panel, i, 1);
332 if (j != i)
333 list->list[j] = list->list[i];
334 j++;
336 if (j == 0)
337 panel->count = set_zero_dir (list);
338 else
339 panel->count = j;
341 if (panel != current_panel)
342 mc_chdir (current_panel->cwd);
345 static void
346 update_one_panel_widget (WPanel *panel, int force_update,
347 const char *current_file)
349 int free_pointer;
350 char *my_current_file = NULL;
352 if (force_update & UP_RELOAD) {
353 panel->is_panelized = 0;
354 mc_setctl (panel->cwd, VFS_SETCTL_FLUSH, 0);
355 memset (&(panel->dir_stat), 0, sizeof (panel->dir_stat));
358 /* If current_file == -1 (an invalid pointer) then preserve selection */
359 if (current_file == UP_KEEPSEL) {
360 free_pointer = 1;
361 my_current_file = g_strdup (panel->dir.list[panel->selected].fname);
362 current_file = my_current_file;
363 } else
364 free_pointer = 0;
366 if (panel->is_panelized)
367 reload_panelized (panel);
368 else
369 panel_reload (panel);
371 try_to_select (panel, current_file);
372 panel->dirty = 1;
374 if (free_pointer)
375 g_free (my_current_file);
378 void
379 panel_clean_dir (WPanel *panel)
381 int count = panel->count;
383 panel->count = 0;
384 panel->top_file = 0;
385 panel->selected = 0;
386 panel->marked = 0;
387 panel->dirs_marked = 0;
388 panel->total = 0;
389 panel->searching = 0;
390 panel->is_panelized = 0;
391 panel->dirty = 1;
393 clean_dir (&panel->dir, count);
396 static void
397 update_one_panel (int which, int force_update, const char *current_file)
399 WPanel *panel;
401 if (get_display_type (which) != view_listing)
402 return;
404 panel = (WPanel *) get_panel_widget (which);
405 update_one_panel_widget (panel, force_update, current_file);
408 /* This routine reloads the directory in both panels. It tries to
409 * select current_file in current_panel and other_file in other_panel.
410 * If current_file == -1 then it automatically sets current_file and
411 * other_file to the currently selected files in the panels.
413 * if force_update has the UP_ONLY_CURRENT bit toggled on, then it
414 * will not reload the other panel.
416 void
417 update_panels (int force_update, const char *current_file)
419 int reload_other = !(force_update & UP_ONLY_CURRENT);
420 WPanel *panel;
422 update_one_panel (get_current_index (), force_update, current_file);
423 if (reload_other)
424 update_one_panel (get_other_index (), force_update, UP_KEEPSEL);
426 if (get_current_type () == view_listing)
427 panel = (WPanel *) get_panel_widget (get_current_index ());
428 else
429 panel = (WPanel *) get_panel_widget (get_other_index ());
431 mc_chdir (panel->cwd);
434 /* Save current stat of directories to avoid reloading the panels */
435 /* when no modifications have taken place */
436 void
437 save_cwds_stat (void)
439 if (fast_reload) {
440 mc_stat (current_panel->cwd, &(current_panel->dir_stat));
441 if (get_other_type () == view_listing)
442 mc_stat (other_panel->cwd, &(other_panel->dir_stat));
446 #ifdef HAVE_SUBSHELL_SUPPORT
447 void
448 do_possible_cd (const char *new_dir)
450 if (!do_cd (new_dir, cd_exact))
451 message (D_ERROR, _("Warning"),
452 _(" The Commander can't change to the directory that \n"
453 " the subshell claims you are in. Perhaps you have \n"
454 " deleted your working directory, or given yourself \n"
455 " extra access permissions with the \"su\" command? "));
458 void
459 do_update_prompt (void)
461 if (update_prompt) {
462 printf ("%s", subshell_prompt);
463 fflush (stdout);
464 update_prompt = 0;
467 #endif /* HAVE_SUBSHELL_SUPPORT */
469 void
470 change_panel (void)
472 free_completions (cmdline);
473 dlg_one_down (midnight_dlg);
476 /* Stop MC main dialog and the current dialog if it exists.
477 * Needed to provide fast exit from MC viewer or editor on shell exit */
478 static void
479 stop_dialogs (void)
481 midnight_dlg->running = 0;
482 if (current_dlg) {
483 current_dlg->running = 0;
487 static int
488 quit_cmd_internal (int quiet)
490 int q = quit;
492 if (quiet || !confirm_exit) {
493 q = 1;
494 } else {
495 if (query_dialog
496 (_(" The Midnight Commander "),
497 _(" Do you really want to quit the Midnight Commander? "), D_NORMAL,
498 2, _("&Yes"), _("&No")) == 0)
499 q = 1;
501 if (q) {
502 #ifdef HAVE_SUBSHELL_SUPPORT
503 if (!use_subshell)
504 stop_dialogs ();
505 else if ((q = exit_subshell ()))
506 #endif
507 stop_dialogs ();
509 if (q)
510 quit |= 1;
511 return quit;
514 static void
515 quit_cmd (void)
517 quit_cmd_internal (0);
520 void
521 quiet_quit_cmd (void)
523 print_last_revert = 1;
524 quit_cmd_internal (1);
528 * Touch window and refresh window functions
531 /* This routine untouches the first line on both panels in order */
532 /* to avoid the refreshing the menu bar */
534 void
535 repaint_screen (void)
537 do_refresh ();
538 mc_refresh ();
541 /* Wrapper for do_subshell_chdir, check for availability of subshell */
542 void
543 subshell_chdir (const char *directory)
545 #ifdef HAVE_SUBSHELL_SUPPORT
546 if (use_subshell) {
547 if (vfs_current_is_local ())
548 do_subshell_chdir (directory, 0, 1);
550 #endif /* HAVE_SUBSHELL_SUPPORT */
553 void
554 directory_history_add (struct WPanel *panel, const char *dir)
556 char *tmp;
558 tmp = g_strdup (dir);
559 strip_password (tmp, 1);
561 panel->dir_history = list_append_unique (panel->dir_history, tmp);
565 * If we moved to the parent directory move the selection pointer to
566 * the old directory name; If we leave VFS dir, remove FS specificator.
568 * You do _NOT_ want to add any vfs aware code here. <pavel@ucw.cz>
570 static const char *
571 get_parent_dir_name (const char *cwd, const char *lwd)
573 const char *p;
574 if (strlen (lwd) > strlen (cwd))
575 if ((p = strrchr (lwd, PATH_SEP)) && !strncmp (cwd, lwd, p - lwd) &&
576 ((gsize)strlen (cwd) == (gsize) p - (gsize) lwd || (p == lwd && cwd[0] == PATH_SEP &&
577 cwd[1] == '\0'))) {
578 return (p + 1);
580 return NULL;
584 * Changes the current directory of the panel.
585 * Don't record change in the directory history.
587 static int
588 _do_panel_cd (WPanel *panel, const char *new_dir, enum cd_enum cd_type)
590 const char *directory;
591 char *olddir;
592 char temp[MC_MAXPATHLEN];
593 char *translated_url;
595 if (cd_type == cd_parse_command) {
596 while (*new_dir == ' ')
597 new_dir++;
600 olddir = g_strdup (panel->cwd);
601 new_dir = translated_url = vfs_translate_url (new_dir);
603 /* Convert *new_path to a suitable pathname, handle ~user */
605 if (cd_type == cd_parse_command) {
606 if (!strcmp (new_dir, "-")) {
607 strcpy (temp, panel->lwd);
608 new_dir = temp;
611 directory = *new_dir ? new_dir : home_dir;
613 if (mc_chdir (directory) == -1) {
614 strcpy (panel->cwd, olddir);
615 g_free (olddir);
616 g_free (translated_url);
617 return 0;
619 g_free (translated_url);
621 /* Success: save previous directory, shutdown status of previous dir */
622 strcpy (panel->lwd, olddir);
623 free_completions (cmdline);
625 mc_get_current_wd (panel->cwd, sizeof (panel->cwd) - 2);
627 vfs_release_path (olddir);
629 subshell_chdir (panel->cwd);
631 /* Reload current panel */
632 panel_clean_dir (panel);
633 panel->count =
634 do_load_dir (panel->cwd, &panel->dir, panel->sort_type,
635 panel->reverse, panel->case_sensitive,
636 panel->exec_first, panel->filter);
637 try_to_select (panel, get_parent_dir_name (panel->cwd, olddir));
638 load_hint (0);
639 panel->dirty = 1;
640 update_xterm_title_path ();
642 g_free (olddir);
644 return 1;
648 * Changes the current directory of the panel.
649 * Record change in the directory history.
652 do_panel_cd (struct WPanel *panel, const char *new_dir, enum cd_enum cd_type)
654 int r;
656 r = _do_panel_cd (panel, new_dir, cd_type);
657 if (r)
658 directory_history_add (panel, panel->cwd);
659 return r;
663 do_cd (const char *new_dir, enum cd_enum exact)
665 return (do_panel_cd (current_panel, new_dir, exact));
668 void
669 directory_history_next (WPanel *panel)
671 GList *nextdir;
673 nextdir = g_list_next (panel->dir_history);
675 if (!nextdir)
676 return;
678 if (_do_panel_cd (panel, (char *) nextdir->data, cd_exact))
679 panel->dir_history = nextdir;
682 void
683 directory_history_prev (WPanel *panel)
685 GList *prevdir;
687 prevdir = g_list_previous (panel->dir_history);
689 if (!prevdir)
690 return;
692 if (_do_panel_cd (panel, (char *) prevdir->data, cd_exact))
693 panel->dir_history = prevdir;
696 void
697 directory_history_list (WPanel *panel)
699 char *s;
701 if (!panel->dir_history)
702 return;
704 s = show_hist (panel->dir_history, panel->widget.x, panel->widget.y);
706 if (!s)
707 return;
709 if (_do_panel_cd (panel, s, cd_exact))
710 directory_history_add (panel, panel->cwd);
711 else
712 message (D_ERROR, MSG_ERROR, _("Cannot change directory"));
713 g_free (s);
716 #ifdef HAVE_SUBSHELL_SUPPORT
718 load_prompt (int fd, void *unused)
720 (void) fd;
721 (void) unused;
723 if (!read_subshell_prompt ())
724 return 0;
726 /* Don't actually change the prompt if it's invisible */
727 if (current_dlg == midnight_dlg && command_prompt) {
728 char *tmp_prompt;
729 int prompt_len;
731 tmp_prompt = strip_ctrl_codes (subshell_prompt);
732 prompt_len = str_term_width1 (tmp_prompt);
734 /* Check for prompts too big */
735 if (COLS > 8 && prompt_len > COLS - 8) {
736 tmp_prompt[COLS - 8] = '\0';
737 prompt_len = COLS - 8;
739 prompt = tmp_prompt;
740 label_set_text (the_prompt, prompt);
741 winput_set_origin ((WInput *) cmdline, prompt_len,
742 COLS - prompt_len);
744 /* since the prompt has changed, and we are called from one of the
745 * get_event channels, the prompt updating does not take place
746 * automatically: force a cursor update and a screen refresh
748 update_cursor (midnight_dlg);
749 mc_refresh ();
751 update_prompt = 1;
752 return 0;
754 #endif /* HAVE_SUBSHELL_SUPPORT */
756 /* Used to emulate Lynx's entering leaving a directory with the arrow keys */
758 maybe_cd (int move_up_dir)
760 if (navigate_with_arrows) {
761 if (!cmdline->buffer[0]) {
762 if (move_up_dir) {
763 do_cd ("..", cd_exact);
764 return 1;
766 if (S_ISDIR (selection (current_panel)->st.st_mode)
767 || link_isdir (selection (current_panel))) {
768 do_cd (selection (current_panel)->fname, cd_exact);
769 return 1;
773 return 0;
776 static void
777 sort_cmd (void)
779 WPanel *p;
780 sortfn *sort_order;
782 if (!SELECTED_IS_PANEL)
783 return;
785 p = MENU_PANEL;
786 sort_order = sort_box (p->sort_type, &p->reverse,
787 &p->case_sensitive,
788 &p->exec_first);
790 panel_set_sort_order (p, sort_order);
794 static void
795 treebox_cmd (void)
797 char *sel_dir;
799 sel_dir = tree_box (selection (current_panel)->fname);
800 if (sel_dir) {
801 do_cd (sel_dir, cd_exact);
802 g_free (sel_dir);
806 #ifdef LISTMODE_EDITOR
807 static void
808 listmode_cmd (void)
810 char *newmode;
812 if (get_current_type () != view_listing)
813 return;
815 newmode = listmode_edit (current_panel->user_format);
816 if (!newmode)
817 return;
819 g_free (current_panel->user_format);
820 current_panel->list_type = list_user;
821 current_panel->user_format = newmode;
822 set_panel_formats (current_panel);
824 do_refresh ();
826 #endif /* LISTMODE_EDITOR */
828 /* NOTICE: hotkeys specified here are overriden in menubar_paint_idx (alex) */
829 static menu_entry LeftMenu[] = {
830 {' ', N_("&Listing mode..."), NULL_HOTKEY, listing_cmd},
831 {' ', N_("&Quick view C-x q"), NULL_HOTKEY, quick_view_cmd},
832 {' ', N_("&Info C-x i"), NULL_HOTKEY, info_cmd},
833 {' ', N_("&Tree"), NULL_HOTKEY, tree_cmd},
834 {' ', "", NULL_HOTKEY, 0},
835 {' ', N_("&Sort order..."), NULL_HOTKEY, sort_cmd},
836 {' ', "", NULL_HOTKEY, 0},
837 {' ', N_("&Filter..."), NULL_HOTKEY, filter_cmd},
838 #ifdef HAVE_CHARSET
839 {' ', "",NULL_HOTKEY, 0},
840 {' ', N_("&Encoding... C-t"), NULL_HOTKEY, encoding_cmd},
841 #endif
842 #ifdef USE_NETCODE
843 {' ', "", NULL_HOTKEY, 0},
844 #ifdef ENABLE_VFS_MCFS
845 {' ', N_("&Network link..."), NULL_HOTKEY, netlink_cmd},
846 #endif
847 {' ', N_("FT&P link..."), NULL_HOTKEY, ftplink_cmd},
848 {' ', N_("S&hell link..."), NULL_HOTKEY, fishlink_cmd},
849 #ifdef WITH_SMBFS
850 {' ', N_("SM&B link..."), NULL_HOTKEY, smblink_cmd},
851 #endif
852 #endif
853 {' ', "", NULL_HOTKEY, 0},
854 {' ', N_("&Rescan C-r"), NULL_HOTKEY, reread_cmd}
857 static menu_entry RightMenu[] = {
858 {' ', N_("&Listing mode..."), NULL_HOTKEY, listing_cmd},
859 {' ', N_("&Quick view C-x q"), NULL_HOTKEY, quick_view_cmd},
860 {' ', N_("&Info C-x i"), NULL_HOTKEY, info_cmd},
861 {' ', N_("&Tree"), NULL_HOTKEY, tree_cmd},
862 {' ', "", NULL_HOTKEY, 0},
863 {' ', N_("&Sort order..."), NULL_HOTKEY, sort_cmd},
864 {' ', "", NULL_HOTKEY, 0},
865 {' ', N_("&Filter..."), NULL_HOTKEY, filter_cmd},
866 #ifdef HAVE_CHARSET
867 {' ', "",NULL_HOTKEY, 0},
868 {' ', N_("&Encoding... C-t"), NULL_HOTKEY, encoding_cmd},
869 #endif
870 #ifdef USE_NETCODE
871 {' ', "", NULL_HOTKEY, 0},
872 #ifdef ENABLE_VFS_MCFS
873 {' ', N_("&Network link..."), NULL_HOTKEY, netlink_cmd},
874 #endif
875 {' ', N_("FT&P link..."), NULL_HOTKEY, ftplink_cmd},
876 {' ', N_("S&hell link..."), NULL_HOTKEY, fishlink_cmd},
877 #ifdef WITH_SMBFS
878 {' ', N_("SM&B link..."), NULL_HOTKEY, smblink_cmd},
879 #endif
880 #endif
881 {' ', "", NULL_HOTKEY, 0},
882 {' ', N_("&Rescan C-r"), NULL_HOTKEY, reread_cmd}
885 static menu_entry FileMenu[] = {
886 {' ', N_("&View F3"), NULL_HOTKEY, view_cmd},
887 {' ', N_("Vie&w file... "), NULL_HOTKEY, view_file_cmd},
888 {' ', N_("&Filtered view M-!"), NULL_HOTKEY, filtered_view_cmd},
889 {' ', N_("&Edit F4"), NULL_HOTKEY, edit_cmd},
890 {' ', N_("&Copy F5"), NULL_HOTKEY, copy_cmd},
891 {' ', N_("c&Hmod C-x c"), NULL_HOTKEY, chmod_cmd},
892 {' ', N_("&Link C-x l"), NULL_HOTKEY, link_cmd},
893 {' ', N_("&SymLink C-x s"), NULL_HOTKEY, symlink_cmd},
894 {' ', N_("edit s&Ymlink C-x C-s"), NULL_HOTKEY, edit_symlink_cmd},
895 {' ', N_("ch&Own C-x o"), NULL_HOTKEY, chown_cmd},
896 {' ', N_("&Advanced chown "), NULL_HOTKEY, chown_advanced_cmd},
897 {' ', N_("&Rename/Move F6"), NULL_HOTKEY, ren_cmd},
898 {' ', N_("&Mkdir F7"), NULL_HOTKEY, mkdir_cmd},
899 {' ', N_("&Delete F8"), NULL_HOTKEY, delete_cmd},
900 {' ', N_("&Quick cd M-c"), NULL_HOTKEY, quick_cd_cmd},
901 {' ', "", NULL_HOTKEY, 0},
902 {' ', N_("select &Group M-+"), NULL_HOTKEY, select_cmd},
903 {' ', N_("u&Nselect group M-\\"), NULL_HOTKEY, unselect_cmd},
904 {' ', N_("reverse selec&Tion M-*"), NULL_HOTKEY, reverse_selection_cmd},
905 {' ', "", NULL_HOTKEY, 0},
906 {' ', N_("e&Xit F10"), NULL_HOTKEY, quit_cmd}
909 static menu_entry CmdMenu[] = {
910 {' ', N_("&User menu F2"), NULL_HOTKEY, user_file_menu_cmd},
911 /* I know, I'm lazy, but the tree widget when it's not running
912 * as a panel still has some problems, I have not yet finished
913 * the WTree widget port, sorry.
915 {' ', N_("&Directory tree"), NULL_HOTKEY, treebox_cmd},
916 {' ', N_("&Find file M-?"), NULL_HOTKEY, find_cmd},
917 {' ', N_("s&Wap panels C-u"), NULL_HOTKEY, swap_cmd},
918 {' ', N_("switch &Panels on/off C-o"), NULL_HOTKEY, view_other_cmd},
919 {' ', N_("&Compare directories C-x d"), NULL_HOTKEY, compare_dirs_cmd},
920 {' ', N_("e&Xternal panelize C-x !"), NULL_HOTKEY, external_panelize},
921 {' ', N_("show directory s&Izes"), NULL_HOTKEY, dirsizes_cmd},
922 {' ', "", NULL_HOTKEY, 0},
923 {' ', N_("Command &history M-h"), NULL_HOTKEY, history_cmd},
924 {' ', N_("di&Rectory hotlist C-\\"), NULL_HOTKEY, quick_chdir_cmd},
925 #ifdef USE_VFS
926 {' ', N_("&Active VFS list C-x a"), NULL_HOTKEY, reselect_vfs},
927 #endif
928 #ifdef WITH_BACKGROUND
929 {' ', N_("&Background jobs C-x j"), NULL_HOTKEY, jobs_cmd},
930 #endif
931 {' ', "", NULL_HOTKEY, 0},
932 #ifdef USE_EXT2FSLIB
933 {' ', N_("&Undelete files (ext2fs only)"), NULL_HOTKEY, undelete_cmd},
934 #endif
935 #ifdef LISTMODE_EDITOR
936 {' ', N_("&Listing format edit"), NULL_HOTKEY, listmode_cmd},
937 #endif
938 #if defined (USE_EXT2FSLIB) || defined (LISTMODE_EDITOR)
939 {' ', "", NULL_HOTKEY, 0},
940 #endif
941 {' ', N_("Edit &extension file"), NULL_HOTKEY, ext_cmd},
942 {' ', N_("Edit &menu file"), NULL_HOTKEY, edit_mc_menu_cmd}
945 /* Must keep in sync with the constants in menu_cmd */
946 static menu_entry OptMenu[] = {
947 {' ', N_("&Configuration..."), NULL_HOTKEY, configure_box},
948 {' ', N_("&Layout..."), NULL_HOTKEY, layout_cmd},
949 {' ', N_("c&Onfirmation..."), NULL_HOTKEY, confirm_box},
950 {' ', N_("&Display bits..."), NULL_HOTKEY, display_bits_box},
951 {' ', N_("learn &Keys..."), NULL_HOTKEY, learn_keys},
952 #ifdef USE_VFS
953 {' ', N_("&Virtual FS..."), NULL_HOTKEY, configure_vfs},
954 #endif /* !USE_VFS */
955 {' ', "", NULL_HOTKEY, 0},
956 {' ', N_("&Save setup"), NULL_HOTKEY, save_setup_cmd}
959 #define menu_entries(x) sizeof(x)/sizeof(menu_entry)
961 static Menu *MenuBar[5];
963 void
964 init_menu (void)
966 MenuBar[0] =
967 create_menu (horizontal_split ? _(" &Above ") : _(" &Left "),
968 LeftMenu, menu_entries (LeftMenu),
969 "[Left and Right Menus]");
970 MenuBar[1] =
971 create_menu (_(" &File "), FileMenu, menu_entries (FileMenu),
972 "[File Menu]");
973 MenuBar[2] =
974 create_menu (_(" &Command "), CmdMenu, menu_entries (CmdMenu),
975 "[Command Menu]");
976 MenuBar[3] =
977 create_menu (_(" &Options "), OptMenu, menu_entries (OptMenu),
978 "[Options Menu]");
979 MenuBar[4] =
980 create_menu (horizontal_split ? _(" &Below ") : _(" &Right "),
981 RightMenu, menu_entries (RightMenu),
982 "[Left and Right Menus]");
985 void
986 done_menu (void)
988 int i;
990 for (i = 0; i < 5; i++) {
991 destroy_menu (MenuBar[i]);
995 static void
996 menu_last_selected_cmd (void)
998 the_menubar->active = 1;
999 the_menubar->dropped = drop_menus;
1000 the_menubar->previous_widget = midnight_dlg->current->dlg_id;
1001 dlg_select_widget (the_menubar);
1004 static void
1005 menu_cmd (void)
1007 if (the_menubar->active)
1008 return;
1010 if ((get_current_index () == 0) ^ (!current_panel->active))
1011 the_menubar->selected = 0;
1012 else
1013 the_menubar->selected = 4;
1014 menu_last_selected_cmd ();
1017 /* Flag toggling functions */
1018 void
1019 toggle_fast_reload (void)
1021 fast_reload = !fast_reload;
1022 if (fast_reload_w == 0 && fast_reload) {
1023 message (D_NORMAL, _(" Information "),
1025 (" Using the fast reload option may not reflect the exact \n"
1026 " directory contents. In this case you'll need to do a \n"
1027 " manual reload of the directory. See the man page for \n"
1028 " the details. "));
1029 fast_reload_w = 1;
1033 void
1034 toggle_mix_all_files (void)
1036 mix_all_files = !mix_all_files;
1037 update_panels (UP_RELOAD, UP_KEEPSEL);
1040 void
1041 toggle_show_backup (void)
1043 show_backups = !show_backups;
1044 update_panels (UP_RELOAD, UP_KEEPSEL);
1047 void
1048 toggle_show_hidden (void)
1050 show_dot_files = !show_dot_files;
1051 update_panels (UP_RELOAD, UP_KEEPSEL);
1055 * Just a hack for allowing url-like pathnames to be accepted from the
1056 * command line.
1058 static void
1059 translated_mc_chdir (char *dir)
1061 char *newdir;
1063 newdir = vfs_translate_url (dir);
1064 mc_chdir (newdir);
1065 g_free (newdir);
1068 static void
1069 create_panels (void)
1071 int current_index;
1072 int other_index;
1073 int current_mode;
1074 int other_mode;
1075 char original_dir[1024];
1077 original_dir[0] = 0;
1079 if (boot_current_is_left) {
1080 current_index = 0;
1081 other_index = 1;
1082 current_mode = startup_left_mode;
1083 other_mode = startup_right_mode;
1084 } else {
1085 current_index = 1;
1086 other_index = 0;
1087 current_mode = startup_right_mode;
1088 other_mode = startup_left_mode;
1090 /* Creates the left panel */
1091 if (this_dir) {
1092 if (other_dir) {
1093 /* Ok, user has specified two dirs, save the original one,
1094 * since we may not be able to chdir to the proper
1095 * second directory later
1097 mc_get_current_wd (original_dir, sizeof (original_dir) - 2);
1099 translated_mc_chdir (this_dir);
1101 set_display_type (current_index, current_mode);
1103 /* The other panel */
1104 if (other_dir) {
1105 if (original_dir[0])
1106 translated_mc_chdir (original_dir);
1107 translated_mc_chdir (other_dir);
1109 set_display_type (other_index, other_mode);
1111 if (startup_left_mode == view_listing) {
1112 current_panel = left_panel;
1113 } else {
1114 if (right_panel)
1115 current_panel = right_panel;
1116 else
1117 current_panel = left_panel;
1120 /* Create the nice widgets */
1121 cmdline = command_new (0, 0, 0);
1122 the_prompt = label_new (0, 0, prompt);
1123 the_prompt->transparent = 1;
1124 the_bar = buttonbar_new (keybar_visible);
1126 the_hint = label_new (0, 0, 0);
1127 the_hint->transparent = 1;
1128 the_hint->auto_adjust_cols = 0;
1129 the_hint->widget.cols = COLS;
1131 the_menubar = menubar_new (0, 0, COLS, MenuBar, 5);
1134 static void
1135 copy_current_pathname (void)
1137 char *cwd_path;
1138 if (!command_prompt)
1139 return;
1141 cwd_path = remove_encoding_from_path (current_panel->cwd);
1142 command_insert (cmdline, cwd_path, 0);
1144 if (cwd_path [strlen (cwd_path ) - 1] != PATH_SEP)
1145 command_insert (cmdline, PATH_SEP_STR, 0);
1146 g_free (cwd_path);
1149 static void
1150 copy_other_pathname (void)
1152 char *cwd_path;
1154 if (get_other_type () != view_listing)
1155 return;
1157 if (!command_prompt)
1158 return;
1160 cwd_path = remove_encoding_from_path (other_panel->cwd);
1161 command_insert (cmdline, cwd_path, 0);
1163 if (cwd_path [strlen (cwd_path ) - 1] != PATH_SEP)
1164 command_insert (cmdline, PATH_SEP_STR, 0);
1165 g_free (cwd_path);
1168 static void
1169 copy_readlink (WPanel *panel)
1171 if (!command_prompt)
1172 return;
1173 if (S_ISLNK (selection (panel)->st.st_mode)) {
1174 char buffer[MC_MAXPATHLEN];
1175 char *p =
1176 concat_dir_and_file (panel->cwd, selection (panel)->fname);
1177 int i;
1179 i = mc_readlink (p, buffer, MC_MAXPATHLEN - 1);
1180 g_free (p);
1181 if (i > 0) {
1182 buffer[i] = 0;
1183 command_insert (cmdline, buffer, 1);
1188 static void
1189 copy_current_readlink (void)
1191 copy_readlink (current_panel);
1194 static void
1195 copy_other_readlink (void)
1197 if (get_other_type () != view_listing)
1198 return;
1199 copy_readlink (other_panel);
1202 /* Insert the selected file name into the input line */
1203 static void
1204 copy_prog_name (void)
1206 char *tmp;
1207 if (!command_prompt)
1208 return;
1210 if (get_current_type () == view_tree) {
1211 WTree *tree = (WTree *) get_panel_widget (get_current_index ());
1212 tmp = tree_selected_name (tree);
1213 } else
1214 tmp = selection (current_panel)->fname;
1216 command_insert (cmdline, tmp, 1);
1219 static void
1220 copy_tagged (WPanel *panel)
1222 int i;
1224 if (!command_prompt)
1225 return;
1226 input_disable_update (cmdline);
1227 if (panel->marked) {
1228 for (i = 0; i < panel->count; i++) {
1229 if (panel->dir.list[i].f.marked)
1230 command_insert (cmdline, panel->dir.list[i].fname, 1);
1232 } else {
1233 command_insert (cmdline, panel->dir.list[panel->selected].fname,
1236 input_enable_update (cmdline);
1239 static void
1240 copy_current_tagged (void)
1242 copy_tagged (current_panel);
1245 static void
1246 copy_other_tagged (void)
1248 if (get_other_type () != view_listing)
1249 return;
1250 copy_tagged (other_panel);
1253 static void
1254 init_labels (void)
1256 buttonbar_set_label (midnight_dlg, 1, _("Help"), help_cmd);
1257 buttonbar_set_label (midnight_dlg, 2, _("Menu"), user_file_menu_cmd);
1258 buttonbar_set_label (midnight_dlg, 9, _("PullDn"), menu_cmd);
1259 buttonbar_set_label (midnight_dlg, 10, _("Quit"), quit_cmd);
1262 static const key_map ctl_x_map[] = {
1263 {XCTRL ('c'), quit_cmd},
1264 {'d', compare_dirs_cmd},
1265 #ifdef USE_VFS
1266 {'a', reselect_vfs},
1267 #endif /* USE_VFS */
1268 {'p', copy_current_pathname},
1269 {XCTRL ('p'), copy_other_pathname},
1270 {'t', copy_current_tagged},
1271 {XCTRL ('t'), copy_other_tagged},
1272 {'c', chmod_cmd},
1273 {'o', chown_cmd},
1274 {'r', copy_current_readlink},
1275 {XCTRL ('r'), copy_other_readlink},
1276 {'l', link_cmd},
1277 {'s', symlink_cmd},
1278 {XCTRL ('s'), edit_symlink_cmd},
1279 {'i', info_cmd_no_menu},
1280 {'q', quick_cmd_no_menu},
1281 {'h', add2hotlist_cmd},
1282 {'!', external_panelize},
1283 #ifdef WITH_BACKGROUND
1284 {'j', jobs_cmd},
1285 #endif /* WITH_BACKGROUND */
1286 {0, 0}
1289 static int ctl_x_map_enabled = 0;
1291 static void
1292 ctl_x_cmd (void)
1294 ctl_x_map_enabled = 1;
1297 static void
1298 nothing (void)
1302 static const key_map default_map[] = {
1303 {KEY_F (19), menu_last_selected_cmd},
1304 {KEY_F (20), quiet_quit_cmd},
1306 {XCTRL ('@'), single_dirsize_cmd},
1308 /* Copy useful information to the command line */
1309 {ALT ('a'), copy_current_pathname},
1310 {ALT ('A'), copy_other_pathname},
1312 {ALT ('c'), quick_cd_cmd},
1314 /* To access the directory hotlist */
1315 {XCTRL ('\\'), quick_chdir_cmd},
1317 /* Suspend */
1318 {XCTRL ('z'), suspend_cmd},
1320 /* The filtered view command */
1321 {ALT ('!'), filtered_view_cmd},
1323 /* Find file */
1324 {ALT ('?'), find_cmd},
1326 /* Panel refresh */
1327 {XCTRL ('r'), reread_cmd},
1329 /* Toggle listing between long, user defined and full formats */
1330 {ALT ('t'), toggle_listing_cmd},
1332 /* Swap panels */
1333 {XCTRL ('u'), swap_cmd},
1335 /* View output */
1336 {XCTRL ('o'), view_other_cmd},
1338 /* Control-X keybindings */
1339 {XCTRL ('x'), ctl_x_cmd},
1341 /* Trap dlg's exit commands */
1342 {ESC_CHAR, nothing},
1343 {XCTRL ('c'), nothing},
1344 {XCTRL ('g'), nothing},
1345 {0, 0},
1348 static void
1349 setup_sigwinch (void)
1351 #if (defined(HAVE_SLANG) || (NCURSES_VERSION_MAJOR >= 4)) && defined(SIGWINCH)
1352 struct sigaction act, oact;
1353 act.sa_handler = flag_winch;
1354 sigemptyset (&act.sa_mask);
1355 act.sa_flags = 0;
1356 #ifdef SA_RESTART
1357 act.sa_flags |= SA_RESTART;
1358 #endif
1359 sigaction (SIGWINCH, &act, &oact);
1360 #endif
1363 static void
1364 setup_pre (void)
1366 /* Call all the inits */
1367 #ifdef HAVE_CHARSET
1369 * Don't restrict the output on the screen manager level,
1370 * the translation tables take care of it.
1372 #define full_eight_bits (1)
1373 #define eight_bit_clean (1)
1374 #endif /* !HAVE_CHARSET */
1376 #ifndef HAVE_SLANG
1377 meta (stdscr, eight_bit_clean);
1378 #else
1379 SLsmg_Display_Eight_Bit = full_eight_bits ? 128 : 160;
1380 #endif
1383 static void
1384 init_xterm_support (void)
1386 const char *termvalue;
1388 termvalue = getenv ("TERM");
1389 if (!termvalue || !(*termvalue)) {
1390 fputs (_("The TERM environment variable is unset!\n"), stderr);
1391 exit (1);
1394 /* Check mouse capabilities */
1395 xmouse_seq = tty_tgetstr ("Km");
1397 if (strcmp (termvalue, "cygwin") == 0) {
1398 force_xterm = 1;
1399 use_mouse_p = MOUSE_DISABLED;
1402 if (force_xterm || strncmp (termvalue, "xterm", 5) == 0
1403 || strncmp (termvalue, "rxvt", 4) == 0
1404 || strcmp (termvalue, "Eterm") == 0
1405 || strcmp (termvalue, "dtterm") == 0) {
1406 xterm_flag = 1;
1408 /* Default to the standard xterm sequence */
1409 if (!xmouse_seq) {
1410 xmouse_seq = ESC_STR "[M";
1413 /* Enable mouse unless explicitly disabled by --nomouse */
1414 if (use_mouse_p != MOUSE_DISABLED) {
1415 const char *color_term = getenv ("COLORTERM");
1416 if (strncmp (termvalue, "rxvt", 4) == 0 ||
1417 (color_term != NULL && strncmp (color_term, "rxvt", 4) == 0) ||
1418 strcmp (termvalue, "Eterm") == 0) {
1419 use_mouse_p = MOUSE_XTERM_NORMAL_TRACKING;
1420 } else {
1421 use_mouse_p = MOUSE_XTERM_BUTTON_EVENT_TRACKING;
1427 static void
1428 setup_mc (void)
1430 setup_pre ();
1431 init_menu ();
1432 create_panels ();
1433 setup_panels ();
1435 #ifdef HAVE_SUBSHELL_SUPPORT
1436 if (use_subshell)
1437 add_select_channel (subshell_pty, load_prompt, 0);
1438 #endif /* !HAVE_SUBSHELL_SUPPORT */
1440 setup_sigwinch ();
1442 if (baudrate () < 9600 || slow_terminal) {
1443 verbose = 0;
1445 init_mouse ();
1448 static void
1449 setup_dummy_mc ()
1451 char d[MC_MAXPATHLEN];
1453 mc_get_current_wd (d, MC_MAXPATHLEN);
1454 setup_mc ();
1455 mc_chdir (d);
1458 static void check_codeset()
1460 const char *_system_codepage = NULL;
1461 #ifdef HAVE_CHARSET
1462 const char *_source_codepage = NULL;
1463 const char *_display_codepage = NULL;
1464 int profile_changed = 0;
1466 #define CONFY 16
1467 #define CONFX 54
1469 if ( !skip_check_codeset ) {
1471 QuickWidget ecs_widgets [] = {
1472 { quick_button, 4, 6, 13, CONFY, N_("&Skip"),
1473 0, B_EXIT, 0, 0, NULL , NULL, NULL},
1474 { quick_button, 1, 11, 13, CONFY, N_("&Fix it"),
1475 0, B_ENTER, 0, 0, NULL , NULL, NULL},
1476 { quick_checkbox, 1, 13, 11, CONFY, N_("don't ask again"),
1477 11, 0, &skip_check_codeset, NULL, NULL , NULL, NULL},
1478 { quick_label, 2, 30, 3, CONFY, N_("Chosen display charset (Settings->Display bits)\n"
1479 "or source codeset (in mcedit ctrl-t) \n"
1480 "does not match one set via locale. \n"
1481 "Set correct codeset manually or press <<Fix it>> \n"
1482 "to set locale default.\n\n"
1483 "Or set \'don't ask again\' and press <<Skip>>"),
1484 0, 0, 0, 0, NULL , NULL, NULL},
1486 NULL_QuickWidget
1489 QuickDialog ecs =
1490 { CONFX, CONFY, -1, -1, N_(" Confirmation "), "[Confirmation]",
1491 ecs_widgets, 0
1495 _system_codepage = str_detect_termencoding();
1496 _source_codepage = get_codepage_id (source_codepage);
1497 _display_codepage = get_codepage_id (display_codepage);
1499 if ( (strcmp (_system_codepage, _display_codepage)) ||
1500 (strcmp (_system_codepage, _source_codepage)) ) {
1501 if (quick_dialog (&ecs) == B_ENTER){
1502 display_codepage = get_codepage_index (_system_codepage);
1503 cp_display = get_codepage_id (display_codepage);
1504 if ( !strcmp (cp_display, _system_codepage)) {
1505 mc_config_set_string(mc_main_config, "Misc", "display_codepage", cp_display);
1506 mc_config_set_string(mc_main_config, "Misc", "source_codepage", cp_display);
1507 display_codepage = get_codepage_index ( cp_display );
1508 utf8_display = str_isutf8 (_system_codepage);
1509 source_codepage = display_codepage;
1510 cp_source = cp_display;
1511 profile_changed = 1;
1513 } else {
1514 if ( skip_check_codeset ) {
1515 mc_config_set_int(mc_main_config, "Midnight-Commander", "skip_check_codeset", 1);
1516 profile_changed = 1;
1520 if ( profile_changed )
1521 save_configure ();
1523 #else /* HAVE_CHARSET */
1524 _system_codepage = str_detect_termencoding();
1525 utf8_display = str_isutf8 (_system_codepage);
1526 #endif /* HAVE_CHARSET */
1529 static void
1530 done_mc (void)
1532 disable_mouse ();
1534 done_menu ();
1536 /* Setup shutdown
1538 * We sync the profiles since the hotlist may have changed, while
1539 * we only change the setup data if we have the auto save feature set
1542 if (auto_save_setup)
1543 save_setup (); /* does also call save_hotlist */
1544 else {
1545 save_hotlist ();
1546 save_panel_types ();
1548 done_screen ();
1549 vfs_add_current_stamps ();
1552 /* This should be called after destroy_dlg since panel widgets
1553 * save their state on the profiles
1555 static void
1556 done_mc_profile (void)
1558 done_setup ();
1561 static cb_ret_t
1562 midnight_callback (struct Dlg_head *h, dlg_msg_t msg, int parm)
1564 int i;
1566 switch (msg) {
1568 case DLG_IDLE:
1569 /* We only need the first idle event */
1570 set_idle_proc (h, 0);
1571 if (auto_menu) {
1572 user_file_menu_cmd ();
1574 return MSG_HANDLED;
1576 case DLG_KEY:
1577 if (ctl_x_map_enabled) {
1578 ctl_x_map_enabled = 0;
1579 for (i = 0; ctl_x_map[i].key_code; i++)
1580 if (parm == ctl_x_map[i].key_code) {
1581 (*ctl_x_map[i].fn) ();
1582 return MSG_HANDLED;
1586 /* FIXME: should handle all menu shortcuts before this point */
1587 if (the_menubar->active)
1588 return MSG_NOT_HANDLED;
1590 if (parm == KEY_F (10)) {
1591 quit_cmd ();
1592 return MSG_HANDLED;
1595 if (parm == '\t')
1596 free_completions (cmdline);
1598 if (parm == '\n') {
1599 for (i = 0; cmdline->buffer[i] && (cmdline->buffer[i] == ' ' ||
1600 cmdline->buffer[i] == '\t'); i++);
1601 if (cmdline->buffer[i]) {
1602 send_message ((Widget *) cmdline, WIDGET_KEY, parm);
1603 return MSG_HANDLED;
1605 stuff (cmdline, "", 0);
1606 cmdline->point = 0;
1609 /* Ctrl-Enter and Alt-Enter */
1610 if (((parm & ~(KEY_M_CTRL | KEY_M_ALT)) == '\n')
1611 && (parm & (KEY_M_CTRL | KEY_M_ALT))) {
1612 copy_prog_name ();
1613 return MSG_HANDLED;
1616 /* Ctrl-Shift-Enter */
1617 if (parm == (KEY_M_CTRL | KEY_M_SHIFT | '\n')) {
1618 copy_current_pathname ();
1619 copy_prog_name ();
1620 return MSG_HANDLED;
1623 if ((!alternate_plus_minus || !(console_flag || xterm_flag))
1624 && !quote && !current_panel->searching) {
1625 if (!only_leading_plus_minus) {
1626 /* Special treatement, since the input line will eat them */
1627 if (parm == '+') {
1628 select_cmd ();
1629 return MSG_HANDLED;
1632 if (parm == '\\' || parm == '-') {
1633 unselect_cmd ();
1634 return MSG_HANDLED;
1637 if (parm == '*') {
1638 reverse_selection_cmd ();
1639 return MSG_HANDLED;
1641 } else if (!command_prompt || !cmdline->buffer[0]) {
1642 /* Special treatement '+', '-', '\', '*' only when this is
1643 * first char on input line
1646 if (parm == '+') {
1647 select_cmd ();
1648 return MSG_HANDLED;
1651 if (parm == '\\' || parm == '-') {
1652 unselect_cmd ();
1653 return MSG_HANDLED;
1656 if (parm == '*') {
1657 reverse_selection_cmd ();
1658 return MSG_HANDLED;
1662 return MSG_NOT_HANDLED;
1664 case DLG_HOTKEY_HANDLED:
1665 if ((get_current_type () == view_listing) && current_panel->searching) {
1666 current_panel->searching = 0;
1667 current_panel->dirty = 1;
1669 return MSG_HANDLED;
1671 case DLG_UNHANDLED_KEY:
1672 if (command_prompt) {
1673 int v;
1675 v = send_message ((Widget *) cmdline, WIDGET_KEY, parm);
1676 if (v)
1677 return v;
1679 if (ctl_x_map_enabled) {
1680 ctl_x_map_enabled = 0;
1681 for (i = 0; ctl_x_map[i].key_code; i++)
1682 if (parm == ctl_x_map[i].key_code) {
1683 (*ctl_x_map[i].fn) ();
1684 return MSG_HANDLED;
1686 } else {
1687 for (i = 0; default_map[i].key_code; i++) {
1688 if (parm == default_map[i].key_code) {
1689 (*default_map[i].fn) ();
1690 return MSG_HANDLED;
1694 return MSG_NOT_HANDLED;
1696 case DLG_DRAW:
1697 /* We handle the special case of the output lines */
1698 if (console_flag && output_lines)
1699 show_console_contents (output_start_y,
1700 LINES - output_lines - keybar_visible -
1701 1, LINES - keybar_visible - 1);
1702 return MSG_HANDLED;
1704 case DLG_POST_KEY:
1705 if (!the_menubar->active)
1706 update_dirty_panels ();
1707 return MSG_HANDLED;
1709 default:
1710 return default_dlg_callback (h, msg, parm);
1714 /* Show current directory in the xterm title */
1715 void
1716 update_xterm_title_path (void)
1718 const char *path;
1719 char host[BUF_TINY];
1720 char *p;
1721 struct passwd *pw = NULL;
1722 char *login = NULL;
1723 int res = 0;
1724 if (xterm_flag && xterm_title) {
1725 path = strip_home_and_password (current_panel->cwd);
1726 res = gethostname(host, sizeof (host));
1727 if ( res ) { /* On success, res = 0 */
1728 host[0] = '\0';
1729 } else {
1730 host[sizeof (host) - 1] = '\0';
1732 pw = getpwuid(getuid());
1733 if ( pw ) {
1734 login = g_strdup_printf ("%s@%s", pw->pw_name, host);
1735 } else {
1736 login = g_strdup (host);
1738 p = g_strdup_printf ("mc [%s]:%s", login, path);
1739 fprintf (stdout, "\33]0;%s\7", str_term_form (p));
1740 g_free (login);
1741 g_free (p);
1742 if (!alternate_plus_minus)
1743 numeric_keypad_mode ();
1744 fflush (stdout);
1749 * Load new hint and display it.
1750 * IF force is not 0, ignore the timeout.
1752 void
1753 load_hint (int force)
1755 char *hint;
1757 if (!the_hint->widget.parent)
1758 return;
1760 if (!message_visible) {
1761 label_set_text (the_hint, 0);
1762 return;
1765 if ((hint = get_random_hint (force))) {
1766 if (*hint)
1767 set_hintbar (hint);
1768 g_free (hint);
1769 } else {
1770 char text[BUF_SMALL];
1772 g_snprintf (text, sizeof (text), _("GNU Midnight Commander %s\n"),
1773 VERSION);
1774 set_hintbar (text);
1778 static void
1779 setup_panels_and_run_mc (void)
1781 add_widget (midnight_dlg, the_menubar);
1782 add_widget (midnight_dlg, get_panel_widget (0));
1783 add_widget (midnight_dlg, get_panel_widget (1));
1784 add_widget (midnight_dlg, the_hint);
1785 load_hint (1);
1786 add_widget (midnight_dlg, cmdline);
1787 add_widget (midnight_dlg, the_prompt);
1788 add_widget (midnight_dlg, the_bar);
1789 init_labels ();
1791 if (boot_current_is_left)
1792 dlg_select_widget (get_panel_widget (0));
1793 else
1794 dlg_select_widget (get_panel_widget (1));
1796 /* Run the Midnight Commander if no file was specified in the command line */
1797 run_dlg (midnight_dlg);
1800 /* result must be free'd (I think this should go in util.c) */
1801 static char *
1802 prepend_cwd_on_local (const char *filename)
1804 char *d;
1805 int l;
1807 if (vfs_file_is_local (filename)) {
1808 if (*filename == PATH_SEP) /* an absolute pathname */
1809 return g_strdup (filename);
1810 d = g_malloc (MC_MAXPATHLEN + strlen (filename) + 2);
1811 mc_get_current_wd (d, MC_MAXPATHLEN);
1812 l = strlen (d);
1813 d[l++] = PATH_SEP;
1814 strcpy (d + l, filename);
1815 canonicalize_pathname (d);
1816 return d;
1817 } else
1818 return g_strdup (filename);
1821 static int
1822 mc_maybe_editor_or_viewer (void)
1824 if (!(view_one_file || edit_one_file))
1825 return 0;
1827 setup_dummy_mc ();
1829 /* Invoke the internal view/edit routine with:
1830 * the default processing and forcing the internal viewer/editor
1832 if (view_one_file) {
1833 char *path = NULL;
1834 path = prepend_cwd_on_local (view_one_file);
1835 view_file (path, 0, 1);
1836 g_free (path);
1838 #ifdef USE_INTERNAL_EDIT
1839 else {
1840 edit_file (edit_one_file, edit_one_file_start_line);
1842 #endif /* USE_INTERNAL_EDIT */
1843 midnight_shutdown = 1;
1844 done_mc ();
1845 return 1;
1848 /* Run the main dialog that occupies the whole screen */
1849 static void
1850 do_nc (void)
1852 int midnight_colors[4];
1854 midnight_colors[0] = NORMAL_COLOR; /* NORMALC */
1855 midnight_colors[1] = REVERSE_COLOR; /* FOCUSC */
1856 midnight_colors[2] = INPUT_COLOR; /* HOT_NORMALC */
1857 midnight_colors[3] = NORMAL_COLOR; /* HOT_FOCUSC */
1860 midnight_dlg = create_dlg (0, 0, LINES, COLS, midnight_colors, midnight_callback,
1861 "[main]", NULL, DLG_WANT_IDLE);
1863 /* start check display_codepage and source_codepage */
1864 check_codeset();
1866 /* Check if we were invoked as an editor or file viewer */
1867 if (!mc_maybe_editor_or_viewer ()) {
1868 setup_mc ();
1869 setup_panels_and_run_mc ();
1871 /* Program end */
1872 midnight_shutdown = 1;
1874 /* destroy_dlg destroys even current_panel->cwd, so we have to save a copy :) */
1875 if (last_wd_file && vfs_current_is_local ()) {
1876 last_wd_string = g_strdup (current_panel->cwd);
1878 done_mc ();
1880 destroy_dlg (midnight_dlg);
1881 current_panel = 0;
1882 done_mc_profile ();
1885 /* POSIX version. The only version we support. */
1886 static void
1887 OS_Setup (void)
1889 const char *mc_libdir;
1890 shell = getenv ("SHELL");
1891 if (!shell || !*shell) {
1892 struct passwd *pwd;
1893 pwd = getpwuid (geteuid ());
1894 if (pwd != NULL)
1895 shell = g_strdup (pwd->pw_shell);
1897 if (!shell || !*shell)
1898 shell = "/bin/sh";
1900 /* This is the directory, where MC was installed, on Unix this is DATADIR */
1901 /* and can be overriden by the MC_DATADIR environment variable */
1902 if ((mc_libdir = getenv ("MC_DATADIR")) != NULL) {
1903 mc_home = g_strdup (mc_libdir);
1904 } else {
1905 mc_home = g_strdup (SYSCONFDIR);
1907 mc_home_alt = mc_libdir != NULL ? g_strdup (SYSCONFDIR) : g_strdup (DATADIR);
1910 static void
1911 sigchld_handler_no_subshell (int sig)
1913 #ifdef __linux__
1914 int pid, status;
1916 if (!console_flag)
1917 return;
1919 /* COMMENT: if it were true that after the call to handle_console(..INIT)
1920 the value of console_flag never changed, we could simply not install
1921 this handler at all if (!console_flag && !use_subshell). */
1923 /* That comment is no longer true. We need to wait() on a sigchld
1924 handler (that's at least what the tarfs code expects currently). */
1926 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
1928 if (pid == cons_saver_pid) {
1930 if (WIFSTOPPED (status)) {
1931 /* Someone has stopped cons.saver - restart it */
1932 kill (pid, SIGCONT);
1933 } else {
1934 /* cons.saver has died - disable console saving */
1935 handle_console (CONSOLE_DONE);
1936 console_flag = 0;
1939 /* If we got here, some other child exited; ignore it */
1940 #endif /* __linux__ */
1942 (void) sig;
1945 static void
1946 init_sigchld (void)
1948 struct sigaction sigchld_action;
1950 sigchld_action.sa_handler =
1951 #ifdef HAVE_SUBSHELL_SUPPORT
1952 use_subshell ? sigchld_handler :
1953 #endif /* HAVE_SUBSHELL_SUPPORT */
1954 sigchld_handler_no_subshell;
1956 sigemptyset (&sigchld_action.sa_mask);
1958 #ifdef SA_RESTART
1959 sigchld_action.sa_flags = SA_RESTART;
1960 #else
1961 sigchld_action.sa_flags = 0;
1962 #endif /* !SA_RESTART */
1964 if (sigaction (SIGCHLD, &sigchld_action, NULL) == -1) {
1965 #ifdef HAVE_SUBSHELL_SUPPORT
1967 * This may happen on QNX Neutrino 6, where SA_RESTART
1968 * is defined but not implemented. Fallback to no subshell.
1970 use_subshell = 0;
1971 #endif /* HAVE_SUBSHELL_SUPPORT */
1975 static void
1976 print_mc_usage (poptContext ctx, FILE *stream)
1978 int leftColWidth;
1980 poptSetOtherOptionHelp (ctx,
1981 _("[flags] [this_dir] [other_panel_dir]\n"));
1983 /* print help for options */
1984 leftColWidth = poptPrintHelp (ctx, stream, 0);
1985 fprintf (stream, " %-*s %s\n", leftColWidth, _("+number"),
1986 _("Set initial line number for the internal editor"));
1987 fputs (_
1988 ("\n"
1989 "Please send any bug reports (including the output of `mc -V')\n"
1990 "to mc-devel@gnome.org\n"), stream);
1991 show_version (0);
1994 static void
1995 print_color_usage (void)
1998 * FIXME: undocumented keywords: viewunderline, editnormal, editbold,
1999 * and editmarked. To preserve translations, lines should be split.
2001 /* TRANSLATORS: don't translate keywords and names of colors */
2002 fputs (_
2003 ("--colors KEYWORD={FORE},{BACK}\n\n"
2004 "{FORE} and {BACK} can be omitted, and the default will be used\n"
2005 "\n" "Keywords:\n"
2006 " Global: errors, reverse, gauge, input, viewunderline\n"
2007 " File display: normal, selected, marked, markselect\n"
2008 " Dialog boxes: dnormal, dfocus, dhotnormal, dhotfocus, errdhotnormal,\n"
2009 " errdhotfocus\n"
2010 " Menus: menu, menuhot, menusel, menuhotsel\n"
2011 " Editor: editnormal, editbold, editmarked, editwhitespace,\n"
2012 " editlinestate\n"), stdout);
2013 fputs (_
2015 " Help: helpnormal, helpitalic, helpbold, helplink, helpslink\n"
2016 " File types: directory, executable, link, stalelink, device, special, core\n"
2017 "\n" "Colors:\n"
2018 " black, gray, red, brightred, green, brightgreen, brown,\n"
2019 " yellow, blue, brightblue, magenta, brightmagenta, cyan,\n"
2020 " brightcyan, lightgray and white\n\n"), stdout);
2023 static void
2024 process_args (poptContext ctx, int c, const char *option_arg)
2026 switch (c) {
2027 case 'V':
2028 show_version (1);
2029 exit (0);
2030 break;
2032 case 'c':
2033 disable_colors = 0;
2034 #ifdef HAVE_SLANG
2035 force_colors = 1;
2036 #endif /* HAVE_SLANG */
2037 break;
2039 case 'f':
2040 printf ("%s (%s)\n", mc_home, mc_home_alt);
2041 exit (0);
2042 break;
2044 #ifdef USE_NETCODE
2045 case 'l':
2046 mc_setctl ("/#ftp:", VFS_SETCTL_LOGFILE, (void *) option_arg);
2047 #ifdef WITH_SMBFS
2048 smbfs_set_debugf (option_arg);
2049 #endif /* WITH_SMBFS */
2050 break;
2052 #ifdef WITH_SMBFS
2053 case 'D':
2054 smbfs_set_debug (atoi (option_arg));
2055 break;
2056 #endif /* WITH_SMBFS */
2057 #endif /* USE_NETCODE */
2059 case 'd':
2060 use_mouse_p = MOUSE_DISABLED;
2061 break;
2063 #ifdef HAVE_SUBSHELL_SUPPORT
2064 case 'u':
2065 use_subshell = 0;
2066 break;
2067 #endif /* HAVE_SUBSHELL_SUPPORT */
2069 case 'H':
2070 print_color_usage ();
2071 exit (0);
2072 break;
2074 case 'h':
2075 print_mc_usage (ctx, stdout);
2076 exit (0);
2080 static const struct poptOption argument_table[] = {
2081 /* generic options */
2082 {"help", 'h', POPT_ARG_NONE, {NULL}, 'h',
2083 N_("Displays this help message"), NULL},
2084 {"version", 'V', POPT_ARG_NONE, {NULL}, 'V',
2085 N_("Displays the current version"), NULL},
2087 /* terminal options */
2088 {"xterm", 'x', POPT_ARG_NONE, {&force_xterm}, 0,
2089 N_("Forces xterm features"), NULL},
2090 {"nomouse", 'd', POPT_ARG_NONE, {NULL}, 'd',
2091 N_("Disable mouse support in text version"), NULL},
2092 #if defined(HAVE_SLANG)
2093 {"termcap", 't', 0, {&SLtt_Try_Termcap}, 0,
2094 N_("Tries to use termcap instead of terminfo"), NULL},
2095 #endif
2096 {"resetsoft", 'k', POPT_ARG_NONE, {&reset_hp_softkeys}, 0,
2097 N_("Resets soft keys on HP terminals"), NULL},
2098 {"slow", 's', POPT_ARG_NONE, {&slow_terminal}, 0,
2099 N_("To run on slow terminals"), NULL},
2100 {"stickchars", 'a', 0, {&force_ugly_line_drawing}, 0,
2101 N_("Use stickchars to draw"), NULL},
2103 /* color options */
2104 {"nocolor", 'b', POPT_ARG_NONE, {&disable_colors}, 0,
2105 N_("Requests to run in black and white"), NULL},
2106 {"color", 'c', POPT_ARG_NONE, {NULL}, 'c',
2107 N_("Request to run in color mode"), NULL},
2108 {"colors", 'C', POPT_ARG_STRING, {&command_line_colors}, 0,
2109 N_("Specifies a color configuration"), NULL},
2110 {"help-colors", 'H', POPT_ARG_NONE, {NULL}, 'H',
2111 N_("Displays a help screen on how to change the color scheme"), NULL},
2113 /* debug options */
2114 #ifdef USE_NETCODE
2115 {"ftplog", 'l', POPT_ARG_STRING, {NULL}, 'l',
2116 N_("Log ftp dialog to specified file"), NULL},
2117 #ifdef WITH_SMBFS
2118 {"debuglevel", 'D', POPT_ARG_STRING, {NULL}, 'D',
2119 N_("Set debug level"), NULL},
2120 #endif
2121 #endif
2123 /* options for wrappers */
2124 {"datadir", 'f', POPT_ARG_NONE, {NULL}, 'f',
2125 N_("Print data directory"), NULL},
2126 {"printwd", 'P', POPT_ARG_STRING, {&last_wd_file}, 0,
2127 N_("Print last working directory to specified file"), NULL},
2129 /* subshell options */
2130 #ifdef HAVE_SUBSHELL_SUPPORT
2131 {"subshell", 'U', POPT_ARG_NONE, {&use_subshell}, 0,
2132 N_("Enables subshell support (default)"), NULL},
2133 {"nosubshell", 'u', POPT_ARG_NONE, {NULL}, 'u',
2134 N_("Disables subshell support"), NULL},
2135 #endif
2137 /* single file operations */
2138 {"view", 'v', POPT_ARG_STRING, {&view_one_file}, 0,
2139 N_("Launches the file viewer on a file"), NULL},
2140 #ifdef USE_INTERNAL_EDIT
2141 {"edit", 'e', POPT_ARG_STRING, {&edit_one_file}, 0,
2142 N_("Edits one file"), NULL},
2143 #endif
2145 {NULL, '\0', 0, {NULL}, 0, NULL , NULL}
2148 static void
2149 handle_args (int argc, char *argv[])
2151 char *tmp;
2152 poptContext ctx;
2153 const char *base;
2154 int c;
2156 ctx =
2157 poptGetContext ("mc", argc, argv, argument_table,
2158 POPT_CONTEXT_NO_EXEC);
2160 while ((c = poptGetNextOpt (ctx)) > 0) {
2161 process_args (ctx, c, poptGetOptArg (ctx));
2164 if (c < -1) {
2165 print_mc_usage (ctx, stderr);
2166 fprintf (stderr, "%s: %s\n",
2167 poptBadOption (ctx, POPT_BADOPTION_NOALIAS),
2168 poptStrerror (c));
2169 exit (1);
2172 tmp = poptGetArg (ctx);
2175 * Check for special invocation names mcedit and mcview,
2176 * if none apply then set the current directory and the other
2177 * directory from the command line arguments
2179 base = x_basename (argv[0]);
2180 if (!STRNCOMP (base, "mce", 3) || !STRCOMP (base, "vi")) {
2181 edit_one_file = "";
2182 if (tmp) {
2184 * Check for filename:lineno, followed by an optional colon.
2185 * This format is used by many programs (especially compilers)
2186 * in error messages and warnings. It is supported so that
2187 * users can quickly copy and paste file locations.
2189 char *end = tmp + strlen (tmp), *p = end;
2190 if (p > tmp && p[-1] == ':')
2191 p--;
2192 while (p > tmp && g_ascii_isdigit ((gchar) p[-1]))
2193 p--;
2194 if (tmp < p && p < end && p[-1] == ':') {
2195 struct stat st;
2196 gchar *fname = g_strndup (tmp, p - 1 - tmp);
2198 * Check that the file before the colon actually exists.
2199 * If it doesn't exist, revert to the old behavior.
2201 if (mc_stat (tmp, &st) == -1 && mc_stat (fname, &st) != -1) {
2202 edit_one_file = fname;
2203 edit_one_file_start_line = atoi (p);
2204 } else {
2205 g_free (fname);
2206 goto try_plus_filename;
2208 } else {
2209 try_plus_filename:
2210 if (*tmp == '+' && g_ascii_isdigit ((gchar) tmp[1])) {
2211 int start_line = atoi (tmp);
2212 if (start_line > 0) {
2213 char *file = poptGetArg (ctx);
2214 if (file) {
2215 tmp = file;
2216 edit_one_file_start_line = start_line;
2220 edit_one_file = g_strdup (tmp);
2223 } else if (!STRNCOMP (base, "mcv", 3) || !STRCOMP (base, "view")) {
2224 if (tmp)
2225 view_one_file = g_strdup (tmp);
2226 else {
2227 fputs ("No arguments given to the viewer\n", stderr);
2228 exit (1);
2230 } else {
2231 /* sets the current dir and the other dir */
2232 if (tmp) {
2233 this_dir = g_strdup (tmp);
2234 if ((tmp = poptGetArg (ctx)))
2235 other_dir = g_strdup (tmp);
2239 poptFreeContext (ctx);
2243 main (int argc, char *argv[])
2245 struct stat s;
2246 char *mc_dir;
2248 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
2249 setlocale (LC_ALL, "");
2250 bindtextdomain ("mc", LOCALEDIR);
2251 textdomain ("mc");
2253 /* Set up temporary directory */
2254 mc_tmpdir ();
2256 OS_Setup ();
2258 /* This variable is used by the subshell */
2259 home_dir = getenv ("HOME");
2260 if (!home_dir) {
2261 /* mc_home was computed by OS_Setup */
2262 home_dir = mc_home;
2265 str_init_strings (NULL);
2267 vfs_init ();
2269 #ifdef USE_INTERNAL_EDIT
2270 edit_stack_init ();
2271 #endif
2273 #ifdef HAVE_SLANG
2274 SLtt_Ignore_Beep = 1;
2275 #endif
2277 handle_args (argc, argv);
2279 /* NOTE: This has to be called before slang_init or whatever routine
2280 calls any define_sequence */
2281 init_key ();
2283 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
2284 handle_console (CONSOLE_INIT);
2286 #ifdef HAVE_SUBSHELL_SUPPORT
2287 /* Don't use subshell when invoked as viewer or editor */
2288 if (edit_one_file || view_one_file)
2289 use_subshell = 0;
2291 if (use_subshell)
2292 subshell_get_console_attributes ();
2293 #endif /* HAVE_SUBSHELL_SUPPORT */
2295 /* Install the SIGCHLD handler; must be done before init_subshell() */
2296 init_sigchld ();
2298 /* We need this, since ncurses endwin () doesn't restore the signals */
2299 save_stop_handler ();
2301 /* Must be done before init_subshell, to set up the terminal size: */
2302 /* FIXME: Should be removed and LINES and COLS computed on subshell */
2303 #ifdef HAVE_SLANG
2304 slang_init ();
2305 #endif
2306 /* NOTE: This call has to be after slang_init. It's the small part from
2307 the previous init_key which had to be moved after the call of slang_init */
2308 init_key_input_fd ();
2310 load_setup ();
2312 init_curses ();
2314 /* create home directory */
2315 /* do it after the screen library initialization to show the error message */
2316 mc_dir = concat_dir_and_file (home_dir, MC_BASE);
2317 canonicalize_pathname (mc_dir);
2318 if ((stat (mc_dir, &s) != 0) && (errno == ENOENT)
2319 && mkdir (mc_dir, 0700) != 0)
2320 message (D_ERROR, _("Warning"),
2321 _("Cannot create %s directory"), mc_dir);
2322 g_free (mc_dir);
2324 init_xterm_support ();
2326 #ifdef HAVE_SUBSHELL_SUPPORT
2328 /* Done here to ensure that the subshell doesn't */
2329 /* inherit the file descriptors opened below, etc */
2330 if (use_subshell)
2331 init_subshell ();
2333 #endif /* HAVE_SUBSHELL_SUPPORT */
2335 /* Removing this from the X code let's us type C-c */
2336 load_key_defs ();
2338 /* Also done after init_subshell, to save any shell init file messages */
2339 if (console_flag)
2340 handle_console (CONSOLE_SAVE);
2342 if (alternate_plus_minus)
2343 application_keypad_mode ();
2345 #ifdef HAVE_SUBSHELL_SUPPORT
2346 if (use_subshell) {
2347 prompt = strip_ctrl_codes (subshell_prompt);
2348 if (!prompt)
2349 prompt = "";
2350 } else
2351 #endif /* HAVE_SUBSHELL_SUPPORT */
2352 prompt = (geteuid () == 0) ? "# " : "$ ";
2354 /* Program main loop */
2355 if (!midnight_shutdown)
2356 do_nc ();
2358 /* Save the tree store */
2359 tree_store_save ();
2361 /* Virtual File System shutdown */
2362 vfs_shut ();
2364 flush_extension_file (); /* does only free memory */
2366 endwin ();
2367 #ifdef HAVE_SLANG
2368 slang_shutdown ();
2369 #endif
2371 if (console_flag && !(quit & SUBSHELL_EXIT))
2372 handle_console (CONSOLE_RESTORE);
2373 if (alternate_plus_minus)
2374 numeric_keypad_mode ();
2376 signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
2378 if (console_flag)
2379 handle_console (CONSOLE_DONE);
2380 putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
2382 if (last_wd_file && last_wd_string && !print_last_revert
2383 && !edit_one_file && !view_one_file) {
2384 int last_wd_fd =
2385 open (last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
2386 S_IRUSR | S_IWUSR);
2388 if (last_wd_fd != -1) {
2389 write (last_wd_fd, last_wd_string, strlen (last_wd_string));
2390 close (last_wd_fd);
2393 g_free (last_wd_string);
2395 g_free (mc_home_alt);
2396 g_free (mc_home);
2397 done_key ();
2398 #ifdef HAVE_CHARSET
2399 free_codepages_list ();
2400 #endif
2401 str_uninit_strings ();
2403 g_free (this_dir);
2404 g_free (other_dir);
2406 #ifdef USE_INTERNAL_EDIT
2407 edit_stack_free ();
2408 #endif
2410 return 0;