(subshell_prompt): changed to GString.
[midnight-commander.git] / src / main.c
blob1123624a544bdea1d45c28462625087416714130
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 gboolean config_migrated = FALSE;
242 char *config_migrate_msg;
243 int exit_code = EXIT_FAILURE;
245 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
246 #ifdef HAVE_SETLOCALE
247 (void) setlocale (LC_ALL, "");
248 #endif
249 (void) bindtextdomain (PACKAGE, LOCALEDIR);
250 (void) textdomain (PACKAGE);
252 /* do this before args parsing */
253 str_init_strings (NULL);
255 if (!mc_args_parse (&argc, &argv, "mc", &error))
257 startup_exit_falure:
258 fprintf (stderr, _("Failed to run:\n%s\n"), error->message);
259 g_error_free (error);
260 g_free (shell);
261 startup_exit_ok:
262 str_uninit_strings ();
263 return exit_code;
266 /* do this before mc_args_show_info () to view paths in the --datadir-info output */
267 OS_Setup ();
269 if (!g_path_is_absolute (mc_config_get_home_dir ()))
271 error = g_error_new (MC_ERROR, 0, "%s: %s", _("Home directory path is not absolute"),
272 mc_config_get_home_dir ());
273 mc_event_deinit (NULL);
274 goto startup_exit_falure;
277 if (!mc_args_show_info ())
279 exit_code = EXIT_SUCCESS;
280 goto startup_exit_ok;
283 if (!events_init (&error))
284 goto startup_exit_falure;
286 mc_config_init_config_paths (&error);
287 if (error == NULL)
288 config_migrated = mc_config_migrate_from_old_place (&error, &config_migrate_msg);
289 if (error != NULL)
291 mc_event_deinit (NULL);
292 goto startup_exit_falure;
295 vfs_init ();
296 vfs_plugins_init ();
297 vfs_setup_work_dir ();
299 /* do this after vfs initialization due to mc_setctl() call in mc_setup_by_args() */
300 if (!mc_setup_by_args (argc, argv, &error))
302 vfs_shut ();
303 mc_event_deinit (NULL);
304 goto startup_exit_falure;
307 /* check terminal type
308 * $TEMR must be set and not empty
309 * mc_global.tty.xterm_flag is used in init_key() and tty_init()
310 * Do this after mc_args_handle() where mc_args__force_xterm is set up.
312 mc_global.tty.xterm_flag = tty_check_term (mc_args__force_xterm);
314 /* NOTE: This has to be called before tty_init or whatever routine
315 calls any define_sequence */
316 init_key ();
318 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
319 handle_console (CONSOLE_INIT);
321 #ifdef ENABLE_SUBSHELL
322 /* Don't use subshell when invoked as viewer or editor */
323 if (mc_global.mc_run_mode != MC_RUN_FULL)
324 mc_global.tty.use_subshell = FALSE;
326 if (mc_global.tty.use_subshell)
327 subshell_get_console_attributes ();
328 #endif /* ENABLE_SUBSHELL */
330 /* Install the SIGCHLD handler; must be done before init_subshell() */
331 init_sigchld ();
333 /* We need this, since ncurses endwin () doesn't restore the signals */
334 save_stop_handler ();
336 /* Must be done before init_subshell, to set up the terminal size: */
337 /* FIXME: Should be removed and LINES and COLS computed on subshell */
338 tty_init (!mc_args__nomouse, mc_global.tty.xterm_flag);
340 load_setup ();
342 /* start check mc_global.display_codepage and mc_global.source_codepage */
343 check_codeset ();
345 /* Removing this from the X code let's us type C-c */
346 load_key_defs ();
348 load_keymap_defs (!mc_args__nokeymap);
350 macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
352 tty_init_colors (mc_global.tty.disable_colors, mc_args__force_colors);
354 mc_skin_init (&error);
355 if (error != NULL)
357 message (D_ERROR, _("Warning"), "%s", error->message);
358 g_error_free (error);
359 error = NULL;
362 dlg_set_default_colors ();
364 #ifdef ENABLE_SUBSHELL
365 /* Done here to ensure that the subshell doesn't */
366 /* inherit the file descriptors opened below, etc */
367 if (mc_global.tty.use_subshell)
368 init_subshell ();
370 #endif /* ENABLE_SUBSHELL */
372 /* Also done after init_subshell, to save any shell init file messages */
373 if (mc_global.tty.console_flag != '\0')
374 handle_console (CONSOLE_SAVE);
376 if (mc_global.tty.alternate_plus_minus)
377 application_keypad_mode ();
379 /* subshell_prompt is NULL here */
380 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
382 if (config_migrated)
384 message (D_ERROR, _("Warning"), "%s", config_migrate_msg);
385 g_free (config_migrate_msg);
388 /* Program main loop */
389 if (mc_global.midnight_shutdown)
390 exit_code = EXIT_SUCCESS;
391 else
392 exit_code = do_nc ()? EXIT_SUCCESS : EXIT_FAILURE;
394 /* Save the tree store */
395 (void) tree_store_save ();
397 free_keymap_defs ();
399 /* Virtual File System shutdown */
400 vfs_shut ();
402 flush_extension_file (); /* does only free memory */
404 mc_skin_deinit ();
405 tty_colors_done ();
407 tty_shutdown ();
409 done_setup ();
411 if (mc_global.tty.console_flag != '\0' && (quit & SUBSHELL_EXIT) == 0)
412 handle_console (CONSOLE_RESTORE);
413 if (mc_global.tty.alternate_plus_minus)
414 numeric_keypad_mode ();
416 (void) signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
418 if (mc_global.tty.console_flag != '\0')
419 handle_console (CONSOLE_DONE);
421 if (mc_global.mc_run_mode == MC_RUN_FULL && mc_args__last_wd_file != NULL
422 && last_wd_string != NULL && !print_last_revert)
424 int last_wd_fd;
426 last_wd_fd = open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
427 S_IRUSR | S_IWUSR);
428 if (last_wd_fd != -1)
430 ssize_t ret1;
431 int ret2;
432 ret1 = write (last_wd_fd, last_wd_string, strlen (last_wd_string));
433 ret2 = close (last_wd_fd);
436 g_free (last_wd_string);
438 g_free (shell);
440 done_key ();
442 if (macros_list != NULL)
444 guint i;
445 macros_t *macros;
446 for (i = 0; i < macros_list->len; i++)
448 macros = &g_array_index (macros_list, struct macros_t, i);
449 if (macros != NULL && macros->macro != NULL)
450 (void) g_array_free (macros->macro, FALSE);
452 (void) g_array_free (macros_list, TRUE);
455 str_uninit_strings ();
457 if (mc_global.mc_run_mode != MC_RUN_EDITOR)
458 g_free (mc_run_param0);
459 else
461 g_list_foreach ((GList *) mc_run_param0, (GFunc) mcedit_arg_free, NULL);
462 g_list_free ((GList *) mc_run_param0);
464 g_free (mc_run_param1);
466 mc_config_deinit_config_paths ();
468 (void) mc_event_deinit (&error);
469 if (error != NULL)
471 fprintf (stderr, _("\nFailed while close:\n%s\n"), error->message);
472 g_error_free (error);
473 exit_code = EXIT_FAILURE;
476 (void) putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
478 return exit_code;
481 /* --------------------------------------------------------------------------------------------- */