8e68166d38bc64627b2a070f791d4d8cc3e0a2fe
[midnight-commander.git] / src / main.c
blob8e68166d38bc64627b2a070f791d4d8cc3e0a2fe
1 /*
2 Main program for the Midnight Commander
4 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
5 2003, 2004, 2005, 2006, 2007, 2009, 2011
6 The Free Software Foundation, Inc.
8 Written by:
9 Miguel de Icaza, 1994, 1995, 1996, 1997
10 Janne Kukonlehto, 1994, 1995
11 Norbert Warmuth, 1997
13 This file is part of the Midnight Commander.
15 The Midnight Commander is free software: you can redistribute it
16 and/or modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation, either version 3 of the License,
18 or (at your option) any later version.
20 The Midnight Commander is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program. If not, see <http://www.gnu.org/licenses/>.
29 /** \file main.c
30 * \brief Source: this is a main module
33 #include <config.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <locale.h>
38 #include <pwd.h> /* for username in xterm title */
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/wait.h>
43 #include <signal.h>
45 #include "lib/global.h"
47 #include "lib/event.h"
48 #include "lib/tty/tty.h"
49 #include "lib/tty/key.h" /* For init_key() */
50 #include "lib/skin.h"
51 #include "lib/filehighlight.h"
52 #include "lib/fileloc.h"
53 #include "lib/strutil.h"
54 #include "lib/util.h"
55 #include "lib/vfs/vfs.h" /* vfs_init(), vfs_shut() */
57 #include "filemanager/midnight.h" /* current_panel */
58 #include "filemanager/treestore.h" /* tree_store_save */
59 #include "filemanager/layout.h" /* command_prompt */
60 #include "filemanager/ext.h" /* flush_extension_file() */
61 #include "filemanager/command.h" /* cmdline */
62 #include "filemanager/panel.h" /* panalized_panel */
64 #include "vfs/plugins_init.h"
66 #include "events_init.h"
67 #include "args.h"
68 #ifdef ENABLE_SUBSHELL
69 #include "subshell.h"
70 #endif
71 #include "setup.h" /* load_setup() */
73 #ifdef HAVE_CHARSET
74 #include "lib/charsets.h"
75 #include "selcodepage.h"
76 #endif /* HAVE_CHARSET */
78 #include "consaver/cons.saver.h" /* cons_saver_pid */
80 /*** global variables ****************************************************************************/
82 /*** file scope macro definitions ****************************************************************/
84 /*** file scope type declarations ****************************************************************/
86 /*** file scope variables ************************************************************************/
88 /*** file scope functions ************************************************************************/
89 /* --------------------------------------------------------------------------------------------- */
91 static void
92 check_codeset (void)
94 const char *current_system_codepage = NULL;
96 current_system_codepage = str_detect_termencoding ();
98 #ifdef HAVE_CHARSET
100 const char *_display_codepage;
102 _display_codepage = get_codepage_id (mc_global.display_codepage);
104 if (strcmp (_display_codepage, current_system_codepage) != 0)
106 mc_global.display_codepage = get_codepage_index (current_system_codepage);
107 if (mc_global.display_codepage == -1)
108 mc_global.display_codepage = 0;
110 mc_config_set_string (mc_main_config, CONFIG_MISC_SECTION, "display_codepage",
111 cp_display);
114 #endif
116 mc_global.utf8_display = str_isutf8 (current_system_codepage);
119 /* --------------------------------------------------------------------------------------------- */
121 /** POSIX version. The only version we support. */
122 static void
123 OS_Setup (void)
125 const char *shell_env;
126 const char *datadir_env;
128 shell_env = getenv ("SHELL");
129 if ((shell_env == NULL) || (shell_env[0] == '\0'))
131 struct passwd *pwd;
132 pwd = getpwuid (geteuid ());
133 if (pwd != NULL)
134 shell = g_strdup (pwd->pw_shell);
136 else
137 shell = g_strdup (shell_env);
139 if ((shell == NULL) || (shell[0] == '\0'))
141 g_free (shell);
142 shell = g_strdup ("/bin/sh");
145 /* This is the directory, where MC was installed, on Unix this is DATADIR */
146 /* and can be overriden by the MC_DATADIR environment variable */
147 datadir_env = g_getenv ("MC_DATADIR");
148 if (datadir_env != NULL)
149 mc_global.sysconfig_dir = g_strdup (datadir_env);
150 else
151 mc_global.sysconfig_dir = g_strdup (SYSCONFDIR);
153 mc_global.share_data_dir = g_strdup (DATADIR);
155 /* Set up temporary directory */
156 mc_tmpdir ();
159 /* --------------------------------------------------------------------------------------------- */
161 static void
162 sigchld_handler_no_subshell (int sig)
164 #ifdef __linux__
165 int pid, status;
167 if (!mc_global.tty.console_flag != '\0')
168 return;
170 /* COMMENT: if it were true that after the call to handle_console(..INIT)
171 the value of mc_global.tty.console_flag never changed, we could simply not install
172 this handler at all if (!mc_global.tty.console_flag && !mc_global.tty.use_subshell). */
174 /* That comment is no longer true. We need to wait() on a sigchld
175 handler (that's at least what the tarfs code expects currently). */
177 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
179 if (pid == cons_saver_pid)
182 if (WIFSTOPPED (status))
184 /* Someone has stopped cons.saver - restart it */
185 kill (pid, SIGCONT);
187 else
189 /* cons.saver has died - disable console saving */
190 handle_console (CONSOLE_DONE);
191 mc_global.tty.console_flag = '\0';
194 /* If we got here, some other child exited; ignore it */
195 #endif /* __linux__ */
197 (void) sig;
200 /* --------------------------------------------------------------------------------------------- */
202 static void
203 init_sigchld (void)
205 struct sigaction sigchld_action;
207 sigchld_action.sa_handler =
208 #ifdef ENABLE_SUBSHELL
209 mc_global.tty.use_subshell ? sigchld_handler :
210 #endif /* ENABLE_SUBSHELL */
211 sigchld_handler_no_subshell;
213 sigemptyset (&sigchld_action.sa_mask);
215 #ifdef SA_RESTART
216 sigchld_action.sa_flags = SA_RESTART;
217 #else
218 sigchld_action.sa_flags = 0;
219 #endif /* !SA_RESTART */
221 if (sigaction (SIGCHLD, &sigchld_action, NULL) == -1)
223 #ifdef ENABLE_SUBSHELL
225 * This may happen on QNX Neutrino 6, where SA_RESTART
226 * is defined but not implemented. Fallback to no subshell.
228 mc_global.tty.use_subshell = FALSE;
229 #endif /* ENABLE_SUBSHELL */
233 /* --------------------------------------------------------------------------------------------- */
234 /*** public functions ****************************************************************************/
235 /* --------------------------------------------------------------------------------------------- */
238 main (int argc, char *argv[])
240 GError *error = NULL;
241 int exit_code = EXIT_FAILURE;
243 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
244 #ifdef HAVE_SETLOCALE
245 (void) setlocale (LC_ALL, "");
246 #endif
247 (void) bindtextdomain (PACKAGE, LOCALEDIR);
248 (void) textdomain (PACKAGE);
250 /* do this before args parsing */
251 str_init_strings (NULL);
253 if (!mc_args_parse (&argc, &argv, "mc", &error))
255 startup_exit_falure:
256 fprintf (stderr, _("Failed to run:\n%s\n"), error->message);
257 g_error_free (error);
258 g_free (shell);
259 startup_exit_ok:
260 str_uninit_strings ();
261 return exit_code;
264 /* do this before mc_args_show_info () to view paths in the --datadir-info output */
265 OS_Setup ();
267 if (!g_path_is_absolute (mc_config_get_home_dir ()))
269 error = g_error_new (MC_ERROR, 0, "%s: %s", _("Home directory path is not absolute"),
270 mc_config_get_home_dir ());
271 mc_event_deinit (NULL);
272 goto startup_exit_falure;
275 if (!mc_args_show_info ())
277 exit_code = EXIT_SUCCESS;
278 goto startup_exit_ok;
281 if (!events_init (&error))
282 goto startup_exit_falure;
284 mc_config_init_config_paths (&error);
285 if (error == NULL && mc_config_deprecated_dir_present ())
286 mc_config_migrate_from_old_place (&error);
287 if (error != NULL)
289 mc_event_deinit (NULL);
290 goto startup_exit_falure;
293 vfs_init ();
294 vfs_plugins_init ();
295 vfs_setup_work_dir ();
297 /* do this after vfs initialization due to mc_setctl() call in mc_setup_by_args() */
298 if (!mc_setup_by_args (argc, argv, &error))
300 vfs_shut ();
301 mc_event_deinit (NULL);
302 goto startup_exit_falure;
305 /* check terminal type
306 * $TEMR must be set and not empty
307 * mc_global.tty.xterm_flag is used in init_key() and tty_init()
308 * Do this after mc_args_handle() where mc_args__force_xterm is set up.
310 mc_global.tty.xterm_flag = tty_check_term (mc_args__force_xterm);
312 /* NOTE: This has to be called before tty_init or whatever routine
313 calls any define_sequence */
314 init_key ();
316 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
317 handle_console (CONSOLE_INIT);
319 #ifdef ENABLE_SUBSHELL
320 /* Don't use subshell when invoked as viewer or editor */
321 if (mc_global.mc_run_mode != MC_RUN_FULL)
322 mc_global.tty.use_subshell = FALSE;
324 if (mc_global.tty.use_subshell)
325 subshell_get_console_attributes ();
326 #endif /* ENABLE_SUBSHELL */
328 /* Install the SIGCHLD handler; must be done before init_subshell() */
329 init_sigchld ();
331 /* We need this, since ncurses endwin () doesn't restore the signals */
332 save_stop_handler ();
334 /* Must be done before init_subshell, to set up the terminal size: */
335 /* FIXME: Should be removed and LINES and COLS computed on subshell */
336 tty_init (!mc_args__nomouse, mc_global.tty.xterm_flag);
338 load_setup ();
340 /* start check mc_global.display_codepage and mc_global.source_codepage */
341 check_codeset ();
343 /* Removing this from the X code let's us type C-c */
344 load_key_defs ();
346 load_keymap_defs (!mc_args__nokeymap);
348 macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
350 tty_init_colors (mc_global.tty.disable_colors, mc_args__force_colors);
352 mc_skin_init (&error);
353 if (error != NULL)
355 message (D_ERROR, _("Warning"), "%s", error->message);
356 g_error_free (error);
357 error = NULL;
360 mc_filehighlight = mc_fhl_new (TRUE);
361 dlg_set_default_colors ();
363 #ifdef ENABLE_SUBSHELL
364 /* Done here to ensure that the subshell doesn't */
365 /* inherit the file descriptors opened below, etc */
366 if (mc_global.tty.use_subshell)
367 init_subshell ();
369 #endif /* ENABLE_SUBSHELL */
371 /* Also done after init_subshell, to save any shell init file messages */
372 if (mc_global.tty.console_flag != '\0')
373 handle_console (CONSOLE_SAVE);
375 if (mc_global.tty.alternate_plus_minus)
376 application_keypad_mode ();
378 #ifdef ENABLE_SUBSHELL
379 if (mc_global.tty.use_subshell)
381 mc_prompt = strip_ctrl_codes (subshell_prompt);
382 if (mc_prompt == NULL)
383 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
385 else
386 #endif /* ENABLE_SUBSHELL */
387 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
389 /* Program main loop */
390 if (mc_global.midnight_shutdown)
391 exit_code = EXIT_SUCCESS;
392 else
393 exit_code = do_nc ()? EXIT_SUCCESS : EXIT_FAILURE;
395 /* Save the tree store */
396 (void) tree_store_save ();
398 free_keymap_defs ();
400 /* Virtual File System shutdown */
401 vfs_shut ();
403 flush_extension_file (); /* does only free memory */
405 mc_fhl_free (&mc_filehighlight);
406 mc_skin_deinit ();
407 tty_colors_done ();
409 tty_shutdown ();
411 done_setup ();
413 if (mc_global.tty.console_flag != '\0' && (quit & SUBSHELL_EXIT) == 0)
414 handle_console (CONSOLE_RESTORE);
415 if (mc_global.tty.alternate_plus_minus)
416 numeric_keypad_mode ();
418 (void) signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
420 if (mc_global.tty.console_flag != '\0')
421 handle_console (CONSOLE_DONE);
423 if (mc_global.mc_run_mode == MC_RUN_FULL && mc_args__last_wd_file != NULL
424 && last_wd_string != NULL && !print_last_revert)
426 int last_wd_fd;
428 last_wd_fd = open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
429 S_IRUSR | S_IWUSR);
430 if (last_wd_fd != -1)
432 ssize_t ret1;
433 int ret2;
434 ret1 = write (last_wd_fd, last_wd_string, strlen (last_wd_string));
435 ret2 = close (last_wd_fd);
438 g_free (last_wd_string);
440 g_free (shell);
442 done_key ();
444 if (macros_list != NULL)
446 guint i;
447 macros_t *macros;
448 for (i = 0; i < macros_list->len; i++)
450 macros = &g_array_index (macros_list, struct macros_t, i);
451 if (macros != NULL && macros->macro != NULL)
452 (void) g_array_free (macros->macro, FALSE);
454 (void) g_array_free (macros_list, TRUE);
457 str_uninit_strings ();
459 if (mc_global.mc_run_mode != MC_RUN_EDITOR)
460 g_free (mc_run_param0);
461 else
463 g_list_foreach ((GList *) mc_run_param0, (GFunc) mcedit_arg_free, NULL);
464 g_list_free ((GList *) mc_run_param0);
466 g_free (mc_run_param1);
468 mc_config_deinit_config_paths ();
470 (void) mc_event_deinit (&error);
471 if (error != NULL)
473 fprintf (stderr, _("\nFailed while close:\n%s\n"), error->message);
474 g_error_free (error);
475 exit_code = EXIT_FAILURE;
478 (void) putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
480 return exit_code;
483 /* --------------------------------------------------------------------------------------------- */