Add lib/strutil/replace:str_replace_all() function.
[midnight-commander.git] / src / main.c
blob4d67fe354e58c1bdf80cb975df016a5669241071
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 <pwd.h> /* for username in xterm title */
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/wait.h>
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/tty/mouse.h" /* init_mouse() */
51 #include "lib/skin.h"
52 #include "lib/filehighlight.h"
53 #include "lib/fileloc.h"
54 #include "lib/strutil.h"
55 #include "lib/util.h"
56 #include "lib/vfs/vfs.h" /* vfs_init(), vfs_shut() */
58 #include "filemanager/midnight.h" /* current_panel */
59 #include "filemanager/treestore.h" /* tree_store_save */
60 #include "filemanager/layout.h" /* command_prompt */
61 #include "filemanager/ext.h" /* flush_extension_file() */
62 #include "filemanager/command.h" /* cmdline */
63 #include "filemanager/panel.h" /* panalized_panel */
65 #include "vfs/plugins_init.h"
67 #include "events_init.h"
68 #include "args.h"
69 #ifdef ENABLE_SUBSHELL
70 #include "subshell.h"
71 #endif
72 #include "setup.h" /* load_setup() */
74 #ifdef HAVE_CHARSET
75 #include "lib/charsets.h"
76 #include "selcodepage.h"
77 #endif /* HAVE_CHARSET */
79 #include "consaver/cons.saver.h" /* cons_saver_pid */
81 /*** global variables ****************************************************************************/
83 /*** file scope macro definitions ****************************************************************/
85 /*** file scope type declarations ****************************************************************/
87 /*** file scope variables ************************************************************************/
89 /*** file scope functions ************************************************************************/
90 /* --------------------------------------------------------------------------------------------- */
92 static void
93 check_codeset (void)
95 const char *current_system_codepage = NULL;
97 current_system_codepage = str_detect_termencoding ();
99 #ifdef HAVE_CHARSET
101 const char *_display_codepage;
103 _display_codepage = get_codepage_id (mc_global.display_codepage);
105 if (strcmp (_display_codepage, current_system_codepage) != 0)
107 mc_global.display_codepage = get_codepage_index (current_system_codepage);
108 if (mc_global.display_codepage == -1)
109 mc_global.display_codepage = 0;
111 mc_config_set_string (mc_main_config, CONFIG_MISC_SECTION, "display_codepage",
112 cp_display);
115 #endif
117 mc_global.utf8_display = str_isutf8 (current_system_codepage);
120 /* --------------------------------------------------------------------------------------------- */
122 /** POSIX version. The only version we support. */
123 static void
124 OS_Setup (void)
126 const char *shell_env;
127 const char *datadir_env;
129 shell_env = getenv ("SHELL");
130 if ((shell_env == NULL) || (shell_env[0] == '\0'))
132 struct passwd *pwd;
134 pwd = getpwuid (geteuid ());
135 if (pwd != NULL)
136 mc_global.tty.shell = g_strdup (pwd->pw_shell);
138 else
139 mc_global.tty.shell = g_strdup (shell_env);
141 if ((mc_global.tty.shell == NULL) || (mc_global.tty.shell[0] == '\0'))
143 g_free (mc_global.tty.shell);
144 mc_global.tty.shell = g_strdup ("/bin/sh");
147 /* This is the directory, where MC was installed, on Unix this is DATADIR */
148 /* and can be overriden by the MC_DATADIR environment variable */
149 datadir_env = g_getenv ("MC_DATADIR");
150 if (datadir_env != NULL)
151 mc_global.sysconfig_dir = g_strdup (datadir_env);
152 else
153 mc_global.sysconfig_dir = g_strdup (SYSCONFDIR);
155 mc_global.share_data_dir = g_strdup (DATADIR);
157 /* Set up temporary directory */
158 mc_tmpdir ();
161 /* --------------------------------------------------------------------------------------------- */
163 static void
164 sigchld_handler_no_subshell (int sig)
166 #ifdef __linux__
167 int pid, status;
169 if (!mc_global.tty.console_flag != '\0')
170 return;
172 /* COMMENT: if it were true that after the call to handle_console(..INIT)
173 the value of mc_global.tty.console_flag never changed, we could simply not install
174 this handler at all if (!mc_global.tty.console_flag && !mc_global.tty.use_subshell). */
176 /* That comment is no longer true. We need to wait() on a sigchld
177 handler (that's at least what the tarfs code expects currently). */
179 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
181 if (pid == cons_saver_pid)
184 if (WIFSTOPPED (status))
186 /* Someone has stopped cons.saver - restart it */
187 kill (pid, SIGCONT);
189 else
191 /* cons.saver has died - disable console saving */
192 handle_console (CONSOLE_DONE);
193 mc_global.tty.console_flag = '\0';
196 /* If we got here, some other child exited; ignore it */
197 #endif /* __linux__ */
199 (void) sig;
202 /* --------------------------------------------------------------------------------------------- */
204 static void
205 init_sigchld (void)
207 struct sigaction sigchld_action;
209 sigchld_action.sa_handler =
210 #ifdef ENABLE_SUBSHELL
211 mc_global.tty.use_subshell ? sigchld_handler :
212 #endif /* ENABLE_SUBSHELL */
213 sigchld_handler_no_subshell;
215 sigemptyset (&sigchld_action.sa_mask);
217 #ifdef SA_RESTART
218 sigchld_action.sa_flags = SA_RESTART;
219 #else
220 sigchld_action.sa_flags = 0;
221 #endif /* !SA_RESTART */
223 if (sigaction (SIGCHLD, &sigchld_action, NULL) == -1)
225 #ifdef ENABLE_SUBSHELL
227 * This may happen on QNX Neutrino 6, where SA_RESTART
228 * is defined but not implemented. Fallback to no subshell.
230 mc_global.tty.use_subshell = FALSE;
231 #endif /* ENABLE_SUBSHELL */
235 /* --------------------------------------------------------------------------------------------- */
236 /*** public functions ****************************************************************************/
237 /* --------------------------------------------------------------------------------------------- */
240 main (int argc, char *argv[])
242 GError *error = NULL;
243 gboolean config_migrated = FALSE;
244 char *config_migrate_msg;
245 int exit_code = EXIT_FAILURE;
247 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
248 #ifdef HAVE_SETLOCALE
249 (void) setlocale (LC_ALL, "");
250 #endif
251 (void) bindtextdomain (PACKAGE, LOCALEDIR);
252 (void) textdomain (PACKAGE);
254 /* do this before args parsing */
255 str_init_strings (NULL);
257 if (!mc_args_parse (&argc, &argv, "mc", &error))
259 startup_exit_falure:
260 fprintf (stderr, _("Failed to run:\n%s\n"), error->message);
261 g_error_free (error);
262 g_free (mc_global.tty.shell);
263 startup_exit_ok:
264 str_uninit_strings ();
265 return exit_code;
268 /* do this before mc_args_show_info () to view paths in the --datadir-info output */
269 OS_Setup ();
271 if (!g_path_is_absolute (mc_config_get_home_dir ()))
273 error = g_error_new (MC_ERROR, 0, "%s: %s", _("Home directory path is not absolute"),
274 mc_config_get_home_dir ());
275 mc_event_deinit (NULL);
276 goto startup_exit_falure;
279 if (!mc_args_show_info ())
281 exit_code = EXIT_SUCCESS;
282 goto startup_exit_ok;
285 if (!events_init (&error))
286 goto startup_exit_falure;
288 mc_config_init_config_paths (&error);
289 if (error == NULL)
290 config_migrated = mc_config_migrate_from_old_place (&error, &config_migrate_msg);
291 if (error != NULL)
293 mc_event_deinit (NULL);
294 goto startup_exit_falure;
297 vfs_init ();
298 vfs_plugins_init ();
299 vfs_setup_work_dir ();
301 /* do this after vfs initialization due to mc_setctl() call in mc_setup_by_args() */
302 if (!mc_setup_by_args (argc, argv, &error))
304 vfs_shut ();
305 mc_event_deinit (NULL);
306 goto startup_exit_falure;
309 /* check terminal type
310 * $TEMR must be set and not empty
311 * mc_global.tty.xterm_flag is used in init_key() and tty_init()
312 * Do this after mc_args_handle() where mc_args__force_xterm is set up.
314 mc_global.tty.xterm_flag = tty_check_term (mc_args__force_xterm);
316 /* NOTE: This has to be called before tty_init or whatever routine
317 calls any define_sequence */
318 init_key ();
320 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
321 handle_console (CONSOLE_INIT);
323 #ifdef ENABLE_SUBSHELL
324 /* Don't use subshell when invoked as viewer or editor */
325 if (mc_global.mc_run_mode != MC_RUN_FULL)
326 mc_global.tty.use_subshell = FALSE;
328 if (mc_global.tty.use_subshell)
329 subshell_get_console_attributes ();
330 #endif /* ENABLE_SUBSHELL */
332 /* Install the SIGCHLD handler; must be done before init_subshell() */
333 init_sigchld ();
335 /* We need this, since ncurses endwin () doesn't restore the signals */
336 save_stop_handler ();
338 /* Must be done before init_subshell, to set up the terminal size: */
339 /* FIXME: Should be removed and LINES and COLS computed on subshell */
340 tty_init (!mc_args__nomouse, mc_global.tty.xterm_flag);
342 load_setup ();
344 /* start check mc_global.display_codepage and mc_global.source_codepage */
345 check_codeset ();
347 /* Removing this from the X code let's us type C-c */
348 load_key_defs ();
350 load_keymap_defs (!mc_args__nokeymap);
352 macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
354 tty_init_colors (mc_global.tty.disable_colors, mc_args__force_colors);
356 mc_skin_init (&error);
357 if (error != NULL)
359 message (D_ERROR, _("Warning"), "%s", error->message);
360 g_error_free (error);
361 error = NULL;
364 dlg_set_default_colors ();
366 #ifdef ENABLE_SUBSHELL
367 /* Done here to ensure that the subshell doesn't */
368 /* inherit the file descriptors opened below, etc */
369 if (mc_global.tty.use_subshell)
370 init_subshell ();
371 #endif /* ENABLE_SUBSHELL */
373 /* Also done after init_subshell, to save any shell init file messages */
374 if (mc_global.tty.console_flag != '\0')
375 handle_console (CONSOLE_SAVE);
377 if (mc_global.tty.alternate_plus_minus)
378 application_keypad_mode ();
380 /* Done after subshell initialization to allow select and paste text by mouse
381 w/o Shift button in subshell in the native console */
382 init_mouse ();
384 /* subshell_prompt is NULL here */
385 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
387 if (config_migrated)
389 message (D_ERROR, _("Warning"), "%s", config_migrate_msg);
390 g_free (config_migrate_msg);
393 /* Program main loop */
394 if (mc_global.midnight_shutdown)
395 exit_code = EXIT_SUCCESS;
396 else
397 exit_code = do_nc ()? EXIT_SUCCESS : EXIT_FAILURE;
399 /* Save the tree store */
400 (void) tree_store_save ();
402 free_keymap_defs ();
404 /* Virtual File System shutdown */
405 vfs_shut ();
407 flush_extension_file (); /* does only free memory */
409 mc_skin_deinit ();
410 tty_colors_done ();
412 tty_shutdown ();
414 done_setup ();
416 if (mc_global.tty.console_flag != '\0' && (quit & SUBSHELL_EXIT) == 0)
417 handle_console (CONSOLE_RESTORE);
418 if (mc_global.tty.alternate_plus_minus)
419 numeric_keypad_mode ();
421 (void) signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
423 if (mc_global.tty.console_flag != '\0')
424 handle_console (CONSOLE_DONE);
426 if (mc_global.mc_run_mode == MC_RUN_FULL && mc_args__last_wd_file != NULL
427 && last_wd_string != NULL && !print_last_revert)
429 int last_wd_fd;
431 last_wd_fd = open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
432 S_IRUSR | S_IWUSR);
433 if (last_wd_fd != -1)
435 ssize_t ret1;
436 int ret2;
437 ret1 = write (last_wd_fd, last_wd_string, strlen (last_wd_string));
438 ret2 = close (last_wd_fd);
439 (void) ret1;
440 (void) ret2;
443 g_free (last_wd_string);
445 g_free (mc_global.tty.shell);
447 done_key ();
449 if (macros_list != NULL)
451 guint i;
452 macros_t *macros;
453 for (i = 0; i < macros_list->len; i++)
455 macros = &g_array_index (macros_list, struct macros_t, i);
456 if (macros != NULL && macros->macro != NULL)
457 (void) g_array_free (macros->macro, FALSE);
459 (void) g_array_free (macros_list, TRUE);
462 str_uninit_strings ();
464 if (mc_global.mc_run_mode != MC_RUN_EDITOR)
465 g_free (mc_run_param0);
466 else
468 g_list_foreach ((GList *) mc_run_param0, (GFunc) mcedit_arg_free, NULL);
469 g_list_free ((GList *) mc_run_param0);
471 g_free (mc_run_param1);
473 mc_config_deinit_config_paths ();
475 (void) mc_event_deinit (&error);
476 if (error != NULL)
478 fprintf (stderr, _("\nFailed while close:\n%s\n"), error->message);
479 g_error_free (error);
480 exit_code = EXIT_FAILURE;
483 (void) putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
485 return exit_code;
488 /* --------------------------------------------------------------------------------------------- */