Merge branch '2677_viewer_double_dialog'
[midnight-commander.git] / src / execute.c
blobd3792127d01721d21b2a1c1c3ecdb591e0a5f58d
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/util.h"
40 #include "lib/widget.h"
42 #include "filemanager/midnight.h"
43 #include "filemanager/layout.h" /* use_dash() */
44 #include "consaver/cons.saver.h"
45 #include "subshell.h"
46 #include "setup.h" /* clear_before_exec */
48 #include "execute.h"
50 /*** global variables ****************************************************************************/
52 int pause_after_run = pause_on_dumb_terminals;
54 /*** file scope macro definitions ****************************************************************/
56 /*** file scope type declarations ****************************************************************/
58 /*** file scope variables ************************************************************************/
60 /*** file scope functions ************************************************************************/
61 /* --------------------------------------------------------------------------------------------- */
63 static void
64 edition_post_exec (void)
66 do_enter_ca_mode ();
68 /* FIXME: Missing on slang endwin? */
69 tty_reset_prog_mode ();
70 tty_flush_input ();
72 tty_keypad (TRUE);
73 tty_raw_mode ();
74 channels_up ();
75 enable_mouse ();
76 if (mc_global.tty.alternate_plus_minus)
77 application_keypad_mode ();
80 /* --------------------------------------------------------------------------------------------- */
82 static void
83 edition_pre_exec (void)
85 if (clear_before_exec)
86 clr_scr ();
87 else
89 if (!(mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag))
90 printf ("\n\n");
93 channels_down ();
94 disable_mouse ();
96 tty_reset_shell_mode ();
97 tty_keypad (FALSE);
98 tty_reset_screen ();
100 numeric_keypad_mode ();
102 /* on xterms: maybe endwin did not leave the terminal on the shell
103 * screen page: do it now.
105 * Do not move this before endwin: in some systems rmcup includes
106 * a call to clear screen, so it will end up clearing the shell screen.
108 do_exit_ca_mode ();
111 /* --------------------------------------------------------------------------------------------- */
113 #ifdef HAVE_SUBSHELL_SUPPORT
114 static void
115 do_possible_cd (const char *new_dir)
117 if (!do_cd (new_dir, cd_exact))
118 message (D_ERROR, _("Warning"),
119 _("The Commander can't change to the directory that\n"
120 "the subshell claims you are in. Perhaps you have\n"
121 "deleted your working directory, or given yourself\n"
122 "extra access permissions with the \"su\" command?"));
124 #endif /* HAVE_SUBSHELL_SUPPORT */
126 /* --------------------------------------------------------------------------------------------- */
128 static void
129 do_execute (const char *lc_shell, const char *command, int flags)
131 #ifdef HAVE_SUBSHELL_SUPPORT
132 char *new_dir = NULL;
133 #endif /* HAVE_SUBSHELL_SUPPORT */
135 char *old_vfs_dir = 0;
137 if (!vfs_current_is_local ())
138 old_vfs_dir = vfs_get_current_dir ();
140 if (mc_global.mc_run_mode == MC_RUN_FULL)
141 save_cwds_stat ();
142 pre_exec ();
143 if (mc_global.tty.console_flag != '\0')
144 handle_console (CONSOLE_RESTORE);
146 if (!mc_global.tty.use_subshell && command && !(flags & EXECUTE_INTERNAL))
148 printf ("%s%s\n", mc_prompt, command);
149 fflush (stdout);
151 #ifdef HAVE_SUBSHELL_SUPPORT
152 if (mc_global.tty.use_subshell && !(flags & EXECUTE_INTERNAL))
154 do_update_prompt ();
156 /* We don't care if it died, higher level takes care of this */
157 invoke_subshell (command, VISIBLY, old_vfs_dir ? NULL : &new_dir);
159 else
160 #endif /* HAVE_SUBSHELL_SUPPORT */
161 my_system (flags, lc_shell, command);
163 if (!(flags & EXECUTE_INTERNAL))
165 if ((pause_after_run == pause_always
166 || (pause_after_run == pause_on_dumb_terminals && !mc_global.tty.xterm_flag
167 && mc_global.tty.console_flag == '\0')) && quit == 0
168 #ifdef HAVE_SUBSHELL_SUPPORT
169 && subshell_state != RUNNING_COMMAND
170 #endif /* HAVE_SUBSHELL_SUPPORT */
173 printf (_("Press any key to continue..."));
174 fflush (stdout);
175 tty_raw_mode ();
176 get_key_code (0);
177 printf ("\r\n");
178 fflush (stdout);
180 if (mc_global.tty.console_flag != '\0')
182 if (output_lines && mc_global.keybar_visible)
184 putchar ('\n');
185 fflush (stdout);
190 if (mc_global.tty.console_flag != '\0')
191 handle_console (CONSOLE_SAVE);
192 edition_post_exec ();
194 #ifdef HAVE_SUBSHELL_SUPPORT
195 if (new_dir)
196 do_possible_cd (new_dir);
198 #endif /* HAVE_SUBSHELL_SUPPORT */
200 if (old_vfs_dir)
202 mc_chdir (old_vfs_dir);
203 g_free (old_vfs_dir);
206 if (mc_global.mc_run_mode == MC_RUN_FULL)
208 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
209 update_xterm_title_path ();
212 do_refresh ();
213 use_dash (TRUE);
216 /* --------------------------------------------------------------------------------------------- */
218 static void
219 do_suspend_cmd (void)
221 pre_exec ();
223 if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
224 handle_console (CONSOLE_RESTORE);
226 #ifdef SIGTSTP
228 struct sigaction sigtstp_action;
230 /* Make sure that the SIGTSTP below will suspend us directly,
231 without calling ncurses' SIGTSTP handler; we *don't* want
232 ncurses to redraw the screen immediately after the SIGCONT */
233 sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
235 kill (getpid (), SIGTSTP);
237 /* Restore previous SIGTSTP action */
238 sigaction (SIGTSTP, &sigtstp_action, NULL);
240 #endif /* SIGTSTP */
242 if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
243 handle_console (CONSOLE_SAVE);
245 edition_post_exec ();
248 /* --------------------------------------------------------------------------------------------- */
249 /*** public functions ****************************************************************************/
250 /* --------------------------------------------------------------------------------------------- */
252 /** Set up the terminal before executing a program */
254 void
255 pre_exec (void)
257 use_dash (FALSE);
258 edition_pre_exec ();
261 /* --------------------------------------------------------------------------------------------- */
262 /** Hide the terminal after executing a program */
263 void
264 post_exec (void)
266 edition_post_exec ();
267 use_dash (TRUE);
268 repaint_screen ();
271 /* --------------------------------------------------------------------------------------------- */
272 /* Executes a command */
274 void
275 shell_execute (const char *command, int flags)
277 char *cmd = NULL;
279 if (flags & EXECUTE_HIDE)
281 cmd = g_strconcat (" ", command, (char *) NULL);
282 flags ^= EXECUTE_HIDE;
285 #ifdef HAVE_SUBSHELL_SUPPORT
286 if (mc_global.tty.use_subshell)
287 if (subshell_state == INACTIVE)
288 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
289 else
290 message (D_ERROR, MSG_ERROR, _("The shell is already running a command"));
291 else
292 #endif /* HAVE_SUBSHELL_SUPPORT */
293 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
295 g_free (cmd);
298 /* --------------------------------------------------------------------------------------------- */
300 void
301 exec_shell (void)
303 do_execute (shell, 0, 0);
306 /* --------------------------------------------------------------------------------------------- */
308 void
309 toggle_panels (void)
311 #ifdef HAVE_SUBSHELL_SUPPORT
312 char *new_dir = NULL;
313 char **new_dir_p;
314 #endif /* HAVE_SUBSHELL_SUPPORT */
316 channels_down ();
317 disable_mouse ();
318 if (clear_before_exec)
319 clr_scr ();
320 if (mc_global.tty.alternate_plus_minus)
321 numeric_keypad_mode ();
322 #ifndef HAVE_SLANG
323 /* With slang we don't want any of this, since there
324 * is no raw_mode supported
326 tty_reset_shell_mode ();
327 #endif /* !HAVE_SLANG */
328 tty_noecho ();
329 tty_keypad (FALSE);
330 tty_reset_screen ();
331 do_exit_ca_mode ();
332 tty_raw_mode ();
333 if (mc_global.tty.console_flag != '\0')
334 handle_console (CONSOLE_RESTORE);
336 #ifdef HAVE_SUBSHELL_SUPPORT
337 if (mc_global.tty.use_subshell)
339 new_dir_p = vfs_current_is_local ()? &new_dir : NULL;
340 invoke_subshell (NULL, VISIBLY, new_dir_p);
342 else
343 #endif /* HAVE_SUBSHELL_SUPPORT */
345 if (output_starts_shell)
347 fprintf (stderr, _("Type `exit' to return to the Midnight Commander"));
348 fprintf (stderr, "\n\r\n\r");
350 my_system (EXECUTE_INTERNAL, shell, NULL);
352 else
353 get_key_code (0);
356 if (mc_global.tty.console_flag != '\0')
357 handle_console (CONSOLE_SAVE);
359 do_enter_ca_mode ();
361 tty_reset_prog_mode ();
362 tty_keypad (TRUE);
364 /* Prevent screen flash when user did 'exit' or 'logout' within
365 subshell */
366 if ((quit & SUBSHELL_EXIT) != 0)
368 /* User did `exit' or `logout': quit MC */
369 if (quiet_quit_cmd ())
370 return;
372 quit = 0;
373 #ifdef HAVE_SUBSHELL_SUPPORT
374 /* restart subshell */
375 if (mc_global.tty.use_subshell)
376 init_subshell ();
377 #endif /* HAVE_SUBSHELL_SUPPORT */
380 enable_mouse ();
381 channels_up ();
382 if (mc_global.tty.alternate_plus_minus)
383 application_keypad_mode ();
385 #ifdef HAVE_SUBSHELL_SUPPORT
386 if (mc_global.tty.use_subshell)
388 load_prompt (0, NULL);
389 if (new_dir)
390 do_possible_cd (new_dir);
391 if (mc_global.tty.console_flag != '\0' && output_lines)
392 show_console_contents (output_start_y,
393 LINES - mc_global.keybar_visible - output_lines -
394 1, LINES - mc_global.keybar_visible - 1);
396 #endif /* HAVE_SUBSHELL_SUPPORT */
398 if (mc_global.mc_run_mode == MC_RUN_FULL)
400 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
401 update_xterm_title_path ();
403 repaint_screen ();
406 /* --------------------------------------------------------------------------------------------- */
408 /* event callback */
409 gboolean
410 execute_suspend (const gchar * event_group_name, const gchar * event_name,
411 gpointer init_data, gpointer data)
413 (void) event_group_name;
414 (void) event_name;
415 (void) init_data;
416 (void) data;
418 if (mc_global.mc_run_mode == MC_RUN_FULL)
419 save_cwds_stat ();
420 do_suspend_cmd ();
421 if (mc_global.mc_run_mode == MC_RUN_FULL)
422 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
423 do_refresh ();
425 return TRUE;
428 /* --------------------------------------------------------------------------------------------- */
430 * Execute command on a filename that can be on VFS.
431 * Errors are reported to the user.
434 void
435 execute_with_vfs_arg (const char *command, const char *filename)
437 char *localcopy;
438 char *fn;
439 struct stat st;
440 time_t mtime;
441 vfs_path_t *vpath = vfs_path_from_str (filename);
443 /* Simplest case, this file is local */
444 if (!filename || vfs_file_is_local (vpath))
446 fn = vfs_path_to_str (vpath);
447 do_execute (command, fn, EXECUTE_INTERNAL);
448 g_free (fn);
449 vfs_path_free (vpath);
450 return;
452 vfs_path_free (vpath);
454 /* FIXME: Creation of new files on VFS is not supported */
455 if (!*filename)
456 return;
458 localcopy = mc_getlocalcopy (filename);
459 if (localcopy == NULL)
461 message (D_ERROR, MSG_ERROR, _("Cannot fetch a local copy of %s"), filename);
462 return;
466 * filename can be an entry on panel, it can be changed by executing
467 * the command, so make a copy. Smarter VFS code would make the code
468 * below unnecessary.
470 fn = g_strdup (filename);
471 mc_stat (localcopy, &st);
472 mtime = st.st_mtime;
473 do_execute (command, localcopy, EXECUTE_INTERNAL);
474 mc_stat (localcopy, &st);
475 mc_ungetlocalcopy (fn, localcopy, mtime != st.st_mtime);
476 g_free (localcopy);
477 g_free (fn);
480 /* --------------------------------------------------------------------------------------------- */