f178bb0621fba39b0f6b8657f86b08b563f53e1b
[midnight-commander.git] / src / execute.c
blobf178bb0621fba39b0f6b8657f86b08b563f53e1b
1 /*
2 Execution routines for GNU Midnight Commander
4 Copyright (C) 2003, 2004, 2005, 2007, 2011
5 The Free Software Foundation, Inc.
7 This file is part of the Midnight Commander.
9 The Midnight Commander is free software: you can redistribute it
10 and/or modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation, either version 3 of the License,
12 or (at your option) any later version.
14 The Midnight Commander 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, see <http://www.gnu.org/licenses/>.
23 /** \file execute.c
24 * \brief Source: execution routines
27 #include <config.h>
29 #include <signal.h>
30 #include <sys/stat.h>
31 #include <sys/time.h>
33 #include "lib/global.h"
35 #include "lib/tty/tty.h"
36 #include "lib/tty/key.h"
37 #include "lib/tty/win.h"
38 #include "lib/vfs/vfs.h"
39 #include "lib/mcconfig.h"
40 #include "lib/util.h"
41 #include "lib/widget.h"
43 #include "filemanager/midnight.h"
44 #include "filemanager/layout.h" /* use_dash() */
45 #include "consaver/cons.saver.h"
46 #ifdef ENABLE_SUBSHELL
47 #include "subshell.h"
48 #endif
49 #include "setup.h" /* clear_before_exec */
51 #include "execute.h"
53 /*** global variables ****************************************************************************/
55 int pause_after_run = pause_on_dumb_terminals;
57 /*** file scope macro definitions ****************************************************************/
59 /*** file scope type declarations ****************************************************************/
61 /*** file scope variables ************************************************************************/
63 /*** file scope functions ************************************************************************/
65 void do_execute (const char *shell, const char *command, int flags);
67 /* --------------------------------------------------------------------------------------------- */
69 static void
70 edition_post_exec (void)
72 do_enter_ca_mode ();
74 /* FIXME: Missing on slang endwin? */
75 tty_reset_prog_mode ();
76 tty_flush_input ();
78 tty_keypad (TRUE);
79 tty_raw_mode ();
80 channels_up ();
81 enable_mouse ();
82 if (mc_global.tty.alternate_plus_minus)
83 application_keypad_mode ();
86 /* --------------------------------------------------------------------------------------------- */
88 static void
89 edition_pre_exec (void)
91 if (clear_before_exec)
92 clr_scr ();
93 else
95 if (!(mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag))
96 printf ("\n\n");
99 channels_down ();
100 disable_mouse ();
102 tty_reset_shell_mode ();
103 tty_keypad (FALSE);
104 tty_reset_screen ();
106 numeric_keypad_mode ();
108 /* on xterms: maybe endwin did not leave the terminal on the shell
109 * screen page: do it now.
111 * Do not move this before endwin: in some systems rmcup includes
112 * a call to clear screen, so it will end up clearing the shell screen.
114 do_exit_ca_mode ();
117 /* --------------------------------------------------------------------------------------------- */
119 #ifdef ENABLE_SUBSHELL
120 static void
121 do_possible_cd (const vfs_path_t * new_dir_vpath)
123 if (!do_cd (new_dir_vpath, cd_exact))
124 message (D_ERROR, _("Warning"),
125 _("The Commander can't change to the directory that\n"
126 "the subshell claims you are in. Perhaps you have\n"
127 "deleted your working directory, or given yourself\n"
128 "extra access permissions with the \"su\" command?"));
130 #endif /* ENABLE_SUBSHELL */
132 /* --------------------------------------------------------------------------------------------- */
134 static void
135 do_suspend_cmd (void)
137 pre_exec ();
139 if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
140 handle_console (CONSOLE_RESTORE);
142 #ifdef SIGTSTP
144 struct sigaction sigtstp_action;
146 /* Make sure that the SIGTSTP below will suspend us directly,
147 without calling ncurses' SIGTSTP handler; we *don't* want
148 ncurses to redraw the screen immediately after the SIGCONT */
149 sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
151 kill (getpid (), SIGTSTP);
153 /* Restore previous SIGTSTP action */
154 sigaction (SIGTSTP, &sigtstp_action, NULL);
156 #endif /* SIGTSTP */
158 if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
159 handle_console (CONSOLE_SAVE);
161 edition_post_exec ();
164 /* --------------------------------------------------------------------------------------------- */
166 static gboolean
167 execute_prepare_with_vfs_arg (const vfs_path_t * filename_vpath, vfs_path_t ** localcopy_vpath, time_t *mtime)
169 struct stat st;
171 /* Simplest case, this file is local */
172 if ((filename_vpath == NULL && vfs_file_is_local (vfs_get_raw_current_dir ()))
173 || vfs_file_is_local (filename_vpath))
174 return TRUE;
176 /* FIXME: Creation of new files on VFS is not supported */
177 if (filename_vpath == NULL)
178 return FALSE;
180 *localcopy_vpath = mc_getlocalcopy (filename_vpath);
181 if (*localcopy_vpath == NULL)
183 char *filename;
185 filename = vfs_path_to_str (filename_vpath);
186 message (D_ERROR, MSG_ERROR, _("Cannot fetch a local copy of %s"), filename);
187 g_free (filename);
188 return FALSE;
191 mc_stat (*localcopy_vpath, &st);
192 *mtime = st.st_mtime;
193 return TRUE;
196 /* --------------------------------------------------------------------------------------------- */
198 static void
199 execute_cleanup_with_vfs_arg (const vfs_path_t * filename_vpath, vfs_path_t ** localcopy_vpath, time_t *mtime)
201 if (*localcopy_vpath != NULL)
203 struct stat st;
206 * filename can be an entry on panel, it can be changed by executing
207 * the command, so make a copy. Smarter VFS code would make the code
208 * below unnecessary.
210 mc_stat (*localcopy_vpath, &st);
211 mc_ungetlocalcopy (filename_vpath, *localcopy_vpath, *mtime != st.st_mtime);
212 vfs_path_free (*localcopy_vpath);
213 *localcopy_vpath = NULL;
217 /* --------------------------------------------------------------------------------------------- */
218 /*** public functions ****************************************************************************/
219 /* --------------------------------------------------------------------------------------------- */
221 void
222 do_execute (const char *shell, const char *command, int flags)
224 #ifdef ENABLE_SUBSHELL
225 vfs_path_t *new_dir_vpath = NULL;
226 #endif /* ENABLE_SUBSHELL */
228 vfs_path_t *old_vfs_dir_vpath = NULL;
230 if (!vfs_current_is_local ())
231 old_vfs_dir_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
233 if (mc_global.mc_run_mode == MC_RUN_FULL)
234 save_cwds_stat ();
235 pre_exec ();
236 if (mc_global.tty.console_flag != '\0')
237 handle_console (CONSOLE_RESTORE);
239 if (!mc_global.tty.use_subshell && command && !(flags & EXECUTE_INTERNAL))
241 printf ("%s%s\n", mc_prompt, command);
242 fflush (stdout);
244 #ifdef ENABLE_SUBSHELL
245 if (mc_global.tty.use_subshell && !(flags & EXECUTE_INTERNAL))
247 do_update_prompt ();
249 /* We don't care if it died, higher level takes care of this */
250 invoke_subshell (command, VISIBLY, old_vfs_dir_vpath != NULL ? NULL : &new_dir_vpath);
252 else
253 #endif /* ENABLE_SUBSHELL */
254 my_system (flags, shell, command);
256 if (!(flags & EXECUTE_INTERNAL))
258 if ((pause_after_run == pause_always
259 || (pause_after_run == pause_on_dumb_terminals && !mc_global.tty.xterm_flag
260 && mc_global.tty.console_flag == '\0')) && quit == 0
261 #ifdef ENABLE_SUBSHELL
262 && subshell_state != RUNNING_COMMAND
263 #endif /* ENABLE_SUBSHELL */
266 printf (_("Press any key to continue..."));
267 fflush (stdout);
268 tty_raw_mode ();
269 get_key_code (0);
270 printf ("\r\n");
271 fflush (stdout);
273 if (mc_global.tty.console_flag != '\0')
275 if (output_lines && mc_global.keybar_visible)
277 putchar ('\n');
278 fflush (stdout);
283 if (mc_global.tty.console_flag != '\0')
284 handle_console (CONSOLE_SAVE);
285 edition_post_exec ();
287 #ifdef ENABLE_SUBSHELL
288 if (new_dir_vpath != NULL)
290 do_possible_cd (new_dir_vpath);
291 vfs_path_free (new_dir_vpath);
294 #endif /* ENABLE_SUBSHELL */
296 if (old_vfs_dir_vpath != NULL)
298 mc_chdir (old_vfs_dir_vpath);
299 vfs_path_free (old_vfs_dir_vpath);
302 if (mc_global.mc_run_mode == MC_RUN_FULL)
304 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
305 update_xterm_title_path ();
308 do_refresh ();
309 use_dash (TRUE);
312 /* --------------------------------------------------------------------------------------------- */
314 /** Set up the terminal before executing a program */
316 void
317 pre_exec (void)
319 use_dash (FALSE);
320 edition_pre_exec ();
323 /* --------------------------------------------------------------------------------------------- */
324 /** Hide the terminal after executing a program */
325 void
326 post_exec (void)
328 edition_post_exec ();
329 use_dash (TRUE);
330 repaint_screen ();
333 /* --------------------------------------------------------------------------------------------- */
334 /* Executes a command */
336 void
337 shell_execute (const char *command, int flags)
339 char *cmd = NULL;
341 if (flags & EXECUTE_HIDE)
343 cmd = g_strconcat (" ", command, (char *) NULL);
344 flags ^= EXECUTE_HIDE;
347 #ifdef ENABLE_SUBSHELL
348 if (mc_global.tty.use_subshell)
349 if (subshell_state == INACTIVE)
350 do_execute (mc_global.tty.shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
351 else
352 message (D_ERROR, MSG_ERROR, _("The shell is already running a command"));
353 else
354 #endif /* ENABLE_SUBSHELL */
355 do_execute (mc_global.tty.shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
357 g_free (cmd);
360 /* --------------------------------------------------------------------------------------------- */
362 void
363 exec_shell (void)
365 do_execute (mc_global.tty.shell, 0, 0);
368 /* --------------------------------------------------------------------------------------------- */
370 void
371 toggle_panels (void)
373 #ifdef ENABLE_SUBSHELL
374 vfs_path_t *new_dir_vpath = NULL;
375 vfs_path_t **new_dir_p;
376 #endif /* ENABLE_SUBSHELL */
378 SIG_ATOMIC_VOLATILE_T was_sigwinch = 0;
380 channels_down ();
381 disable_mouse ();
382 if (clear_before_exec)
383 clr_scr ();
384 if (mc_global.tty.alternate_plus_minus)
385 numeric_keypad_mode ();
386 #ifndef HAVE_SLANG
387 /* With slang we don't want any of this, since there
388 * is no raw_mode supported
390 tty_reset_shell_mode ();
391 #endif /* !HAVE_SLANG */
392 tty_noecho ();
393 tty_keypad (FALSE);
394 tty_reset_screen ();
395 do_exit_ca_mode ();
396 tty_raw_mode ();
397 if (mc_global.tty.console_flag != '\0')
398 handle_console (CONSOLE_RESTORE);
400 #ifdef ENABLE_SUBSHELL
401 if (mc_global.tty.use_subshell)
403 new_dir_p = vfs_current_is_local ()? &new_dir_vpath : NULL;
404 invoke_subshell (NULL, VISIBLY, new_dir_p);
406 else
407 #endif /* ENABLE_SUBSHELL */
409 if (output_starts_shell)
411 fprintf (stderr, _("Type `exit' to return to the Midnight Commander"));
412 fprintf (stderr, "\n\r\n\r");
414 my_system (EXECUTE_INTERNAL, mc_global.tty.shell, NULL);
416 else
417 get_key_code (0);
420 if (mc_global.tty.console_flag != '\0')
421 handle_console (CONSOLE_SAVE);
423 do_enter_ca_mode ();
425 tty_reset_prog_mode ();
426 tty_keypad (TRUE);
428 /* Prevent screen flash when user did 'exit' or 'logout' within
429 subshell */
430 if ((quit & SUBSHELL_EXIT) != 0)
432 /* User did `exit' or `logout': quit MC */
433 if (quiet_quit_cmd ())
434 return;
436 quit = 0;
437 #ifdef ENABLE_SUBSHELL
438 /* restart subshell */
439 if (mc_global.tty.use_subshell)
440 init_subshell ();
441 #endif /* ENABLE_SUBSHELL */
444 enable_mouse ();
445 channels_up ();
446 if (mc_global.tty.alternate_plus_minus)
447 application_keypad_mode ();
449 /* HACK:
450 * Save sigwinch flag that will be reset in mc_refresh() called via update_panels().
451 * There is some problem with screen redraw in ncurses-based mc in this situation.
453 was_sigwinch = mc_global.tty.winch_flag;
454 mc_global.tty.winch_flag = 0;
456 #ifdef ENABLE_SUBSHELL
457 if (mc_global.tty.use_subshell)
459 do_load_prompt ();
460 if (new_dir_vpath != NULL)
461 do_possible_cd (new_dir_vpath);
462 if (mc_global.tty.console_flag != '\0' && output_lines)
463 show_console_contents (output_start_y,
464 LINES - mc_global.keybar_visible - output_lines -
465 1, LINES - mc_global.keybar_visible - 1);
468 vfs_path_free (new_dir_vpath);
469 #endif /* ENABLE_SUBSHELL */
471 if (mc_global.mc_run_mode == MC_RUN_FULL)
473 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
474 update_xterm_title_path ();
477 if (was_sigwinch != 0 || mc_global.tty.winch_flag != 0)
478 dialog_change_screen_size ();
479 else
480 repaint_screen ();
483 /* --------------------------------------------------------------------------------------------- */
485 /* event callback */
486 gboolean
487 execute_suspend (const gchar * event_group_name, const gchar * event_name,
488 gpointer init_data, gpointer data)
490 (void) event_group_name;
491 (void) event_name;
492 (void) init_data;
493 (void) data;
495 if (mc_global.mc_run_mode == MC_RUN_FULL)
496 save_cwds_stat ();
497 do_suspend_cmd ();
498 if (mc_global.mc_run_mode == MC_RUN_FULL)
499 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
500 do_refresh ();
502 return TRUE;
505 /* --------------------------------------------------------------------------------------------- */
508 * Execute command on a filename that can be on VFS.
509 * Errors are reported to the user.
512 void
513 execute_with_vfs_arg (const char *command, const vfs_path_t * filename_vpath)
515 vfs_path_t *localcopy_vpath = NULL;
516 const vfs_path_t *do_execute_vpath;
517 time_t mtime;
519 if (!execute_prepare_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime))
520 return;
522 do_execute_vpath = (localcopy_vpath == NULL) ? filename_vpath : localcopy_vpath;
524 do_execute (command, vfs_path_get_last_path_str (do_execute_vpath), EXECUTE_INTERNAL);
526 execute_cleanup_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime);
529 /* --------------------------------------------------------------------------------------------- */