lib/widget/input_complete.c: minor refactoring and optimization.
[midnight-commander.git] / src / main.c
blob573fa21a60db77a95aae2dc44e26754898157926
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;
133 pwd = getpwuid (geteuid ());
134 if (pwd != NULL)
135 mc_global.tty.shell = g_strdup (pwd->pw_shell);
137 else
138 mc_global.tty.shell = g_strdup (shell_env);
140 if ((mc_global.tty.shell == NULL) || (mc_global.tty.shell[0] == '\0'))
142 g_free (mc_global.tty.shell);
143 mc_global.tty.shell = g_strdup ("/bin/sh");
146 /* This is the directory, where MC was installed, on Unix this is DATADIR */
147 /* and can be overriden by the MC_DATADIR environment variable */
148 datadir_env = g_getenv ("MC_DATADIR");
149 if (datadir_env != NULL)
150 mc_global.sysconfig_dir = g_strdup (datadir_env);
151 else
152 mc_global.sysconfig_dir = g_strdup (SYSCONFDIR);
154 mc_global.share_data_dir = g_strdup (DATADIR);
156 /* Set up temporary directory */
157 mc_tmpdir ();
160 /* --------------------------------------------------------------------------------------------- */
162 static void
163 sigchld_handler_no_subshell (int sig)
165 #ifdef __linux__
166 int pid, status;
168 if (!mc_global.tty.console_flag != '\0')
169 return;
171 /* COMMENT: if it were true that after the call to handle_console(..INIT)
172 the value of mc_global.tty.console_flag never changed, we could simply not install
173 this handler at all if (!mc_global.tty.console_flag && !mc_global.tty.use_subshell). */
175 /* That comment is no longer true. We need to wait() on a sigchld
176 handler (that's at least what the tarfs code expects currently). */
178 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
180 if (pid == cons_saver_pid)
183 if (WIFSTOPPED (status))
185 /* Someone has stopped cons.saver - restart it */
186 kill (pid, SIGCONT);
188 else
190 /* cons.saver has died - disable console saving */
191 handle_console (CONSOLE_DONE);
192 mc_global.tty.console_flag = '\0';
195 /* If we got here, some other child exited; ignore it */
196 #endif /* __linux__ */
198 (void) sig;
201 /* --------------------------------------------------------------------------------------------- */
203 static void
204 init_sigchld (void)
206 struct sigaction sigchld_action;
208 sigchld_action.sa_handler =
209 #ifdef ENABLE_SUBSHELL
210 mc_global.tty.use_subshell ? sigchld_handler :
211 #endif /* ENABLE_SUBSHELL */
212 sigchld_handler_no_subshell;
214 sigemptyset (&sigchld_action.sa_mask);
216 #ifdef SA_RESTART
217 sigchld_action.sa_flags = SA_RESTART;
218 #else
219 sigchld_action.sa_flags = 0;
220 #endif /* !SA_RESTART */
222 if (sigaction (SIGCHLD, &sigchld_action, NULL) == -1)
224 #ifdef ENABLE_SUBSHELL
226 * This may happen on QNX Neutrino 6, where SA_RESTART
227 * is defined but not implemented. Fallback to no subshell.
229 mc_global.tty.use_subshell = FALSE;
230 #endif /* ENABLE_SUBSHELL */
234 /* --------------------------------------------------------------------------------------------- */
235 /*** public functions ****************************************************************************/
236 /* --------------------------------------------------------------------------------------------- */
239 main (int argc, char *argv[])
241 GError *error = NULL;
242 gboolean config_migrated = FALSE;
243 char *config_migrate_msg;
244 int exit_code = EXIT_FAILURE;
246 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
247 #ifdef HAVE_SETLOCALE
248 (void) setlocale (LC_ALL, "");
249 #endif
250 (void) bindtextdomain (PACKAGE, LOCALEDIR);
251 (void) textdomain (PACKAGE);
253 /* do this before args parsing */
254 str_init_strings (NULL);
256 if (!mc_args_parse (&argc, &argv, "mc", &error))
258 startup_exit_falure:
259 fprintf (stderr, _("Failed to run:\n%s\n"), error->message);
260 g_error_free (error);
261 g_free (mc_global.tty.shell);
262 startup_exit_ok:
263 str_uninit_strings ();
264 return exit_code;
267 /* do this before mc_args_show_info () to view paths in the --datadir-info output */
268 OS_Setup ();
270 if (!g_path_is_absolute (mc_config_get_home_dir ()))
272 error = g_error_new (MC_ERROR, 0, "%s: %s", _("Home directory path is not absolute"),
273 mc_config_get_home_dir ());
274 mc_event_deinit (NULL);
275 goto startup_exit_falure;
278 if (!mc_args_show_info ())
280 exit_code = EXIT_SUCCESS;
281 goto startup_exit_ok;
284 if (!events_init (&error))
285 goto startup_exit_falure;
287 mc_config_init_config_paths (&error);
288 if (error == NULL)
289 config_migrated = mc_config_migrate_from_old_place (&error, &config_migrate_msg);
290 if (error != NULL)
292 mc_event_deinit (NULL);
293 goto startup_exit_falure;
296 vfs_init ();
297 vfs_plugins_init ();
298 vfs_setup_work_dir ();
300 /* do this after vfs initialization due to mc_setctl() call in mc_setup_by_args() */
301 if (!mc_setup_by_args (argc, argv, &error))
303 vfs_shut ();
304 mc_event_deinit (NULL);
305 goto startup_exit_falure;
308 /* check terminal type
309 * $TEMR must be set and not empty
310 * mc_global.tty.xterm_flag is used in init_key() and tty_init()
311 * Do this after mc_args_handle() where mc_args__force_xterm is set up.
313 mc_global.tty.xterm_flag = tty_check_term (mc_args__force_xterm);
315 /* NOTE: This has to be called before tty_init or whatever routine
316 calls any define_sequence */
317 init_key ();
319 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
320 handle_console (CONSOLE_INIT);
322 #ifdef ENABLE_SUBSHELL
323 /* Don't use subshell when invoked as viewer or editor */
324 if (mc_global.mc_run_mode != MC_RUN_FULL)
325 mc_global.tty.use_subshell = FALSE;
327 if (mc_global.tty.use_subshell)
328 subshell_get_console_attributes ();
329 #endif /* ENABLE_SUBSHELL */
331 /* Install the SIGCHLD handler; must be done before init_subshell() */
332 init_sigchld ();
334 /* We need this, since ncurses endwin () doesn't restore the signals */
335 save_stop_handler ();
337 /* Must be done before init_subshell, to set up the terminal size: */
338 /* FIXME: Should be removed and LINES and COLS computed on subshell */
339 tty_init (!mc_args__nomouse, mc_global.tty.xterm_flag);
341 load_setup ();
343 /* start check mc_global.display_codepage and mc_global.source_codepage */
344 check_codeset ();
346 /* Removing this from the X code let's us type C-c */
347 load_key_defs ();
349 load_keymap_defs (!mc_args__nokeymap);
351 macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
353 tty_init_colors (mc_global.tty.disable_colors, mc_args__force_colors);
355 mc_skin_init (&error);
356 if (error != NULL)
358 message (D_ERROR, _("Warning"), "%s", error->message);
359 g_error_free (error);
360 error = NULL;
363 dlg_set_default_colors ();
365 #ifdef ENABLE_SUBSHELL
366 /* Done here to ensure that the subshell doesn't */
367 /* inherit the file descriptors opened below, etc */
368 if (mc_global.tty.use_subshell)
369 init_subshell ();
371 #endif /* ENABLE_SUBSHELL */
373 /* Also done after init_subshell, to save any shell init file messages */
374 if (mc_global.tty.console_flag != '\0')
375 handle_console (CONSOLE_SAVE);
377 if (mc_global.tty.alternate_plus_minus)
378 application_keypad_mode ();
380 /* subshell_prompt is NULL here */
381 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
383 if (config_migrated)
385 message (D_ERROR, _("Warning"), "%s", config_migrate_msg);
386 g_free (config_migrate_msg);
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_skin_deinit ();
406 tty_colors_done ();
408 tty_shutdown ();
410 done_setup ();
412 if (mc_global.tty.console_flag != '\0' && (quit & SUBSHELL_EXIT) == 0)
413 handle_console (CONSOLE_RESTORE);
414 if (mc_global.tty.alternate_plus_minus)
415 numeric_keypad_mode ();
417 (void) signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
419 if (mc_global.tty.console_flag != '\0')
420 handle_console (CONSOLE_DONE);
422 if (mc_global.mc_run_mode == MC_RUN_FULL && mc_args__last_wd_file != NULL
423 && last_wd_string != NULL && !print_last_revert)
425 int last_wd_fd;
427 last_wd_fd = open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
428 S_IRUSR | S_IWUSR);
429 if (last_wd_fd != -1)
431 ssize_t ret1;
432 int ret2;
433 ret1 = write (last_wd_fd, last_wd_string, strlen (last_wd_string));
434 ret2 = close (last_wd_fd);
435 (void) ret1;
436 (void) ret2;
439 g_free (last_wd_string);
441 g_free (mc_global.tty.shell);
443 done_key ();
445 if (macros_list != NULL)
447 guint i;
448 macros_t *macros;
449 for (i = 0; i < macros_list->len; i++)
451 macros = &g_array_index (macros_list, struct macros_t, i);
452 if (macros != NULL && macros->macro != NULL)
453 (void) g_array_free (macros->macro, FALSE);
455 (void) g_array_free (macros_list, TRUE);
458 str_uninit_strings ();
460 if (mc_global.mc_run_mode != MC_RUN_EDITOR)
461 g_free (mc_run_param0);
462 else
464 g_list_foreach ((GList *) mc_run_param0, (GFunc) mcedit_arg_free, NULL);
465 g_list_free ((GList *) mc_run_param0);
467 g_free (mc_run_param1);
469 mc_config_deinit_config_paths ();
471 (void) mc_event_deinit (&error);
472 if (error != NULL)
474 fprintf (stderr, _("\nFailed while close:\n%s\n"), error->message);
475 g_error_free (error);
476 exit_code = EXIT_FAILURE;
479 (void) putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
481 return exit_code;
484 /* --------------------------------------------------------------------------------------------- */