Merge branch 'DEV_mcview2'
[midnight-commander.git] / src / execute.c
blob2dc41116e9db220c74ce0580fd6cfddc62237a78
1 /* Execution routines for GNU Midnight Commander
2 Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 /** \file execute.c
19 * \brief Source: execution routines
22 #include <config.h>
24 #include <signal.h>
25 #include <sys/stat.h>
26 #include <sys/time.h>
28 #include "global.h"
30 #include "../src/tty/tty.h"
31 #include "../src/tty/key.h"
32 #include "../src/tty/win.h"
34 #include "main.h"
35 #include "cons.saver.h"
36 #include "subshell.h"
37 #include "layout.h"
38 #include "dialog.h"
39 #include "wtools.h"
40 #include "panel.h" /* update_panels() */
41 #include "execute.h"
42 #include "../vfs/vfs.h"
45 static void
46 edition_post_exec (void)
48 do_enter_ca_mode ();
50 /* FIXME: Missing on slang endwin? */
51 tty_reset_prog_mode ();
52 tty_flush_input ();
54 tty_keypad (TRUE);
55 tty_raw_mode ();
56 channels_up ();
57 enable_mouse ();
58 if (alternate_plus_minus)
59 application_keypad_mode ();
63 static void
64 edition_pre_exec (void)
66 if (clear_before_exec)
67 clr_scr ();
68 else {
69 if (!(console_flag || xterm_flag))
70 printf ("\n\n");
73 channels_down ();
74 disable_mouse ();
76 tty_reset_shell_mode ();
77 tty_keypad (FALSE);
78 tty_reset_screen ();
80 numeric_keypad_mode ();
82 /* on xterms: maybe endwin did not leave the terminal on the shell
83 * screen page: do it now.
85 * Do not move this before endwin: in some systems rmcup includes
86 * a call to clear screen, so it will end up clearing the shell screen.
88 do_exit_ca_mode ();
92 /* Set up the terminal before executing a program */
93 static void
94 pre_exec (void)
96 use_dash (0);
97 edition_pre_exec ();
101 #ifdef HAVE_SUBSHELL_SUPPORT
102 static void
103 do_possible_cd (const char *new_dir)
105 if (!do_cd (new_dir, cd_exact))
106 message (D_ERROR, _("Warning"),
107 _(" The Commander can't change to the directory that \n"
108 " the subshell claims you are in. Perhaps you have \n"
109 " deleted your working directory, or given yourself \n"
110 " extra access permissions with the \"su\" command? "));
112 #endif /* HAVE_SUBSHELL_SUPPORT */
114 static void
115 do_execute (const char *shell, const char *command, int flags)
117 #ifdef HAVE_SUBSHELL_SUPPORT
118 char *new_dir = NULL;
119 #endif /* HAVE_SUBSHELL_SUPPORT */
121 #ifdef USE_VFS
122 char *old_vfs_dir = 0;
124 if (!vfs_current_is_local ())
125 old_vfs_dir = g_strdup (vfs_get_current_dir ());
126 #endif /* USE_VFS */
128 save_cwds_stat ();
129 pre_exec ();
130 if (console_flag)
131 handle_console (CONSOLE_RESTORE);
133 if (!use_subshell && command && !(flags & EXECUTE_INTERNAL)) {
134 printf ("%s%s\n", prompt, command);
135 fflush (stdout);
137 #ifdef HAVE_SUBSHELL_SUPPORT
138 if (use_subshell && !(flags & EXECUTE_INTERNAL)) {
139 do_update_prompt ();
141 /* We don't care if it died, higher level takes care of this */
142 #ifdef USE_VFS
143 invoke_subshell (command, VISIBLY, old_vfs_dir ? NULL : &new_dir);
144 #else
145 invoke_subshell (command, VISIBLY, &new_dir);
146 #endif /* !USE_VFS */
147 } else
148 #endif /* HAVE_SUBSHELL_SUPPORT */
149 my_system (flags, shell, command);
151 if (!(flags & EXECUTE_INTERNAL)) {
152 if ((pause_after_run == pause_always
153 || (pause_after_run == pause_on_dumb_terminals && !xterm_flag
154 && !console_flag)) && !quit
155 #ifdef HAVE_SUBSHELL_SUPPORT
156 && subshell_state != RUNNING_COMMAND
157 #endif /* HAVE_SUBSHELL_SUPPORT */
159 printf (_("Press any key to continue..."));
160 fflush (stdout);
161 tty_raw_mode ();
162 get_key_code (0);
163 printf ("\r\n");
164 fflush (stdout);
166 if (console_flag) {
167 if (output_lines && keybar_visible) {
168 putchar ('\n');
169 fflush (stdout);
174 if (console_flag)
175 handle_console (CONSOLE_SAVE);
176 edition_post_exec ();
178 #ifdef HAVE_SUBSHELL_SUPPORT
179 if (new_dir)
180 do_possible_cd (new_dir);
182 #endif /* HAVE_SUBSHELL_SUPPORT */
184 #ifdef USE_VFS
185 if (old_vfs_dir) {
186 mc_chdir (old_vfs_dir);
187 g_free (old_vfs_dir);
189 #endif /* USE_VFS */
191 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
192 update_xterm_title_path ();
194 do_refresh ();
195 use_dash (TRUE);
199 /* Executes a command */
200 void
201 shell_execute (const char *command, int flags)
203 char *cmd = NULL;
205 if (flags & EXECUTE_HIDE) {
206 cmd = g_strconcat (" ", command, (char *) NULL);
207 flags ^= EXECUTE_HIDE;
210 #ifdef HAVE_SUBSHELL_SUPPORT
211 if (use_subshell)
212 if (subshell_state == INACTIVE)
213 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
214 else
215 message (D_ERROR, MSG_ERROR,
216 _(" The shell is already running a command "));
217 else
218 #endif /* HAVE_SUBSHELL_SUPPORT */
219 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
221 g_free (cmd);
225 void
226 exec_shell (void)
228 do_execute (shell, 0, 0);
232 void
233 toggle_panels (void)
235 #ifdef HAVE_SUBSHELL_SUPPORT
236 char *new_dir = NULL;
237 char **new_dir_p;
238 #endif /* HAVE_SUBSHELL_SUPPORT */
240 channels_down ();
241 disable_mouse ();
242 if (clear_before_exec)
243 clr_scr ();
244 if (alternate_plus_minus)
245 numeric_keypad_mode ();
246 #ifndef HAVE_SLANG
247 /* With slang we don't want any of this, since there
248 * is no raw_mode supported
250 tty_reset_shell_mode ();
251 #endif /* !HAVE_SLANG */
252 tty_noecho ();
253 tty_keypad (FALSE);
254 tty_reset_screen ();
255 do_exit_ca_mode ();
256 tty_raw_mode ();
257 if (console_flag)
258 handle_console (CONSOLE_RESTORE);
260 #ifdef HAVE_SUBSHELL_SUPPORT
261 if (use_subshell) {
262 new_dir_p = vfs_current_is_local ()? &new_dir : NULL;
263 if (invoke_subshell (NULL, VISIBLY, new_dir_p))
264 quiet_quit_cmd (); /* User did `exit' or `logout': quit MC quietly */
265 } else
266 #endif /* HAVE_SUBSHELL_SUPPORT */
268 if (output_starts_shell) {
269 fprintf (stderr,
270 _("Type `exit' to return to the Midnight Commander"));
271 fprintf (stderr, "\n\r\n\r");
273 my_system (EXECUTE_INTERNAL, shell, NULL);
274 } else
275 get_key_code (0);
277 if (console_flag)
278 handle_console (CONSOLE_SAVE);
280 do_enter_ca_mode ();
282 tty_reset_prog_mode ();
283 tty_keypad (TRUE);
285 /* Prevent screen flash when user did 'exit' or 'logout' within
286 subshell */
287 if (quit)
288 return;
290 enable_mouse ();
291 channels_up ();
292 if (alternate_plus_minus)
293 application_keypad_mode ();
295 #ifdef HAVE_SUBSHELL_SUPPORT
296 if (use_subshell) {
297 load_prompt (0, 0);
298 if (new_dir)
299 do_possible_cd (new_dir);
300 if (console_flag && output_lines)
301 show_console_contents (output_start_y,
302 LINES - keybar_visible - output_lines -
303 1, LINES - keybar_visible - 1);
305 #endif /* HAVE_SUBSHELL_SUPPORT */
307 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
308 update_xterm_title_path ();
309 repaint_screen ();
313 static void
314 do_suspend_cmd (void)
316 pre_exec ();
318 if (console_flag && !use_subshell)
319 handle_console (CONSOLE_RESTORE);
321 #ifdef SIGTSTP
323 struct sigaction sigtstp_action;
325 /* Make sure that the SIGTSTP below will suspend us directly,
326 without calling ncurses' SIGTSTP handler; we *don't* want
327 ncurses to redraw the screen immediately after the SIGCONT */
328 sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
330 kill (getpid (), SIGTSTP);
332 /* Restore previous SIGTSTP action */
333 sigaction (SIGTSTP, &sigtstp_action, NULL);
335 #endif /* SIGTSTP */
337 if (console_flag && !use_subshell)
338 handle_console (CONSOLE_SAVE);
340 edition_post_exec ();
344 void
345 suspend_cmd (void)
347 save_cwds_stat ();
348 do_suspend_cmd ();
349 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
350 do_refresh ();
355 * Execute command on a filename that can be on VFS.
356 * Errors are reported to the user.
358 void
359 execute_with_vfs_arg (const char *command, const char *filename)
361 char *localcopy;
362 char *fn;
363 struct stat st;
364 time_t mtime;
366 /* Simplest case, this file is local */
367 if (!filename || vfs_file_is_local (filename)) {
368 fn = vfs_canon_and_translate (filename);
369 do_execute (command, fn, EXECUTE_INTERNAL);
370 g_free (fn);
371 return;
374 /* FIXME: Creation of new files on VFS is not supported */
375 if (!*filename)
376 return;
378 localcopy = mc_getlocalcopy (filename);
379 if (localcopy == NULL) {
380 message (D_ERROR, MSG_ERROR, _(" Cannot fetch a local copy of %s "),
381 filename);
382 return;
386 * filename can be an entry on panel, it can be changed by executing
387 * the command, so make a copy. Smarter VFS code would make the code
388 * below unnecessary.
390 fn = g_strdup (filename);
391 mc_stat (localcopy, &st);
392 mtime = st.st_mtime;
393 do_execute (command, localcopy, EXECUTE_INTERNAL);
394 mc_stat (localcopy, &st);
395 mc_ungetlocalcopy (fn, localcopy, mtime != st.st_mtime);
396 g_free (localcopy);
397 g_free (fn);