Allow override standard dialog actions in some dialog.
[midnight-commander.git] / src / main.c
blob637923ddf9cd734eff0ef9b5430590d2f38ae129
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 /* --------------------------------------------------------------------------------------------- */
261 gboolean
262 do_cd (const vfs_path_t * new_dir_vpath, enum cd_enum exact)
264 gboolean res;
265 const vfs_path_t *_new_dir_vpath = new_dir_vpath;
267 if (current_panel->is_panelized)
269 size_t new_vpath_len;
271 new_vpath_len = vfs_path_len (new_dir_vpath);
272 if (vfs_path_ncmp (new_dir_vpath, panelized_panel.root_vpath, new_vpath_len) == 0)
273 _new_dir_vpath = panelized_panel.root_vpath;
276 res = do_panel_cd (current_panel, _new_dir_vpath, exact);
278 #if HAVE_CHARSET
279 if (res)
281 const vfs_path_element_t *path_element;
283 path_element = vfs_path_get_by_index (current_panel->cwd_vpath, -1);
284 if (path_element->encoding != NULL)
285 current_panel->codepage = get_codepage_index (path_element->encoding);
286 else
287 current_panel->codepage = SELECT_CHARSET_NO_TRANSLATE;
289 #endif /* HAVE_CHARSET */
291 return res;
294 /* --------------------------------------------------------------------------------------------- */
296 #ifdef HAVE_SUBSHELL_SUPPORT
297 gboolean
298 do_load_prompt (void)
300 gboolean ret = FALSE;
302 if (!read_subshell_prompt ())
303 return ret;
305 /* Don't actually change the prompt if it's invisible */
306 if (((Dlg_head *) top_dlg->data == midnight_dlg) && command_prompt)
308 setup_cmdline ();
310 /* since the prompt has changed, and we are called from one of the
311 * tty_get_event channels, the prompt updating does not take place
312 * automatically: force a cursor update and a screen refresh
314 update_cursor (midnight_dlg);
315 mc_refresh ();
316 ret = TRUE;
318 update_subshell_prompt = TRUE;
319 return ret;
322 /* --------------------------------------------------------------------------------------------- */
325 load_prompt (int fd, void *unused)
327 (void) fd;
328 (void) unused;
330 do_load_prompt ();
331 return 0;
333 #endif /* HAVE_SUBSHELL_SUPPORT */
335 /* --------------------------------------------------------------------------------------------- */
337 void
338 title_path_prepare (char **path, char **login)
341 char host[BUF_TINY];
342 struct passwd *pw = NULL;
343 int res = 0;
345 *login = NULL;
348 *path =
349 vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_STRIP_HOME | VPF_STRIP_PASSWORD);
350 res = gethostname (host, sizeof (host));
351 if (res)
352 { /* On success, res = 0 */
353 host[0] = '\0';
355 else
357 host[sizeof (host) - 1] = '\0';
359 pw = getpwuid (getuid ());
360 if (pw)
362 *login = g_strdup_printf ("%s@%s", pw->pw_name, host);
364 else
366 *login = g_strdup (host);
370 /* --------------------------------------------------------------------------------------------- */
372 /** Show current directory in the xterm title */
373 void
374 update_xterm_title_path (void)
376 char *p;
377 char *path;
378 char *login;
380 if (!(mc_global.tty.xterm_flag && xterm_title))
381 return;
383 title_path_prepare (&path, &login);
385 p = g_strdup_printf ("mc [%s]:%s", login, path);
386 fprintf (stdout, "\33]0;%s\7", str_term_form (p));
387 g_free (login);
388 g_free (p);
389 if (!mc_global.tty.alternate_plus_minus)
390 numeric_keypad_mode ();
391 (void) fflush (stdout);
392 g_free (path);
395 /* --------------------------------------------------------------------------------------------- */
398 main (int argc, char *argv[])
400 GError *error = NULL;
401 gboolean isInitialized;
403 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
404 (void) setlocale (LC_ALL, "");
405 (void) bindtextdomain ("mc", LOCALEDIR);
406 (void) textdomain ("mc");
408 if (!events_init (&error))
410 fprintf (stderr, _("Failed to run:\n%s\n"), error->message);
411 g_error_free (error);
412 (void) mc_event_deinit (NULL);
413 exit (EXIT_FAILURE);
416 /* Set up temporary directory */
417 (void) mc_tmpdir ();
419 OS_Setup ();
421 str_init_strings (NULL);
423 /* Initialize and create home directories */
424 /* do it after the screen library initialization to show the error message */
425 mc_config_init_config_paths (&error);
427 if (error == NULL && mc_config_deprecated_dir_present ())
428 mc_config_migrate_from_old_place (&error);
430 vfs_init ();
431 vfs_plugins_init ();
432 vfs_setup_work_dir ();
434 if (!mc_args_handle (argc, argv, "mc"))
435 exit (EXIT_FAILURE);
437 /* check terminal type
438 * $TEMR must be set and not empty
439 * mc_global.tty.xterm_flag is used in init_key() and tty_init()
440 * Do this after mc_args_handle() where mc_args__force_xterm is set up.
442 mc_global.tty.xterm_flag = tty_check_term (mc_args__force_xterm);
444 /* NOTE: This has to be called before tty_init or whatever routine
445 calls any define_sequence */
446 init_key ();
448 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
449 handle_console (CONSOLE_INIT);
451 #ifdef HAVE_SUBSHELL_SUPPORT
452 /* Don't use subshell when invoked as viewer or editor */
453 if (mc_global.mc_run_mode != MC_RUN_FULL)
454 mc_global.tty.use_subshell = FALSE;
456 if (mc_global.tty.use_subshell)
457 subshell_get_console_attributes ();
458 #endif /* HAVE_SUBSHELL_SUPPORT */
460 /* Install the SIGCHLD handler; must be done before init_subshell() */
461 init_sigchld ();
463 /* We need this, since ncurses endwin () doesn't restore the signals */
464 save_stop_handler ();
466 /* Must be done before init_subshell, to set up the terminal size: */
467 /* FIXME: Should be removed and LINES and COLS computed on subshell */
468 tty_init (!mc_args__nomouse, mc_global.tty.xterm_flag);
470 load_setup ();
472 /* start check mc_global.display_codepage and mc_global.source_codepage */
473 check_codeset ();
475 /* Removing this from the X code let's us type C-c */
476 load_key_defs ();
478 load_keymap_defs (!mc_args__nokeymap);
480 macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
482 tty_init_colors (mc_global.tty.disable_colors, mc_args__force_colors);
485 GError *error2 = NULL;
486 isInitialized = mc_skin_init (&error2);
487 mc_filehighlight = mc_fhl_new (TRUE);
488 dlg_set_default_colors ();
490 if (!isInitialized)
492 message (D_ERROR, _("Warning"), "%s", error2->message);
493 g_error_free (error2);
494 error2 = NULL;
498 if (error != NULL)
500 message (D_ERROR, _("Warning"), "%s", error->message);
501 g_error_free (error);
502 error = NULL;
506 #ifdef HAVE_SUBSHELL_SUPPORT
507 /* Done here to ensure that the subshell doesn't */
508 /* inherit the file descriptors opened below, etc */
509 if (mc_global.tty.use_subshell)
510 init_subshell ();
512 #endif /* HAVE_SUBSHELL_SUPPORT */
514 /* Also done after init_subshell, to save any shell init file messages */
515 if (mc_global.tty.console_flag != '\0')
516 handle_console (CONSOLE_SAVE);
518 if (mc_global.tty.alternate_plus_minus)
519 application_keypad_mode ();
521 #ifdef HAVE_SUBSHELL_SUPPORT
522 if (mc_global.tty.use_subshell)
524 mc_prompt = strip_ctrl_codes (subshell_prompt);
525 if (mc_prompt == NULL)
526 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
528 else
529 #endif /* HAVE_SUBSHELL_SUPPORT */
530 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
532 /* Program main loop */
533 if (!mc_global.widget.midnight_shutdown)
534 do_nc ();
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 g_free (mc_run_param0);
601 g_free (mc_run_param1);
603 (void) mc_event_deinit (&error);
605 mc_config_deinit_config_paths ();
607 if (error != NULL)
609 fprintf (stderr, _("\nFailed while close:\n%s\n"), error->message);
610 g_error_free (error);
611 exit (EXIT_FAILURE);
614 (void) putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
616 return 0;
619 /* --------------------------------------------------------------------------------------------- */