Merge branch '2677_viewer_double_dialog'
[midnight-commander.git] / src / main.c
blobe5d95dea9db2c4bb0911c8beec233e4fd1edec59
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 char *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, "Misc", "display_codepage", cp_display);
153 #endif
155 mc_global.utf8_display = str_isutf8 (current_system_codepage);
158 /* --------------------------------------------------------------------------------------------- */
160 /** POSIX version. The only version we support. */
161 static void
162 OS_Setup (void)
164 const char *shell_env = getenv ("SHELL");
166 if ((shell_env == NULL) || (shell_env[0] == '\0'))
168 struct passwd *pwd;
169 pwd = getpwuid (geteuid ());
170 if (pwd != NULL)
171 shell = g_strdup (pwd->pw_shell);
173 else
174 shell = g_strdup (shell_env);
176 if ((shell == NULL) || (shell[0] == '\0'))
178 g_free (shell);
179 shell = g_strdup ("/bin/sh");
183 /* --------------------------------------------------------------------------------------------- */
185 static void
186 sigchld_handler_no_subshell (int sig)
188 #ifdef __linux__
189 int pid, status;
191 if (!mc_global.tty.console_flag != '\0')
192 return;
194 /* COMMENT: if it were true that after the call to handle_console(..INIT)
195 the value of mc_global.tty.console_flag never changed, we could simply not install
196 this handler at all if (!mc_global.tty.console_flag && !mc_global.tty.use_subshell). */
198 /* That comment is no longer true. We need to wait() on a sigchld
199 handler (that's at least what the tarfs code expects currently). */
201 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
203 if (pid == cons_saver_pid)
206 if (WIFSTOPPED (status))
208 /* Someone has stopped cons.saver - restart it */
209 kill (pid, SIGCONT);
211 else
213 /* cons.saver has died - disable console saving */
214 handle_console (CONSOLE_DONE);
215 mc_global.tty.console_flag = '\0';
218 /* If we got here, some other child exited; ignore it */
219 #endif /* __linux__ */
221 (void) sig;
224 /* --------------------------------------------------------------------------------------------- */
226 static void
227 init_sigchld (void)
229 struct sigaction sigchld_action;
231 sigchld_action.sa_handler =
232 #ifdef HAVE_SUBSHELL_SUPPORT
233 mc_global.tty.use_subshell ? sigchld_handler :
234 #endif /* HAVE_SUBSHELL_SUPPORT */
235 sigchld_handler_no_subshell;
237 sigemptyset (&sigchld_action.sa_mask);
239 #ifdef SA_RESTART
240 sigchld_action.sa_flags = SA_RESTART;
241 #else
242 sigchld_action.sa_flags = 0;
243 #endif /* !SA_RESTART */
245 if (sigaction (SIGCHLD, &sigchld_action, NULL) == -1)
247 #ifdef HAVE_SUBSHELL_SUPPORT
249 * This may happen on QNX Neutrino 6, where SA_RESTART
250 * is defined but not implemented. Fallback to no subshell.
252 mc_global.tty.use_subshell = FALSE;
253 #endif /* HAVE_SUBSHELL_SUPPORT */
257 /* --------------------------------------------------------------------------------------------- */
258 /*** public functions ****************************************************************************/
259 /* --------------------------------------------------------------------------------------------- */
262 do_cd (const char *new_dir, enum cd_enum exact)
264 gboolean res;
265 const char *_new_dir = new_dir;
267 if (current_panel->is_panelized && _new_dir[0] == '.' && _new_dir[1] == '.' && _new_dir[2] == 0)
268 _new_dir = panelized_panel.root;
270 res = do_panel_cd (current_panel, _new_dir, exact);
272 #if HAVE_CHARSET
273 if (res)
275 vfs_path_t *vpath = vfs_path_from_str (current_panel->cwd);
276 vfs_path_element_t *path_element = vfs_path_get_by_index (vpath, -1);
278 if (path_element->encoding != NULL)
279 current_panel->codepage = get_codepage_index (path_element->encoding);
280 else
281 current_panel->codepage = SELECT_CHARSET_NO_TRANSLATE;
283 vfs_path_free (vpath);
285 #endif /* HAVE_CHARSET */
287 return res ? 1 : 0;
290 /* --------------------------------------------------------------------------------------------- */
292 #ifdef HAVE_SUBSHELL_SUPPORT
294 load_prompt (int fd, void *unused)
296 (void) fd;
297 (void) unused;
299 if (!read_subshell_prompt ())
300 return 0;
302 /* Don't actually change the prompt if it's invisible */
303 if (((Dlg_head *) top_dlg->data == midnight_dlg) && command_prompt)
305 char *tmp_prompt;
306 int prompt_len;
308 tmp_prompt = strip_ctrl_codes (subshell_prompt);
309 prompt_len = str_term_width1 (tmp_prompt);
311 /* Check for prompts too big */
312 if (COLS > 8 && prompt_len > COLS - 8)
314 prompt_len = COLS - 8;
315 tmp_prompt[prompt_len] = '\0';
317 mc_prompt = tmp_prompt;
318 label_set_text (the_prompt, mc_prompt);
319 input_set_origin ((WInput *) cmdline, prompt_len, COLS - prompt_len);
321 /* since the prompt has changed, and we are called from one of the
322 * tty_get_event channels, the prompt updating does not take place
323 * automatically: force a cursor update and a screen refresh
325 update_cursor (midnight_dlg);
326 mc_refresh ();
328 update_subshell_prompt = TRUE;
329 return 0;
331 #endif /* HAVE_SUBSHELL_SUPPORT */
333 /* --------------------------------------------------------------------------------------------- */
335 /** Show current directory in the xterm title */
336 void
337 update_xterm_title_path (void)
339 /* TODO: share code with midnight_get_title () */
341 const char *path;
342 char host[BUF_TINY];
343 char *p;
344 struct passwd *pw = NULL;
345 char *login = NULL;
346 int res = 0;
348 if (mc_global.tty.xterm_flag && xterm_title)
350 path = strip_home_and_password (current_panel->cwd);
351 res = gethostname (host, sizeof (host));
352 if (res)
353 { /* On success, res = 0 */
354 host[0] = '\0';
356 else
358 host[sizeof (host) - 1] = '\0';
360 pw = getpwuid (getuid ());
361 if (pw)
363 login = g_strdup_printf ("%s@%s", pw->pw_name, host);
365 else
367 login = g_strdup (host);
369 p = g_strdup_printf ("mc [%s]:%s", login, path);
370 fprintf (stdout, "\33]0;%s\7", str_term_form (p));
371 g_free (login);
372 g_free (p);
373 if (!mc_global.tty.alternate_plus_minus)
374 numeric_keypad_mode ();
375 (void) fflush (stdout);
379 /* --------------------------------------------------------------------------------------------- */
382 main (int argc, char *argv[])
384 GError *error = NULL;
385 gboolean isInitialized;
387 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
388 (void) setlocale (LC_ALL, "");
389 (void) bindtextdomain ("mc", LOCALEDIR);
390 (void) textdomain ("mc");
392 if (!events_init (&error))
394 fprintf (stderr, _("Failed to run:\n%s\n"), error->message);
395 g_error_free (error);
396 (void) mc_event_deinit (NULL);
397 exit (EXIT_FAILURE);
400 /* Set up temporary directory */
401 (void) mc_tmpdir ();
403 OS_Setup ();
405 str_init_strings (NULL);
407 /* Initialize and create home directories */
408 /* do it after the screen library initialization to show the error message */
409 mc_config_init_config_paths (&error);
411 if (error == NULL && mc_config_deprecated_dir_present ())
412 mc_config_migrate_from_old_place (&error);
414 vfs_init ();
415 vfs_plugins_init ();
416 vfs_setup_work_dir ();
418 if (!mc_args_handle (argc, argv, "mc"))
419 exit (EXIT_FAILURE);
421 /* check terminal type
422 * $TEMR must be set and not empty
423 * mc_global.tty.xterm_flag is used in init_key() and tty_init()
424 * Do this after mc_args_handle() where mc_args__force_xterm is set up.
426 mc_global.tty.xterm_flag = tty_check_term (mc_args__force_xterm);
428 /* NOTE: This has to be called before tty_init or whatever routine
429 calls any define_sequence */
430 init_key ();
432 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
433 handle_console (CONSOLE_INIT);
435 #ifdef HAVE_SUBSHELL_SUPPORT
436 /* Don't use subshell when invoked as viewer or editor */
437 if (mc_global.mc_run_mode != MC_RUN_FULL)
438 mc_global.tty.use_subshell = FALSE;
440 if (mc_global.tty.use_subshell)
441 subshell_get_console_attributes ();
442 #endif /* HAVE_SUBSHELL_SUPPORT */
444 /* Install the SIGCHLD handler; must be done before init_subshell() */
445 init_sigchld ();
447 /* We need this, since ncurses endwin () doesn't restore the signals */
448 save_stop_handler ();
450 /* Must be done before init_subshell, to set up the terminal size: */
451 /* FIXME: Should be removed and LINES and COLS computed on subshell */
452 tty_init (!mc_args__nomouse, mc_global.tty.xterm_flag);
454 load_setup ();
456 /* start check mc_global.display_codepage and mc_global.source_codepage */
457 check_codeset ();
459 /* Removing this from the X code let's us type C-c */
460 load_key_defs ();
462 load_keymap_defs (!mc_args__nokeymap);
464 macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
466 tty_init_colors (mc_global.tty.disable_colors, mc_args__force_colors);
469 GError *error2 = NULL;
470 isInitialized = mc_skin_init (&error2);
471 mc_filehighlight = mc_fhl_new (TRUE);
472 dlg_set_default_colors ();
474 if (!isInitialized)
476 message (D_ERROR, _("Warning"), "%s", error2->message);
477 g_error_free (error2);
478 error2 = NULL;
482 if (error != NULL)
484 message (D_ERROR, _("Warning"), "%s", error->message);
485 g_error_free (error);
486 error = NULL;
490 #ifdef HAVE_SUBSHELL_SUPPORT
491 /* Done here to ensure that the subshell doesn't */
492 /* inherit the file descriptors opened below, etc */
493 if (mc_global.tty.use_subshell)
494 init_subshell ();
496 #endif /* HAVE_SUBSHELL_SUPPORT */
498 /* Also done after init_subshell, to save any shell init file messages */
499 if (mc_global.tty.console_flag != '\0')
500 handle_console (CONSOLE_SAVE);
502 if (mc_global.tty.alternate_plus_minus)
503 application_keypad_mode ();
505 #ifdef HAVE_SUBSHELL_SUPPORT
506 if (mc_global.tty.use_subshell)
508 mc_prompt = strip_ctrl_codes (subshell_prompt);
509 if (mc_prompt == NULL)
510 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
512 else
513 #endif /* HAVE_SUBSHELL_SUPPORT */
514 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
516 /* Program main loop */
517 if (!mc_global.widget.midnight_shutdown)
518 do_nc ();
520 /* Save the tree store */
521 (void) tree_store_save ();
523 free_keymap_defs ();
525 /* Virtual File System shutdown */
526 vfs_shut ();
528 flush_extension_file (); /* does only free memory */
530 mc_fhl_free (&mc_filehighlight);
531 mc_skin_deinit ();
532 tty_colors_done ();
534 tty_shutdown ();
536 done_setup ();
538 if (mc_global.tty.console_flag != '\0' && (quit & SUBSHELL_EXIT) == 0)
539 handle_console (CONSOLE_RESTORE);
540 if (mc_global.tty.alternate_plus_minus)
541 numeric_keypad_mode ();
543 (void) signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
545 if (mc_global.tty.console_flag != '\0')
546 handle_console (CONSOLE_DONE);
548 if (mc_global.mc_run_mode == MC_RUN_FULL && mc_args__last_wd_file != NULL
549 && last_wd_string != NULL && !print_last_revert)
551 int last_wd_fd;
553 last_wd_fd = open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
554 S_IRUSR | S_IWUSR);
555 if (last_wd_fd != -1)
557 ssize_t ret1;
558 int ret2;
559 ret1 = write (last_wd_fd, last_wd_string, strlen (last_wd_string));
560 ret2 = close (last_wd_fd);
563 g_free (last_wd_string);
565 g_free (shell);
567 done_key ();
569 if (macros_list != NULL)
571 guint i;
572 macros_t *macros;
573 for (i = 0; i < macros_list->len; i++)
575 macros = &g_array_index (macros_list, struct macros_t, i);
576 if (macros != NULL && macros->macro != NULL)
577 (void) g_array_free (macros->macro, FALSE);
579 (void) g_array_free (macros_list, TRUE);
582 str_uninit_strings ();
584 g_free (mc_run_param0);
585 g_free (mc_run_param1);
587 (void) mc_event_deinit (&error);
589 mc_config_deinit_config_paths ();
591 if (error != NULL)
593 fprintf (stderr, _("\nFailed while close:\n%s\n"), error->message);
594 g_error_free (error);
595 exit (EXIT_FAILURE);
598 (void) putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
600 return 0;
603 /* --------------------------------------------------------------------------------------------- */