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/>.
24 * \brief Source: execution routines
34 #include "lib/global.h"
36 #include "lib/tty/tty.h"
37 #include "lib/tty/key.h"
38 #include "lib/tty/win.h"
39 #include "lib/vfs/vfs.h"
40 #include "lib/mcconfig.h"
42 #include "lib/strutil.h" /* str_replace_all_substrings() */
43 #include "lib/widget.h"
45 #include "filemanager/midnight.h"
46 #include "filemanager/layout.h" /* use_dash() */
47 #include "consaver/cons.saver.h"
48 #ifdef ENABLE_SUBSHELL
51 #include "setup.h" /* clear_before_exec */
55 /*** global variables ****************************************************************************/
57 int pause_after_run
= pause_on_dumb_terminals
;
59 /*** file scope macro definitions ****************************************************************/
61 /*** file scope type declarations ****************************************************************/
63 /*** file scope variables ************************************************************************/
65 /*** file scope functions ************************************************************************/
67 void do_execute (const char *shell
, const char *command
, int flags
);
68 void do_executev (const char *shell
, int flags
, char *const argv
[]);
69 char *execute_get_external_cmd_opts_from_config (const char *command
,
70 const vfs_path_t
* filename_vpath
, int start_line
);
72 /* --------------------------------------------------------------------------------------------- */
75 edition_post_exec (void)
79 /* FIXME: Missing on slang endwin? */
80 tty_reset_prog_mode ();
87 if (mc_global
.tty
.alternate_plus_minus
)
88 application_keypad_mode ();
91 /* --------------------------------------------------------------------------------------------- */
94 edition_pre_exec (void)
96 if (clear_before_exec
)
100 if (!(mc_global
.tty
.console_flag
!= '\0' || mc_global
.tty
.xterm_flag
))
107 tty_reset_shell_mode ();
111 numeric_keypad_mode ();
113 /* on xterms: maybe endwin did not leave the terminal on the shell
114 * screen page: do it now.
116 * Do not move this before endwin: in some systems rmcup includes
117 * a call to clear screen, so it will end up clearing the shell screen.
122 /* --------------------------------------------------------------------------------------------- */
124 #ifdef ENABLE_SUBSHELL
126 do_possible_cd (const vfs_path_t
* new_dir_vpath
)
128 if (!do_cd (new_dir_vpath
, cd_exact
))
129 message (D_ERROR
, _("Warning"),
130 _("The Commander can't change to the directory that\n"
131 "the subshell claims you are in. Perhaps you have\n"
132 "deleted your working directory, or given yourself\n"
133 "extra access permissions with the \"su\" command?"));
135 #endif /* ENABLE_SUBSHELL */
137 /* --------------------------------------------------------------------------------------------- */
140 do_suspend_cmd (void)
144 if (mc_global
.tty
.console_flag
!= '\0' && !mc_global
.tty
.use_subshell
)
145 handle_console (CONSOLE_RESTORE
);
149 struct sigaction sigtstp_action
;
151 /* Make sure that the SIGTSTP below will suspend us directly,
152 without calling ncurses' SIGTSTP handler; we *don't* want
153 ncurses to redraw the screen immediately after the SIGCONT */
154 sigaction (SIGTSTP
, &startup_handler
, &sigtstp_action
);
156 kill (getpid (), SIGTSTP
);
158 /* Restore previous SIGTSTP action */
159 sigaction (SIGTSTP
, &sigtstp_action
, NULL
);
163 if (mc_global
.tty
.console_flag
!= '\0' && !mc_global
.tty
.use_subshell
)
164 handle_console (CONSOLE_SAVE
);
166 edition_post_exec ();
169 /* --------------------------------------------------------------------------------------------- */
172 execute_prepare_with_vfs_arg (const vfs_path_t
* filename_vpath
, vfs_path_t
** localcopy_vpath
,
177 /* Simplest case, this file is local */
178 if ((filename_vpath
== NULL
&& vfs_file_is_local (vfs_get_raw_current_dir ()))
179 || vfs_file_is_local (filename_vpath
))
182 /* FIXME: Creation of new files on VFS is not supported */
183 if (filename_vpath
== NULL
)
186 *localcopy_vpath
= mc_getlocalcopy (filename_vpath
);
187 if (*localcopy_vpath
== NULL
)
191 filename
= vfs_path_to_str (filename_vpath
);
192 message (D_ERROR
, MSG_ERROR
, _("Cannot fetch a local copy of %s"), filename
);
197 mc_stat (*localcopy_vpath
, &st
);
198 *mtime
= st
.st_mtime
;
202 /* --------------------------------------------------------------------------------------------- */
205 execute_cleanup_with_vfs_arg (const vfs_path_t
* filename_vpath
, vfs_path_t
** localcopy_vpath
,
208 if (*localcopy_vpath
!= NULL
)
213 * filename can be an entry on panel, it can be changed by executing
214 * the command, so make a copy. Smarter VFS code would make the code
217 mc_stat (*localcopy_vpath
, &st
);
218 mc_ungetlocalcopy (filename_vpath
, *localcopy_vpath
, *mtime
!= st
.st_mtime
);
219 vfs_path_free (*localcopy_vpath
);
220 *localcopy_vpath
= NULL
;
224 /* --------------------------------------------------------------------------------------------- */
227 execute_get_opts_from_cfg (const char *command
, const char *default_str
)
229 char *str_from_config
;
232 mc_config_get_string_raw (mc_main_config
, CONFIG_EXT_EDITOR_VIEWER_SECTION
, command
, NULL
);
234 if (str_from_config
== NULL
)
238 cfg
= mc_config_init (global_profile_name
, TRUE
);
240 return g_strdup (default_str
);
243 mc_config_get_string_raw (cfg
, CONFIG_EXT_EDITOR_VIEWER_SECTION
, command
, default_str
);
245 mc_config_deinit (cfg
);
248 return str_from_config
;
251 /* --------------------------------------------------------------------------------------------- */
252 /*** public functions ****************************************************************************/
253 /* --------------------------------------------------------------------------------------------- */
256 execute_get_external_cmd_opts_from_config (const char *command
, const vfs_path_t
* filename_vpath
,
259 char *str_from_config
, *return_str
;
262 if (filename_vpath
== NULL
)
263 return g_strdup ("");
265 str_from_config
= execute_get_opts_from_cfg (command
, "%filename");
267 parameter
= g_shell_quote (vfs_path_get_last_path_str (filename_vpath
));
268 return_str
= str_replace_all (str_from_config
, "%filename", parameter
);
270 g_free (str_from_config
);
271 str_from_config
= return_str
;
273 parameter
= g_strdup_printf ("%d", start_line
);
274 return_str
= str_replace_all (str_from_config
, "%lineno", parameter
);
276 g_free (str_from_config
);
281 /* --------------------------------------------------------------------------------------------- */
284 do_executev (const char *shell
, int flags
, char *const argv
[])
286 #ifdef ENABLE_SUBSHELL
287 vfs_path_t
*new_dir_vpath
= NULL
;
288 #endif /* ENABLE_SUBSHELL */
290 vfs_path_t
*old_vfs_dir_vpath
= NULL
;
292 if (!vfs_current_is_local ())
293 old_vfs_dir_vpath
= vfs_path_clone (vfs_get_raw_current_dir ());
295 if (mc_global
.mc_run_mode
== MC_RUN_FULL
)
298 if (mc_global
.tty
.console_flag
!= '\0')
299 handle_console (CONSOLE_RESTORE
);
301 if (!mc_global
.tty
.use_subshell
&& *argv
!= NULL
&& (flags
& EXECUTE_INTERNAL
) == 0)
303 printf ("%s%s\n", mc_prompt
, *argv
);
306 #ifdef ENABLE_SUBSHELL
307 if (mc_global
.tty
.use_subshell
&& (flags
& EXECUTE_INTERNAL
) == 0)
311 /* We don't care if it died, higher level takes care of this */
312 invoke_subshell (*argv
, VISIBLY
, old_vfs_dir_vpath
!= NULL
? NULL
: &new_dir_vpath
);
315 #endif /* ENABLE_SUBSHELL */
316 my_systemv_flags (flags
, shell
, argv
);
318 if ((flags
& EXECUTE_INTERNAL
) == 0)
320 if ((pause_after_run
== pause_always
321 || (pause_after_run
== pause_on_dumb_terminals
&& !mc_global
.tty
.xterm_flag
322 && mc_global
.tty
.console_flag
== '\0')) && quit
== 0
323 #ifdef ENABLE_SUBSHELL
324 && subshell_state
!= RUNNING_COMMAND
325 #endif /* ENABLE_SUBSHELL */
328 printf (_("Press any key to continue..."));
335 if (mc_global
.tty
.console_flag
!= '\0' && output_lines
!= 0 && mc_global
.keybar_visible
)
342 if (mc_global
.tty
.console_flag
!= '\0')
343 handle_console (CONSOLE_SAVE
);
344 edition_post_exec ();
346 #ifdef ENABLE_SUBSHELL
347 if (new_dir_vpath
!= NULL
)
349 do_possible_cd (new_dir_vpath
);
350 vfs_path_free (new_dir_vpath
);
353 #endif /* ENABLE_SUBSHELL */
355 if (old_vfs_dir_vpath
!= NULL
)
357 mc_chdir (old_vfs_dir_vpath
);
358 vfs_path_free (old_vfs_dir_vpath
);
361 if (mc_global
.mc_run_mode
== MC_RUN_FULL
)
363 update_panels (UP_OPTIMIZE
, UP_KEEPSEL
);
364 update_xterm_title_path ();
371 /* --------------------------------------------------------------------------------------------- */
374 do_execute (const char *shell
, const char *command
, int flags
)
376 GPtrArray
*args_array
;
378 args_array
= g_ptr_array_new ();
379 g_ptr_array_add (args_array
, (char *) command
);
380 g_ptr_array_add (args_array
, NULL
);
382 do_executev (shell
, flags
, (char *const *) args_array
->pdata
);
384 g_ptr_array_free (args_array
, TRUE
);
387 /* --------------------------------------------------------------------------------------------- */
389 /** Set up the terminal before executing a program */
398 /* --------------------------------------------------------------------------------------------- */
399 /** Hide the terminal after executing a program */
403 edition_post_exec ();
408 /* --------------------------------------------------------------------------------------------- */
409 /* Executes a command */
412 shell_execute (const char *command
, int flags
)
416 if (flags
& EXECUTE_HIDE
)
418 cmd
= g_strconcat (" ", command
, (char *) NULL
);
419 flags
^= EXECUTE_HIDE
;
422 #ifdef ENABLE_SUBSHELL
423 if (mc_global
.tty
.use_subshell
)
424 if (subshell_state
== INACTIVE
)
425 do_execute (mc_global
.tty
.shell
, cmd
? cmd
: command
, flags
| EXECUTE_AS_SHELL
);
427 message (D_ERROR
, MSG_ERROR
, _("The shell is already running a command"));
429 #endif /* ENABLE_SUBSHELL */
430 do_execute (mc_global
.tty
.shell
, cmd
? cmd
: command
, flags
| EXECUTE_AS_SHELL
);
435 /* --------------------------------------------------------------------------------------------- */
440 do_execute (mc_global
.tty
.shell
, 0, 0);
443 /* --------------------------------------------------------------------------------------------- */
448 #ifdef ENABLE_SUBSHELL
449 vfs_path_t
*new_dir_vpath
= NULL
;
450 vfs_path_t
**new_dir_p
;
451 #endif /* ENABLE_SUBSHELL */
453 SIG_ATOMIC_VOLATILE_T was_sigwinch
= 0;
457 if (clear_before_exec
)
459 if (mc_global
.tty
.alternate_plus_minus
)
460 numeric_keypad_mode ();
462 /* With slang we don't want any of this, since there
463 * is no raw_mode supported
465 tty_reset_shell_mode ();
466 #endif /* !HAVE_SLANG */
472 if (mc_global
.tty
.console_flag
!= '\0')
473 handle_console (CONSOLE_RESTORE
);
475 #ifdef ENABLE_SUBSHELL
476 if (mc_global
.tty
.use_subshell
)
478 new_dir_p
= vfs_current_is_local ()? &new_dir_vpath
: NULL
;
479 invoke_subshell (NULL
, VISIBLY
, new_dir_p
);
482 #endif /* ENABLE_SUBSHELL */
484 if (output_starts_shell
)
486 fprintf (stderr
, _("Type `exit' to return to the Midnight Commander"));
487 fprintf (stderr
, "\n\r\n\r");
489 my_system (EXECUTE_INTERNAL
, mc_global
.tty
.shell
, NULL
);
495 if (mc_global
.tty
.console_flag
!= '\0')
496 handle_console (CONSOLE_SAVE
);
500 tty_reset_prog_mode ();
503 /* Prevent screen flash when user did 'exit' or 'logout' within
505 if ((quit
& SUBSHELL_EXIT
) != 0)
507 /* User did `exit' or `logout': quit MC */
508 if (quiet_quit_cmd ())
512 #ifdef ENABLE_SUBSHELL
513 /* restart subshell */
514 if (mc_global
.tty
.use_subshell
)
516 #endif /* ENABLE_SUBSHELL */
521 if (mc_global
.tty
.alternate_plus_minus
)
522 application_keypad_mode ();
525 * Save sigwinch flag that will be reset in mc_refresh() called via update_panels().
526 * There is some problem with screen redraw in ncurses-based mc in this situation.
528 was_sigwinch
= mc_global
.tty
.winch_flag
;
529 mc_global
.tty
.winch_flag
= 0;
531 #ifdef ENABLE_SUBSHELL
532 if (mc_global
.tty
.use_subshell
)
535 if (new_dir_vpath
!= NULL
)
536 do_possible_cd (new_dir_vpath
);
537 if (mc_global
.tty
.console_flag
!= '\0' && output_lines
)
538 show_console_contents (output_start_y
,
539 LINES
- mc_global
.keybar_visible
- output_lines
-
540 1, LINES
- mc_global
.keybar_visible
- 1);
543 vfs_path_free (new_dir_vpath
);
544 #endif /* ENABLE_SUBSHELL */
546 if (mc_global
.mc_run_mode
== MC_RUN_FULL
)
548 update_panels (UP_OPTIMIZE
, UP_KEEPSEL
);
549 update_xterm_title_path ();
552 if (was_sigwinch
!= 0 || mc_global
.tty
.winch_flag
!= 0)
553 dialog_change_screen_size ();
558 /* --------------------------------------------------------------------------------------------- */
562 execute_suspend (const gchar
* event_group_name
, const gchar
* event_name
,
563 gpointer init_data
, gpointer data
)
565 (void) event_group_name
;
570 if (mc_global
.mc_run_mode
== MC_RUN_FULL
)
573 if (mc_global
.mc_run_mode
== MC_RUN_FULL
)
574 update_panels (UP_OPTIMIZE
, UP_KEEPSEL
);
580 /* --------------------------------------------------------------------------------------------- */
583 * Execute command on a filename that can be on VFS.
584 * Errors are reported to the user.
588 execute_with_vfs_arg (const char *command
, const vfs_path_t
* filename_vpath
)
590 vfs_path_t
*localcopy_vpath
= NULL
;
591 const vfs_path_t
*do_execute_vpath
;
594 if (!execute_prepare_with_vfs_arg (filename_vpath
, &localcopy_vpath
, &mtime
))
597 do_execute_vpath
= (localcopy_vpath
== NULL
) ? filename_vpath
: localcopy_vpath
;
599 do_execute (command
, vfs_path_get_last_path_str (do_execute_vpath
), EXECUTE_INTERNAL
);
601 execute_cleanup_with_vfs_arg (filename_vpath
, &localcopy_vpath
, &mtime
);
604 /* --------------------------------------------------------------------------------------------- */
606 * Execute external editor or viewer.
608 * @param command editor/viewer to run
609 * @param filename_vpath path for edit/view
610 * @param start_line cursor will be placed at the 'start_line' position after opening file
614 execute_external_editor_or_viewer (const char *command
, const vfs_path_t
* filename_vpath
,
617 vfs_path_t
*localcopy_vpath
= NULL
;
618 const vfs_path_t
*do_execute_vpath
;
619 char *extern_cmd_options
;
622 if (!execute_prepare_with_vfs_arg (filename_vpath
, &localcopy_vpath
, &mtime
))
625 do_execute_vpath
= (localcopy_vpath
== NULL
) ? filename_vpath
: localcopy_vpath
;
628 execute_get_external_cmd_opts_from_config (command
, do_execute_vpath
, start_line
);
630 if (extern_cmd_options
!= NULL
)
632 char **argv_cmd_options
;
635 g_shell_parse_argv (extern_cmd_options
, &argv_count
, &argv_cmd_options
, NULL
);
636 g_free (extern_cmd_options
);
638 do_executev (command
, EXECUTE_INTERNAL
, argv_cmd_options
);
640 g_strfreev (argv_cmd_options
);
643 execute_cleanup_with_vfs_arg (filename_vpath
, &localcopy_vpath
, &mtime
);
646 /* --------------------------------------------------------------------------------------------- */