From: Daniel Carl Date: Mon, 9 Jun 2014 12:52:14 +0000 (+0200) Subject: Don't use g_shell_parse_argv for shortcuts (#88). X-Git-Url: https://git.owens.tech/projects.html/projects.html/git?a=commitdiff_plain;h=9348ab88370b8f6ba02f07cf2124fcf9eb78c3f5;p=vimb.git Don't use g_shell_parse_argv for shortcuts (#88). This function was really handy, but it does not allow to ignore unmatched quotes which lead to errors that could not be handled very well for the user. This patch adds a stripped down to the minimum parser for the shortcut parameters to allow also unmatched single- or double quotes. --- diff --git a/src/shortcut.c b/src/shortcut.c index 94990cd..190f92f 100644 --- a/src/shortcut.c +++ b/src/shortcut.c @@ -20,6 +20,7 @@ #include "main.h" #include "shortcut.h" #include "util.h" +#include "ascii.h" extern VbCore vb; @@ -70,20 +71,20 @@ gboolean shortcut_set_default(const char *key) char *shortcut_get_uri(const char *string) { const char *tmpl, *query = NULL; - char *uri, **argv, *quoted_param, ph[3] = "$0"; - int i, max, argc; - GError *error = NULL; + char *uri, *quoted_param; + int max_num, current_num; + GString *token; tmpl = shortcut_lookup(string, &query); if (!tmpl) { return NULL; } - max = get_max_placeholder(tmpl); + max_num = get_max_placeholder(tmpl); /* if there are only $0 placeholders we don't need to split the parameters */ - if (max == 0) { + if (max_num == 0) { quoted_param = soup_uri_encode(query, "&"); - uri = util_str_replace(ph, quoted_param, tmpl); + uri = util_str_replace("$0", quoted_param, tmpl); g_free(quoted_param); return uri; @@ -92,46 +93,65 @@ char *shortcut_get_uri(const char *string) uri = g_strdup(tmpl); /* skip if no placeholders found */ - if (max < 0) { + if (max_num < 0) { return uri; } - /* for multiple placeholders - split the parameters */ - if (!g_shell_parse_argv(query, &argc, &argv, &error)) { -#ifndef TESTLIB - vb_echo(VB_MSG_ERROR, true, error->message); -#endif - g_clear_error(&error); + current_num = 0; + token = g_string_new(NULL); + while (*query) { + /* parse the query tokens */ + if (*query == '"' || *query == '\'') { + /* save the last used quote char to find it's matching counterpart */ + char last_quote = *query; + + /* skip the quote */ + query++; + /* collect the char until the closing quote or end of string */ + while (*query && *query != last_quote) { + g_string_append_c(token, *query); + query++; + } + /* if we end up at the closing quote - skip this quote too */ + if (*query == last_quote) { + query++; + } + } else if (VB_IS_SPACE(*query)) { + /* skip whitespace */ + query++; + + continue; + } else if (current_num >= max_num) { + /* if we have parsed as many params like placeholders - put the + * rest of the query as last parameter */ + while (*query) { + g_string_append_c(token, *query); + query++; + } + } else { + /* collect the following character up to the next whitespace */ + while (*query && !VB_IS_SPACE(*query)) { + g_string_append_c(token, *query); + query++; + } + } - /* us the shortcut template uri like it is */ - return uri; - } + /* replace the placeholders with parsed token */ + if (token->len) { + char *new; - for (i = 0; i < argc; i++) { - char *new, *qs, *combined; - - ph[1] = i + '0'; - /* if we reached the last placeholder put all other tokens into it */ - if (i >= max) { - combined = g_strjoinv(" ", &(argv[i])); - qs = soup_uri_encode(combined, "&"); - new = util_str_replace(ph, qs, uri); - g_free(combined); - g_free(qs); + quoted_param = soup_uri_encode(token->str, "&"); + new = util_str_replace((char[]){'$', current_num + '0', '\0'}, quoted_param, uri); + g_free(quoted_param); g_free(uri); uri = new; - /* we are done - break the loop */ - break; + /* truncate the last token to fill for next loop */ + g_string_truncate(token, 0); } - - qs = soup_uri_encode(argv[i], "&"); - new = util_str_replace(ph, qs, uri); - g_free(qs); - g_free(uri); - uri = new; + current_num++; } - g_strfreev(argv); + g_string_free(token, true); return uri; } diff --git a/tests/test-shortcut.c b/tests/test-shortcut.c index 6733a06..7ab046a 100644 --- a/tests/test-shortcut.c +++ b/tests/test-shortcut.c @@ -75,27 +75,29 @@ static void test_shortcut_shell_param(void) { char *uri; + /* double quotes */ + uri = shortcut_get_uri("_vimb6_ \"rail station\" city hall"); + g_assert_cmpstr(uri, ==, "shell:rail%20station-city%20hall"); + g_free(uri); + /* single quotes */ uri = shortcut_get_uri("_vimb6_ 'rail station' 'city hall'"); g_assert_cmpstr(uri, ==, "shell:rail%20station-city%20hall"); g_free(uri); - /* double quotes */ - uri = shortcut_get_uri("_vimb6_ \"rail station\" city hall"); + /* ignore none matching quote errors */ + uri = shortcut_get_uri("_vimb6_ \"rail station\" \"city hall"); g_assert_cmpstr(uri, ==, "shell:rail%20station-city%20hall"); g_free(uri); -} -static void test_shortcut_shell_param_invalid(void) -{ - char *uri; - /* if parsing fails we expect the shortcut template to be returned */ - uri = shortcut_get_uri("_vimb6_ 'rail station' 'city hall"); - g_assert_cmpstr(uri, ==, "shell:$0-$1"); + /* don't fill up quoted param with unquoted stuff */ + uri = shortcut_get_uri("_vimb6_ \"param 1\" \"param 2\" ignored params"); + g_assert_cmpstr(uri, ==, "shell:param%201-param%202"); g_free(uri); - uri = shortcut_get_uri("_vimb6_ can't parse"); - g_assert_cmpstr(uri, ==, "shell:$0-$1"); + /* allo quotes within tha last parameter */ + uri = shortcut_get_uri("_vimb6_ param1 param2 \"containing quotes\""); + g_assert_cmpstr(uri, ==, "shell:param1-param2%20%22containing%20quotes%22"); g_free(uri); } @@ -130,7 +132,6 @@ int main(int argc, char *argv[]) g_test_add_func("/test-shortcut/get_uri/keep-unmatched", test_shortcut_keep_unmatched); g_test_add_func("/test-shortcut/get_uri/fullrange", test_shortcut_fullrange); g_test_add_func("/test-shortcut/get_uri/shell-param", test_shortcut_shell_param); - g_test_add_func("/test-shortcut/get_uri/shell-param-invalid", test_shortcut_shell_param_invalid); g_test_add_func("/test-shortcut/remove", test_shortcut_remove); result = g_test_run();