Add src/execute.c:execute_external_editor_or_viewer() function.
authorSlava Zanko <slavazanko@gmail.com>
Thu, 10 Jan 2013 17:20:58 +0000 (10 20:20 +0300)
committerSlava Zanko <slavazanko@gmail.com>
Sat, 16 Feb 2013 14:39:33 +0000 (16 17:39 +0300)
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
src/execute.c
src/execute.h
src/filemanager/cmd.c
tests/src/Makefile.am
tests/src/execute__common.c
tests/src/execute__execute_external_editor_or_viewer.c [new file with mode: 0644]

index f178bb0..0d13222 100644 (file)
@@ -63,6 +63,9 @@ int pause_after_run = pause_on_dumb_terminals;
 /*** file scope functions ************************************************************************/
 
 void do_execute (const char *shell, const char *command, int flags);
+void do_executev (const char *shell, int flags, char *const argv[]);
+char *execute_get_external_cmd_opts_from_config (const char *command,
+                                                 const vfs_path_t * filename_vpath, int start_line);
 
 /* --------------------------------------------------------------------------------------------- */
 
@@ -164,7 +167,8 @@ do_suspend_cmd (void)
 /* --------------------------------------------------------------------------------------------- */
 
 static gboolean
-execute_prepare_with_vfs_arg (const vfs_path_t * filename_vpath, vfs_path_t ** localcopy_vpath, time_t *mtime)
+execute_prepare_with_vfs_arg (const vfs_path_t * filename_vpath, vfs_path_t ** localcopy_vpath,
+                              time_t * mtime)
 {
     struct stat st;
 
@@ -196,7 +200,8 @@ execute_prepare_with_vfs_arg (const vfs_path_t * filename_vpath, vfs_path_t ** l
 /* --------------------------------------------------------------------------------------------- */
 
 static void
-execute_cleanup_with_vfs_arg (const vfs_path_t * filename_vpath, vfs_path_t ** localcopy_vpath, time_t *mtime)
+execute_cleanup_with_vfs_arg (const vfs_path_t * filename_vpath, vfs_path_t ** localcopy_vpath,
+                              time_t * mtime)
 {
     if (*localcopy_vpath != NULL)
     {
@@ -218,8 +223,23 @@ execute_cleanup_with_vfs_arg (const vfs_path_t * filename_vpath, vfs_path_t ** l
 /*** public functions ****************************************************************************/
 /* --------------------------------------------------------------------------------------------- */
 
+char *
+execute_get_external_cmd_opts_from_config (const char *command, const vfs_path_t * filename_vpath,
+                                           int start_line)
+{
+    (void) command;
+    (void) start_line;
+
+    if (filename_vpath == NULL)
+        return g_strdup ("");
+
+    return g_strdup (vfs_path_get_last_path_str (filename_vpath));
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
 void
-do_execute (const char *shell, const char *command, int flags)
+do_executev (const char *shell, int flags, char *const argv[])
 {
 #ifdef ENABLE_SUBSHELL
     vfs_path_t *new_dir_vpath = NULL;
@@ -236,24 +256,24 @@ do_execute (const char *shell, const char *command, int flags)
     if (mc_global.tty.console_flag != '\0')
         handle_console (CONSOLE_RESTORE);
 
-    if (!mc_global.tty.use_subshell && command && !(flags & EXECUTE_INTERNAL))
+    if (!mc_global.tty.use_subshell && *argv != NULL && (flags & EXECUTE_INTERNAL) == 0)
     {
-        printf ("%s%s\n", mc_prompt, command);
+        printf ("%s%s\n", mc_prompt, *argv);
         fflush (stdout);
     }
 #ifdef ENABLE_SUBSHELL
-    if (mc_global.tty.use_subshell && !(flags & EXECUTE_INTERNAL))
+    if (mc_global.tty.use_subshell && (flags & EXECUTE_INTERNAL) == 0)
     {
         do_update_prompt ();
 
         /* We don't care if it died, higher level takes care of this */
-        invoke_subshell (command, VISIBLY, old_vfs_dir_vpath != NULL ? NULL : &new_dir_vpath);
+        invoke_subshell (*argv, VISIBLY, old_vfs_dir_vpath != NULL ? NULL : &new_dir_vpath);
     }
     else
 #endif /* ENABLE_SUBSHELL */
-        my_system (flags, shell, command);
+        my_systemv_flags (flags, shell, argv);
 
-    if (!(flags & EXECUTE_INTERNAL))
+    if ((flags & EXECUTE_INTERNAL) == 0)
     {
         if ((pause_after_run == pause_always
              || (pause_after_run == pause_on_dumb_terminals && !mc_global.tty.xterm_flag
@@ -270,13 +290,10 @@ do_execute (const char *shell, const char *command, int flags)
             printf ("\r\n");
             fflush (stdout);
         }
-        if (mc_global.tty.console_flag != '\0')
+        if (mc_global.tty.console_flag != '\0' && output_lines != 0 && mc_global.keybar_visible)
         {
-            if (output_lines && mc_global.keybar_visible)
-            {
-                putchar ('\n');
-                fflush (stdout);
-            }
+            putchar ('\n');
+            fflush (stdout);
         }
     }
 
@@ -311,6 +328,22 @@ do_execute (const char *shell, const char *command, int flags)
 
 /* --------------------------------------------------------------------------------------------- */
 
+void
+do_execute (const char *shell, const char *command, int flags)
+{
+    GPtrArray *args_array;
+
+    args_array = g_ptr_array_new ();
+    g_ptr_array_add (args_array, (char *) command);
+    g_ptr_array_add (args_array, NULL);
+
+    do_executev (shell, flags, (char *const *) args_array->pdata);
+
+    g_ptr_array_free (args_array, TRUE);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
 /** Set up the terminal before executing a program */
 
 void
@@ -527,3 +560,45 @@ execute_with_vfs_arg (const char *command, const vfs_path_t * filename_vpath)
 }
 
 /* --------------------------------------------------------------------------------------------- */
+/**
+ * Execute external editor or viewer.
+ *
+ * @param command editor/viewer to run
+ * @param filename_vpath path for edit/view
+ * @param start_line cursor will be placed at the 'start_line' position after opening file
+ */
+
+void
+execute_external_editor_or_viewer (const char *command, const vfs_path_t * filename_vpath,
+                                   int start_line)
+{
+    vfs_path_t *localcopy_vpath = NULL;
+    const vfs_path_t *do_execute_vpath;
+    char *extern_cmd_options;
+    time_t mtime;
+
+    if (!execute_prepare_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime))
+        return;
+
+    do_execute_vpath = (localcopy_vpath == NULL) ? filename_vpath : localcopy_vpath;
+
+    extern_cmd_options =
+        execute_get_external_cmd_opts_from_config (command, do_execute_vpath, start_line);
+
+    if (extern_cmd_options != NULL)
+    {
+        char **argv_cmd_options;
+        int argv_count;
+
+        g_shell_parse_argv (extern_cmd_options, &argv_count, &argv_cmd_options, NULL);
+        g_free (extern_cmd_options);
+
+        do_executev (command, EXECUTE_INTERNAL, argv_cmd_options);
+
+        g_strfreev (argv_cmd_options);
+    }
+
+    execute_cleanup_with_vfs_arg (filename_vpath, &localcopy_vpath, &mtime);
+}
+
+/* --------------------------------------------------------------------------------------------- */
index 43dbc97..469b2be 100644 (file)
@@ -43,6 +43,8 @@ gboolean execute_suspend (const gchar * event_group_name, const gchar * event_na
 
 /* Execute command on a filename that can be on VFS */
 void execute_with_vfs_arg (const char *command, const vfs_path_t * filename_vpath);
+void execute_external_editor_or_viewer (const char *command, const vfs_path_t * filename_vpath,
+                                        int start_line);
 
 void post_exec (void);
 void pre_exec (void);
index d504117..bbefb6a 100644 (file)
@@ -669,7 +669,7 @@ view_file_at_line (const vfs_path_t * filename_vpath, int plain_view, int intern
                 viewer = "view";
         }
 
-        execute_with_vfs_arg (viewer, filename_vpath);
+        execute_external_editor_or_viewer (viewer, filename_vpath, start_line);
     }
 
     return ret;
@@ -769,8 +769,6 @@ do_edit_at_line (const vfs_path_t * what_vpath, gboolean internal, int start_lin
     if (internal)
         edit_file (what_vpath, start_line);
     else
-#else
-    (void) start_line;
 #endif /* USE_INTERNAL_EDIT */
     {
         if (editor == NULL)
@@ -779,7 +777,7 @@ do_edit_at_line (const vfs_path_t * what_vpath, gboolean internal, int start_lin
             if (editor == NULL)
                 editor = get_default_editor ();
         }
-        execute_with_vfs_arg (editor, what_vpath);
+        execute_external_editor_or_viewer (editor, what_vpath, start_line);
     }
 
     if (mc_global.mc_run_mode == MC_RUN_FULL)
index c5b4f9f..cff096d 100644 (file)
@@ -20,9 +20,14 @@ endif
 EXTRA_DIST = execute__common.c
 
 TESTS = \
-       execute__execute_with_vfs_arg
+       execute__execute_with_vfs_arg \
+       execute__execute_external_editor_or_viewer
 
 check_PROGRAMS = $(TESTS)
 
 execute__execute_with_vfs_arg_SOURCES = \
        execute__execute_with_vfs_arg.c
+
+
+execute__execute_external_editor_or_viewer_SOURCES = \
+       execute__execute_external_editor_or_viewer.c
\ No newline at end of file
index 97d12f0..883b30a 100644 (file)
@@ -110,14 +110,14 @@ mc_getlocalcopy (const vfs_path_t * pathname_vpath)
 }
 
 static void
-mc_getlocalcopy__init ()
+mc_getlocalcopy__init (void)
 {
     mc_getlocalcopy__pathname_vpath__captured = NULL;
     mc_getlocalcopy__return_value = NULL;
 }
 
 static void
-mc_getlocalcopy__deinit ()
+mc_getlocalcopy__deinit (void)
 {
     vfs_path_free (mc_getlocalcopy__pathname_vpath__captured);
 }
@@ -151,7 +151,7 @@ message (int flags, const char *title, const char *text, ...)
 }
 
 static void
-message__init ()
+message__init (void)
 {
     message_flags__captured = 0;
     message_title__captured = NULL;
@@ -159,7 +159,7 @@ message__init ()
 }
 
 static void
-message__deinit ()
+message__deinit (void)
 {
     g_free (message_title__captured);
     g_free (message_text__captured);
@@ -184,13 +184,13 @@ mc_stat (const vfs_path_t * vpath, struct stat *stat_ignored)
 
 
 static void
-mc_stat__init ()
+mc_stat__init (void)
 {
     mc_stat__vpath__captured = g_ptr_array_new ();
 }
 
 static void
-mc_stat__deinit ()
+mc_stat__deinit (void)
 {
     g_ptr_array_foreach (mc_stat__vpath__captured, (GFunc) vfs_path_free, NULL);
     g_ptr_array_free (mc_stat__vpath__captured, TRUE);
@@ -218,14 +218,14 @@ mc_ungetlocalcopy (const vfs_path_t * pathname_vpath, const vfs_path_t * local_v
 }
 
 static void
-mc_ungetlocalcopy__init ()
+mc_ungetlocalcopy__init (void)
 {
     mc_ungetlocalcopy__pathname_vpath__captured = NULL;
     mc_ungetlocalcopy__local_vpath__captured = NULL;
 }
 
 static void
-mc_ungetlocalcopy__deinit ()
+mc_ungetlocalcopy__deinit (void)
 {
     vfs_path_free (mc_ungetlocalcopy__pathname_vpath__captured);
     vfs_path_free (mc_ungetlocalcopy__local_vpath__captured);
diff --git a/tests/src/execute__execute_external_editor_or_viewer.c b/tests/src/execute__execute_external_editor_or_viewer.c
new file mode 100644 (file)
index 0000000..0d4fe1d
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+   src - tests for execute_external_editor_or_viewer() function
+
+   Copyright (C) 2013
+   The Free Software Foundation, Inc.
+
+   Written by:
+   Slava Zanko <slavazanko@gmail.com>, 2013
+
+   This file is part of the Midnight Commander.
+
+   The Midnight Commander is free software: you can redistribute it
+   and/or modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation, either version 3 of the License,
+   or (at your option) any later version.
+
+   The Midnight Commander is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define TEST_SUITE_NAME "/src"
+
+#include <config.h>
+
+#include <check.h>
+
+#include "lib/global.h"
+
+#include "execute__common.c"
+
+/* --------------------------------------------------------------------------------------------- */
+
+char *execute_get_external_cmd_opts_from_config (const char *command,
+                                                 const vfs_path_t * filename_vpath, int start_line);
+
+/* @CapturedValue */
+static char *execute_external_cmd_opts__command__captured;
+/* @CapturedValue */
+static vfs_path_t *execute_external_cmd_opts__filename_vpath__captured;
+/* @CapturedValue */
+static int execute_external_cmd_opts__start_line__captured;
+
+/* @ThenReturnValue */
+static char *execute_external_cmd_opts__return_value;
+
+/* @Mock */
+char *
+execute_get_external_cmd_opts_from_config (const char *command, const vfs_path_t * filename_vpath,
+                                           int start_line)
+{
+    execute_external_cmd_opts__command__captured = g_strdup (command);
+    execute_external_cmd_opts__filename_vpath__captured = vfs_path_clone (filename_vpath);
+    execute_external_cmd_opts__start_line__captured = start_line;
+
+    return execute_external_cmd_opts__return_value;
+}
+
+static void
+execute_get_external_cmd_opts_from_config__init (void)
+{
+    execute_external_cmd_opts__command__captured = NULL;
+    execute_external_cmd_opts__filename_vpath__captured = NULL;
+    execute_external_cmd_opts__start_line__captured = 0;
+}
+
+static void
+execute_get_external_cmd_opts_from_config__deinit (void)
+{
+    g_free (execute_external_cmd_opts__command__captured);
+    vfs_path_free (execute_external_cmd_opts__filename_vpath__captured);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+void do_executev (const char *lc_shell, int flags, char *const argv[]);
+
+/* @CapturedValue */
+static char *do_executev__lc_shell__captured;
+/* @CapturedValue */
+static int do_executev__flags__captured;
+/* @CapturedValue */
+static GPtrArray *do_executev__argv__captured;
+
+/* @Mock */
+void
+do_executev (const char *lc_shell, int flags, char *const argv[])
+{
+    do_executev__lc_shell__captured = g_strdup (lc_shell);
+    do_executev__flags__captured = flags;
+
+    for (; argv != NULL && *argv != NULL; argv++)
+        g_ptr_array_add (do_executev__argv__captured, g_strdup (*argv));
+}
+
+static void
+do_executev__init (void)
+{
+    do_executev__lc_shell__captured = NULL;
+    do_executev__argv__captured = g_ptr_array_new ();
+    do_executev__flags__captured = 0;
+}
+
+static void
+do_executev__deinit (void)
+{
+    g_free (do_executev__lc_shell__captured);
+    g_ptr_array_foreach (do_executev__argv__captured, (GFunc) g_free, NULL);
+    g_ptr_array_free (do_executev__argv__captured, TRUE);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+/* @Before */
+static void
+my_setup (void)
+{
+    setup ();
+
+    execute_get_external_cmd_opts_from_config__init ();
+    do_executev__init ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+/* @After */
+static void
+my_teardown (void)
+{
+    do_executev__deinit ();
+    execute_get_external_cmd_opts_from_config__deinit ();
+
+    teardown ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+/* @Test */
+/* *INDENT-OFF* */
+START_TEST (do_open_external_editor_or_viewer)
+/* *INDENT-ON* */
+{
+    /* given */
+    vfs_path_t *filename_vpath;
+    filename_vpath = vfs_path_from_str ("/path/to/file.txt");
+
+    vfs_file_is_local__return_value = TRUE;
+    execute_external_cmd_opts__return_value =
+        g_strdup
+        (" 'param 1 with spaces' \"param 2\"           -a -b -cdef /path/to/file.txt +123");
+
+    /* when */
+    execute_external_editor_or_viewer ("editor_or_viewer", filename_vpath, 123);
+
+    /* then */
+
+    /* check call to execute_get_external_cmd_opts_from_config() */
+    g_assert_cmpstr (execute_external_cmd_opts__command__captured, ==, "editor_or_viewer");
+    ck_assert_int_eq (vfs_path_cmp
+                      (execute_external_cmd_opts__filename_vpath__captured, filename_vpath), 0);
+    ck_assert_int_eq (execute_external_cmd_opts__start_line__captured, 123);
+
+    /* check call to do_executev() */
+    g_assert_cmpstr (do_executev__lc_shell__captured, ==, "editor_or_viewer");
+    ck_assert_int_eq (do_executev__flags__captured, EXECUTE_INTERNAL);
+    ck_assert_int_eq (do_executev__argv__captured->len, 7);
+
+    g_assert_cmpstr (g_ptr_array_index (do_executev__argv__captured, 0), ==, "param 1 with spaces");
+    g_assert_cmpstr (g_ptr_array_index (do_executev__argv__captured, 1), ==, "param 2");
+    g_assert_cmpstr (g_ptr_array_index (do_executev__argv__captured, 2), ==, "-a");
+    g_assert_cmpstr (g_ptr_array_index (do_executev__argv__captured, 3), ==, "-b");
+    g_assert_cmpstr (g_ptr_array_index (do_executev__argv__captured, 4), ==, "-cdef");
+    g_assert_cmpstr (g_ptr_array_index (do_executev__argv__captured, 5), ==, "/path/to/file.txt");
+    g_assert_cmpstr (g_ptr_array_index (do_executev__argv__captured, 6), ==, "+123");
+
+    vfs_path_free (filename_vpath);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+main (void)
+{
+    int number_failed;
+
+    Suite *s = suite_create (TEST_SUITE_NAME);
+    TCase *tc_core = tcase_create ("Core");
+    SRunner *sr;
+
+    tcase_add_checked_fixture (tc_core, my_setup, my_teardown);
+
+    /* Add new tests here: *************** */
+    tcase_add_test (tc_core, do_open_external_editor_or_viewer);
+    /* *********************************** */
+
+    suite_add_tcase (s, tc_core);
+    sr = srunner_create (s);
+    srunner_set_log (sr, "execute__execute_external_editor_or_viewer.log");
+    srunner_run_all (sr, CK_NORMAL);
+    number_failed = srunner_ntests_failed (sr);
+    srunner_free (sr);
+    return (number_failed == 0) ? 0 : 1;
+}
+
+/* --------------------------------------------------------------------------------------------- */