Fixed preprocessor conditions.
[midnight-commander.git] / src / main.c
blob4dccde65f945a772c11825e9489900d8352cddbc
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, 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 gboolean
278 do_cd (const char *new_dir, enum cd_enum exact)
280 gboolean res;
281 const char *_new_dir = new_dir;
283 if (current_panel->is_panelized && _new_dir[0] == '.' && _new_dir[1] == '.' && _new_dir[2] == 0)
284 _new_dir = panelized_panel.root;
286 res = do_panel_cd (current_panel, _new_dir, exact);
288 #ifdef HAVE_CHARSET
289 if (res)
291 vfs_path_t *vpath = vfs_path_from_str (current_panel->cwd);
292 vfs_path_element_t *path_element = vfs_path_get_by_index (vpath, -1);
294 if (path_element->encoding != NULL)
295 current_panel->codepage = get_codepage_index (path_element->encoding);
296 else
297 current_panel->codepage = SELECT_CHARSET_NO_TRANSLATE;
299 vfs_path_free (vpath);
301 #endif /* HAVE_CHARSET */
303 return res;
306 /* --------------------------------------------------------------------------------------------- */
308 #ifdef HAVE_SUBSHELL_SUPPORT
309 gboolean
310 do_load_prompt (void)
312 gboolean ret = FALSE;
314 if (!read_subshell_prompt ())
315 return ret;
317 /* Don't actually change the prompt if it's invisible */
318 if (((Dlg_head *) top_dlg->data == midnight_dlg) && command_prompt)
320 setup_cmdline ();
322 /* since the prompt has changed, and we are called from one of the
323 * tty_get_event channels, the prompt updating does not take place
324 * automatically: force a cursor update and a screen refresh
326 update_cursor (midnight_dlg);
327 mc_refresh ();
328 ret = TRUE;
330 update_subshell_prompt = TRUE;
331 return ret;
334 /* --------------------------------------------------------------------------------------------- */
337 load_prompt (int fd, void *unused)
339 (void) fd;
340 (void) unused;
342 do_load_prompt ();
343 return 0;
345 #endif /* HAVE_SUBSHELL_SUPPORT */
347 /* --------------------------------------------------------------------------------------------- */
349 /** Show current directory in the xterm title */
350 void
351 update_xterm_title_path (void)
353 /* TODO: share code with midnight_get_title () */
355 const char *path;
356 char host[BUF_TINY];
357 char *p;
358 struct passwd *pw = NULL;
359 char *login = NULL;
360 int res = 0;
362 if (mc_global.tty.xterm_flag && xterm_title)
364 path = strip_home_and_password (current_panel->cwd);
365 res = gethostname (host, sizeof (host));
366 if (res)
367 { /* On success, res = 0 */
368 host[0] = '\0';
370 else
372 host[sizeof (host) - 1] = '\0';
374 pw = getpwuid (getuid ());
375 if (pw)
377 login = g_strdup_printf ("%s@%s", pw->pw_name, host);
379 else
381 login = g_strdup (host);
383 p = g_strdup_printf ("mc [%s]:%s", login, path);
384 fprintf (stdout, "\33]0;%s\7", str_term_form (p));
385 g_free (login);
386 g_free (p);
387 if (!mc_global.tty.alternate_plus_minus)
388 numeric_keypad_mode ();
389 (void) fflush (stdout);
393 /* --------------------------------------------------------------------------------------------- */
396 main (int argc, char *argv[])
398 GError *error = NULL;
399 int exit_code = EXIT_FAILURE;
401 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
402 (void) setlocale (LC_ALL, "");
403 (void) bindtextdomain ("mc", LOCALEDIR);
404 (void) textdomain ("mc");
406 /* do this before args parsing */
407 str_init_strings (NULL);
409 if (!mc_args_parse (&argc, &argv, "mc", &error))
411 startup_exit_falure:
412 fprintf (stderr, _("Failed to run:\n%s\n"), error->message);
413 g_error_free (error);
414 g_free (shell);
415 startup_exit_ok:
416 str_uninit_strings ();
417 return exit_code;
420 /* do this before mc_args_show_info () to view paths in the --datadir-info output */
421 OS_Setup ();
423 if (!g_path_is_absolute (mc_config_get_home_dir ()))
425 error = g_error_new (MC_ERROR, 0, "%s: %s", _("Home directory path is not absolute"),
426 mc_config_get_home_dir ());
427 mc_event_deinit (NULL);
428 goto startup_exit_falure;
431 if (!mc_args_show_info ())
433 exit_code = EXIT_SUCCESS;
434 goto startup_exit_ok;
437 if (!events_init (&error))
438 goto startup_exit_falure;
440 mc_config_init_config_paths (&error);
441 if (error == NULL && mc_config_deprecated_dir_present ())
442 mc_config_migrate_from_old_place (&error);
443 if (error != NULL)
445 mc_event_deinit (NULL);
446 goto startup_exit_falure;
449 vfs_init ();
450 vfs_plugins_init ();
451 vfs_setup_work_dir ();
453 /* do this after vfs initialization due to mc_setctl() call in mc_setup_by_args() */
454 if (!mc_setup_by_args (argc, argv, &error))
456 vfs_shut ();
457 mc_event_deinit (NULL);
458 goto startup_exit_falure;
461 /* check terminal type
462 * $TEMR must be set and not empty
463 * mc_global.tty.xterm_flag is used in init_key() and tty_init()
464 * Do this after mc_args_handle() where mc_args__force_xterm is set up.
466 mc_global.tty.xterm_flag = tty_check_term (mc_args__force_xterm);
468 /* NOTE: This has to be called before tty_init or whatever routine
469 calls any define_sequence */
470 init_key ();
472 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
473 handle_console (CONSOLE_INIT);
475 #ifdef HAVE_SUBSHELL_SUPPORT
476 /* Don't use subshell when invoked as viewer or editor */
477 if (mc_global.mc_run_mode != MC_RUN_FULL)
478 mc_global.tty.use_subshell = FALSE;
480 if (mc_global.tty.use_subshell)
481 subshell_get_console_attributes ();
482 #endif /* HAVE_SUBSHELL_SUPPORT */
484 /* Install the SIGCHLD handler; must be done before init_subshell() */
485 init_sigchld ();
487 /* We need this, since ncurses endwin () doesn't restore the signals */
488 save_stop_handler ();
490 /* Must be done before init_subshell, to set up the terminal size: */
491 /* FIXME: Should be removed and LINES and COLS computed on subshell */
492 tty_init (!mc_args__nomouse, mc_global.tty.xterm_flag);
494 load_setup ();
496 /* start check mc_global.display_codepage and mc_global.source_codepage */
497 check_codeset ();
499 /* Removing this from the X code let's us type C-c */
500 load_key_defs ();
502 load_keymap_defs (!mc_args__nokeymap);
504 macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
506 tty_init_colors (mc_global.tty.disable_colors, mc_args__force_colors);
508 mc_skin_init (&error);
509 if (error != NULL)
511 message (D_ERROR, _("Warning"), "%s", error->message);
512 g_error_free (error);
513 error = NULL;
516 mc_filehighlight = mc_fhl_new (TRUE);
517 dlg_set_default_colors ();
519 #ifdef HAVE_SUBSHELL_SUPPORT
520 /* Done here to ensure that the subshell doesn't */
521 /* inherit the file descriptors opened below, etc */
522 if (mc_global.tty.use_subshell)
523 init_subshell ();
525 #endif /* HAVE_SUBSHELL_SUPPORT */
527 /* Also done after init_subshell, to save any shell init file messages */
528 if (mc_global.tty.console_flag != '\0')
529 handle_console (CONSOLE_SAVE);
531 if (mc_global.tty.alternate_plus_minus)
532 application_keypad_mode ();
534 #ifdef HAVE_SUBSHELL_SUPPORT
535 if (mc_global.tty.use_subshell)
537 mc_prompt = strip_ctrl_codes (subshell_prompt);
538 if (mc_prompt == NULL)
539 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
541 else
542 #endif /* HAVE_SUBSHELL_SUPPORT */
543 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
545 /* Program main loop */
546 if (mc_global.midnight_shutdown)
547 exit_code = EXIT_SUCCESS;
548 else
549 exit_code = do_nc () ? EXIT_SUCCESS : EXIT_FAILURE;
551 /* Save the tree store */
552 (void) tree_store_save ();
554 free_keymap_defs ();
556 /* Virtual File System shutdown */
557 vfs_shut ();
559 flush_extension_file (); /* does only free memory */
561 mc_fhl_free (&mc_filehighlight);
562 mc_skin_deinit ();
563 tty_colors_done ();
565 tty_shutdown ();
567 done_setup ();
569 if (mc_global.tty.console_flag != '\0' && (quit & SUBSHELL_EXIT) == 0)
570 handle_console (CONSOLE_RESTORE);
571 if (mc_global.tty.alternate_plus_minus)
572 numeric_keypad_mode ();
574 (void) signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
576 if (mc_global.tty.console_flag != '\0')
577 handle_console (CONSOLE_DONE);
579 if (mc_global.mc_run_mode == MC_RUN_FULL && mc_args__last_wd_file != NULL
580 && last_wd_string != NULL && !print_last_revert)
582 int last_wd_fd;
584 last_wd_fd = open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
585 S_IRUSR | S_IWUSR);
586 if (last_wd_fd != -1)
588 ssize_t ret1;
589 int ret2;
590 ret1 = write (last_wd_fd, last_wd_string, strlen (last_wd_string));
591 ret2 = close (last_wd_fd);
594 g_free (last_wd_string);
596 g_free (shell);
598 done_key ();
600 if (macros_list != NULL)
602 guint i;
603 macros_t *macros;
604 for (i = 0; i < macros_list->len; i++)
606 macros = &g_array_index (macros_list, struct macros_t, i);
607 if (macros != NULL && macros->macro != NULL)
608 (void) g_array_free (macros->macro, FALSE);
610 (void) g_array_free (macros_list, TRUE);
613 str_uninit_strings ();
615 g_free (mc_run_param0);
616 g_free (mc_run_param1);
618 mc_config_deinit_config_paths ();
620 (void) mc_event_deinit (&error);
621 if (error != NULL)
623 fprintf (stderr, _("\nFailed while close:\n%s\n"), error->message);
624 g_error_free (error);
625 exit_code = EXIT_FAILURE;
628 (void) putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
630 return exit_code;
633 /* --------------------------------------------------------------------------------------------- */