Use vfs_path_t in execute.c and subshell.c.
[midnight-commander.git] / src / execute.c
blob4a0bf89cb036547e04f20b58516540ba5fa95661
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 #include "subshell.h"
47 #include "setup.h" /* clear_before_exec */
49 #include "execute.h"
51 /*** global variables ****************************************************************************/
53 int pause_after_run = pause_on_dumb_terminals;
55 /*** file scope macro definitions ****************************************************************/
57 /*** file scope type declarations ****************************************************************/
59 /*** file scope variables ************************************************************************/
61 /*** file scope functions ************************************************************************/
62 /* --------------------------------------------------------------------------------------------- */
64 static void
65 edition_post_exec (void)
67 do_enter_ca_mode ();
69 /* FIXME: Missing on slang endwin? */
70 tty_reset_prog_mode ();
71 tty_flush_input ();
73 tty_keypad (TRUE);
74 tty_raw_mode ();
75 channels_up ();
76 enable_mouse ();
77 if (mc_global.tty.alternate_plus_minus)
78 application_keypad_mode ();
81 /* --------------------------------------------------------------------------------------------- */
83 static void
84 edition_pre_exec (void)
86 if (clear_before_exec)
87 clr_scr ();
88 else
90 if (!(mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag))
91 printf ("\n\n");
94 channels_down ();
95 disable_mouse ();
97 tty_reset_shell_mode ();
98 tty_keypad (FALSE);
99 tty_reset_screen ();
101 numeric_keypad_mode ();
103 /* on xterms: maybe endwin did not leave the terminal on the shell
104 * screen page: do it now.
106 * Do not move this before endwin: in some systems rmcup includes
107 * a call to clear screen, so it will end up clearing the shell screen.
109 do_exit_ca_mode ();
112 /* --------------------------------------------------------------------------------------------- */
114 #ifdef HAVE_SUBSHELL_SUPPORT
115 static void
116 do_possible_cd (const vfs_path_t * new_dir_vpath)
118 if (!do_cd (new_dir_vpath, cd_exact))
119 message (D_ERROR, _("Warning"),
120 _("The Commander can't change to the directory that\n"
121 "the subshell claims you are in. Perhaps you have\n"
122 "deleted your working directory, or given yourself\n"
123 "extra access permissions with the \"su\" command?"));
125 #endif /* HAVE_SUBSHELL_SUPPORT */
127 /* --------------------------------------------------------------------------------------------- */
129 static void
130 do_execute (const char *lc_shell, const char *command, int flags)
132 #ifdef HAVE_SUBSHELL_SUPPORT
133 vfs_path_t *new_dir_vpath = NULL;
134 #endif /* HAVE_SUBSHELL_SUPPORT */
136 vfs_path_t *old_vfs_dir_vpath = NULL;
138 if (!vfs_current_is_local ())
139 old_vfs_dir_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
141 if (mc_global.mc_run_mode == MC_RUN_FULL)
142 save_cwds_stat ();
143 pre_exec ();
144 if (mc_global.tty.console_flag != '\0')
145 handle_console (CONSOLE_RESTORE);
147 if (!mc_global.tty.use_subshell && command && !(flags & EXECUTE_INTERNAL))
149 printf ("%s%s\n", mc_prompt, command);
150 fflush (stdout);
152 #ifdef HAVE_SUBSHELL_SUPPORT
153 if (mc_global.tty.use_subshell && !(flags & EXECUTE_INTERNAL))
155 do_update_prompt ();
157 /* We don't care if it died, higher level takes care of this */
158 invoke_subshell (command, VISIBLY, old_vfs_dir_vpath != NULL ? NULL : &new_dir_vpath);
160 else
161 #endif /* HAVE_SUBSHELL_SUPPORT */
162 my_system (flags, lc_shell, command);
164 if (!(flags & EXECUTE_INTERNAL))
166 if ((pause_after_run == pause_always
167 || (pause_after_run == pause_on_dumb_terminals && !mc_global.tty.xterm_flag
168 && mc_global.tty.console_flag == '\0')) && quit == 0
169 #ifdef HAVE_SUBSHELL_SUPPORT
170 && subshell_state != RUNNING_COMMAND
171 #endif /* HAVE_SUBSHELL_SUPPORT */
174 printf (_("Press any key to continue..."));
175 fflush (stdout);
176 tty_raw_mode ();
177 get_key_code (0);
178 printf ("\r\n");
179 fflush (stdout);
181 if (mc_global.tty.console_flag != '\0')
183 if (output_lines && mc_global.keybar_visible)
185 putchar ('\n');
186 fflush (stdout);
191 if (mc_global.tty.console_flag != '\0')
192 handle_console (CONSOLE_SAVE);
193 edition_post_exec ();
195 #ifdef HAVE_SUBSHELL_SUPPORT
196 if (new_dir_vpath != NULL)
198 do_possible_cd (new_dir_vpath);
199 vfs_path_free (new_dir_vpath);
202 #endif /* HAVE_SUBSHELL_SUPPORT */
204 if (old_vfs_dir_vpath != NULL)
206 mc_chdir (old_vfs_dir_vpath);
207 vfs_path_free (old_vfs_dir_vpath);
210 if (mc_global.mc_run_mode == MC_RUN_FULL)
212 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
213 update_xterm_title_path ();
216 do_refresh ();
217 use_dash (TRUE);
220 /* --------------------------------------------------------------------------------------------- */
222 static void
223 do_suspend_cmd (void)
225 pre_exec ();
227 if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
228 handle_console (CONSOLE_RESTORE);
230 #ifdef SIGTSTP
232 struct sigaction sigtstp_action;
234 /* Make sure that the SIGTSTP below will suspend us directly,
235 without calling ncurses' SIGTSTP handler; we *don't* want
236 ncurses to redraw the screen immediately after the SIGCONT */
237 sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
239 kill (getpid (), SIGTSTP);
241 /* Restore previous SIGTSTP action */
242 sigaction (SIGTSTP, &sigtstp_action, NULL);
244 #endif /* SIGTSTP */
246 if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
247 handle_console (CONSOLE_SAVE);
249 edition_post_exec ();
252 /* --------------------------------------------------------------------------------------------- */
253 /*** public functions ****************************************************************************/
254 /* --------------------------------------------------------------------------------------------- */
256 /** Set up the terminal before executing a program */
258 void
259 pre_exec (void)
261 use_dash (FALSE);
262 edition_pre_exec ();
265 /* --------------------------------------------------------------------------------------------- */
266 /** Hide the terminal after executing a program */
267 void
268 post_exec (void)
270 edition_post_exec ();
271 use_dash (TRUE);
272 repaint_screen ();
275 /* --------------------------------------------------------------------------------------------- */
276 /* Executes a command */
278 void
279 shell_execute (const char *command, int flags)
281 char *cmd = NULL;
283 if (flags & EXECUTE_HIDE)
285 cmd = g_strconcat (" ", command, (char *) NULL);
286 flags ^= EXECUTE_HIDE;
289 #ifdef HAVE_SUBSHELL_SUPPORT
290 if (mc_global.tty.use_subshell)
291 if (subshell_state == INACTIVE)
292 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
293 else
294 message (D_ERROR, MSG_ERROR, _("The shell is already running a command"));
295 else
296 #endif /* HAVE_SUBSHELL_SUPPORT */
297 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
299 g_free (cmd);
302 /* --------------------------------------------------------------------------------------------- */
304 void
305 exec_shell (void)
307 do_execute (shell, 0, 0);
310 /* --------------------------------------------------------------------------------------------- */
312 void
313 toggle_panels (void)
315 #ifdef HAVE_SUBSHELL_SUPPORT
316 vfs_path_t *new_dir_vpath = NULL;
317 vfs_path_t **new_dir_p;
318 #endif /* HAVE_SUBSHELL_SUPPORT */
320 channels_down ();
321 disable_mouse ();
322 if (clear_before_exec)
323 clr_scr ();
324 if (mc_global.tty.alternate_plus_minus)
325 numeric_keypad_mode ();
326 #ifndef HAVE_SLANG
327 /* With slang we don't want any of this, since there
328 * is no raw_mode supported
330 tty_reset_shell_mode ();
331 #endif /* !HAVE_SLANG */
332 tty_noecho ();
333 tty_keypad (FALSE);
334 tty_reset_screen ();
335 do_exit_ca_mode ();
336 tty_raw_mode ();
337 if (mc_global.tty.console_flag != '\0')
338 handle_console (CONSOLE_RESTORE);
340 #ifdef HAVE_SUBSHELL_SUPPORT
341 if (mc_global.tty.use_subshell)
343 new_dir_p = vfs_current_is_local () ? &new_dir_vpath : NULL;
344 invoke_subshell (NULL, VISIBLY, new_dir_p);
346 else
347 #endif /* HAVE_SUBSHELL_SUPPORT */
349 if (output_starts_shell)
351 fprintf (stderr, _("Type `exit' to return to the Midnight Commander"));
352 fprintf (stderr, "\n\r\n\r");
354 my_system (EXECUTE_INTERNAL, shell, NULL);
356 else
357 get_key_code (0);
360 if (mc_global.tty.console_flag != '\0')
361 handle_console (CONSOLE_SAVE);
363 do_enter_ca_mode ();
365 tty_reset_prog_mode ();
366 tty_keypad (TRUE);
368 /* Prevent screen flash when user did 'exit' or 'logout' within
369 subshell */
370 if ((quit & SUBSHELL_EXIT) != 0)
372 /* User did `exit' or `logout': quit MC */
373 if (quiet_quit_cmd ())
374 return;
376 quit = 0;
377 #ifdef HAVE_SUBSHELL_SUPPORT
378 /* restart subshell */
379 if (mc_global.tty.use_subshell)
380 init_subshell ();
381 #endif /* HAVE_SUBSHELL_SUPPORT */
384 enable_mouse ();
385 channels_up ();
386 if (mc_global.tty.alternate_plus_minus)
387 application_keypad_mode ();
389 #ifdef HAVE_SUBSHELL_SUPPORT
390 if (mc_global.tty.use_subshell)
392 do_load_prompt ();
393 if (new_dir_vpath != NULL)
394 do_possible_cd (new_dir_vpath);
395 if (mc_global.tty.console_flag != '\0' && output_lines)
396 show_console_contents (output_start_y,
397 LINES - mc_global.keybar_visible - output_lines -
398 1, LINES - mc_global.keybar_visible - 1);
401 vfs_path_free (new_dir_vpath);
402 #endif /* HAVE_SUBSHELL_SUPPORT */
404 if (mc_global.mc_run_mode == MC_RUN_FULL)
406 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
407 update_xterm_title_path ();
409 repaint_screen ();
412 /* --------------------------------------------------------------------------------------------- */
414 /* event callback */
415 gboolean
416 execute_suspend (const gchar * event_group_name, const gchar * event_name,
417 gpointer init_data, gpointer data)
419 (void) event_group_name;
420 (void) event_name;
421 (void) init_data;
422 (void) data;
424 if (mc_global.mc_run_mode == MC_RUN_FULL)
425 save_cwds_stat ();
426 do_suspend_cmd ();
427 if (mc_global.mc_run_mode == MC_RUN_FULL)
428 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
429 do_refresh ();
431 return TRUE;
434 /* --------------------------------------------------------------------------------------------- */
436 * Execute command on a filename that can be on VFS.
437 * Errors are reported to the user.
440 void
441 execute_with_vfs_arg (const char *command, const char *filename)
443 struct stat st;
444 time_t mtime;
445 vfs_path_t *vpath = vfs_path_from_str (filename);
446 vfs_path_t *localcopy_vpath;
448 /* Simplest case, this file is local */
449 if (!filename || vfs_file_is_local (vpath))
451 do_execute (command, vfs_path_get_last_path_str (vpath), EXECUTE_INTERNAL);
452 vfs_path_free (vpath);
453 return;
456 /* FIXME: Creation of new files on VFS is not supported */
457 if (!*filename)
459 vfs_path_free (vpath);
460 return;
463 localcopy_vpath = mc_getlocalcopy (vpath);
464 if (localcopy_vpath == NULL)
466 message (D_ERROR, MSG_ERROR, _("Cannot fetch a local copy of %s"), filename);
467 vfs_path_free (vpath);
468 return;
472 * filename can be an entry on panel, it can be changed by executing
473 * the command, so make a copy. Smarter VFS code would make the code
474 * below unnecessary.
476 mc_stat (localcopy_vpath, &st);
477 mtime = st.st_mtime;
478 do_execute (command, vfs_path_get_last_path_str (localcopy_vpath), EXECUTE_INTERNAL);
479 mc_stat (localcopy_vpath, &st);
480 mc_ungetlocalcopy (vpath, localcopy_vpath, mtime != st.st_mtime);
481 vfs_path_free (localcopy_vpath);
482 vfs_path_free (vpath);
485 /* --------------------------------------------------------------------------------------------- */