move do_cd from src/main.c to src/filemanager/panel.c
[midnight-commander.git] / src / main.c
blob4222a5eefbeaa88fcb2764658a1fb8ca7aee4a69
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 #ifdef HAVE_SUBSHELL_SUPPORT
278 gboolean
279 do_load_prompt (void)
281 gboolean ret = FALSE;
283 if (!read_subshell_prompt ())
284 return ret;
286 /* Don't actually change the prompt if it's invisible */
287 if (top_dlg != NULL && ((Dlg_head *) top_dlg->data == midnight_dlg) && command_prompt)
289 setup_cmdline ();
291 /* since the prompt has changed, and we are called from one of the
292 * tty_get_event channels, the prompt updating does not take place
293 * automatically: force a cursor update and a screen refresh
295 update_cursor (midnight_dlg);
296 mc_refresh ();
297 ret = TRUE;
299 update_subshell_prompt = TRUE;
300 return ret;
303 /* --------------------------------------------------------------------------------------------- */
306 load_prompt (int fd, void *unused)
308 (void) fd;
309 (void) unused;
311 do_load_prompt ();
312 return 0;
314 #endif /* HAVE_SUBSHELL_SUPPORT */
316 /* --------------------------------------------------------------------------------------------- */
318 void
319 title_path_prepare (char **path, char **login)
322 char host[BUF_TINY];
323 struct passwd *pw = NULL;
324 int res = 0;
326 *login = NULL;
329 *path =
330 vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_STRIP_HOME | VPF_STRIP_PASSWORD);
331 res = gethostname (host, sizeof (host));
332 if (res)
333 { /* On success, res = 0 */
334 host[0] = '\0';
336 else
338 host[sizeof (host) - 1] = '\0';
340 pw = getpwuid (getuid ());
341 if (pw)
343 *login = g_strdup_printf ("%s@%s", pw->pw_name, host);
345 else
347 *login = g_strdup (host);
351 /* --------------------------------------------------------------------------------------------- */
353 /** Show current directory in the xterm title */
354 void
355 update_xterm_title_path (void)
357 char *p;
358 char *path;
359 char *login;
361 if (!(mc_global.tty.xterm_flag && xterm_title))
362 return;
364 title_path_prepare (&path, &login);
366 p = g_strdup_printf ("mc [%s]:%s", login, path);
367 fprintf (stdout, "\33]0;%s\7", str_term_form (p));
368 g_free (login);
369 g_free (p);
370 if (!mc_global.tty.alternate_plus_minus)
371 numeric_keypad_mode ();
372 (void) fflush (stdout);
373 g_free (path);
376 /* --------------------------------------------------------------------------------------------- */
379 main (int argc, char *argv[])
381 GError *error = NULL;
382 int exit_code = EXIT_FAILURE;
384 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
385 #ifdef HAVE_SETLOCALE
386 (void) setlocale (LC_ALL, "");
387 #endif
388 (void) bindtextdomain (PACKAGE, LOCALEDIR);
389 (void) textdomain (PACKAGE);
391 /* do this before args parsing */
392 str_init_strings (NULL);
394 if (!mc_args_parse (&argc, &argv, "mc", &error))
396 startup_exit_falure:
397 fprintf (stderr, _("Failed to run:\n%s\n"), error->message);
398 g_error_free (error);
399 g_free (shell);
400 startup_exit_ok:
401 str_uninit_strings ();
402 return exit_code;
405 /* do this before mc_args_show_info () to view paths in the --datadir-info output */
406 OS_Setup ();
408 if (!g_path_is_absolute (mc_config_get_home_dir ()))
410 error = g_error_new (MC_ERROR, 0, "%s: %s", _("Home directory path is not absolute"),
411 mc_config_get_home_dir ());
412 mc_event_deinit (NULL);
413 goto startup_exit_falure;
416 if (!mc_args_show_info ())
418 exit_code = EXIT_SUCCESS;
419 goto startup_exit_ok;
422 if (!events_init (&error))
423 goto startup_exit_falure;
425 mc_config_init_config_paths (&error);
426 if (error == NULL && mc_config_deprecated_dir_present ())
427 mc_config_migrate_from_old_place (&error);
428 if (error != NULL)
430 mc_event_deinit (NULL);
431 goto startup_exit_falure;
434 vfs_init ();
435 vfs_plugins_init ();
436 vfs_setup_work_dir ();
438 /* do this after vfs initialization due to mc_setctl() call in mc_setup_by_args() */
439 if (!mc_setup_by_args (argc, argv, &error))
441 vfs_shut ();
442 mc_event_deinit (NULL);
443 goto startup_exit_falure;
446 /* check terminal type
447 * $TEMR must be set and not empty
448 * mc_global.tty.xterm_flag is used in init_key() and tty_init()
449 * Do this after mc_args_handle() where mc_args__force_xterm is set up.
451 mc_global.tty.xterm_flag = tty_check_term (mc_args__force_xterm);
453 /* NOTE: This has to be called before tty_init or whatever routine
454 calls any define_sequence */
455 init_key ();
457 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
458 handle_console (CONSOLE_INIT);
460 #ifdef HAVE_SUBSHELL_SUPPORT
461 /* Don't use subshell when invoked as viewer or editor */
462 if (mc_global.mc_run_mode != MC_RUN_FULL)
463 mc_global.tty.use_subshell = FALSE;
465 if (mc_global.tty.use_subshell)
466 subshell_get_console_attributes ();
467 #endif /* HAVE_SUBSHELL_SUPPORT */
469 /* Install the SIGCHLD handler; must be done before init_subshell() */
470 init_sigchld ();
472 /* We need this, since ncurses endwin () doesn't restore the signals */
473 save_stop_handler ();
475 /* Must be done before init_subshell, to set up the terminal size: */
476 /* FIXME: Should be removed and LINES and COLS computed on subshell */
477 tty_init (!mc_args__nomouse, mc_global.tty.xterm_flag);
479 load_setup ();
481 /* start check mc_global.display_codepage and mc_global.source_codepage */
482 check_codeset ();
484 /* Removing this from the X code let's us type C-c */
485 load_key_defs ();
487 load_keymap_defs (!mc_args__nokeymap);
489 macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
491 tty_init_colors (mc_global.tty.disable_colors, mc_args__force_colors);
493 mc_skin_init (&error);
494 if (error != NULL)
496 message (D_ERROR, _("Warning"), "%s", error->message);
497 g_error_free (error);
498 error = NULL;
501 mc_filehighlight = mc_fhl_new (TRUE);
502 dlg_set_default_colors ();
504 #ifdef HAVE_SUBSHELL_SUPPORT
505 /* Done here to ensure that the subshell doesn't */
506 /* inherit the file descriptors opened below, etc */
507 if (mc_global.tty.use_subshell)
508 init_subshell ();
510 #endif /* HAVE_SUBSHELL_SUPPORT */
512 /* Also done after init_subshell, to save any shell init file messages */
513 if (mc_global.tty.console_flag != '\0')
514 handle_console (CONSOLE_SAVE);
516 if (mc_global.tty.alternate_plus_minus)
517 application_keypad_mode ();
519 #ifdef HAVE_SUBSHELL_SUPPORT
520 if (mc_global.tty.use_subshell)
522 mc_prompt = strip_ctrl_codes (subshell_prompt);
523 if (mc_prompt == NULL)
524 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
526 else
527 #endif /* HAVE_SUBSHELL_SUPPORT */
528 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
530 /* Program main loop */
531 if (mc_global.midnight_shutdown)
532 exit_code = EXIT_SUCCESS;
533 else
534 exit_code = do_nc ()? EXIT_SUCCESS : EXIT_FAILURE;
536 /* Save the tree store */
537 (void) tree_store_save ();
539 free_keymap_defs ();
541 /* Virtual File System shutdown */
542 vfs_shut ();
544 flush_extension_file (); /* does only free memory */
546 mc_fhl_free (&mc_filehighlight);
547 mc_skin_deinit ();
548 tty_colors_done ();
550 tty_shutdown ();
552 done_setup ();
554 if (mc_global.tty.console_flag != '\0' && (quit & SUBSHELL_EXIT) == 0)
555 handle_console (CONSOLE_RESTORE);
556 if (mc_global.tty.alternate_plus_minus)
557 numeric_keypad_mode ();
559 (void) signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
561 if (mc_global.tty.console_flag != '\0')
562 handle_console (CONSOLE_DONE);
564 if (mc_global.mc_run_mode == MC_RUN_FULL && mc_args__last_wd_file != NULL
565 && last_wd_string != NULL && !print_last_revert)
567 int last_wd_fd;
569 last_wd_fd = open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
570 S_IRUSR | S_IWUSR);
571 if (last_wd_fd != -1)
573 ssize_t ret1;
574 int ret2;
575 ret1 = write (last_wd_fd, last_wd_string, strlen (last_wd_string));
576 ret2 = close (last_wd_fd);
579 g_free (last_wd_string);
581 g_free (shell);
583 done_key ();
585 if (macros_list != NULL)
587 guint i;
588 macros_t *macros;
589 for (i = 0; i < macros_list->len; i++)
591 macros = &g_array_index (macros_list, struct macros_t, i);
592 if (macros != NULL && macros->macro != NULL)
593 (void) g_array_free (macros->macro, FALSE);
595 (void) g_array_free (macros_list, TRUE);
598 str_uninit_strings ();
600 if (mc_global.mc_run_mode != MC_RUN_EDITOR)
601 g_free (mc_run_param0);
602 else
604 g_list_foreach ((GList *) mc_run_param0, (GFunc) mcedit_arg_free, NULL);
605 g_list_free ((GList *) mc_run_param0);
607 g_free (mc_run_param1);
609 mc_config_deinit_config_paths ();
611 (void) mc_event_deinit (&error);
612 if (error != NULL)
614 fprintf (stderr, _("\nFailed while close:\n%s\n"), error->message);
615 g_error_free (error);
616 exit_code = EXIT_FAILURE;
619 (void) putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
621 return exit_code;
624 /* --------------------------------------------------------------------------------------------- */