move do_load_prompt() and load_prompt() from src/main.c to src/filemanager/layout.c
[midnight-commander.git] / src / main.c
bloba09ade1426e981ec3884d016510f7e0105a5ae26
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 <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sys/wait.h>
42 #include <pwd.h> /* for username in xterm title */
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 #include "subshell.h"
69 #include "setup.h" /* load_setup() */
71 #ifdef HAVE_CHARSET
72 #include "lib/charsets.h"
73 #include "selcodepage.h"
74 #endif /* HAVE_CHARSET */
76 #include "consaver/cons.saver.h" /* cons_saver_pid */
78 #include "main.h"
80 /*** global variables ****************************************************************************/
82 mc_fhl_t *mc_filehighlight;
84 /* Set when main loop should be terminated */
85 int quit = 0;
87 #ifdef HAVE_CHARSET
88 /* Numbers of (file I/O) and (input/display) codepages. -1 if not selected */
89 int default_source_codepage = -1;
90 char *autodetect_codeset = NULL;
91 gboolean is_autodetect_codeset_enabled = FALSE;
92 #endif /* !HAVE_CHARSET */
94 /* If true use the internal viewer */
95 int use_internal_view = 1;
96 /* If set, use the builtin editor */
97 int use_internal_edit = 1;
99 void *mc_run_param0 = NULL;
100 char *mc_run_param1 = NULL;
102 /* The user's shell */
103 char *shell = NULL;
105 /* The prompt */
106 const char *mc_prompt = NULL;
108 /* Set to TRUE to suppress printing the last directory */
109 int print_last_revert = FALSE;
111 /* If set, then print to the given file the last directory we were at */
112 char *last_wd_string = NULL;
114 /* index to record_macro_buf[], -1 if not recording a macro */
115 int macro_index = -1;
117 /* macro stuff */
118 struct macro_action_t record_macro_buf[MAX_MACRO_LENGTH];
120 GArray *macros_list;
122 /*** file scope macro definitions ****************************************************************/
124 /*** file scope type declarations ****************************************************************/
126 /*** file scope variables ************************************************************************/
128 /*** file scope functions ************************************************************************/
129 /* --------------------------------------------------------------------------------------------- */
131 static void
132 check_codeset (void)
134 const char *current_system_codepage = NULL;
136 current_system_codepage = str_detect_termencoding ();
138 #ifdef HAVE_CHARSET
140 const char *_display_codepage;
142 _display_codepage = get_codepage_id (mc_global.display_codepage);
144 if (strcmp (_display_codepage, current_system_codepage) != 0)
146 mc_global.display_codepage = get_codepage_index (current_system_codepage);
147 if (mc_global.display_codepage == -1)
148 mc_global.display_codepage = 0;
150 mc_config_set_string (mc_main_config, CONFIG_MISC_SECTION, "display_codepage",
151 cp_display);
154 #endif
156 mc_global.utf8_display = str_isutf8 (current_system_codepage);
159 /* --------------------------------------------------------------------------------------------- */
161 /** POSIX version. The only version we support. */
162 static void
163 OS_Setup (void)
165 const char *shell_env;
166 const char *datadir_env;
168 shell_env = getenv ("SHELL");
169 if ((shell_env == NULL) || (shell_env[0] == '\0'))
171 struct passwd *pwd;
172 pwd = getpwuid (geteuid ());
173 if (pwd != NULL)
174 shell = g_strdup (pwd->pw_shell);
176 else
177 shell = g_strdup (shell_env);
179 if ((shell == NULL) || (shell[0] == '\0'))
181 g_free (shell);
182 shell = g_strdup ("/bin/sh");
185 /* This is the directory, where MC was installed, on Unix this is DATADIR */
186 /* and can be overriden by the MC_DATADIR environment variable */
187 datadir_env = g_getenv ("MC_DATADIR");
188 if (datadir_env != NULL)
189 mc_global.sysconfig_dir = g_strdup (datadir_env);
190 else
191 mc_global.sysconfig_dir = g_strdup (SYSCONFDIR);
193 mc_global.share_data_dir = g_strdup (DATADIR);
195 /* Set up temporary directory */
196 mc_tmpdir ();
199 /* --------------------------------------------------------------------------------------------- */
201 static void
202 sigchld_handler_no_subshell (int sig)
204 #ifdef __linux__
205 int pid, status;
207 if (!mc_global.tty.console_flag != '\0')
208 return;
210 /* COMMENT: if it were true that after the call to handle_console(..INIT)
211 the value of mc_global.tty.console_flag never changed, we could simply not install
212 this handler at all if (!mc_global.tty.console_flag && !mc_global.tty.use_subshell). */
214 /* That comment is no longer true. We need to wait() on a sigchld
215 handler (that's at least what the tarfs code expects currently). */
217 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
219 if (pid == cons_saver_pid)
222 if (WIFSTOPPED (status))
224 /* Someone has stopped cons.saver - restart it */
225 kill (pid, SIGCONT);
227 else
229 /* cons.saver has died - disable console saving */
230 handle_console (CONSOLE_DONE);
231 mc_global.tty.console_flag = '\0';
234 /* If we got here, some other child exited; ignore it */
235 #endif /* __linux__ */
237 (void) sig;
240 /* --------------------------------------------------------------------------------------------- */
242 static void
243 init_sigchld (void)
245 struct sigaction sigchld_action;
247 sigchld_action.sa_handler =
248 #ifdef HAVE_SUBSHELL_SUPPORT
249 mc_global.tty.use_subshell ? sigchld_handler :
250 #endif /* HAVE_SUBSHELL_SUPPORT */
251 sigchld_handler_no_subshell;
253 sigemptyset (&sigchld_action.sa_mask);
255 #ifdef SA_RESTART
256 sigchld_action.sa_flags = SA_RESTART;
257 #else
258 sigchld_action.sa_flags = 0;
259 #endif /* !SA_RESTART */
261 if (sigaction (SIGCHLD, &sigchld_action, NULL) == -1)
263 #ifdef HAVE_SUBSHELL_SUPPORT
265 * This may happen on QNX Neutrino 6, where SA_RESTART
266 * is defined but not implemented. Fallback to no subshell.
268 mc_global.tty.use_subshell = FALSE;
269 #endif /* HAVE_SUBSHELL_SUPPORT */
273 /* --------------------------------------------------------------------------------------------- */
274 /*** public functions ****************************************************************************/
275 /* --------------------------------------------------------------------------------------------- */
277 void
278 title_path_prepare (char **path, char **login)
281 char host[BUF_TINY];
282 struct passwd *pw = NULL;
283 int res = 0;
285 *login = NULL;
288 *path =
289 vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_STRIP_HOME | VPF_STRIP_PASSWORD);
290 res = gethostname (host, sizeof (host));
291 if (res)
292 { /* On success, res = 0 */
293 host[0] = '\0';
295 else
297 host[sizeof (host) - 1] = '\0';
299 pw = getpwuid (getuid ());
300 if (pw)
302 *login = g_strdup_printf ("%s@%s", pw->pw_name, host);
304 else
306 *login = g_strdup (host);
310 /* --------------------------------------------------------------------------------------------- */
312 /** Show current directory in the xterm title */
313 void
314 update_xterm_title_path (void)
316 char *p;
317 char *path;
318 char *login;
320 if (!(mc_global.tty.xterm_flag && xterm_title))
321 return;
323 title_path_prepare (&path, &login);
325 p = g_strdup_printf ("mc [%s]:%s", login, path);
326 fprintf (stdout, "\33]0;%s\7", str_term_form (p));
327 g_free (login);
328 g_free (p);
329 if (!mc_global.tty.alternate_plus_minus)
330 numeric_keypad_mode ();
331 (void) fflush (stdout);
332 g_free (path);
335 /* --------------------------------------------------------------------------------------------- */
338 main (int argc, char *argv[])
340 GError *error = NULL;
341 int exit_code = EXIT_FAILURE;
343 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
344 #ifdef HAVE_SETLOCALE
345 (void) setlocale (LC_ALL, "");
346 #endif
347 (void) bindtextdomain (PACKAGE, LOCALEDIR);
348 (void) textdomain (PACKAGE);
350 /* do this before args parsing */
351 str_init_strings (NULL);
353 if (!mc_args_parse (&argc, &argv, "mc", &error))
355 startup_exit_falure:
356 fprintf (stderr, _("Failed to run:\n%s\n"), error->message);
357 g_error_free (error);
358 g_free (shell);
359 startup_exit_ok:
360 str_uninit_strings ();
361 return exit_code;
364 /* do this before mc_args_show_info () to view paths in the --datadir-info output */
365 OS_Setup ();
367 if (!g_path_is_absolute (mc_config_get_home_dir ()))
369 error = g_error_new (MC_ERROR, 0, "%s: %s", _("Home directory path is not absolute"),
370 mc_config_get_home_dir ());
371 mc_event_deinit (NULL);
372 goto startup_exit_falure;
375 if (!mc_args_show_info ())
377 exit_code = EXIT_SUCCESS;
378 goto startup_exit_ok;
381 if (!events_init (&error))
382 goto startup_exit_falure;
384 mc_config_init_config_paths (&error);
385 if (error == NULL && mc_config_deprecated_dir_present ())
386 mc_config_migrate_from_old_place (&error);
387 if (error != NULL)
389 mc_event_deinit (NULL);
390 goto startup_exit_falure;
393 vfs_init ();
394 vfs_plugins_init ();
395 vfs_setup_work_dir ();
397 /* do this after vfs initialization due to mc_setctl() call in mc_setup_by_args() */
398 if (!mc_setup_by_args (argc, argv, &error))
400 vfs_shut ();
401 mc_event_deinit (NULL);
402 goto startup_exit_falure;
405 /* check terminal type
406 * $TEMR must be set and not empty
407 * mc_global.tty.xterm_flag is used in init_key() and tty_init()
408 * Do this after mc_args_handle() where mc_args__force_xterm is set up.
410 mc_global.tty.xterm_flag = tty_check_term (mc_args__force_xterm);
412 /* NOTE: This has to be called before tty_init or whatever routine
413 calls any define_sequence */
414 init_key ();
416 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
417 handle_console (CONSOLE_INIT);
419 #ifdef HAVE_SUBSHELL_SUPPORT
420 /* Don't use subshell when invoked as viewer or editor */
421 if (mc_global.mc_run_mode != MC_RUN_FULL)
422 mc_global.tty.use_subshell = FALSE;
424 if (mc_global.tty.use_subshell)
425 subshell_get_console_attributes ();
426 #endif /* HAVE_SUBSHELL_SUPPORT */
428 /* Install the SIGCHLD handler; must be done before init_subshell() */
429 init_sigchld ();
431 /* We need this, since ncurses endwin () doesn't restore the signals */
432 save_stop_handler ();
434 /* Must be done before init_subshell, to set up the terminal size: */
435 /* FIXME: Should be removed and LINES and COLS computed on subshell */
436 tty_init (!mc_args__nomouse, mc_global.tty.xterm_flag);
438 load_setup ();
440 /* start check mc_global.display_codepage and mc_global.source_codepage */
441 check_codeset ();
443 /* Removing this from the X code let's us type C-c */
444 load_key_defs ();
446 load_keymap_defs (!mc_args__nokeymap);
448 macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
450 tty_init_colors (mc_global.tty.disable_colors, mc_args__force_colors);
452 mc_skin_init (&error);
453 if (error != NULL)
455 message (D_ERROR, _("Warning"), "%s", error->message);
456 g_error_free (error);
457 error = NULL;
460 mc_filehighlight = mc_fhl_new (TRUE);
461 dlg_set_default_colors ();
463 #ifdef HAVE_SUBSHELL_SUPPORT
464 /* Done here to ensure that the subshell doesn't */
465 /* inherit the file descriptors opened below, etc */
466 if (mc_global.tty.use_subshell)
467 init_subshell ();
469 #endif /* HAVE_SUBSHELL_SUPPORT */
471 /* Also done after init_subshell, to save any shell init file messages */
472 if (mc_global.tty.console_flag != '\0')
473 handle_console (CONSOLE_SAVE);
475 if (mc_global.tty.alternate_plus_minus)
476 application_keypad_mode ();
478 #ifdef HAVE_SUBSHELL_SUPPORT
479 if (mc_global.tty.use_subshell)
481 mc_prompt = strip_ctrl_codes (subshell_prompt);
482 if (mc_prompt == NULL)
483 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
485 else
486 #endif /* HAVE_SUBSHELL_SUPPORT */
487 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
489 /* Program main loop */
490 if (mc_global.midnight_shutdown)
491 exit_code = EXIT_SUCCESS;
492 else
493 exit_code = do_nc ()? EXIT_SUCCESS : EXIT_FAILURE;
495 /* Save the tree store */
496 (void) tree_store_save ();
498 free_keymap_defs ();
500 /* Virtual File System shutdown */
501 vfs_shut ();
503 flush_extension_file (); /* does only free memory */
505 mc_fhl_free (&mc_filehighlight);
506 mc_skin_deinit ();
507 tty_colors_done ();
509 tty_shutdown ();
511 done_setup ();
513 if (mc_global.tty.console_flag != '\0' && (quit & SUBSHELL_EXIT) == 0)
514 handle_console (CONSOLE_RESTORE);
515 if (mc_global.tty.alternate_plus_minus)
516 numeric_keypad_mode ();
518 (void) signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
520 if (mc_global.tty.console_flag != '\0')
521 handle_console (CONSOLE_DONE);
523 if (mc_global.mc_run_mode == MC_RUN_FULL && mc_args__last_wd_file != NULL
524 && last_wd_string != NULL && !print_last_revert)
526 int last_wd_fd;
528 last_wd_fd = open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
529 S_IRUSR | S_IWUSR);
530 if (last_wd_fd != -1)
532 ssize_t ret1;
533 int ret2;
534 ret1 = write (last_wd_fd, last_wd_string, strlen (last_wd_string));
535 ret2 = close (last_wd_fd);
538 g_free (last_wd_string);
540 g_free (shell);
542 done_key ();
544 if (macros_list != NULL)
546 guint i;
547 macros_t *macros;
548 for (i = 0; i < macros_list->len; i++)
550 macros = &g_array_index (macros_list, struct macros_t, i);
551 if (macros != NULL && macros->macro != NULL)
552 (void) g_array_free (macros->macro, FALSE);
554 (void) g_array_free (macros_list, TRUE);
557 str_uninit_strings ();
559 if (mc_global.mc_run_mode != MC_RUN_EDITOR)
560 g_free (mc_run_param0);
561 else
563 g_list_foreach ((GList *) mc_run_param0, (GFunc) mcedit_arg_free, NULL);
564 g_list_free ((GList *) mc_run_param0);
566 g_free (mc_run_param1);
568 mc_config_deinit_config_paths ();
570 (void) mc_event_deinit (&error);
571 if (error != NULL)
573 fprintf (stderr, _("\nFailed while close:\n%s\n"), error->message);
574 g_error_free (error);
575 exit_code = EXIT_FAILURE;
578 (void) putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
580 return exit_code;
583 /* --------------------------------------------------------------------------------------------- */