Ticket #2451: allow do not variable substite in the command line.
[midnight-commander.git] / src / main.c
blob58a03f681beb0c7ccfb813a7c53f8dec40845a73
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 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;
290 /* --------------------------------------------------------------------------------------------- */
292 #ifdef HAVE_SUBSHELL_SUPPORT
293 gboolean
294 do_load_prompt (void)
296 gboolean ret = FALSE;
298 if (!read_subshell_prompt ())
299 return ret;
301 /* Don't actually change the prompt if it's invisible */
302 if (((Dlg_head *) top_dlg->data == midnight_dlg) && command_prompt)
304 setup_cmdline ();
306 /* since the prompt has changed, and we are called from one of the
307 * tty_get_event channels, the prompt updating does not take place
308 * automatically: force a cursor update and a screen refresh
310 update_cursor (midnight_dlg);
311 mc_refresh ();
312 ret = TRUE;
314 update_subshell_prompt = TRUE;
315 return ret;
318 /* --------------------------------------------------------------------------------------------- */
321 load_prompt (int fd, void *unused)
323 (void) fd;
324 (void) unused;
326 do_load_prompt ();
327 return 0;
329 #endif /* HAVE_SUBSHELL_SUPPORT */
331 /* --------------------------------------------------------------------------------------------- */
333 /** Show current directory in the xterm title */
334 void
335 update_xterm_title_path (void)
337 /* TODO: share code with midnight_get_title () */
339 const char *path;
340 char host[BUF_TINY];
341 char *p;
342 struct passwd *pw = NULL;
343 char *login = NULL;
344 int res = 0;
346 if (mc_global.tty.xterm_flag && xterm_title)
348 path = strip_home_and_password (current_panel->cwd);
349 res = gethostname (host, sizeof (host));
350 if (res)
351 { /* On success, res = 0 */
352 host[0] = '\0';
354 else
356 host[sizeof (host) - 1] = '\0';
358 pw = getpwuid (getuid ());
359 if (pw)
361 login = g_strdup_printf ("%s@%s", pw->pw_name, host);
363 else
365 login = g_strdup (host);
367 p = g_strdup_printf ("mc [%s]:%s", login, path);
368 fprintf (stdout, "\33]0;%s\7", str_term_form (p));
369 g_free (login);
370 g_free (p);
371 if (!mc_global.tty.alternate_plus_minus)
372 numeric_keypad_mode ();
373 (void) fflush (stdout);
377 /* --------------------------------------------------------------------------------------------- */
380 main (int argc, char *argv[])
382 GError *error = NULL;
383 gboolean isInitialized;
385 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
386 (void) setlocale (LC_ALL, "");
387 (void) bindtextdomain ("mc", LOCALEDIR);
388 (void) textdomain ("mc");
390 if (!events_init (&error))
392 fprintf (stderr, _("Failed to run:\n%s\n"), error->message);
393 g_error_free (error);
394 (void) mc_event_deinit (NULL);
395 exit (EXIT_FAILURE);
398 /* Set up temporary directory */
399 (void) mc_tmpdir ();
401 OS_Setup ();
403 str_init_strings (NULL);
405 /* Initialize and create home directories */
406 /* do it after the screen library initialization to show the error message */
407 mc_config_init_config_paths (&error);
409 if (error == NULL && mc_config_deprecated_dir_present ())
410 mc_config_migrate_from_old_place (&error);
412 vfs_init ();
413 vfs_plugins_init ();
414 vfs_setup_work_dir ();
416 if (!mc_args_handle (argc, argv, "mc"))
417 exit (EXIT_FAILURE);
419 /* check terminal type
420 * $TEMR must be set and not empty
421 * mc_global.tty.xterm_flag is used in init_key() and tty_init()
422 * Do this after mc_args_handle() where mc_args__force_xterm is set up.
424 mc_global.tty.xterm_flag = tty_check_term (mc_args__force_xterm);
426 /* NOTE: This has to be called before tty_init or whatever routine
427 calls any define_sequence */
428 init_key ();
430 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
431 handle_console (CONSOLE_INIT);
433 #ifdef HAVE_SUBSHELL_SUPPORT
434 /* Don't use subshell when invoked as viewer or editor */
435 if (mc_global.mc_run_mode != MC_RUN_FULL)
436 mc_global.tty.use_subshell = FALSE;
438 if (mc_global.tty.use_subshell)
439 subshell_get_console_attributes ();
440 #endif /* HAVE_SUBSHELL_SUPPORT */
442 /* Install the SIGCHLD handler; must be done before init_subshell() */
443 init_sigchld ();
445 /* We need this, since ncurses endwin () doesn't restore the signals */
446 save_stop_handler ();
448 /* Must be done before init_subshell, to set up the terminal size: */
449 /* FIXME: Should be removed and LINES and COLS computed on subshell */
450 tty_init (!mc_args__nomouse, mc_global.tty.xterm_flag);
452 load_setup ();
454 /* start check mc_global.display_codepage and mc_global.source_codepage */
455 check_codeset ();
457 /* Removing this from the X code let's us type C-c */
458 load_key_defs ();
460 load_keymap_defs (!mc_args__nokeymap);
462 macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
464 tty_init_colors (mc_global.tty.disable_colors, mc_args__force_colors);
467 GError *error2 = NULL;
468 isInitialized = mc_skin_init (&error2);
469 mc_filehighlight = mc_fhl_new (TRUE);
470 dlg_set_default_colors ();
472 if (!isInitialized)
474 message (D_ERROR, _("Warning"), "%s", error2->message);
475 g_error_free (error2);
476 error2 = NULL;
480 if (error != NULL)
482 message (D_ERROR, _("Warning"), "%s", error->message);
483 g_error_free (error);
484 error = NULL;
488 #ifdef HAVE_SUBSHELL_SUPPORT
489 /* Done here to ensure that the subshell doesn't */
490 /* inherit the file descriptors opened below, etc */
491 if (mc_global.tty.use_subshell)
492 init_subshell ();
494 #endif /* HAVE_SUBSHELL_SUPPORT */
496 /* Also done after init_subshell, to save any shell init file messages */
497 if (mc_global.tty.console_flag != '\0')
498 handle_console (CONSOLE_SAVE);
500 if (mc_global.tty.alternate_plus_minus)
501 application_keypad_mode ();
503 #ifdef HAVE_SUBSHELL_SUPPORT
504 if (mc_global.tty.use_subshell)
506 mc_prompt = strip_ctrl_codes (subshell_prompt);
507 if (mc_prompt == NULL)
508 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
510 else
511 #endif /* HAVE_SUBSHELL_SUPPORT */
512 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
514 /* Program main loop */
515 if (!mc_global.widget.midnight_shutdown)
516 do_nc ();
518 /* Save the tree store */
519 (void) tree_store_save ();
521 free_keymap_defs ();
523 /* Virtual File System shutdown */
524 vfs_shut ();
526 flush_extension_file (); /* does only free memory */
528 mc_fhl_free (&mc_filehighlight);
529 mc_skin_deinit ();
530 tty_colors_done ();
532 tty_shutdown ();
534 done_setup ();
536 if (mc_global.tty.console_flag != '\0' && (quit & SUBSHELL_EXIT) == 0)
537 handle_console (CONSOLE_RESTORE);
538 if (mc_global.tty.alternate_plus_minus)
539 numeric_keypad_mode ();
541 (void) signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
543 if (mc_global.tty.console_flag != '\0')
544 handle_console (CONSOLE_DONE);
546 if (mc_global.mc_run_mode == MC_RUN_FULL && mc_args__last_wd_file != NULL
547 && last_wd_string != NULL && !print_last_revert)
549 int last_wd_fd;
551 last_wd_fd = open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
552 S_IRUSR | S_IWUSR);
553 if (last_wd_fd != -1)
555 ssize_t ret1;
556 int ret2;
557 ret1 = write (last_wd_fd, last_wd_string, strlen (last_wd_string));
558 ret2 = close (last_wd_fd);
561 g_free (last_wd_string);
563 g_free (shell);
565 done_key ();
567 if (macros_list != NULL)
569 guint i;
570 macros_t *macros;
571 for (i = 0; i < macros_list->len; i++)
573 macros = &g_array_index (macros_list, struct macros_t, i);
574 if (macros != NULL && macros->macro != NULL)
575 (void) g_array_free (macros->macro, FALSE);
577 (void) g_array_free (macros_list, TRUE);
580 str_uninit_strings ();
582 g_free (mc_run_param0);
583 g_free (mc_run_param1);
585 (void) mc_event_deinit (&error);
587 mc_config_deinit_config_paths ();
589 if (error != NULL)
591 fprintf (stderr, _("\nFailed while close:\n%s\n"), error->message);
592 g_error_free (error);
593 exit (EXIT_FAILURE);
596 (void) putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
598 return 0;
601 /* --------------------------------------------------------------------------------------------- */