root/src/execute.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. edition_post_exec
  2. edition_pre_exec
  3. do_possible_cd
  4. do_suspend_cmd
  5. execute_prepare_with_vfs_arg
  6. execute_cleanup_with_vfs_arg
  7. execute_get_opts_from_cfg
  8. execute_get_external_cmd_opts_from_config
  9. do_executev
  10. do_execute
  11. pre_exec
  12. post_exec
  13. shell_execute
  14. toggle_subshell
  15. execute_suspend
  16. execute_with_vfs_arg
  17. execute_external_editor_or_viewer

   1 /*
   2    Execution routines for GNU Midnight Commander
   3 
   4    Copyright (C) 2003-2025
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Slava Zanko <slavazanko@gmail.com>, 2013
   9 
  10    This file is part of the Midnight Commander.
  11 
  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.
  16 
  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.
  21 
  22    You should have received a copy of the GNU General Public License
  23    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  24  */
  25 
  26 /** \file  execute.c
  27  *  \brief Source: execution routines
  28  */
  29 
  30 #include <config.h>
  31 
  32 #include <signal.h>
  33 #include <string.h>
  34 #include <sys/stat.h>
  35 #include <sys/time.h>
  36 
  37 #include "lib/global.h"
  38 
  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"
  47 
  48 #include "filemanager/filemanager.h"
  49 #include "filemanager/layout.h"  // use_dash()
  50 #include "consaver/cons.saver.h"
  51 #ifdef ENABLE_SUBSHELL
  52 #    include "subshell/subshell.h"
  53 #endif
  54 #include "setup.h"  // clear_before_exec
  55 
  56 #include "execute.h"
  57 
  58 /*** global variables ****************************************************************************/
  59 
  60 int pause_after_run = pause_on_dumb_terminals;
  61 
  62 /*** file scope macro definitions ****************************************************************/
  63 
  64 /*** file scope type declarations ****************************************************************/
  65 
  66 /*** forward declarations (file scope functions) *************************************************/
  67 
  68 MC_MOCKABLE void do_execute (const char *shell, const char *command, int flags);
  69 MC_MOCKABLE void do_executev (const char *shell, int flags, char *const argv[]);
  70 MC_MOCKABLE char *execute_get_external_cmd_opts_from_config (const char *command,
  71                                                              const vfs_path_t *filename_vpath,
  72                                                              long start_line);
  73 
  74 /*** file scope variables ************************************************************************/
  75 
  76 /* --------------------------------------------------------------------------------------------- */
  77 /*** file scope functions ************************************************************************/
  78 /* --------------------------------------------------------------------------------------------- */
  79 
  80 static void
  81 edition_post_exec (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  82 {
  83     tty_enter_ca_mode ();
  84 
  85     // FIXME: Missing on slang endwin?
  86     tty_reset_prog_mode ();
  87     tty_flush_input ();
  88 
  89     tty_keypad (TRUE);
  90     tty_raw_mode ();
  91     channels_up ();
  92     enable_mouse ();
  93     enable_bracketed_paste ();
  94     if (mc_global.tty.alternate_plus_minus)
  95         application_keypad_mode ();
  96 }
  97 
  98 /* --------------------------------------------------------------------------------------------- */
  99 
 100 static void
 101 edition_pre_exec (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 102 {
 103     if (clear_before_exec)
 104         tty_clear_screen ();
 105     else
 106     {
 107         if (!(mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag))
 108             printf ("\n\n");
 109     }
 110 
 111     channels_down ();
 112     disable_mouse ();
 113     disable_bracketed_paste ();
 114 
 115     tty_reset_shell_mode ();
 116     tty_keypad (FALSE);
 117     tty_reset_screen ();
 118 
 119     numeric_keypad_mode ();
 120 
 121     /* on xterms: maybe endwin did not leave the terminal on the shell
 122      * screen page: do it now.
 123      *
 124      * Do not move this before endwin: in some systems rmcup includes
 125      * a call to clear screen, so it will end up clearing the shell screen.
 126      */
 127     tty_exit_ca_mode ();
 128 }
 129 
 130 /* --------------------------------------------------------------------------------------------- */
 131 
 132 #ifdef ENABLE_SUBSHELL
 133 static void
 134 do_possible_cd (const vfs_path_t *new_dir_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 135 {
 136     if (!panel_cd (current_panel, new_dir_vpath, cd_exact))
 137         message (D_ERROR, _ ("Warning"), "%s",
 138                  _ ("The Commander can't change to the directory that\n"
 139                     "the subshell claims you are in. Perhaps you have\n"
 140                     "deleted your working directory, or given yourself\n"
 141                     "extra access permissions with the \"su\" command?"));
 142 }
 143 #endif
 144 
 145 /* --------------------------------------------------------------------------------------------- */
 146 
 147 static void
 148 do_suspend_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 149 {
 150     pre_exec ();
 151 
 152     if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
 153         handle_console (CONSOLE_RESTORE);
 154 
 155 #ifdef SIGTSTP
 156     {
 157         struct sigaction sigtstp_action;
 158 
 159         memset (&sigtstp_action, 0, sizeof (sigtstp_action));
 160         /* Make sure that the SIGTSTP below will suspend us directly,
 161            without calling ncurses' SIGTSTP handler; we *don't* want
 162            ncurses to redraw the screen immediately after the SIGCONT */
 163         my_sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
 164 
 165         kill (getpid (), SIGTSTP);
 166 
 167         // Restore previous SIGTSTP action
 168         my_sigaction (SIGTSTP, &sigtstp_action, NULL);
 169     }
 170 #endif
 171 
 172     if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
 173         handle_console (CONSOLE_SAVE);
 174 
 175     edition_post_exec ();
 176 }
 177 
 178 /* --------------------------------------------------------------------------------------------- */
 179 
 180 static gboolean
 181 execute_prepare_with_vfs_arg (const vfs_path_t *filename_vpath, vfs_path_t **localcopy_vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 182                               time_t *mtime)
 183 {
 184     struct stat st;
 185 
 186     // Simplest case, this file is local
 187     if ((filename_vpath == NULL && vfs_file_is_local (vfs_get_raw_current_dir ()))
 188         || vfs_file_is_local (filename_vpath))
 189         return TRUE;
 190 
 191     // FIXME: Creation of new files on VFS is not supported
 192     if (filename_vpath == NULL)
 193         return FALSE;
 194 
 195     *localcopy_vpath = mc_getlocalcopy (filename_vpath);
 196     if (*localcopy_vpath == NULL)
 197     {
 198         message (D_ERROR, MSG_ERROR, _ ("Cannot fetch a local copy of %s"),
 199                  vfs_path_as_str (filename_vpath));
 200         return FALSE;
 201     }
 202 
 203     mc_stat (*localcopy_vpath, &st);
 204     *mtime = st.st_mtime;
 205     return TRUE;
 206 }
 207 
 208 /* --------------------------------------------------------------------------------------------- */
 209 
 210 static void
 211 execute_cleanup_with_vfs_arg (const vfs_path_t *filename_vpath, vfs_path_t **localcopy_vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 212                               time_t *mtime)
 213 {
 214     if (*localcopy_vpath != NULL)
 215     {
 216         struct stat st;
 217 
 218         /*
 219          * filename can be an entry on panel, it can be changed by executing
 220          * the command, so make a copy.  Smarter VFS code would make the code
 221          * below unnecessary.
 222          */
 223         mc_stat (*localcopy_vpath, &st);
 224         mc_ungetlocalcopy (filename_vpath, *localcopy_vpath, *mtime != st.st_mtime);
 225         vfs_path_free (*localcopy_vpath, TRUE);
 226         *localcopy_vpath = NULL;
 227     }
 228 }
 229 
 230 /* --------------------------------------------------------------------------------------------- */
 231 
 232 static char *
 233 execute_get_opts_from_cfg (const char *command, const char *default_str)
     /* [previous][next][first][last][top][bottom][index][help]  */
 234 {
 235     char *str_from_config;
 236 
 237     str_from_config = mc_config_get_string_raw (mc_global.main_config,
 238                                                 CONFIG_EXT_EDITOR_VIEWER_SECTION, command, NULL);
 239 
 240     if (str_from_config == NULL)
 241     {
 242         mc_config_t *cfg;
 243 
 244         cfg = mc_config_init (mc_global.profile_name, TRUE);
 245         if (cfg == NULL)
 246             return g_strdup (default_str);
 247 
 248         str_from_config =
 249             mc_config_get_string_raw (cfg, CONFIG_EXT_EDITOR_VIEWER_SECTION, command, default_str);
 250 
 251         mc_config_deinit (cfg);
 252     }
 253 
 254     return str_from_config;
 255 }
 256 
 257 /* --------------------------------------------------------------------------------------------- */
 258 /*** public functions ****************************************************************************/
 259 /* --------------------------------------------------------------------------------------------- */
 260 
 261 char *
 262 execute_get_external_cmd_opts_from_config (const char *command, const vfs_path_t *filename_vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 263                                            long start_line)
 264 {
 265     char *str_from_config, *return_str;
 266     char *parameter;
 267 
 268     if (filename_vpath == NULL)
 269         return g_strdup ("");
 270 
 271     parameter = g_shell_quote (vfs_path_get_last_path_str (filename_vpath));
 272 
 273     if (start_line <= 0)
 274         return parameter;
 275 
 276     str_from_config = execute_get_opts_from_cfg (command, "%filename");
 277 
 278     return_str = str_replace_all (str_from_config, "%filename", parameter);
 279     g_free (parameter);
 280     g_free (str_from_config);
 281     str_from_config = return_str;
 282 
 283     parameter = g_strdup_printf ("%ld", start_line);
 284     return_str = str_replace_all (str_from_config, "%lineno", parameter);
 285     g_free (parameter);
 286     g_free (str_from_config);
 287 
 288     return return_str;
 289 }
 290 
 291 /* --------------------------------------------------------------------------------------------- */
 292 
 293 void
 294 do_executev (const char *shell, int flags, char *const argv[])
     /* [previous][next][first][last][top][bottom][index][help]  */
 295 {
 296 #ifdef ENABLE_SUBSHELL
 297     vfs_path_t *new_dir_vpath = NULL;
 298 #endif
 299 
 300     vfs_path_t *old_vfs_dir_vpath = NULL;
 301 
 302     if (!vfs_current_is_local ())
 303         old_vfs_dir_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
 304 
 305     if (mc_global.mc_run_mode == MC_RUN_FULL)
 306         save_cwds_stat ();
 307     pre_exec ();
 308     if (mc_global.tty.console_flag != '\0')
 309         handle_console (CONSOLE_RESTORE);
 310 
 311     if (!mc_global.tty.use_subshell && (flags & EXECUTE_INTERNAL) == 0 && argv != NULL
 312         && *argv != NULL)
 313     {
 314         printf ("%s%s\n", mc_prompt, *argv);
 315         fflush (stdout);
 316     }
 317 #ifdef ENABLE_SUBSHELL
 318     if (mc_global.tty.use_subshell && (flags & EXECUTE_INTERNAL) == 0 && argv != NULL)
 319     {
 320         do_update_prompt ();
 321 
 322         // We don't care if it died, higher level takes care of this
 323         invoke_subshell (*argv, VISIBLY, old_vfs_dir_vpath != NULL ? NULL : &new_dir_vpath);
 324     }
 325     else
 326 #endif
 327         my_systemv_flags (flags, shell, argv);
 328 
 329     if ((flags & EXECUTE_INTERNAL) == 0)
 330     {
 331         if ((pause_after_run == pause_always
 332              || (pause_after_run == pause_on_dumb_terminals && !mc_global.tty.xterm_flag
 333                  && mc_global.tty.console_flag == '\0'))
 334             && quit == 0
 335 #ifdef ENABLE_SUBSHELL
 336             && subshell_state != RUNNING_COMMAND
 337 #endif
 338         )
 339         {
 340             printf ("%s", _ ("Press any key to continue..."));
 341             fflush (stdout);
 342             tty_raw_mode ();
 343             get_key_code (0);
 344             printf ("\r\n");
 345             fflush (stdout);
 346         }
 347         if (mc_global.tty.console_flag != '\0' && output_lines != 0 && mc_global.keybar_visible)
 348         {
 349             putchar ('\n');
 350             fflush (stdout);
 351         }
 352     }
 353 
 354     if (mc_global.tty.console_flag != '\0')
 355         handle_console (CONSOLE_SAVE);
 356     edition_post_exec ();
 357 
 358 #ifdef ENABLE_SUBSHELL
 359     if (new_dir_vpath != NULL)
 360     {
 361         do_possible_cd (new_dir_vpath);
 362         vfs_path_free (new_dir_vpath, TRUE);
 363     }
 364 
 365 #endif
 366 
 367     if (old_vfs_dir_vpath != NULL)
 368     {
 369         mc_chdir (old_vfs_dir_vpath);
 370         vfs_path_free (old_vfs_dir_vpath, TRUE);
 371     }
 372 
 373     if (mc_global.mc_run_mode == MC_RUN_FULL)
 374     {
 375         update_panels (UP_OPTIMIZE, UP_KEEPSEL);
 376         update_xterm_title_path ();
 377         update_terminal_cwd ();
 378     }
 379 
 380     do_refresh ();
 381     use_dash (TRUE);
 382 }
 383 
 384 /* --------------------------------------------------------------------------------------------- */
 385 
 386 void
 387 do_execute (const char *shell, const char *command, int flags)
     /* [previous][next][first][last][top][bottom][index][help]  */
 388 {
 389     GPtrArray *args_array;
 390 
 391     args_array = g_ptr_array_new ();
 392     g_ptr_array_add (args_array, (char *) command);
 393     g_ptr_array_add (args_array, NULL);
 394 
 395     do_executev (shell, flags, (char *const *) args_array->pdata);
 396 
 397     g_ptr_array_free (args_array, TRUE);
 398 }
 399 
 400 /* --------------------------------------------------------------------------------------------- */
 401 
 402 /** Set up the terminal before executing a program */
 403 
 404 void
 405 pre_exec (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 406 {
 407     use_dash (FALSE);
 408     edition_pre_exec ();
 409 }
 410 
 411 /* --------------------------------------------------------------------------------------------- */
 412 /** Hide the terminal after executing a program */
 413 void
 414 post_exec (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 415 {
 416     edition_post_exec ();
 417     use_dash (TRUE);
 418     repaint_screen ();
 419 }
 420 
 421 /* --------------------------------------------------------------------------------------------- */
 422 /* Executes a command */
 423 
 424 void
 425 shell_execute (const char *command, int flags)
     /* [previous][next][first][last][top][bottom][index][help]  */
 426 {
 427     char *cmd = NULL;
 428 
 429     if ((flags & EXECUTE_HIDE) != 0)
 430     {
 431         cmd = g_strconcat (" ", command, (char *) NULL);
 432         flags ^= EXECUTE_HIDE;
 433     }
 434 
 435 #ifdef ENABLE_SUBSHELL
 436     if (mc_global.tty.use_subshell)
 437     {
 438         if (subshell_state == INACTIVE)
 439             do_execute (mc_global.shell->path, cmd != NULL ? cmd : command,
 440                         flags | EXECUTE_AS_SHELL);
 441         else
 442             message (D_ERROR, MSG_ERROR, "%s", _ ("The shell is already running a command"));
 443     }
 444     else
 445 #endif
 446         do_execute (mc_global.shell->path, cmd != NULL ? cmd : command, flags | EXECUTE_AS_SHELL);
 447 
 448     g_free (cmd);
 449 }
 450 
 451 /* --------------------------------------------------------------------------------------------- */
 452 
 453 void
 454 toggle_subshell (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 455 {
 456     static gboolean message_flag = TRUE;
 457 
 458 #ifdef ENABLE_SUBSHELL
 459     vfs_path_t *new_dir_vpath = NULL;
 460 #endif
 461 
 462     SIG_ATOMIC_VOLATILE_T was_sigwinch = 0;
 463 
 464     if (!(mc_global.tty.xterm_flag || mc_global.tty.console_flag != '\0'
 465           || mc_global.tty.use_subshell || output_starts_shell))
 466     {
 467         if (message_flag)
 468             message (D_ERROR, MSG_ERROR,
 469                      _ ("Not an xterm or Linux console;\nthe subshell cannot be toggled."));
 470         message_flag = FALSE;
 471         return;
 472     }
 473 
 474     channels_down ();
 475     disable_mouse ();
 476     disable_bracketed_paste ();
 477     if (clear_before_exec)
 478         tty_clear_screen ();
 479     if (mc_global.tty.alternate_plus_minus)
 480         numeric_keypad_mode ();
 481 #ifndef HAVE_SLANG
 482     /* With slang we don't want any of this, since there
 483      * is no raw_mode supported
 484      */
 485     tty_reset_shell_mode ();
 486 #endif
 487     tty_noecho ();
 488     tty_keypad (FALSE);
 489     tty_reset_screen ();
 490     tty_exit_ca_mode ();
 491     tty_raw_mode ();
 492     if (mc_global.tty.console_flag != '\0')
 493         handle_console (CONSOLE_RESTORE);
 494 
 495 #ifdef ENABLE_SUBSHELL
 496     if (mc_global.tty.use_subshell)
 497     {
 498         vfs_path_t **new_dir_p;
 499 
 500         new_dir_p = vfs_current_is_local () ? &new_dir_vpath : NULL;
 501         invoke_subshell (NULL, VISIBLY, new_dir_p);
 502     }
 503     else
 504 #endif
 505     {
 506         if (output_starts_shell)
 507         {
 508             fputs (_ ("Type 'exit' to return to the Midnight Commander"), stderr);
 509             fputs ("\n\r\n\r", stderr);
 510 
 511             my_system (EXECUTE_INTERNAL, mc_global.shell->path, NULL);
 512         }
 513         else
 514             get_key_code (0);
 515     }
 516 
 517     if (mc_global.tty.console_flag != '\0')
 518         handle_console (CONSOLE_SAVE);
 519 
 520     tty_enter_ca_mode ();
 521 
 522     tty_reset_prog_mode ();
 523     tty_keypad (TRUE);
 524 
 525     /* Prevent screen flash when user did 'exit' or 'logout' within
 526        subshell */
 527     if ((quit & SUBSHELL_EXIT) != 0)
 528     {
 529         // User did 'exit' or 'logout': quit MC
 530         if (quiet_quit_cmd ())
 531             return;
 532 
 533         quit = 0;
 534 #ifdef ENABLE_SUBSHELL
 535         // restart subshell
 536         if (mc_global.tty.use_subshell)
 537             init_subshell ();
 538 #endif
 539     }
 540 
 541     enable_mouse ();
 542     enable_bracketed_paste ();
 543     channels_up ();
 544     if (mc_global.tty.alternate_plus_minus)
 545         application_keypad_mode ();
 546 
 547     /* HACK:
 548      * Save sigwinch flag that will be reset in mc_refresh() called via update_panels().
 549      * There is some problem with screen redraw in ncurses-based mc in this situation.
 550      */
 551     was_sigwinch = tty_flush_winch ();
 552 
 553 #ifdef ENABLE_SUBSHELL
 554     if (mc_global.tty.use_subshell)
 555     {
 556         if (mc_global.mc_run_mode == MC_RUN_FULL)
 557         {
 558             if (new_dir_vpath != NULL)
 559                 do_possible_cd (new_dir_vpath);
 560         }
 561         else if (new_dir_vpath != NULL && mc_chdir (new_dir_vpath) != -1)
 562             vfs_setup_cwd ();
 563     }
 564 
 565     vfs_path_free (new_dir_vpath, TRUE);
 566 #endif
 567 
 568     if (mc_global.mc_run_mode == MC_RUN_FULL)
 569     {
 570         update_panels (UP_OPTIMIZE, UP_KEEPSEL);
 571         update_xterm_title_path ();
 572         update_terminal_cwd ();
 573     }
 574 
 575     if (was_sigwinch != 0 || tty_got_winch ())
 576         dialog_change_screen_size ();
 577     else
 578         repaint_screen ();
 579 }
 580 
 581 /* --------------------------------------------------------------------------------------------- */
 582 
 583 /* event callback */
 584 gboolean
 585 execute_suspend (const gchar *event_group_name, const gchar *event_name, gpointer init_data,
     /* [previous][next][first][last][top][bottom][index][help]  */
 586                  gpointer data)
 587 {
 588     (void) event_group_name;
 589     (void) event_name;
 590     (void) init_data;
 591     (void) data;
 592 
 593     if (mc_global.mc_run_mode == MC_RUN_FULL)
 594         save_cwds_stat ();
 595     do_suspend_cmd ();
 596     if (mc_global.mc_run_mode == MC_RUN_FULL)
 597         update_panels (UP_OPTIMIZE, UP_KEEPSEL);
 598     do_refresh ();
 599 
 600     return TRUE;
 601 }
 602 
 603 /* --------------------------------------------------------------------------------------------- */
 604 
 605 /**
 606  * Execute command on a filename that can be on VFS.
 607  * Errors are reported to the user.
 608  */
 609 
 610 void
 611 execute_with_vfs_arg (const char *command, const vfs_path_t *filename_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 612 {
 613     vfs_path_t *localcopy_vpath = NULL;
 614     const vfs_path_t *do_execute_vpath;
 615     time_t mtime;
 616 
 617     if (!execute_prepare_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime))
 618         return;
 619 
 620     do_execute_vpath = (localcopy_vpath == NULL) ? filename_vpath : localcopy_vpath;
 621 
 622     do_execute (command, vfs_path_get_last_path_str (do_execute_vpath), EXECUTE_INTERNAL);
 623 
 624     execute_cleanup_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime);
 625 }
 626 
 627 /* --------------------------------------------------------------------------------------------- */
 628 /**
 629  * Execute external editor or viewer.
 630  *
 631  * @param command editor/viewer to run
 632  * @param filename_vpath path for edit/view
 633  * @param start_line cursor will be placed at the 'start_line' position after opening file
 634  *        if start_line is 0 or negative, no start line will be passed to editor/viewer
 635  */
 636 
 637 void
 638 execute_external_editor_or_viewer (const char *command, const vfs_path_t *filename_vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 639                                    long start_line)
 640 {
 641     vfs_path_t *localcopy_vpath = NULL;
 642     const vfs_path_t *do_execute_vpath;
 643     char *extern_cmd_options;
 644     time_t mtime = 0;
 645 
 646     if (!execute_prepare_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime))
 647         return;
 648 
 649     do_execute_vpath = (localcopy_vpath == NULL) ? filename_vpath : localcopy_vpath;
 650 
 651     extern_cmd_options =
 652         execute_get_external_cmd_opts_from_config (command, do_execute_vpath, start_line);
 653 
 654     if (extern_cmd_options != NULL)
 655     {
 656         char **argv_cmd_options;
 657         int argv_count;
 658 
 659         if (g_shell_parse_argv (extern_cmd_options, &argv_count, &argv_cmd_options, NULL))
 660         {
 661             do_executev (command, EXECUTE_INTERNAL, argv_cmd_options);
 662             g_strfreev (argv_cmd_options);
 663         }
 664         else
 665             do_executev (command, EXECUTE_INTERNAL, NULL);
 666 
 667         g_free (extern_cmd_options);
 668     }
 669 
 670     execute_cleanup_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime);
 671 }
 672 
 673 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */