Merge branch '2509_diff_quick_move'
[homework-seath.git] / src / main.c
blobc54d82db0389548328de34322c0b9c5ef895d6dc
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/tty/tty.h"
45 #include "lib/tty/key.h" /* For init_key() */
46 #include "lib/tty/win.h" /* xterm_flag */
47 #include "lib/skin.h"
48 #include "lib/filehighlight.h"
49 #include "lib/fileloc.h"
50 #include "lib/strutil.h"
51 #include "lib/util.h"
52 #include "lib/vfs/mc-vfs/vfs.h" /* vfs_init(), vfs_shut() */
54 #include "filemanager/midnight.h" /* current_panel */
55 #include "filemanager/treestore.h" /* tree_store_save */
56 #include "filemanager/layout.h" /* command_prompt */
57 #include "filemanager/ext.h" /* flush_extension_file() */
58 #include "filemanager/command.h" /* cmdline */
60 #include "args.h"
61 #include "subshell.h"
62 #include "setup.h" /* load_setup() */
64 #ifdef HAVE_CHARSET
65 #include "lib/charsets.h"
66 #include "selcodepage.h"
67 #endif /* HAVE_CHARSET */
69 #include "consaver/cons.saver.h" /* console_flag */
71 #include "main.h"
73 /*** global variables ****************************************************************************/
75 mc_fhl_t *mc_filehighlight;
77 /* Set when main loop should be terminated */
78 int quit = 0;
80 #ifdef HAVE_CHARSET
81 /* Numbers of (file I/O) and (input/display) codepages. -1 if not selected */
82 int source_codepage = -1;
83 int default_source_codepage = -1;
84 int display_codepage = -1;
85 char *autodetect_codeset = NULL;
86 gboolean is_autodetect_codeset_enabled = FALSE;
87 #else
88 /* If true, allow characters in the range 160-255 */
89 int eight_bit_clean = 1;
91 * If true, also allow characters in the range 128-159.
92 * This is reported to break on many terminals (xterm, qansi-m).
94 int full_eight_bits = 0;
95 #endif /* !HAVE_CHARSET */
98 * If utf-8 terminal utf8_display = 1
99 * Display bits set UTF-8
101 int utf8_display = 0;
103 /* If true use the internal viewer */
104 int use_internal_view = 1;
105 /* If set, use the builtin editor */
106 int use_internal_edit = 1;
108 mc_run_mode_t mc_run_mode = MC_RUN_FULL;
109 char *mc_run_param0 = NULL;
110 char *mc_run_param1 = NULL;
112 /* Used so that widgets know if they are being destroyed or
113 shut down */
114 int midnight_shutdown = 0;
116 /* The user's shell */
117 char *shell = NULL;
119 /* The prompt */
120 const char *mc_prompt = NULL;
122 /* mc_sysconfig_dir: Area for default settings from maintainers of distributuves
123 default is /etc/mc or may be defined by MC_DATADIR
125 char *mc_sysconfig_dir = NULL;
127 /* mc_share_data_dir: Area for default settings from developers */
128 char *mc_share_data_dir = NULL;
130 /* Set to TRUE to suppress printing the last directory */
131 int print_last_revert = FALSE;
133 /* If set, then print to the given file the last directory we were at */
134 char *last_wd_string = NULL;
136 /*** file scope macro definitions ****************************************************************/
138 /*** file scope type declarations ****************************************************************/
140 /*** file scope variables ************************************************************************/
142 /*** file scope functions ************************************************************************/
143 /* --------------------------------------------------------------------------------------------- */
145 static void
146 check_codeset (void)
148 const char *current_system_codepage = NULL;
150 current_system_codepage = str_detect_termencoding ();
152 #ifdef HAVE_CHARSET
154 const char *_display_codepage;
156 _display_codepage = get_codepage_id (display_codepage);
158 if (strcmp (_display_codepage, current_system_codepage) != 0)
160 display_codepage = get_codepage_index (current_system_codepage);
161 if (display_codepage == -1)
162 display_codepage = 0;
164 mc_config_set_string (mc_main_config, "Misc", "display_codepage", cp_display);
167 #endif
169 utf8_display = str_isutf8 (current_system_codepage);
172 /* --------------------------------------------------------------------------------------------- */
174 /** POSIX version. The only version we support. */
175 static void
176 OS_Setup (void)
178 const char *shell_env = getenv ("SHELL");
179 const char *mc_libdir;
181 if ((shell_env == NULL) || (shell_env[0] == '\0'))
183 struct passwd *pwd;
184 pwd = getpwuid (geteuid ());
185 if (pwd != NULL)
186 shell = g_strdup (pwd->pw_shell);
188 else
189 shell = g_strdup (shell_env);
191 if ((shell == NULL) || (shell[0] == '\0'))
193 g_free (shell);
194 shell = g_strdup ("/bin/sh");
197 /* This is the directory, where MC was installed, on Unix this is DATADIR */
198 /* and can be overriden by the MC_DATADIR environment variable */
199 mc_libdir = getenv ("MC_DATADIR");
200 if (mc_libdir != NULL)
202 mc_sysconfig_dir = g_strdup (mc_libdir);
203 mc_share_data_dir = g_strdup (SYSCONFDIR);
205 else
207 mc_sysconfig_dir = g_strdup (SYSCONFDIR);
208 mc_share_data_dir = g_strdup (DATADIR);
213 /* --------------------------------------------------------------------------------------------- */
215 static void
216 sigchld_handler_no_subshell (int sig)
218 #ifdef __linux__
219 int pid, status;
221 if (!console_flag)
222 return;
224 /* COMMENT: if it were true that after the call to handle_console(..INIT)
225 the value of console_flag never changed, we could simply not install
226 this handler at all if (!console_flag && !use_subshell). */
228 /* That comment is no longer true. We need to wait() on a sigchld
229 handler (that's at least what the tarfs code expects currently). */
231 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
233 if (pid == cons_saver_pid)
236 if (WIFSTOPPED (status))
238 /* Someone has stopped cons.saver - restart it */
239 kill (pid, SIGCONT);
241 else
243 /* cons.saver has died - disable console saving */
244 handle_console (CONSOLE_DONE);
245 console_flag = 0;
248 /* If we got here, some other child exited; ignore it */
249 #endif /* __linux__ */
251 (void) sig;
254 /* --------------------------------------------------------------------------------------------- */
256 static void
257 init_sigchld (void)
259 struct sigaction sigchld_action;
261 sigchld_action.sa_handler =
262 #ifdef HAVE_SUBSHELL_SUPPORT
263 use_subshell ? sigchld_handler :
264 #endif /* HAVE_SUBSHELL_SUPPORT */
265 sigchld_handler_no_subshell;
267 sigemptyset (&sigchld_action.sa_mask);
269 #ifdef SA_RESTART
270 sigchld_action.sa_flags = SA_RESTART;
271 #else
272 sigchld_action.sa_flags = 0;
273 #endif /* !SA_RESTART */
275 if (sigaction (SIGCHLD, &sigchld_action, NULL) == -1)
277 #ifdef HAVE_SUBSHELL_SUPPORT
279 * This may happen on QNX Neutrino 6, where SA_RESTART
280 * is defined but not implemented. Fallback to no subshell.
282 use_subshell = 0;
283 #endif /* HAVE_SUBSHELL_SUPPORT */
287 /* --------------------------------------------------------------------------------------------- */
288 /*** public functions ****************************************************************************/
289 /* --------------------------------------------------------------------------------------------- */
291 /** Define this function for glib-style error handling */
292 GQuark
293 mc_main_error_quark (void)
295 return g_quark_from_static_string (PACKAGE);
298 /* --------------------------------------------------------------------------------------------- */
301 do_cd (const char *new_dir, enum cd_enum exact)
303 gboolean res;
305 res = do_panel_cd (current_panel, new_dir, exact);
307 #if HAVE_CHARSET
308 if (res)
310 const char *enc_name;
312 enc_name = vfs_get_encoding (current_panel->cwd);
313 if (enc_name != NULL)
314 current_panel->codepage = get_codepage_index (enc_name);
315 else
316 current_panel->codepage = SELECT_CHARSET_NO_TRANSLATE;
318 #endif /* HAVE_CHARSET */
320 return res ? 1 : 0;
323 /* --------------------------------------------------------------------------------------------- */
325 #ifdef HAVE_SUBSHELL_SUPPORT
327 load_prompt (int fd, void *unused)
329 (void) fd;
330 (void) unused;
332 if (!read_subshell_prompt ())
333 return 0;
335 /* Don't actually change the prompt if it's invisible */
336 if (((Dlg_head *) top_dlg->data == midnight_dlg) && command_prompt)
338 char *tmp_prompt;
339 int prompt_len;
341 tmp_prompt = strip_ctrl_codes (subshell_prompt);
342 prompt_len = str_term_width1 (tmp_prompt);
344 /* Check for prompts too big */
345 if (COLS > 8 && prompt_len > COLS - 8)
347 prompt_len = COLS - 8;
348 tmp_prompt[prompt_len] = '\0';
350 mc_prompt = tmp_prompt;
351 label_set_text (the_prompt, mc_prompt);
352 input_set_origin ((WInput *) cmdline, prompt_len, COLS - prompt_len);
354 /* since the prompt has changed, and we are called from one of the
355 * tty_get_event channels, the prompt updating does not take place
356 * automatically: force a cursor update and a screen refresh
358 update_cursor (midnight_dlg);
359 mc_refresh ();
361 update_subshell_prompt = TRUE;
362 return 0;
364 #endif /* HAVE_SUBSHELL_SUPPORT */
366 /* --------------------------------------------------------------------------------------------- */
368 /** Show current directory in the xterm title */
369 void
370 update_xterm_title_path (void)
372 /* TODO: share code with midnight_get_title () */
374 const char *path;
375 char host[BUF_TINY];
376 char *p;
377 struct passwd *pw = NULL;
378 char *login = NULL;
379 int res = 0;
381 if (xterm_flag && xterm_title)
383 path = strip_home_and_password (current_panel->cwd);
384 res = gethostname (host, sizeof (host));
385 if (res)
386 { /* On success, res = 0 */
387 host[0] = '\0';
389 else
391 host[sizeof (host) - 1] = '\0';
393 pw = getpwuid (getuid ());
394 if (pw)
396 login = g_strdup_printf ("%s@%s", pw->pw_name, host);
398 else
400 login = g_strdup (host);
402 p = g_strdup_printf ("mc [%s]:%s", login, path);
403 fprintf (stdout, "\33]0;%s\7", str_term_form (p));
404 g_free (login);
405 g_free (p);
406 if (!alternate_plus_minus)
407 numeric_keypad_mode ();
408 fflush (stdout);
412 /* --------------------------------------------------------------------------------------------- */
415 main (int argc, char *argv[])
417 GError *error = NULL;
418 gboolean isInitialized;
420 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
421 setlocale (LC_ALL, "");
422 bindtextdomain ("mc", LOCALEDIR);
423 textdomain ("mc");
426 /* Set up temporary directory */
427 mc_tmpdir ();
429 OS_Setup ();
431 str_init_strings (NULL);
433 vfs_init ();
435 if (!mc_args_handle (argc, argv, "mc"))
436 exit (EXIT_FAILURE);
438 /* NOTE: This has to be called before tty_init or whatever routine
439 calls any define_sequence */
440 init_key ();
442 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
443 handle_console (CONSOLE_INIT);
445 #ifdef HAVE_SUBSHELL_SUPPORT
446 /* Don't use subshell when invoked as viewer or editor */
447 if (mc_run_mode != MC_RUN_FULL)
448 use_subshell = 0;
450 if (use_subshell)
451 subshell_get_console_attributes ();
452 #endif /* HAVE_SUBSHELL_SUPPORT */
454 /* Install the SIGCHLD handler; must be done before init_subshell() */
455 init_sigchld ();
457 /* We need this, since ncurses endwin () doesn't restore the signals */
458 save_stop_handler ();
460 /* Initialize and create home directories */
461 /* do it after the screen library initialization to show the error message */
462 mc_config_init_config_paths (&error);
463 if (error == NULL)
465 if (mc_config_deprecated_dir_present ())
467 mc_config_migrate_from_old_place (&error);
471 /* Must be done before init_subshell, to set up the terminal size: */
472 /* FIXME: Should be removed and LINES and COLS computed on subshell */
473 tty_init ((gboolean) mc_args__slow_terminal, (gboolean) mc_args__ugly_line_drawing);
475 load_setup ();
477 /* start check display_codepage and source_codepage */
478 check_codeset ();
480 /* Removing this from the X code let's us type C-c */
481 load_key_defs ();
483 load_keymap_defs ();
485 tty_init_colors (mc_args__disable_colors, mc_args__force_colors);
488 GError *error2 = NULL;
489 isInitialized = mc_skin_init (&error2);
490 mc_filehighlight = mc_fhl_new (TRUE);
491 dlg_set_default_colors ();
493 if (!isInitialized)
495 message (D_ERROR, _("Warning"), "%s", error2->message);
496 g_error_free (error2);
497 error2 = NULL;
501 if (error != NULL)
503 message (D_ERROR, _("Warning"), "%s", error->message);
504 g_error_free (error);
505 error = NULL;
509 #ifdef HAVE_SUBSHELL_SUPPORT
510 /* Done here to ensure that the subshell doesn't */
511 /* inherit the file descriptors opened below, etc */
512 if (use_subshell)
513 init_subshell ();
515 #endif /* HAVE_SUBSHELL_SUPPORT */
517 /* Also done after init_subshell, to save any shell init file messages */
518 if (console_flag)
519 handle_console (CONSOLE_SAVE);
521 if (alternate_plus_minus)
522 application_keypad_mode ();
524 #ifdef HAVE_SUBSHELL_SUPPORT
525 if (use_subshell)
527 mc_prompt = strip_ctrl_codes (subshell_prompt);
528 if (mc_prompt == NULL)
529 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
531 else
532 #endif /* HAVE_SUBSHELL_SUPPORT */
533 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
535 /* Program main loop */
536 if (!midnight_shutdown)
537 do_nc ();
539 /* Save the tree store */
540 tree_store_save ();
542 free_keymap_defs ();
544 /* Virtual File System shutdown */
545 vfs_shut ();
547 flush_extension_file (); /* does only free memory */
549 mc_fhl_free (&mc_filehighlight);
550 mc_skin_deinit ();
551 tty_colors_done ();
553 tty_shutdown ();
555 done_setup ();
557 if (console_flag && (quit & SUBSHELL_EXIT) == 0)
558 handle_console (CONSOLE_RESTORE);
559 if (alternate_plus_minus)
560 numeric_keypad_mode ();
562 signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
564 if (console_flag)
565 handle_console (CONSOLE_DONE);
567 if (mc_run_mode == MC_RUN_FULL && mc_args__last_wd_file != NULL
568 && last_wd_string != NULL && !print_last_revert)
570 int last_wd_fd;
572 last_wd_fd = open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
573 S_IRUSR | S_IWUSR);
574 if (last_wd_fd != -1)
576 ssize_t ret1;
577 int ret2;
578 ret1 = write (last_wd_fd, last_wd_string, strlen (last_wd_string));
579 ret2 = close (last_wd_fd);
582 g_free (last_wd_string);
584 g_free (mc_share_data_dir);
585 g_free (mc_sysconfig_dir);
586 g_free (shell);
588 done_key ();
590 str_uninit_strings ();
592 g_free (mc_run_param0);
593 g_free (mc_run_param1);
595 mc_config_deinit_config_paths ();
597 putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
599 return 0;
602 /* --------------------------------------------------------------------------------------------- */