Support of multiple editors and viewers.
[midnight-commander.git] / src / execute.c
blob9fcbadb274a1c1b8391c64ad76313b2e76172c83
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
70 if (!(console_flag || xterm_flag))
71 printf ("\n\n");
74 channels_down ();
75 disable_mouse ();
77 tty_reset_shell_mode ();
78 tty_keypad (FALSE);
79 tty_reset_screen ();
81 numeric_keypad_mode ();
83 /* on xterms: maybe endwin did not leave the terminal on the shell
84 * screen page: do it now.
86 * Do not move this before endwin: in some systems rmcup includes
87 * a call to clear screen, so it will end up clearing the shell screen.
89 do_exit_ca_mode ();
93 /* Set up the terminal before executing a program */
94 static void
95 pre_exec (void)
97 use_dash (0);
98 edition_pre_exec ();
102 #ifdef HAVE_SUBSHELL_SUPPORT
103 static void
104 do_possible_cd (const char *new_dir)
106 if (!do_cd (new_dir, cd_exact))
107 message (D_ERROR, _("Warning"),
108 _("The Commander can't change to the directory that\n"
109 "the subshell claims you are in. Perhaps you have\n"
110 "deleted your working directory, or given yourself\n"
111 "extra access permissions with the \"su\" command?"));
113 #endif /* HAVE_SUBSHELL_SUPPORT */
115 static void
116 do_execute (const char *lc_shell, const char *command, int flags)
118 #ifdef HAVE_SUBSHELL_SUPPORT
119 char *new_dir = NULL;
120 #endif /* HAVE_SUBSHELL_SUPPORT */
122 #ifdef ENABLE_VFS
123 char *old_vfs_dir = 0;
125 if (!vfs_current_is_local ())
126 old_vfs_dir = g_strdup (vfs_get_current_dir ());
127 #endif /* ENABLE_VFS */
129 if (mc_run_mode == MC_RUN_FULL)
130 save_cwds_stat ();
131 pre_exec ();
132 if (console_flag)
133 handle_console (CONSOLE_RESTORE);
135 if (!use_subshell && command && !(flags & EXECUTE_INTERNAL))
137 printf ("%s%s\n", mc_prompt, command);
138 fflush (stdout);
140 #ifdef HAVE_SUBSHELL_SUPPORT
141 if (use_subshell && !(flags & EXECUTE_INTERNAL))
143 do_update_prompt ();
145 /* We don't care if it died, higher level takes care of this */
146 #ifdef ENABLE_VFS
147 invoke_subshell (command, VISIBLY, old_vfs_dir ? NULL : &new_dir);
148 #else
149 invoke_subshell (command, VISIBLY, &new_dir);
150 #endif /* !ENABLE_VFS */
152 else
153 #endif /* HAVE_SUBSHELL_SUPPORT */
154 my_system (flags, lc_shell, command);
156 if (!(flags & EXECUTE_INTERNAL))
158 if ((pause_after_run == pause_always
159 || (pause_after_run == pause_on_dumb_terminals && !xterm_flag
160 && !console_flag)) && !quit
161 #ifdef HAVE_SUBSHELL_SUPPORT
162 && subshell_state != RUNNING_COMMAND
163 #endif /* HAVE_SUBSHELL_SUPPORT */
166 printf (_("Press any key to continue..."));
167 fflush (stdout);
168 tty_raw_mode ();
169 get_key_code (0);
170 printf ("\r\n");
171 fflush (stdout);
173 if (console_flag)
175 if (output_lines && keybar_visible)
177 putchar ('\n');
178 fflush (stdout);
183 if (console_flag)
184 handle_console (CONSOLE_SAVE);
185 edition_post_exec ();
187 #ifdef HAVE_SUBSHELL_SUPPORT
188 if (new_dir)
189 do_possible_cd (new_dir);
191 #endif /* HAVE_SUBSHELL_SUPPORT */
193 #ifdef ENABLE_VFS
194 if (old_vfs_dir)
196 mc_chdir (old_vfs_dir);
197 g_free (old_vfs_dir);
199 #endif /* ENABLE_VFS */
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);
212 /* Executes a command */
213 void
214 shell_execute (const char *command, int flags)
216 char *cmd = NULL;
218 if (flags & EXECUTE_HIDE)
220 cmd = g_strconcat (" ", command, (char *) NULL);
221 flags ^= EXECUTE_HIDE;
224 #ifdef HAVE_SUBSHELL_SUPPORT
225 if (use_subshell)
226 if (subshell_state == INACTIVE)
227 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
228 else
229 message (D_ERROR, MSG_ERROR, _("The shell is already running a command"));
230 else
231 #endif /* HAVE_SUBSHELL_SUPPORT */
232 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
234 g_free (cmd);
238 void
239 exec_shell (void)
241 do_execute (shell, 0, 0);
245 void
246 toggle_panels (void)
248 #ifdef HAVE_SUBSHELL_SUPPORT
249 char *new_dir = NULL;
250 char **new_dir_p;
251 #endif /* HAVE_SUBSHELL_SUPPORT */
253 channels_down ();
254 disable_mouse ();
255 if (clear_before_exec)
256 clr_scr ();
257 if (alternate_plus_minus)
258 numeric_keypad_mode ();
259 #ifndef HAVE_SLANG
260 /* With slang we don't want any of this, since there
261 * is no raw_mode supported
263 tty_reset_shell_mode ();
264 #endif /* !HAVE_SLANG */
265 tty_noecho ();
266 tty_keypad (FALSE);
267 tty_reset_screen ();
268 do_exit_ca_mode ();
269 tty_raw_mode ();
270 if (console_flag)
271 handle_console (CONSOLE_RESTORE);
273 #ifdef HAVE_SUBSHELL_SUPPORT
274 if (use_subshell)
276 new_dir_p = vfs_current_is_local ()? &new_dir : NULL;
277 if (invoke_subshell (NULL, VISIBLY, new_dir_p))
278 quiet_quit_cmd (); /* User did `exit' or `logout': quit MC quietly */
280 else
281 #endif /* HAVE_SUBSHELL_SUPPORT */
283 if (output_starts_shell)
285 fprintf (stderr, _("Type `exit' to return to the Midnight Commander"));
286 fprintf (stderr, "\n\r\n\r");
288 my_system (EXECUTE_INTERNAL, shell, NULL);
290 else
291 get_key_code (0);
293 if (console_flag)
294 handle_console (CONSOLE_SAVE);
296 do_enter_ca_mode ();
298 tty_reset_prog_mode ();
299 tty_keypad (TRUE);
301 /* Prevent screen flash when user did 'exit' or 'logout' within
302 subshell */
303 if (quit)
304 return;
306 enable_mouse ();
307 channels_up ();
308 if (alternate_plus_minus)
309 application_keypad_mode ();
311 #ifdef HAVE_SUBSHELL_SUPPORT
312 if (use_subshell)
314 load_prompt (0, 0);
315 if (new_dir)
316 do_possible_cd (new_dir);
317 if (console_flag && output_lines)
318 show_console_contents (output_start_y,
319 LINES - keybar_visible - output_lines -
320 1, LINES - keybar_visible - 1);
322 #endif /* HAVE_SUBSHELL_SUPPORT */
324 if (mc_run_mode == MC_RUN_FULL)
326 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
327 update_xterm_title_path ();
329 repaint_screen ();
333 static void
334 do_suspend_cmd (void)
336 pre_exec ();
338 if (console_flag && !use_subshell)
339 handle_console (CONSOLE_RESTORE);
341 #ifdef SIGTSTP
343 struct sigaction sigtstp_action;
345 /* Make sure that the SIGTSTP below will suspend us directly,
346 without calling ncurses' SIGTSTP handler; we *don't* want
347 ncurses to redraw the screen immediately after the SIGCONT */
348 sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
350 kill (getpid (), SIGTSTP);
352 /* Restore previous SIGTSTP action */
353 sigaction (SIGTSTP, &sigtstp_action, NULL);
355 #endif /* SIGTSTP */
357 if (console_flag && !use_subshell)
358 handle_console (CONSOLE_SAVE);
360 edition_post_exec ();
364 void
365 suspend_cmd (void)
367 if (mc_run_mode == MC_RUN_FULL)
368 save_cwds_stat ();
369 do_suspend_cmd ();
370 if (mc_run_mode == MC_RUN_FULL)
371 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
372 do_refresh ();
377 * Execute command on a filename that can be on VFS.
378 * Errors are reported to the user.
380 void
381 execute_with_vfs_arg (const char *command, const char *filename)
383 char *localcopy;
384 char *fn;
385 struct stat st;
386 time_t mtime;
388 /* Simplest case, this file is local */
389 if (!filename || vfs_file_is_local (filename))
391 fn = vfs_canon_and_translate (filename);
392 do_execute (command, fn, EXECUTE_INTERNAL);
393 g_free (fn);
394 return;
397 /* FIXME: Creation of new files on VFS is not supported */
398 if (!*filename)
399 return;
401 localcopy = mc_getlocalcopy (filename);
402 if (localcopy == NULL)
404 message (D_ERROR, MSG_ERROR, _("Cannot fetch a local copy of %s"), filename);
405 return;
409 * filename can be an entry on panel, it can be changed by executing
410 * the command, so make a copy. Smarter VFS code would make the code
411 * below unnecessary.
413 fn = g_strdup (filename);
414 mc_stat (localcopy, &st);
415 mtime = st.st_mtime;
416 do_execute (command, localcopy, EXECUTE_INTERNAL);
417 mc_stat (localcopy, &st);
418 mc_ungetlocalcopy (fn, localcopy, mtime != st.st_mtime);
419 g_free (localcopy);
420 g_free (fn);