0d13222f148048316934219aaa30d1bb7a82c3ac
[midnight-commander.git] / src / execute.c
blob0d13222f148048316934219aaa30d1bb7a82c3ac
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 ************************************************************************/
65 void do_execute (const char *shell, const char *command, int flags);
66 void do_executev (const char *shell, int flags, char *const argv[]);
67 char *execute_get_external_cmd_opts_from_config (const char *command,
68 const vfs_path_t * filename_vpath, int start_line);
70 /* --------------------------------------------------------------------------------------------- */
72 static void
73 edition_post_exec (void)
75 do_enter_ca_mode ();
77 /* FIXME: Missing on slang endwin? */
78 tty_reset_prog_mode ();
79 tty_flush_input ();
81 tty_keypad (TRUE);
82 tty_raw_mode ();
83 channels_up ();
84 enable_mouse ();
85 if (mc_global.tty.alternate_plus_minus)
86 application_keypad_mode ();
89 /* --------------------------------------------------------------------------------------------- */
91 static void
92 edition_pre_exec (void)
94 if (clear_before_exec)
95 clr_scr ();
96 else
98 if (!(mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag))
99 printf ("\n\n");
102 channels_down ();
103 disable_mouse ();
105 tty_reset_shell_mode ();
106 tty_keypad (FALSE);
107 tty_reset_screen ();
109 numeric_keypad_mode ();
111 /* on xterms: maybe endwin did not leave the terminal on the shell
112 * screen page: do it now.
114 * Do not move this before endwin: in some systems rmcup includes
115 * a call to clear screen, so it will end up clearing the shell screen.
117 do_exit_ca_mode ();
120 /* --------------------------------------------------------------------------------------------- */
122 #ifdef ENABLE_SUBSHELL
123 static void
124 do_possible_cd (const vfs_path_t * new_dir_vpath)
126 if (!do_cd (new_dir_vpath, cd_exact))
127 message (D_ERROR, _("Warning"),
128 _("The Commander can't change to the directory that\n"
129 "the subshell claims you are in. Perhaps you have\n"
130 "deleted your working directory, or given yourself\n"
131 "extra access permissions with the \"su\" command?"));
133 #endif /* ENABLE_SUBSHELL */
135 /* --------------------------------------------------------------------------------------------- */
137 static void
138 do_suspend_cmd (void)
140 pre_exec ();
142 if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
143 handle_console (CONSOLE_RESTORE);
145 #ifdef SIGTSTP
147 struct sigaction sigtstp_action;
149 /* Make sure that the SIGTSTP below will suspend us directly,
150 without calling ncurses' SIGTSTP handler; we *don't* want
151 ncurses to redraw the screen immediately after the SIGCONT */
152 sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
154 kill (getpid (), SIGTSTP);
156 /* Restore previous SIGTSTP action */
157 sigaction (SIGTSTP, &sigtstp_action, NULL);
159 #endif /* SIGTSTP */
161 if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
162 handle_console (CONSOLE_SAVE);
164 edition_post_exec ();
167 /* --------------------------------------------------------------------------------------------- */
169 static gboolean
170 execute_prepare_with_vfs_arg (const vfs_path_t * filename_vpath, vfs_path_t ** localcopy_vpath,
171 time_t * mtime)
173 struct stat st;
175 /* Simplest case, this file is local */
176 if ((filename_vpath == NULL && vfs_file_is_local (vfs_get_raw_current_dir ()))
177 || vfs_file_is_local (filename_vpath))
178 return TRUE;
180 /* FIXME: Creation of new files on VFS is not supported */
181 if (filename_vpath == NULL)
182 return FALSE;
184 *localcopy_vpath = mc_getlocalcopy (filename_vpath);
185 if (*localcopy_vpath == NULL)
187 char *filename;
189 filename = vfs_path_to_str (filename_vpath);
190 message (D_ERROR, MSG_ERROR, _("Cannot fetch a local copy of %s"), filename);
191 g_free (filename);
192 return FALSE;
195 mc_stat (*localcopy_vpath, &st);
196 *mtime = st.st_mtime;
197 return TRUE;
200 /* --------------------------------------------------------------------------------------------- */
202 static void
203 execute_cleanup_with_vfs_arg (const vfs_path_t * filename_vpath, vfs_path_t ** localcopy_vpath,
204 time_t * mtime)
206 if (*localcopy_vpath != NULL)
208 struct stat st;
211 * filename can be an entry on panel, it can be changed by executing
212 * the command, so make a copy. Smarter VFS code would make the code
213 * below unnecessary.
215 mc_stat (*localcopy_vpath, &st);
216 mc_ungetlocalcopy (filename_vpath, *localcopy_vpath, *mtime != st.st_mtime);
217 vfs_path_free (*localcopy_vpath);
218 *localcopy_vpath = NULL;
222 /* --------------------------------------------------------------------------------------------- */
223 /*** public functions ****************************************************************************/
224 /* --------------------------------------------------------------------------------------------- */
226 char *
227 execute_get_external_cmd_opts_from_config (const char *command, const vfs_path_t * filename_vpath,
228 int start_line)
230 (void) command;
231 (void) start_line;
233 if (filename_vpath == NULL)
234 return g_strdup ("");
236 return g_strdup (vfs_path_get_last_path_str (filename_vpath));
239 /* --------------------------------------------------------------------------------------------- */
241 void
242 do_executev (const char *shell, int flags, char *const argv[])
244 #ifdef ENABLE_SUBSHELL
245 vfs_path_t *new_dir_vpath = NULL;
246 #endif /* ENABLE_SUBSHELL */
248 vfs_path_t *old_vfs_dir_vpath = NULL;
250 if (!vfs_current_is_local ())
251 old_vfs_dir_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
253 if (mc_global.mc_run_mode == MC_RUN_FULL)
254 save_cwds_stat ();
255 pre_exec ();
256 if (mc_global.tty.console_flag != '\0')
257 handle_console (CONSOLE_RESTORE);
259 if (!mc_global.tty.use_subshell && *argv != NULL && (flags & EXECUTE_INTERNAL) == 0)
261 printf ("%s%s\n", mc_prompt, *argv);
262 fflush (stdout);
264 #ifdef ENABLE_SUBSHELL
265 if (mc_global.tty.use_subshell && (flags & EXECUTE_INTERNAL) == 0)
267 do_update_prompt ();
269 /* We don't care if it died, higher level takes care of this */
270 invoke_subshell (*argv, VISIBLY, old_vfs_dir_vpath != NULL ? NULL : &new_dir_vpath);
272 else
273 #endif /* ENABLE_SUBSHELL */
274 my_systemv_flags (flags, shell, argv);
276 if ((flags & EXECUTE_INTERNAL) == 0)
278 if ((pause_after_run == pause_always
279 || (pause_after_run == pause_on_dumb_terminals && !mc_global.tty.xterm_flag
280 && mc_global.tty.console_flag == '\0')) && quit == 0
281 #ifdef ENABLE_SUBSHELL
282 && subshell_state != RUNNING_COMMAND
283 #endif /* ENABLE_SUBSHELL */
286 printf (_("Press any key to continue..."));
287 fflush (stdout);
288 tty_raw_mode ();
289 get_key_code (0);
290 printf ("\r\n");
291 fflush (stdout);
293 if (mc_global.tty.console_flag != '\0' && output_lines != 0 && mc_global.keybar_visible)
295 putchar ('\n');
296 fflush (stdout);
300 if (mc_global.tty.console_flag != '\0')
301 handle_console (CONSOLE_SAVE);
302 edition_post_exec ();
304 #ifdef ENABLE_SUBSHELL
305 if (new_dir_vpath != NULL)
307 do_possible_cd (new_dir_vpath);
308 vfs_path_free (new_dir_vpath);
311 #endif /* ENABLE_SUBSHELL */
313 if (old_vfs_dir_vpath != NULL)
315 mc_chdir (old_vfs_dir_vpath);
316 vfs_path_free (old_vfs_dir_vpath);
319 if (mc_global.mc_run_mode == MC_RUN_FULL)
321 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
322 update_xterm_title_path ();
325 do_refresh ();
326 use_dash (TRUE);
329 /* --------------------------------------------------------------------------------------------- */
331 void
332 do_execute (const char *shell, const char *command, int flags)
334 GPtrArray *args_array;
336 args_array = g_ptr_array_new ();
337 g_ptr_array_add (args_array, (char *) command);
338 g_ptr_array_add (args_array, NULL);
340 do_executev (shell, flags, (char *const *) args_array->pdata);
342 g_ptr_array_free (args_array, TRUE);
345 /* --------------------------------------------------------------------------------------------- */
347 /** Set up the terminal before executing a program */
349 void
350 pre_exec (void)
352 use_dash (FALSE);
353 edition_pre_exec ();
356 /* --------------------------------------------------------------------------------------------- */
357 /** Hide the terminal after executing a program */
358 void
359 post_exec (void)
361 edition_post_exec ();
362 use_dash (TRUE);
363 repaint_screen ();
366 /* --------------------------------------------------------------------------------------------- */
367 /* Executes a command */
369 void
370 shell_execute (const char *command, int flags)
372 char *cmd = NULL;
374 if (flags & EXECUTE_HIDE)
376 cmd = g_strconcat (" ", command, (char *) NULL);
377 flags ^= EXECUTE_HIDE;
380 #ifdef ENABLE_SUBSHELL
381 if (mc_global.tty.use_subshell)
382 if (subshell_state == INACTIVE)
383 do_execute (mc_global.tty.shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
384 else
385 message (D_ERROR, MSG_ERROR, _("The shell is already running a command"));
386 else
387 #endif /* ENABLE_SUBSHELL */
388 do_execute (mc_global.tty.shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
390 g_free (cmd);
393 /* --------------------------------------------------------------------------------------------- */
395 void
396 exec_shell (void)
398 do_execute (mc_global.tty.shell, 0, 0);
401 /* --------------------------------------------------------------------------------------------- */
403 void
404 toggle_panels (void)
406 #ifdef ENABLE_SUBSHELL
407 vfs_path_t *new_dir_vpath = NULL;
408 vfs_path_t **new_dir_p;
409 #endif /* ENABLE_SUBSHELL */
411 SIG_ATOMIC_VOLATILE_T was_sigwinch = 0;
413 channels_down ();
414 disable_mouse ();
415 if (clear_before_exec)
416 clr_scr ();
417 if (mc_global.tty.alternate_plus_minus)
418 numeric_keypad_mode ();
419 #ifndef HAVE_SLANG
420 /* With slang we don't want any of this, since there
421 * is no raw_mode supported
423 tty_reset_shell_mode ();
424 #endif /* !HAVE_SLANG */
425 tty_noecho ();
426 tty_keypad (FALSE);
427 tty_reset_screen ();
428 do_exit_ca_mode ();
429 tty_raw_mode ();
430 if (mc_global.tty.console_flag != '\0')
431 handle_console (CONSOLE_RESTORE);
433 #ifdef ENABLE_SUBSHELL
434 if (mc_global.tty.use_subshell)
436 new_dir_p = vfs_current_is_local ()? &new_dir_vpath : NULL;
437 invoke_subshell (NULL, VISIBLY, new_dir_p);
439 else
440 #endif /* ENABLE_SUBSHELL */
442 if (output_starts_shell)
444 fprintf (stderr, _("Type `exit' to return to the Midnight Commander"));
445 fprintf (stderr, "\n\r\n\r");
447 my_system (EXECUTE_INTERNAL, mc_global.tty.shell, NULL);
449 else
450 get_key_code (0);
453 if (mc_global.tty.console_flag != '\0')
454 handle_console (CONSOLE_SAVE);
456 do_enter_ca_mode ();
458 tty_reset_prog_mode ();
459 tty_keypad (TRUE);
461 /* Prevent screen flash when user did 'exit' or 'logout' within
462 subshell */
463 if ((quit & SUBSHELL_EXIT) != 0)
465 /* User did `exit' or `logout': quit MC */
466 if (quiet_quit_cmd ())
467 return;
469 quit = 0;
470 #ifdef ENABLE_SUBSHELL
471 /* restart subshell */
472 if (mc_global.tty.use_subshell)
473 init_subshell ();
474 #endif /* ENABLE_SUBSHELL */
477 enable_mouse ();
478 channels_up ();
479 if (mc_global.tty.alternate_plus_minus)
480 application_keypad_mode ();
482 /* HACK:
483 * Save sigwinch flag that will be reset in mc_refresh() called via update_panels().
484 * There is some problem with screen redraw in ncurses-based mc in this situation.
486 was_sigwinch = mc_global.tty.winch_flag;
487 mc_global.tty.winch_flag = 0;
489 #ifdef ENABLE_SUBSHELL
490 if (mc_global.tty.use_subshell)
492 do_load_prompt ();
493 if (new_dir_vpath != NULL)
494 do_possible_cd (new_dir_vpath);
495 if (mc_global.tty.console_flag != '\0' && output_lines)
496 show_console_contents (output_start_y,
497 LINES - mc_global.keybar_visible - output_lines -
498 1, LINES - mc_global.keybar_visible - 1);
501 vfs_path_free (new_dir_vpath);
502 #endif /* ENABLE_SUBSHELL */
504 if (mc_global.mc_run_mode == MC_RUN_FULL)
506 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
507 update_xterm_title_path ();
510 if (was_sigwinch != 0 || mc_global.tty.winch_flag != 0)
511 dialog_change_screen_size ();
512 else
513 repaint_screen ();
516 /* --------------------------------------------------------------------------------------------- */
518 /* event callback */
519 gboolean
520 execute_suspend (const gchar * event_group_name, const gchar * event_name,
521 gpointer init_data, gpointer data)
523 (void) event_group_name;
524 (void) event_name;
525 (void) init_data;
526 (void) data;
528 if (mc_global.mc_run_mode == MC_RUN_FULL)
529 save_cwds_stat ();
530 do_suspend_cmd ();
531 if (mc_global.mc_run_mode == MC_RUN_FULL)
532 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
533 do_refresh ();
535 return TRUE;
538 /* --------------------------------------------------------------------------------------------- */
541 * Execute command on a filename that can be on VFS.
542 * Errors are reported to the user.
545 void
546 execute_with_vfs_arg (const char *command, const vfs_path_t * filename_vpath)
548 vfs_path_t *localcopy_vpath = NULL;
549 const vfs_path_t *do_execute_vpath;
550 time_t mtime;
552 if (!execute_prepare_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime))
553 return;
555 do_execute_vpath = (localcopy_vpath == NULL) ? filename_vpath : localcopy_vpath;
557 do_execute (command, vfs_path_get_last_path_str (do_execute_vpath), EXECUTE_INTERNAL);
559 execute_cleanup_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime);
562 /* --------------------------------------------------------------------------------------------- */
564 * Execute external editor or viewer.
566 * @param command editor/viewer to run
567 * @param filename_vpath path for edit/view
568 * @param start_line cursor will be placed at the 'start_line' position after opening file
571 void
572 execute_external_editor_or_viewer (const char *command, const vfs_path_t * filename_vpath,
573 int start_line)
575 vfs_path_t *localcopy_vpath = NULL;
576 const vfs_path_t *do_execute_vpath;
577 char *extern_cmd_options;
578 time_t mtime;
580 if (!execute_prepare_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime))
581 return;
583 do_execute_vpath = (localcopy_vpath == NULL) ? filename_vpath : localcopy_vpath;
585 extern_cmd_options =
586 execute_get_external_cmd_opts_from_config (command, do_execute_vpath, start_line);
588 if (extern_cmd_options != NULL)
590 char **argv_cmd_options;
591 int argv_count;
593 g_shell_parse_argv (extern_cmd_options, &argv_count, &argv_cmd_options, NULL);
594 g_free (extern_cmd_options);
596 do_executev (command, EXECUTE_INTERNAL, argv_cmd_options);
598 g_strfreev (argv_cmd_options);
601 execute_cleanup_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime);
604 /* --------------------------------------------------------------------------------------------- */