Ticket #2611: FISH: broken panels drawing after entering password
[midnight-commander.git] / src / execute.c
blob029f9715fa4dc81fc35d3a0202e4bf3c946416e6
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 "lib/global.h"
30 #include "lib/tty/tty.h"
31 #include "lib/tty/key.h"
32 #include "lib/tty/win.h"
33 #include "lib/vfs/mc-vfs/vfs.h"
34 #include "lib/util.h"
35 #include "lib/widget.h"
37 #include "filemanager/midnight.h"
38 #include "filemanager/layout.h" /* use_dash() */
39 #include "consaver/cons.saver.h"
40 #include "subshell.h"
41 #include "setup.h" /* clear_before_exec */
43 #include "execute.h"
45 /*** global variables ****************************************************************************/
47 int pause_after_run = pause_on_dumb_terminals;
49 /*** file scope macro definitions ****************************************************************/
51 /*** file scope type declarations ****************************************************************/
53 /*** file scope variables ************************************************************************/
55 /*** file scope functions ************************************************************************/
56 /* --------------------------------------------------------------------------------------------- */
58 static void
59 edition_post_exec (void)
61 do_enter_ca_mode ();
63 /* FIXME: Missing on slang endwin? */
64 tty_reset_prog_mode ();
65 tty_flush_input ();
67 tty_keypad (TRUE);
68 tty_raw_mode ();
69 channels_up ();
70 enable_mouse ();
71 if (alternate_plus_minus)
72 application_keypad_mode ();
75 /* --------------------------------------------------------------------------------------------- */
77 static void
78 edition_pre_exec (void)
80 if (clear_before_exec)
81 clr_scr ();
82 else
84 if (!(console_flag || xterm_flag))
85 printf ("\n\n");
88 channels_down ();
89 disable_mouse ();
91 tty_reset_shell_mode ();
92 tty_keypad (FALSE);
93 tty_reset_screen ();
95 numeric_keypad_mode ();
97 /* on xterms: maybe endwin did not leave the terminal on the shell
98 * screen page: do it now.
100 * Do not move this before endwin: in some systems rmcup includes
101 * a call to clear screen, so it will end up clearing the shell screen.
103 do_exit_ca_mode ();
106 /* --------------------------------------------------------------------------------------------- */
108 #ifdef HAVE_SUBSHELL_SUPPORT
109 static void
110 do_possible_cd (const char *new_dir)
112 if (!do_cd (new_dir, cd_exact))
113 message (D_ERROR, _("Warning"),
114 _("The Commander can't change to the directory that\n"
115 "the subshell claims you are in. Perhaps you have\n"
116 "deleted your working directory, or given yourself\n"
117 "extra access permissions with the \"su\" command?"));
119 #endif /* HAVE_SUBSHELL_SUPPORT */
121 /* --------------------------------------------------------------------------------------------- */
123 static void
124 do_execute (const char *lc_shell, const char *command, int flags)
126 #ifdef HAVE_SUBSHELL_SUPPORT
127 char *new_dir = NULL;
128 #endif /* HAVE_SUBSHELL_SUPPORT */
130 char *old_vfs_dir = 0;
132 if (!vfs_current_is_local ())
133 old_vfs_dir = g_strdup (vfs_get_current_dir ());
135 if (mc_run_mode == MC_RUN_FULL)
136 save_cwds_stat ();
137 pre_exec ();
138 if (console_flag)
139 handle_console (CONSOLE_RESTORE);
141 if (!use_subshell && command && !(flags & EXECUTE_INTERNAL))
143 printf ("%s%s\n", mc_prompt, command);
144 fflush (stdout);
146 #ifdef HAVE_SUBSHELL_SUPPORT
147 if (use_subshell && !(flags & EXECUTE_INTERNAL))
149 do_update_prompt ();
151 /* We don't care if it died, higher level takes care of this */
152 invoke_subshell (command, VISIBLY, old_vfs_dir ? NULL : &new_dir);
154 else
155 #endif /* HAVE_SUBSHELL_SUPPORT */
156 my_system (flags, lc_shell, command);
158 if (!(flags & EXECUTE_INTERNAL))
160 if ((pause_after_run == pause_always
161 || (pause_after_run == pause_on_dumb_terminals && !xterm_flag
162 && !console_flag)) && quit == 0
163 #ifdef HAVE_SUBSHELL_SUPPORT
164 && subshell_state != RUNNING_COMMAND
165 #endif /* HAVE_SUBSHELL_SUPPORT */
168 printf (_("Press any key to continue..."));
169 fflush (stdout);
170 tty_raw_mode ();
171 get_key_code (0);
172 printf ("\r\n");
173 fflush (stdout);
175 if (console_flag)
177 if (output_lines && keybar_visible)
179 putchar ('\n');
180 fflush (stdout);
185 if (console_flag)
186 handle_console (CONSOLE_SAVE);
187 edition_post_exec ();
189 #ifdef HAVE_SUBSHELL_SUPPORT
190 if (new_dir)
191 do_possible_cd (new_dir);
193 #endif /* HAVE_SUBSHELL_SUPPORT */
195 if (old_vfs_dir)
197 mc_chdir (old_vfs_dir);
198 g_free (old_vfs_dir);
201 if (mc_run_mode == MC_RUN_FULL)
203 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
204 update_xterm_title_path ();
207 do_refresh ();
208 use_dash (TRUE);
211 /* --------------------------------------------------------------------------------------------- */
213 static void
214 do_suspend_cmd (void)
216 pre_exec ();
218 if (console_flag && !use_subshell)
219 handle_console (CONSOLE_RESTORE);
221 #ifdef SIGTSTP
223 struct sigaction sigtstp_action;
225 /* Make sure that the SIGTSTP below will suspend us directly,
226 without calling ncurses' SIGTSTP handler; we *don't* want
227 ncurses to redraw the screen immediately after the SIGCONT */
228 sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
230 kill (getpid (), SIGTSTP);
232 /* Restore previous SIGTSTP action */
233 sigaction (SIGTSTP, &sigtstp_action, NULL);
235 #endif /* SIGTSTP */
237 if (console_flag && !use_subshell)
238 handle_console (CONSOLE_SAVE);
240 edition_post_exec ();
243 /* --------------------------------------------------------------------------------------------- */
244 /*** public functions ****************************************************************************/
245 /* --------------------------------------------------------------------------------------------- */
247 /** Set up the terminal before executing a program */
249 void
250 pre_exec (void)
252 use_dash (FALSE);
253 edition_pre_exec ();
256 /* --------------------------------------------------------------------------------------------- */
257 /** Hide the terminal after executing a program */
258 void
259 post_exec (void)
261 edition_post_exec ();
262 use_dash (TRUE);
263 repaint_screen ();
266 /* --------------------------------------------------------------------------------------------- */
267 /* Executes a command */
269 void
270 shell_execute (const char *command, int flags)
272 char *cmd = NULL;
274 if (flags & EXECUTE_HIDE)
276 cmd = g_strconcat (" ", command, (char *) NULL);
277 flags ^= EXECUTE_HIDE;
280 #ifdef HAVE_SUBSHELL_SUPPORT
281 if (use_subshell)
282 if (subshell_state == INACTIVE)
283 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
284 else
285 message (D_ERROR, MSG_ERROR, _("The shell is already running a command"));
286 else
287 #endif /* HAVE_SUBSHELL_SUPPORT */
288 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
290 g_free (cmd);
293 /* --------------------------------------------------------------------------------------------- */
295 void
296 exec_shell (void)
298 do_execute (shell, 0, 0);
301 /* --------------------------------------------------------------------------------------------- */
303 void
304 toggle_panels (void)
306 #ifdef HAVE_SUBSHELL_SUPPORT
307 char *new_dir = NULL;
308 char **new_dir_p;
309 #endif /* HAVE_SUBSHELL_SUPPORT */
311 channels_down ();
312 disable_mouse ();
313 if (clear_before_exec)
314 clr_scr ();
315 if (alternate_plus_minus)
316 numeric_keypad_mode ();
317 #ifndef HAVE_SLANG
318 /* With slang we don't want any of this, since there
319 * is no raw_mode supported
321 tty_reset_shell_mode ();
322 #endif /* !HAVE_SLANG */
323 tty_noecho ();
324 tty_keypad (FALSE);
325 tty_reset_screen ();
326 do_exit_ca_mode ();
327 tty_raw_mode ();
328 if (console_flag)
329 handle_console (CONSOLE_RESTORE);
331 #ifdef HAVE_SUBSHELL_SUPPORT
332 if (use_subshell)
334 new_dir_p = vfs_current_is_local ()? &new_dir : NULL;
335 invoke_subshell (NULL, VISIBLY, new_dir_p);
337 else
338 #endif /* HAVE_SUBSHELL_SUPPORT */
340 if (output_starts_shell)
342 fprintf (stderr, _("Type `exit' to return to the Midnight Commander"));
343 fprintf (stderr, "\n\r\n\r");
345 my_system (EXECUTE_INTERNAL, shell, NULL);
347 else
348 get_key_code (0);
351 if (console_flag)
352 handle_console (CONSOLE_SAVE);
354 do_enter_ca_mode ();
356 tty_reset_prog_mode ();
357 tty_keypad (TRUE);
359 /* Prevent screen flash when user did 'exit' or 'logout' within
360 subshell */
361 if ((quit & SUBSHELL_EXIT) != 0)
363 /* User did `exit' or `logout': quit MC */
364 if (quiet_quit_cmd ())
365 return;
367 quit = 0;
368 #ifdef HAVE_SUBSHELL_SUPPORT
369 /* restart subshell */
370 if (use_subshell)
371 init_subshell ();
372 #endif /* HAVE_SUBSHELL_SUPPORT */
375 enable_mouse ();
376 channels_up ();
377 if (alternate_plus_minus)
378 application_keypad_mode ();
380 #ifdef HAVE_SUBSHELL_SUPPORT
381 if (use_subshell)
383 load_prompt (0, NULL);
384 if (new_dir)
385 do_possible_cd (new_dir);
386 if (console_flag && output_lines)
387 show_console_contents (output_start_y,
388 LINES - keybar_visible - output_lines -
389 1, LINES - keybar_visible - 1);
391 #endif /* HAVE_SUBSHELL_SUPPORT */
393 if (mc_run_mode == MC_RUN_FULL)
395 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
396 update_xterm_title_path ();
398 repaint_screen ();
401 /* --------------------------------------------------------------------------------------------- */
403 void
404 suspend_cmd (void)
406 if (mc_run_mode == MC_RUN_FULL)
407 save_cwds_stat ();
408 do_suspend_cmd ();
409 if (mc_run_mode == MC_RUN_FULL)
410 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
411 do_refresh ();
414 /* --------------------------------------------------------------------------------------------- */
416 * Execute command on a filename that can be on VFS.
417 * Errors are reported to the user.
420 void
421 execute_with_vfs_arg (const char *command, const char *filename)
423 char *localcopy;
424 char *fn;
425 struct stat st;
426 time_t mtime;
428 /* Simplest case, this file is local */
429 if (!filename || vfs_file_is_local (filename))
431 fn = vfs_canon_and_translate (filename);
432 do_execute (command, fn, EXECUTE_INTERNAL);
433 g_free (fn);
434 return;
437 /* FIXME: Creation of new files on VFS is not supported */
438 if (!*filename)
439 return;
441 localcopy = mc_getlocalcopy (filename);
442 if (localcopy == NULL)
444 message (D_ERROR, MSG_ERROR, _("Cannot fetch a local copy of %s"), filename);
445 return;
449 * filename can be an entry on panel, it can be changed by executing
450 * the command, so make a copy. Smarter VFS code would make the code
451 * below unnecessary.
453 fn = g_strdup (filename);
454 mc_stat (localcopy, &st);
455 mtime = st.st_mtime;
456 do_execute (command, localcopy, EXECUTE_INTERNAL);
457 mc_stat (localcopy, &st);
458 mc_ungetlocalcopy (fn, localcopy, mtime != st.st_mtime);
459 g_free (localcopy);
460 g_free (fn);
463 /* --------------------------------------------------------------------------------------------- */