Define winch_flag as volatile sig_atomic_t.
[midnight-commander.git] / src / execute.c
blobba1b0c6dd766437f9d12e932305b907426efeb98
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 ************************************************************************/
64 /* --------------------------------------------------------------------------------------------- */
66 static void
67 edition_post_exec (void)
69 do_enter_ca_mode ();
71 /* FIXME: Missing on slang endwin? */
72 tty_reset_prog_mode ();
73 tty_flush_input ();
75 tty_keypad (TRUE);
76 tty_raw_mode ();
77 channels_up ();
78 enable_mouse ();
79 if (mc_global.tty.alternate_plus_minus)
80 application_keypad_mode ();
83 /* --------------------------------------------------------------------------------------------- */
85 static void
86 edition_pre_exec (void)
88 if (clear_before_exec)
89 clr_scr ();
90 else
92 if (!(mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag))
93 printf ("\n\n");
96 channels_down ();
97 disable_mouse ();
99 tty_reset_shell_mode ();
100 tty_keypad (FALSE);
101 tty_reset_screen ();
103 numeric_keypad_mode ();
105 /* on xterms: maybe endwin did not leave the terminal on the shell
106 * screen page: do it now.
108 * Do not move this before endwin: in some systems rmcup includes
109 * a call to clear screen, so it will end up clearing the shell screen.
111 do_exit_ca_mode ();
114 /* --------------------------------------------------------------------------------------------- */
116 #ifdef ENABLE_SUBSHELL
117 static void
118 do_possible_cd (const vfs_path_t * new_dir_vpath)
120 if (!do_cd (new_dir_vpath, cd_exact))
121 message (D_ERROR, _("Warning"),
122 _("The Commander can't change to the directory that\n"
123 "the subshell claims you are in. Perhaps you have\n"
124 "deleted your working directory, or given yourself\n"
125 "extra access permissions with the \"su\" command?"));
127 #endif /* ENABLE_SUBSHELL */
129 /* --------------------------------------------------------------------------------------------- */
131 static void
132 do_execute (const char *lc_shell, const char *command, int flags)
134 #ifdef ENABLE_SUBSHELL
135 vfs_path_t *new_dir_vpath = NULL;
136 #endif /* ENABLE_SUBSHELL */
138 vfs_path_t *old_vfs_dir_vpath = NULL;
140 if (!vfs_current_is_local ())
141 old_vfs_dir_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
143 if (mc_global.mc_run_mode == MC_RUN_FULL)
144 save_cwds_stat ();
145 pre_exec ();
146 if (mc_global.tty.console_flag != '\0')
147 handle_console (CONSOLE_RESTORE);
149 if (!mc_global.tty.use_subshell && command && !(flags & EXECUTE_INTERNAL))
151 printf ("%s%s\n", mc_prompt, command);
152 fflush (stdout);
154 #ifdef ENABLE_SUBSHELL
155 if (mc_global.tty.use_subshell && !(flags & EXECUTE_INTERNAL))
157 do_update_prompt ();
159 /* We don't care if it died, higher level takes care of this */
160 invoke_subshell (command, VISIBLY, old_vfs_dir_vpath != NULL ? NULL : &new_dir_vpath);
162 else
163 #endif /* ENABLE_SUBSHELL */
164 my_system (flags, lc_shell, command);
166 if (!(flags & EXECUTE_INTERNAL))
168 if ((pause_after_run == pause_always
169 || (pause_after_run == pause_on_dumb_terminals && !mc_global.tty.xterm_flag
170 && mc_global.tty.console_flag == '\0')) && quit == 0
171 #ifdef ENABLE_SUBSHELL
172 && subshell_state != RUNNING_COMMAND
173 #endif /* ENABLE_SUBSHELL */
176 printf (_("Press any key to continue..."));
177 fflush (stdout);
178 tty_raw_mode ();
179 get_key_code (0);
180 printf ("\r\n");
181 fflush (stdout);
183 if (mc_global.tty.console_flag != '\0')
185 if (output_lines && mc_global.keybar_visible)
187 putchar ('\n');
188 fflush (stdout);
193 if (mc_global.tty.console_flag != '\0')
194 handle_console (CONSOLE_SAVE);
195 edition_post_exec ();
197 #ifdef ENABLE_SUBSHELL
198 if (new_dir_vpath != NULL)
200 do_possible_cd (new_dir_vpath);
201 vfs_path_free (new_dir_vpath);
204 #endif /* ENABLE_SUBSHELL */
206 if (old_vfs_dir_vpath != NULL)
208 mc_chdir (old_vfs_dir_vpath);
209 vfs_path_free (old_vfs_dir_vpath);
212 if (mc_global.mc_run_mode == MC_RUN_FULL)
214 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
215 update_xterm_title_path ();
218 do_refresh ();
219 use_dash (TRUE);
222 /* --------------------------------------------------------------------------------------------- */
224 static void
225 do_suspend_cmd (void)
227 pre_exec ();
229 if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
230 handle_console (CONSOLE_RESTORE);
232 #ifdef SIGTSTP
234 struct sigaction sigtstp_action;
236 /* Make sure that the SIGTSTP below will suspend us directly,
237 without calling ncurses' SIGTSTP handler; we *don't* want
238 ncurses to redraw the screen immediately after the SIGCONT */
239 sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
241 kill (getpid (), SIGTSTP);
243 /* Restore previous SIGTSTP action */
244 sigaction (SIGTSTP, &sigtstp_action, NULL);
246 #endif /* SIGTSTP */
248 if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
249 handle_console (CONSOLE_SAVE);
251 edition_post_exec ();
254 /* --------------------------------------------------------------------------------------------- */
255 /*** public functions ****************************************************************************/
256 /* --------------------------------------------------------------------------------------------- */
258 /** Set up the terminal before executing a program */
260 void
261 pre_exec (void)
263 use_dash (FALSE);
264 edition_pre_exec ();
267 /* --------------------------------------------------------------------------------------------- */
268 /** Hide the terminal after executing a program */
269 void
270 post_exec (void)
272 edition_post_exec ();
273 use_dash (TRUE);
274 repaint_screen ();
277 /* --------------------------------------------------------------------------------------------- */
278 /* Executes a command */
280 void
281 shell_execute (const char *command, int flags)
283 char *cmd = NULL;
285 if (flags & EXECUTE_HIDE)
287 cmd = g_strconcat (" ", command, (char *) NULL);
288 flags ^= EXECUTE_HIDE;
291 #ifdef ENABLE_SUBSHELL
292 if (mc_global.tty.use_subshell)
293 if (subshell_state == INACTIVE)
294 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
295 else
296 message (D_ERROR, MSG_ERROR, _("The shell is already running a command"));
297 else
298 #endif /* ENABLE_SUBSHELL */
299 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
301 g_free (cmd);
304 /* --------------------------------------------------------------------------------------------- */
306 void
307 exec_shell (void)
309 do_execute (shell, 0, 0);
312 /* --------------------------------------------------------------------------------------------- */
314 void
315 toggle_panels (void)
317 #ifdef ENABLE_SUBSHELL
318 vfs_path_t *new_dir_vpath = NULL;
319 vfs_path_t **new_dir_p;
320 #endif /* ENABLE_SUBSHELL */
322 volatile sig_atomic_t was_sigwinch = 0;
324 channels_down ();
325 disable_mouse ();
326 if (clear_before_exec)
327 clr_scr ();
328 if (mc_global.tty.alternate_plus_minus)
329 numeric_keypad_mode ();
330 #ifndef HAVE_SLANG
331 /* With slang we don't want any of this, since there
332 * is no raw_mode supported
334 tty_reset_shell_mode ();
335 #endif /* !HAVE_SLANG */
336 tty_noecho ();
337 tty_keypad (FALSE);
338 tty_reset_screen ();
339 do_exit_ca_mode ();
340 tty_raw_mode ();
341 if (mc_global.tty.console_flag != '\0')
342 handle_console (CONSOLE_RESTORE);
344 #ifdef ENABLE_SUBSHELL
345 if (mc_global.tty.use_subshell)
347 new_dir_p = vfs_current_is_local ()? &new_dir_vpath : NULL;
348 invoke_subshell (NULL, VISIBLY, new_dir_p);
350 else
351 #endif /* ENABLE_SUBSHELL */
353 if (output_starts_shell)
355 fprintf (stderr, _("Type `exit' to return to the Midnight Commander"));
356 fprintf (stderr, "\n\r\n\r");
358 my_system (EXECUTE_INTERNAL, shell, NULL);
360 else
361 get_key_code (0);
364 if (mc_global.tty.console_flag != '\0')
365 handle_console (CONSOLE_SAVE);
367 do_enter_ca_mode ();
369 tty_reset_prog_mode ();
370 tty_keypad (TRUE);
372 /* Prevent screen flash when user did 'exit' or 'logout' within
373 subshell */
374 if ((quit & SUBSHELL_EXIT) != 0)
376 /* User did `exit' or `logout': quit MC */
377 if (quiet_quit_cmd ())
378 return;
380 quit = 0;
381 #ifdef ENABLE_SUBSHELL
382 /* restart subshell */
383 if (mc_global.tty.use_subshell)
384 init_subshell ();
385 #endif /* ENABLE_SUBSHELL */
388 enable_mouse ();
389 channels_up ();
390 if (mc_global.tty.alternate_plus_minus)
391 application_keypad_mode ();
393 /* HACK:
394 * Save sigwinch flag that will be reset in mc_refresh() called via update_panels().
395 * There is some problem with screen redraw in ncurses-based mc in this situation.
397 was_sigwinch = mc_global.tty.winch_flag;
398 mc_global.tty.winch_flag = 0;
400 #ifdef ENABLE_SUBSHELL
401 if (mc_global.tty.use_subshell)
403 do_load_prompt ();
404 if (new_dir_vpath != NULL)
405 do_possible_cd (new_dir_vpath);
406 if (mc_global.tty.console_flag != '\0' && output_lines)
407 show_console_contents (output_start_y,
408 LINES - mc_global.keybar_visible - output_lines -
409 1, LINES - mc_global.keybar_visible - 1);
412 vfs_path_free (new_dir_vpath);
413 #endif /* ENABLE_SUBSHELL */
415 if (mc_global.mc_run_mode == MC_RUN_FULL)
417 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
418 update_xterm_title_path ();
421 if (was_sigwinch != 0 || mc_global.tty.winch_flag != 0)
422 dialog_change_screen_size ();
423 else
424 repaint_screen ();
427 /* --------------------------------------------------------------------------------------------- */
429 /* event callback */
430 gboolean
431 execute_suspend (const gchar * event_group_name, const gchar * event_name,
432 gpointer init_data, gpointer data)
434 (void) event_group_name;
435 (void) event_name;
436 (void) init_data;
437 (void) data;
439 if (mc_global.mc_run_mode == MC_RUN_FULL)
440 save_cwds_stat ();
441 do_suspend_cmd ();
442 if (mc_global.mc_run_mode == MC_RUN_FULL)
443 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
444 do_refresh ();
446 return TRUE;
449 /* --------------------------------------------------------------------------------------------- */
451 * Execute command on a filename that can be on VFS.
452 * Errors are reported to the user.
455 void
456 execute_with_vfs_arg (const char *command, const vfs_path_t * filename_vpath)
458 struct stat st;
459 time_t mtime;
460 vfs_path_t *localcopy_vpath;
462 /* Simplest case, this file is local */
463 if (filename_vpath == NULL || vfs_file_is_local (filename_vpath))
465 do_execute (command, vfs_path_get_last_path_str (filename_vpath), EXECUTE_INTERNAL);
466 return;
469 /* FIXME: Creation of new files on VFS is not supported */
470 if (vfs_path_len (filename_vpath) == 0)
471 return;
473 localcopy_vpath = mc_getlocalcopy (filename_vpath);
474 if (localcopy_vpath == NULL)
476 char *filename;
478 filename = vfs_path_to_str (filename_vpath);
479 message (D_ERROR, MSG_ERROR, _("Cannot fetch a local copy of %s"), filename);
480 g_free (filename);
481 return;
485 * filename can be an entry on panel, it can be changed by executing
486 * the command, so make a copy. Smarter VFS code would make the code
487 * below unnecessary.
489 mc_stat (localcopy_vpath, &st);
490 mtime = st.st_mtime;
491 do_execute (command, vfs_path_get_last_path_str (localcopy_vpath), EXECUTE_INTERNAL);
492 mc_stat (localcopy_vpath, &st);
493 mc_ungetlocalcopy (filename_vpath, localcopy_vpath, mtime != st.st_mtime);
494 vfs_path_free (localcopy_vpath);
497 /* --------------------------------------------------------------------------------------------- */