(make_fullname): removed. Use mc_build_filename() instead.
[midnight-commander.git] / src / main.c
blob5f548c71f32dc68789f978b4152710870fdf6dcc
1 /* Main program for the Midnight Commander
2 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
3 2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
5 Written by: 1994, 1995, 1996, 1997 Miguel de Icaza
6 1994, 1995 Janne Kukonlehto
7 1997 Norbert Warmuth
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
23 /** \file main.c
24 * \brief Source: this is a main module
27 #include <config.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #include <locale.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/wait.h>
39 #include <unistd.h>
40 #include <pwd.h> /* for username in xterm title */
42 #include "lib/global.h"
44 #include "lib/event.h"
45 #include "lib/tty/tty.h"
46 #include "lib/tty/key.h" /* For init_key() */
47 #include "lib/tty/win.h" /* xterm_flag */
48 #include "lib/skin.h"
49 #include "lib/filehighlight.h"
50 #include "lib/fileloc.h"
51 #include "lib/strutil.h"
52 #include "lib/util.h"
53 #include "lib/vfs/vfs.h" /* vfs_init(), vfs_shut() */
55 #include "filemanager/midnight.h" /* current_panel */
56 #include "filemanager/treestore.h" /* tree_store_save */
57 #include "filemanager/layout.h" /* command_prompt */
58 #include "filemanager/ext.h" /* flush_extension_file() */
59 #include "filemanager/command.h" /* cmdline */
61 #include "vfs/plugins_init.h"
63 #include "events_init.h"
64 #include "args.h"
65 #include "subshell.h"
66 #include "setup.h" /* load_setup() */
68 #ifdef HAVE_CHARSET
69 #include "lib/charsets.h"
70 #include "selcodepage.h"
71 #endif /* HAVE_CHARSET */
73 #include "consaver/cons.saver.h" /* cons_saver_pid */
75 #include "main.h"
77 /*** global variables ****************************************************************************/
79 mc_fhl_t *mc_filehighlight;
81 /* Set when main loop should be terminated */
82 int quit = 0;
84 #ifdef HAVE_CHARSET
85 /* Numbers of (file I/O) and (input/display) codepages. -1 if not selected */
86 int default_source_codepage = -1;
87 char *autodetect_codeset = NULL;
88 gboolean is_autodetect_codeset_enabled = FALSE;
89 #endif /* !HAVE_CHARSET */
91 /* If true use the internal viewer */
92 int use_internal_view = 1;
93 /* If set, use the builtin editor */
94 int use_internal_edit = 1;
96 char *mc_run_param0 = NULL;
97 char *mc_run_param1 = NULL;
99 /* The user's shell */
100 char *shell = NULL;
102 /* The prompt */
103 const char *mc_prompt = NULL;
105 /* Set to TRUE to suppress printing the last directory */
106 int print_last_revert = FALSE;
108 /* If set, then print to the given file the last directory we were at */
109 char *last_wd_string = NULL;
111 /* index to record_macro_buf[], -1 if not recording a macro */
112 int macro_index = -1;
114 GArray *macros_list;
116 /*** file scope macro definitions ****************************************************************/
118 /*** file scope type declarations ****************************************************************/
120 /*** file scope variables ************************************************************************/
122 /*** file scope functions ************************************************************************/
123 /* --------------------------------------------------------------------------------------------- */
125 static void
126 check_codeset (void)
128 const char *current_system_codepage = NULL;
130 current_system_codepage = str_detect_termencoding ();
132 #ifdef HAVE_CHARSET
134 const char *_display_codepage;
136 _display_codepage = get_codepage_id (mc_global.display_codepage);
138 if (strcmp (_display_codepage, current_system_codepage) != 0)
140 mc_global.display_codepage = get_codepage_index (current_system_codepage);
141 if (mc_global.display_codepage == -1)
142 mc_global.display_codepage = 0;
144 mc_config_set_string (mc_main_config, "Misc", "display_codepage", cp_display);
147 #endif
149 mc_global.utf8_display = str_isutf8 (current_system_codepage);
152 /* --------------------------------------------------------------------------------------------- */
154 /** POSIX version. The only version we support. */
155 static void
156 OS_Setup (void)
158 const char *shell_env = getenv ("SHELL");
160 if ((shell_env == NULL) || (shell_env[0] == '\0'))
162 struct passwd *pwd;
163 pwd = getpwuid (geteuid ());
164 if (pwd != NULL)
165 shell = g_strdup (pwd->pw_shell);
167 else
168 shell = g_strdup (shell_env);
170 if ((shell == NULL) || (shell[0] == '\0'))
172 g_free (shell);
173 shell = g_strdup ("/bin/sh");
177 /* --------------------------------------------------------------------------------------------- */
179 static void
180 sigchld_handler_no_subshell (int sig)
182 #ifdef __linux__
183 int pid, status;
185 if (!mc_global.tty.console_flag)
186 return;
188 /* COMMENT: if it were true that after the call to handle_console(..INIT)
189 the value of mc_global.tty.console_flag never changed, we could simply not install
190 this handler at all if (!mc_global.tty.console_flag && !mc_global.tty.use_subshell). */
192 /* That comment is no longer true. We need to wait() on a sigchld
193 handler (that's at least what the tarfs code expects currently). */
195 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
197 if (pid == cons_saver_pid)
200 if (WIFSTOPPED (status))
202 /* Someone has stopped cons.saver - restart it */
203 kill (pid, SIGCONT);
205 else
207 /* cons.saver has died - disable console saving */
208 handle_console (CONSOLE_DONE);
209 mc_global.tty.console_flag = '\0';
212 /* If we got here, some other child exited; ignore it */
213 #endif /* __linux__ */
215 (void) sig;
218 /* --------------------------------------------------------------------------------------------- */
220 static void
221 init_sigchld (void)
223 struct sigaction sigchld_action;
225 sigchld_action.sa_handler =
226 #ifdef HAVE_SUBSHELL_SUPPORT
227 mc_global.tty.use_subshell ? sigchld_handler :
228 #endif /* HAVE_SUBSHELL_SUPPORT */
229 sigchld_handler_no_subshell;
231 sigemptyset (&sigchld_action.sa_mask);
233 #ifdef SA_RESTART
234 sigchld_action.sa_flags = SA_RESTART;
235 #else
236 sigchld_action.sa_flags = 0;
237 #endif /* !SA_RESTART */
239 if (sigaction (SIGCHLD, &sigchld_action, NULL) == -1)
241 #ifdef HAVE_SUBSHELL_SUPPORT
243 * This may happen on QNX Neutrino 6, where SA_RESTART
244 * is defined but not implemented. Fallback to no subshell.
246 mc_global.tty.use_subshell = FALSE;
247 #endif /* HAVE_SUBSHELL_SUPPORT */
251 /* --------------------------------------------------------------------------------------------- */
252 /*** public functions ****************************************************************************/
253 /* --------------------------------------------------------------------------------------------- */
256 do_cd (const char *new_dir, enum cd_enum exact)
258 gboolean res;
260 res = do_panel_cd (current_panel, new_dir, exact);
262 #if HAVE_CHARSET
263 if (res)
265 vfs_path_t *vpath = vfs_path_from_str (current_panel->cwd);
266 vfs_path_element_t *path_element = vfs_path_get_by_index (vpath, -1);
268 if (path_element->encoding != NULL)
269 current_panel->codepage = get_codepage_index (path_element->encoding);
270 else
271 current_panel->codepage = SELECT_CHARSET_NO_TRANSLATE;
273 vfs_path_free (vpath);
275 #endif /* HAVE_CHARSET */
277 return res ? 1 : 0;
280 /* --------------------------------------------------------------------------------------------- */
282 #ifdef HAVE_SUBSHELL_SUPPORT
284 load_prompt (int fd, void *unused)
286 (void) fd;
287 (void) unused;
289 if (!read_subshell_prompt ())
290 return 0;
292 /* Don't actually change the prompt if it's invisible */
293 if (((Dlg_head *) top_dlg->data == midnight_dlg) && command_prompt)
295 char *tmp_prompt;
296 int prompt_len;
298 tmp_prompt = strip_ctrl_codes (subshell_prompt);
299 prompt_len = str_term_width1 (tmp_prompt);
301 /* Check for prompts too big */
302 if (COLS > 8 && prompt_len > COLS - 8)
304 prompt_len = COLS - 8;
305 tmp_prompt[prompt_len] = '\0';
307 mc_prompt = tmp_prompt;
308 label_set_text (the_prompt, mc_prompt);
309 input_set_origin ((WInput *) cmdline, prompt_len, COLS - prompt_len);
311 /* since the prompt has changed, and we are called from one of the
312 * tty_get_event channels, the prompt updating does not take place
313 * automatically: force a cursor update and a screen refresh
315 update_cursor (midnight_dlg);
316 mc_refresh ();
318 update_subshell_prompt = TRUE;
319 return 0;
321 #endif /* HAVE_SUBSHELL_SUPPORT */
323 /* --------------------------------------------------------------------------------------------- */
325 /** Show current directory in the xterm title */
326 void
327 update_xterm_title_path (void)
329 /* TODO: share code with midnight_get_title () */
331 const char *path;
332 char host[BUF_TINY];
333 char *p;
334 struct passwd *pw = NULL;
335 char *login = NULL;
336 int res = 0;
338 if (xterm_flag && xterm_title)
340 path = strip_home_and_password (current_panel->cwd);
341 res = gethostname (host, sizeof (host));
342 if (res)
343 { /* On success, res = 0 */
344 host[0] = '\0';
346 else
348 host[sizeof (host) - 1] = '\0';
350 pw = getpwuid (getuid ());
351 if (pw)
353 login = g_strdup_printf ("%s@%s", pw->pw_name, host);
355 else
357 login = g_strdup (host);
359 p = g_strdup_printf ("mc [%s]:%s", login, path);
360 fprintf (stdout, "\33]0;%s\7", str_term_form (p));
361 g_free (login);
362 g_free (p);
363 if (!alternate_plus_minus)
364 numeric_keypad_mode ();
365 fflush (stdout);
369 /* --------------------------------------------------------------------------------------------- */
372 main (int argc, char *argv[])
374 GError *error = NULL;
375 gboolean isInitialized;
377 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
378 setlocale (LC_ALL, "");
379 bindtextdomain ("mc", LOCALEDIR);
380 textdomain ("mc");
382 if (!events_init (&error))
384 fprintf (stderr, _("Failed to run:\n%s\n"), error->message);
385 g_error_free (error);
386 (void) mc_event_deinit (NULL);
387 exit (EXIT_FAILURE);
390 /* Set up temporary directory */
391 mc_tmpdir ();
393 OS_Setup ();
395 str_init_strings (NULL);
397 /* Initialize and create home directories */
398 /* do it after the screen library initialization to show the error message */
399 mc_config_init_config_paths (&error);
401 if (error == NULL && mc_config_deprecated_dir_present ())
402 mc_config_migrate_from_old_place (&error);
404 vfs_init ();
405 vfs_plugins_init ();
406 vfs_setup_work_dir ();
408 if (!mc_args_handle (argc, argv, "mc"))
409 exit (EXIT_FAILURE);
411 /* NOTE: This has to be called before tty_init or whatever routine
412 calls any define_sequence */
413 init_key ();
415 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
416 handle_console (CONSOLE_INIT);
418 #ifdef HAVE_SUBSHELL_SUPPORT
419 /* Don't use subshell when invoked as viewer or editor */
420 if (mc_global.mc_run_mode != MC_RUN_FULL)
421 mc_global.tty.use_subshell = FALSE;
423 if (mc_global.tty.use_subshell)
424 subshell_get_console_attributes ();
425 #endif /* HAVE_SUBSHELL_SUPPORT */
427 /* Install the SIGCHLD handler; must be done before init_subshell() */
428 init_sigchld ();
430 /* We need this, since ncurses endwin () doesn't restore the signals */
431 save_stop_handler ();
433 /* Must be done before init_subshell, to set up the terminal size: */
434 /* FIXME: Should be removed and LINES and COLS computed on subshell */
435 tty_init (mc_global.args.slow_terminal, mc_global.args.ugly_line_drawing);
437 load_setup ();
439 /* start check mc_global.display_codepage and mc_global.source_codepage */
440 check_codeset ();
442 /* Removing this from the X code let's us type C-c */
443 load_key_defs ();
445 load_keymap_defs (!mc_args__nokeymap);
447 macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
449 tty_init_colors (mc_global.args.disable_colors, mc_args__force_colors);
452 GError *error2 = NULL;
453 isInitialized = mc_skin_init (&error2);
454 mc_filehighlight = mc_fhl_new (TRUE);
455 dlg_set_default_colors ();
457 if (!isInitialized)
459 message (D_ERROR, _("Warning"), "%s", error2->message);
460 g_error_free (error2);
461 error2 = NULL;
465 if (error != NULL)
467 message (D_ERROR, _("Warning"), "%s", error->message);
468 g_error_free (error);
469 error = NULL;
473 #ifdef HAVE_SUBSHELL_SUPPORT
474 /* Done here to ensure that the subshell doesn't */
475 /* inherit the file descriptors opened below, etc */
476 if (mc_global.tty.use_subshell)
477 init_subshell ();
479 #endif /* HAVE_SUBSHELL_SUPPORT */
481 /* Also done after init_subshell, to save any shell init file messages */
482 if (mc_global.tty.console_flag)
483 handle_console (CONSOLE_SAVE);
485 if (alternate_plus_minus)
486 application_keypad_mode ();
488 #ifdef HAVE_SUBSHELL_SUPPORT
489 if (mc_global.tty.use_subshell)
491 mc_prompt = strip_ctrl_codes (subshell_prompt);
492 if (mc_prompt == NULL)
493 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
495 else
496 #endif /* HAVE_SUBSHELL_SUPPORT */
497 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
499 /* Program main loop */
500 if (!mc_global.widget.midnight_shutdown)
501 do_nc ();
503 /* Save the tree store */
504 tree_store_save ();
506 free_keymap_defs ();
508 /* Virtual File System shutdown */
509 vfs_shut ();
511 flush_extension_file (); /* does only free memory */
513 mc_fhl_free (&mc_filehighlight);
514 mc_skin_deinit ();
515 tty_colors_done ();
517 tty_shutdown ();
519 done_setup ();
521 if (mc_global.tty.console_flag && (quit & SUBSHELL_EXIT) == 0)
522 handle_console (CONSOLE_RESTORE);
523 if (alternate_plus_minus)
524 numeric_keypad_mode ();
526 signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
528 if (mc_global.tty.console_flag)
529 handle_console (CONSOLE_DONE);
531 if (mc_global.mc_run_mode == MC_RUN_FULL && mc_args__last_wd_file != NULL
532 && last_wd_string != NULL && !print_last_revert)
534 int last_wd_fd;
536 last_wd_fd = open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
537 S_IRUSR | S_IWUSR);
538 if (last_wd_fd != -1)
540 ssize_t ret1;
541 int ret2;
542 ret1 = write (last_wd_fd, last_wd_string, strlen (last_wd_string));
543 ret2 = close (last_wd_fd);
546 g_free (last_wd_string);
548 g_free (shell);
550 done_key ();
552 if (macros_list != NULL)
554 guint i;
555 macros_t *macros;
556 for (i = 0; i < macros_list->len; i++)
558 macros = &g_array_index (macros_list, struct macros_t, i);
559 if (macros != NULL && macros->macro != NULL)
560 g_array_free (macros->macro, FALSE);
562 g_array_free (macros_list, TRUE);
565 str_uninit_strings ();
567 g_free (mc_run_param0);
568 g_free (mc_run_param1);
570 mc_event_deinit (&error);
572 mc_config_deinit_config_paths ();
574 if (error != NULL)
576 fprintf (stderr, _("\nFailed while close:\n%s\n"), error->message);
577 g_error_free (error);
578 exit (EXIT_FAILURE);
581 putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
583 return 0;
586 /* --------------------------------------------------------------------------------------------- */