Remove input_set_origin(). Use widget_set_size() instead.
[midnight-commander.git] / src / execute.c
blobde3401a1f3c9f8d60343234d34ad9ba15dcedc93
1 /*
2 Execution routines for GNU Midnight Commander
4 Copyright (C) 2003, 2004, 2005, 2007, 2011, 2013
5 The Free Software Foundation, Inc.
7 Written by:
8 Slava Zanko <slavazanko@gmail.com>, 2013
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 /** \file execute.c
27 * \brief Source: execution routines
30 #include <config.h>
32 #include <signal.h>
33 #include <string.h>
34 #include <sys/stat.h>
35 #include <sys/time.h>
37 #include "lib/global.h"
39 #include "lib/tty/tty.h"
40 #include "lib/tty/key.h"
41 #include "lib/tty/win.h"
42 #include "lib/vfs/vfs.h"
43 #include "lib/mcconfig.h"
44 #include "lib/util.h"
45 #include "lib/strutil.h" /* str_replace_all_substrings() */
46 #include "lib/widget.h"
48 #include "filemanager/midnight.h"
49 #include "filemanager/layout.h" /* use_dash() */
50 #include "consaver/cons.saver.h"
51 #ifdef ENABLE_SUBSHELL
52 #include "subshell.h"
53 #endif
54 #include "setup.h" /* clear_before_exec */
56 #include "execute.h"
58 /*** global variables ****************************************************************************/
60 int pause_after_run = pause_on_dumb_terminals;
62 /*** file scope macro definitions ****************************************************************/
64 /*** file scope type declarations ****************************************************************/
66 /*** file scope variables ************************************************************************/
68 /*** file scope functions ************************************************************************/
70 void do_execute (const char *shell, const char *command, int flags);
71 void do_executev (const char *shell, int flags, char *const argv[]);
72 char *execute_get_external_cmd_opts_from_config (const char *command,
73 const vfs_path_t * filename_vpath,
74 long start_line);
76 /* --------------------------------------------------------------------------------------------- */
78 static void
79 edition_post_exec (void)
81 do_enter_ca_mode ();
83 /* FIXME: Missing on slang endwin? */
84 tty_reset_prog_mode ();
85 tty_flush_input ();
87 tty_keypad (TRUE);
88 tty_raw_mode ();
89 channels_up ();
90 enable_mouse ();
91 enable_bracketed_paste ();
92 if (mc_global.tty.alternate_plus_minus)
93 application_keypad_mode ();
96 /* --------------------------------------------------------------------------------------------- */
98 static void
99 edition_pre_exec (void)
101 if (clear_before_exec)
102 clr_scr ();
103 else
105 if (!(mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag))
106 printf ("\n\n");
109 channels_down ();
110 disable_mouse ();
111 disable_bracketed_paste ();
113 tty_reset_shell_mode ();
114 tty_keypad (FALSE);
115 tty_reset_screen ();
117 numeric_keypad_mode ();
119 /* on xterms: maybe endwin did not leave the terminal on the shell
120 * screen page: do it now.
122 * Do not move this before endwin: in some systems rmcup includes
123 * a call to clear screen, so it will end up clearing the shell screen.
125 do_exit_ca_mode ();
128 /* --------------------------------------------------------------------------------------------- */
130 #ifdef ENABLE_SUBSHELL
131 static void
132 do_possible_cd (const vfs_path_t * new_dir_vpath)
134 if (!do_cd (new_dir_vpath, cd_exact))
135 message (D_ERROR, _("Warning"),
136 _("The Commander can't change to the directory that\n"
137 "the subshell claims you are in. Perhaps you have\n"
138 "deleted your working directory, or given yourself\n"
139 "extra access permissions with the \"su\" command?"));
141 #endif /* ENABLE_SUBSHELL */
143 /* --------------------------------------------------------------------------------------------- */
145 static void
146 do_suspend_cmd (void)
148 pre_exec ();
150 if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
151 handle_console (CONSOLE_RESTORE);
153 #ifdef SIGTSTP
155 struct sigaction sigtstp_action;
157 /* Make sure that the SIGTSTP below will suspend us directly,
158 without calling ncurses' SIGTSTP handler; we *don't* want
159 ncurses to redraw the screen immediately after the SIGCONT */
160 sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
162 kill (getpid (), SIGTSTP);
164 /* Restore previous SIGTSTP action */
165 sigaction (SIGTSTP, &sigtstp_action, NULL);
167 #endif /* SIGTSTP */
169 if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
170 handle_console (CONSOLE_SAVE);
172 edition_post_exec ();
175 /* --------------------------------------------------------------------------------------------- */
177 static gboolean
178 execute_prepare_with_vfs_arg (const vfs_path_t * filename_vpath, vfs_path_t ** localcopy_vpath,
179 time_t * mtime)
181 struct stat st;
183 /* Simplest case, this file is local */
184 if ((filename_vpath == NULL && vfs_file_is_local (vfs_get_raw_current_dir ()))
185 || vfs_file_is_local (filename_vpath))
186 return TRUE;
188 /* FIXME: Creation of new files on VFS is not supported */
189 if (filename_vpath == NULL)
190 return FALSE;
192 *localcopy_vpath = mc_getlocalcopy (filename_vpath);
193 if (*localcopy_vpath == NULL)
195 message (D_ERROR, MSG_ERROR, _("Cannot fetch a local copy of %s"),
196 vfs_path_as_str (filename_vpath));
197 return FALSE;
200 mc_stat (*localcopy_vpath, &st);
201 *mtime = st.st_mtime;
202 return TRUE;
205 /* --------------------------------------------------------------------------------------------- */
207 static void
208 execute_cleanup_with_vfs_arg (const vfs_path_t * filename_vpath, vfs_path_t ** localcopy_vpath,
209 time_t * mtime)
211 if (*localcopy_vpath != NULL)
213 struct stat st;
216 * filename can be an entry on panel, it can be changed by executing
217 * the command, so make a copy. Smarter VFS code would make the code
218 * below unnecessary.
220 mc_stat (*localcopy_vpath, &st);
221 mc_ungetlocalcopy (filename_vpath, *localcopy_vpath, *mtime != st.st_mtime);
222 vfs_path_free (*localcopy_vpath);
223 *localcopy_vpath = NULL;
227 /* --------------------------------------------------------------------------------------------- */
229 static char *
230 execute_get_opts_from_cfg (const char *command, const char *default_str)
232 char *str_from_config;
234 str_from_config =
235 mc_config_get_string_raw (mc_main_config, CONFIG_EXT_EDITOR_VIEWER_SECTION, command, NULL);
237 if (str_from_config == NULL)
239 mc_config_t *cfg;
241 cfg = mc_config_init (global_profile_name, TRUE);
242 if (cfg == NULL)
243 return g_strdup (default_str);
245 str_from_config =
246 mc_config_get_string_raw (cfg, CONFIG_EXT_EDITOR_VIEWER_SECTION, command, default_str);
248 mc_config_deinit (cfg);
251 return str_from_config;
254 /* --------------------------------------------------------------------------------------------- */
255 /*** public functions ****************************************************************************/
256 /* --------------------------------------------------------------------------------------------- */
258 char *
259 execute_get_external_cmd_opts_from_config (const char *command, const vfs_path_t * filename_vpath,
260 long start_line)
262 char *str_from_config, *return_str;
263 char *parameter;
265 if (filename_vpath == NULL)
266 return g_strdup ("");
268 str_from_config = execute_get_opts_from_cfg (command, "%filename");
270 parameter = g_shell_quote (vfs_path_get_last_path_str (filename_vpath));
271 return_str = str_replace_all (str_from_config, "%filename", parameter);
272 g_free (parameter);
273 g_free (str_from_config);
274 str_from_config = return_str;
276 parameter = g_strdup_printf ("%ld", start_line);
277 return_str = str_replace_all (str_from_config, "%lineno", parameter);
278 g_free (parameter);
279 g_free (str_from_config);
281 return return_str;
284 /* --------------------------------------------------------------------------------------------- */
286 void
287 do_executev (const char *shell, int flags, char *const argv[])
289 #ifdef ENABLE_SUBSHELL
290 vfs_path_t *new_dir_vpath = NULL;
291 #endif /* ENABLE_SUBSHELL */
293 vfs_path_t *old_vfs_dir_vpath = NULL;
295 if (!vfs_current_is_local ())
296 old_vfs_dir_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
298 if (mc_global.mc_run_mode == MC_RUN_FULL)
299 save_cwds_stat ();
300 pre_exec ();
301 if (mc_global.tty.console_flag != '\0')
302 handle_console (CONSOLE_RESTORE);
304 if (!mc_global.tty.use_subshell && *argv != NULL && (flags & EXECUTE_INTERNAL) == 0)
306 printf ("%s%s\n", mc_prompt, *argv);
307 fflush (stdout);
309 #ifdef ENABLE_SUBSHELL
310 if (mc_global.tty.use_subshell && (flags & EXECUTE_INTERNAL) == 0)
312 do_update_prompt ();
314 /* We don't care if it died, higher level takes care of this */
315 invoke_subshell (*argv, VISIBLY, old_vfs_dir_vpath != NULL ? NULL : &new_dir_vpath);
317 else
318 #endif /* ENABLE_SUBSHELL */
319 my_systemv_flags (flags, shell, argv);
321 if ((flags & EXECUTE_INTERNAL) == 0)
323 if ((pause_after_run == pause_always
324 || (pause_after_run == pause_on_dumb_terminals && !mc_global.tty.xterm_flag
325 && mc_global.tty.console_flag == '\0')) && quit == 0
326 #ifdef ENABLE_SUBSHELL
327 && subshell_state != RUNNING_COMMAND
328 #endif /* ENABLE_SUBSHELL */
331 printf (_("Press any key to continue..."));
332 fflush (stdout);
333 tty_raw_mode ();
334 get_key_code (0);
335 printf ("\r\n");
336 fflush (stdout);
338 if (mc_global.tty.console_flag != '\0' && output_lines != 0 && mc_global.keybar_visible)
340 putchar ('\n');
341 fflush (stdout);
345 if (mc_global.tty.console_flag != '\0')
346 handle_console (CONSOLE_SAVE);
347 edition_post_exec ();
349 #ifdef ENABLE_SUBSHELL
350 if (new_dir_vpath != NULL)
352 do_possible_cd (new_dir_vpath);
353 vfs_path_free (new_dir_vpath);
356 #endif /* ENABLE_SUBSHELL */
358 if (old_vfs_dir_vpath != NULL)
360 mc_chdir (old_vfs_dir_vpath);
361 vfs_path_free (old_vfs_dir_vpath);
364 if (mc_global.mc_run_mode == MC_RUN_FULL)
366 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
367 update_xterm_title_path ();
370 do_refresh ();
371 use_dash (TRUE);
374 /* --------------------------------------------------------------------------------------------- */
376 void
377 do_execute (const char *shell, const char *command, int flags)
379 GPtrArray *args_array;
381 args_array = g_ptr_array_new ();
382 g_ptr_array_add (args_array, (char *) command);
383 g_ptr_array_add (args_array, NULL);
385 do_executev (shell, flags, (char *const *) args_array->pdata);
387 g_ptr_array_free (args_array, TRUE);
390 /* --------------------------------------------------------------------------------------------- */
392 /** Set up the terminal before executing a program */
394 void
395 pre_exec (void)
397 use_dash (FALSE);
398 edition_pre_exec ();
401 /* --------------------------------------------------------------------------------------------- */
402 /** Hide the terminal after executing a program */
403 void
404 post_exec (void)
406 edition_post_exec ();
407 use_dash (TRUE);
408 repaint_screen ();
411 /* --------------------------------------------------------------------------------------------- */
412 /* Executes a command */
414 void
415 shell_execute (const char *command, int flags)
417 char *cmd = NULL;
419 if (flags & EXECUTE_HIDE)
421 cmd = g_strconcat (" ", command, (char *) NULL);
422 flags ^= EXECUTE_HIDE;
425 #ifdef ENABLE_SUBSHELL
426 if (mc_global.tty.use_subshell)
427 if (subshell_state == INACTIVE)
428 do_execute (mc_global.tty.shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
429 else
430 message (D_ERROR, MSG_ERROR, _("The shell is already running a command"));
431 else
432 #endif /* ENABLE_SUBSHELL */
433 do_execute (mc_global.tty.shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
435 g_free (cmd);
438 /* --------------------------------------------------------------------------------------------- */
440 void
441 exec_shell (void)
443 do_execute (mc_global.tty.shell, 0, 0);
446 /* --------------------------------------------------------------------------------------------- */
448 void
449 toggle_panels (void)
451 #ifdef ENABLE_SUBSHELL
452 vfs_path_t *new_dir_vpath = NULL;
453 vfs_path_t **new_dir_p;
454 #endif /* ENABLE_SUBSHELL */
456 SIG_ATOMIC_VOLATILE_T was_sigwinch = 0;
458 channels_down ();
459 disable_mouse ();
460 disable_bracketed_paste ();
461 if (clear_before_exec)
462 clr_scr ();
463 if (mc_global.tty.alternate_plus_minus)
464 numeric_keypad_mode ();
465 #ifndef HAVE_SLANG
466 /* With slang we don't want any of this, since there
467 * is no raw_mode supported
469 tty_reset_shell_mode ();
470 #endif /* !HAVE_SLANG */
471 tty_noecho ();
472 tty_keypad (FALSE);
473 tty_reset_screen ();
474 do_exit_ca_mode ();
475 tty_raw_mode ();
476 if (mc_global.tty.console_flag != '\0')
477 handle_console (CONSOLE_RESTORE);
479 #ifdef ENABLE_SUBSHELL
480 if (mc_global.tty.use_subshell)
482 new_dir_p = vfs_current_is_local ()? &new_dir_vpath : NULL;
483 invoke_subshell (NULL, VISIBLY, new_dir_p);
485 else
486 #endif /* ENABLE_SUBSHELL */
488 if (output_starts_shell)
490 fprintf (stderr, _("Type 'exit' to return to the Midnight Commander"));
491 fprintf (stderr, "\n\r\n\r");
493 my_system (EXECUTE_INTERNAL, mc_global.tty.shell, NULL);
495 else
496 get_key_code (0);
499 if (mc_global.tty.console_flag != '\0')
500 handle_console (CONSOLE_SAVE);
502 do_enter_ca_mode ();
504 tty_reset_prog_mode ();
505 tty_keypad (TRUE);
507 /* Prevent screen flash when user did 'exit' or 'logout' within
508 subshell */
509 if ((quit & SUBSHELL_EXIT) != 0)
511 /* User did 'exit' or 'logout': quit MC */
512 if (quiet_quit_cmd ())
513 return;
515 quit = 0;
516 #ifdef ENABLE_SUBSHELL
517 /* restart subshell */
518 if (mc_global.tty.use_subshell)
519 init_subshell ();
520 #endif /* ENABLE_SUBSHELL */
523 enable_mouse ();
524 enable_bracketed_paste ();
525 channels_up ();
526 if (mc_global.tty.alternate_plus_minus)
527 application_keypad_mode ();
529 /* HACK:
530 * Save sigwinch flag that will be reset in mc_refresh() called via update_panels().
531 * There is some problem with screen redraw in ncurses-based mc in this situation.
533 was_sigwinch = mc_global.tty.winch_flag;
534 mc_global.tty.winch_flag = 0;
536 #ifdef ENABLE_SUBSHELL
537 if (mc_global.tty.use_subshell)
539 do_load_prompt ();
540 if (new_dir_vpath != NULL)
541 do_possible_cd (new_dir_vpath);
542 if (mc_global.tty.console_flag != '\0' && output_lines)
543 show_console_contents (output_start_y,
544 LINES - mc_global.keybar_visible - output_lines -
545 1, LINES - mc_global.keybar_visible - 1);
548 vfs_path_free (new_dir_vpath);
549 #endif /* ENABLE_SUBSHELL */
551 if (mc_global.mc_run_mode == MC_RUN_FULL)
553 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
554 update_xterm_title_path ();
557 if (was_sigwinch != 0 || mc_global.tty.winch_flag != 0)
558 dialog_change_screen_size ();
559 else
560 repaint_screen ();
563 /* --------------------------------------------------------------------------------------------- */
565 /* event callback */
566 gboolean
567 execute_suspend (const gchar * event_group_name, const gchar * event_name,
568 gpointer init_data, gpointer data)
570 (void) event_group_name;
571 (void) event_name;
572 (void) init_data;
573 (void) data;
575 if (mc_global.mc_run_mode == MC_RUN_FULL)
576 save_cwds_stat ();
577 do_suspend_cmd ();
578 if (mc_global.mc_run_mode == MC_RUN_FULL)
579 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
580 do_refresh ();
582 return TRUE;
585 /* --------------------------------------------------------------------------------------------- */
588 * Execute command on a filename that can be on VFS.
589 * Errors are reported to the user.
592 void
593 execute_with_vfs_arg (const char *command, const vfs_path_t * filename_vpath)
595 vfs_path_t *localcopy_vpath = NULL;
596 const vfs_path_t *do_execute_vpath;
597 time_t mtime;
599 if (!execute_prepare_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime))
600 return;
602 do_execute_vpath = (localcopy_vpath == NULL) ? filename_vpath : localcopy_vpath;
604 do_execute (command, vfs_path_get_last_path_str (do_execute_vpath), EXECUTE_INTERNAL);
606 execute_cleanup_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime);
609 /* --------------------------------------------------------------------------------------------- */
611 * Execute external editor or viewer.
613 * @param command editor/viewer to run
614 * @param filename_vpath path for edit/view
615 * @param start_line cursor will be placed at the 'start_line' position after opening file
618 void
619 execute_external_editor_or_viewer (const char *command, const vfs_path_t * filename_vpath,
620 long start_line)
622 vfs_path_t *localcopy_vpath = NULL;
623 const vfs_path_t *do_execute_vpath;
624 char *extern_cmd_options;
625 time_t mtime;
627 if (!execute_prepare_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime))
628 return;
630 do_execute_vpath = (localcopy_vpath == NULL) ? filename_vpath : localcopy_vpath;
632 extern_cmd_options =
633 execute_get_external_cmd_opts_from_config (command, do_execute_vpath, start_line);
635 if (extern_cmd_options != NULL)
637 char **argv_cmd_options;
638 int argv_count;
640 if (g_shell_parse_argv (extern_cmd_options, &argv_count, &argv_cmd_options, NULL))
642 do_executev (command, EXECUTE_INTERNAL, argv_cmd_options);
643 g_strfreev (argv_cmd_options);
645 else
646 do_executev (command, EXECUTE_INTERNAL, NULL);
648 g_free (extern_cmd_options);
652 execute_cleanup_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime);
655 /* --------------------------------------------------------------------------------------------- */