From 2a2bc562219f87343977301eaaac59da8154cab0 Mon Sep 17 00:00:00 2001 From: Slava Zanko Date: Thu, 10 Jan 2013 20:20:58 +0300 Subject: [PATCH] Add src/execute.c:execute_external_editor_or_viewer() function. Signed-off-by: Slava Zanko --- src/execute.c | 105 +++++++-- src/execute.h | 2 + src/filemanager/cmd.c | 6 +- tests/src/Makefile.am | 7 +- tests/src/execute__common.c | 16 +- ...ecute__execute_external_editor_or_viewer.c | 211 ++++++++++++++++++ 6 files changed, 319 insertions(+), 28 deletions(-) create mode 100644 tests/src/execute__execute_external_editor_or_viewer.c diff --git a/src/execute.c b/src/execute.c index f178bb062..0d13222f1 100644 --- a/src/execute.c +++ b/src/execute.c @@ -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); +} + +/* --------------------------------------------------------------------------------------------- */ diff --git a/src/execute.h b/src/execute.h index 43dbc9750..469b2be88 100644 --- a/src/execute.h +++ b/src/execute.h @@ -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); diff --git a/src/filemanager/cmd.c b/src/filemanager/cmd.c index d50411732..bbefb6a94 100644 --- a/src/filemanager/cmd.c +++ b/src/filemanager/cmd.c @@ -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) diff --git a/tests/src/Makefile.am b/tests/src/Makefile.am index c5b4f9faa..cff096de5 100644 --- a/tests/src/Makefile.am +++ b/tests/src/Makefile.am @@ -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 diff --git a/tests/src/execute__common.c b/tests/src/execute__common.c index 97d12f09b..883b30a50 100644 --- a/tests/src/execute__common.c +++ b/tests/src/execute__common.c @@ -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 index 000000000..0d4fe1d15 --- /dev/null +++ b/tests/src/execute__execute_external_editor_or_viewer.c @@ -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 , 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 . + */ + +#define TEST_SUITE_NAME "/src" + +#include + +#include + +#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; +} + +/* --------------------------------------------------------------------------------------------- */