Ticket #2127: updated file extension for "sh"
[midnight-commander.git] / src / execute.c
blob234429cec020dbdeec7526069785448689f93cc2
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"
34 #include "main.h"
35 #include "consaver/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 "lib/vfs/mc-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 *lc_shell, const char *command, int flags)
117 #ifdef HAVE_SUBSHELL_SUPPORT
118 char *new_dir = NULL;
119 #endif /* HAVE_SUBSHELL_SUPPORT */
121 #ifdef ENABLE_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 /* ENABLE_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", mc_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 ENABLE_VFS
143 invoke_subshell (command, VISIBLY, old_vfs_dir ? NULL : &new_dir);
144 #else
145 invoke_subshell (command, VISIBLY, &new_dir);
146 #endif /* !ENABLE_VFS */
147 } else
148 #endif /* HAVE_SUBSHELL_SUPPORT */
149 my_system (flags, lc_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 ENABLE_VFS
185 if (old_vfs_dir) {
186 mc_chdir (old_vfs_dir);
187 g_free (old_vfs_dir);
189 #endif /* ENABLE_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 if (mc_run_mode == MC_RUN_FULL) {
308 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
309 update_xterm_title_path ();
311 repaint_screen ();
315 static void
316 do_suspend_cmd (void)
318 pre_exec ();
320 if (console_flag && !use_subshell)
321 handle_console (CONSOLE_RESTORE);
323 #ifdef SIGTSTP
325 struct sigaction sigtstp_action;
327 /* Make sure that the SIGTSTP below will suspend us directly,
328 without calling ncurses' SIGTSTP handler; we *don't* want
329 ncurses to redraw the screen immediately after the SIGCONT */
330 sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
332 kill (getpid (), SIGTSTP);
334 /* Restore previous SIGTSTP action */
335 sigaction (SIGTSTP, &sigtstp_action, NULL);
337 #endif /* SIGTSTP */
339 if (console_flag && !use_subshell)
340 handle_console (CONSOLE_SAVE);
342 edition_post_exec ();
346 void
347 suspend_cmd (void)
349 save_cwds_stat ();
350 do_suspend_cmd ();
351 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
352 do_refresh ();
357 * Execute command on a filename that can be on VFS.
358 * Errors are reported to the user.
360 void
361 execute_with_vfs_arg (const char *command, const char *filename)
363 char *localcopy;
364 char *fn;
365 struct stat st;
366 time_t mtime;
368 /* Simplest case, this file is local */
369 if (!filename || vfs_file_is_local (filename)) {
370 fn = vfs_canon_and_translate (filename);
371 do_execute (command, fn, EXECUTE_INTERNAL);
372 g_free (fn);
373 return;
376 /* FIXME: Creation of new files on VFS is not supported */
377 if (!*filename)
378 return;
380 localcopy = mc_getlocalcopy (filename);
381 if (localcopy == NULL) {
382 message (D_ERROR, MSG_ERROR, _(" Cannot fetch a local copy of %s "),
383 filename);
384 return;
388 * filename can be an entry on panel, it can be changed by executing
389 * the command, so make a copy. Smarter VFS code would make the code
390 * below unnecessary.
392 fn = g_strdup (filename);
393 mc_stat (localcopy, &st);
394 mtime = st.st_mtime;
395 do_execute (command, localcopy, EXECUTE_INTERNAL);
396 mc_stat (localcopy, &st);
397 mc_ungetlocalcopy (fn, localcopy, mtime != st.st_mtime);
398 g_free (localcopy);
399 g_free (fn);