You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by gb...@apache.org on 2013/10/11 19:41:19 UTC
svn commit: r1531371 - in
/subversion/branches/invoke-diff-cmd-feature/subversion: libsvn_subr/io.c
tests/cmdline/diff_tests.py
Author: gbg
Date: Fri Oct 11 17:41:19 2013
New Revision: 1531371
URL: http://svn.apache.org/r1531371
Log:
On the invoke-diff-cmd branch: rewrite __create_custom_diff_cmd and
it's python test to preserve strings inside the command string that is
expanded.
* subversion/libsvn_subr/io.c
(__create_custom_diff_cmd): Preserve internal strings that have
spaces as one arg for result[].
(svn_io_run_diff2): Add advice where to find the test for this
function.
* subversion/tests/cmdline/diff_tests.py
(diff_invoke_external_diffcmd): Add tests for the above behavior.
Modified:
subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c
subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/diff_tests.py
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c?rev=1531371&r1=1531370&r2=1531371&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c Fri Oct 11 17:41:19 2013
@@ -3115,10 +3115,8 @@ __create_custom_diff_cmd(const char *lab
apr_pool_t *pool)
{
/*
- We use the delimiter's characters to find the correct index.
-
- This function can be tested by using the test
- /subversion/tests/cmdline/diff_tests.py diff_invoke_external_diffcmd
+ This function can be tested with:
+ /subversion/tests/cmdline/diff_tests.py diff_invoke_external_diffcmd
*/
struct replace_tokens_t
@@ -3135,7 +3133,7 @@ __create_custom_diff_cmd(const char *lab
apr_array_header_t *words;
const char ** result;
- int argv;
+ int argv, item;
apr_pool_t *scratch_pool = svn_pool_create(pool);
/* split the user command into an array of words */
@@ -3144,52 +3142,92 @@ __create_custom_diff_cmd(const char *lab
result = apr_palloc(pool,
(words->nelts+1) * words->elt_size * sizeof(char *) );
- for (argv = 0; argv < words->nelts; argv++)
+ /* argv indexes result[], item indexes words */
+ for (item = 0, argv = 0; item < words->nelts; argv++, item++)
{
- int j = 0;
svn_stringbuf_t *word;
char special_start_marker = 0;
char special_end_marker = 0;
word = svn_stringbuf_create_empty(scratch_pool);
- svn_stringbuf_appendcstr(word, APR_ARRAY_IDX(words, argv, char *));
+ svn_stringbuf_appendcstr(word, APR_ARRAY_IDX(words, item, char *));
/* If the first character of the string is a alphanumeric, it's
- not a delimiter. */
- if (!isalnum(word->data[j]))
+ not a delimiter or a quote and we're done. */
+ if ( isalnum(word->data[0]) )
+ goto check_done;
+
+ if (word->data[0] != '"')
{
/* check for the case that the first character is not a ';' and
that the second character is a ';' */
- if ( (word->data[j] != ';') && (word->data[j+1] == ';') )
+ if ( (word->data[0] != ';') && (word->data[1] == ';') )
{
- /* there are some cases where a '+' or other non-alphanumeric
- character can be prepended to a file name. It's simpler if
- this is removed for the check and added back onto the result. */
+ /* there are some cases where a '+' or other
+ non-alphanumeric character can be prepended to a file
+ name. It's simpler if this is removed for the check
+ and added back onto the result.*/
special_start_marker = word->data[0];
svn_stringbuf_remove(word, 0, 1);
}
+ }
+
+ /* check for quoted text that may contain spaces and needs to be
+ treated as one element and so the next entries need to be
+ collated until the original quoted string is restored. This
+ occurs because svn_cstring_split() splits on spaces and does
+ not protect quoted entities, ie, "a b c" expresses as
+ '"a','b','c"' */
+ if ( (word->data[0] == '"') && (word->data[word->len-1] != '"') )
+ {
+ svn_stringbuf_t * complete = svn_stringbuf_create_empty(scratch_pool);
+
+ while(item < words->nelts)
+ {
+ svn_stringbuf_appendcstr(complete,
+ APR_ARRAY_IDX(words, item, char *));
+
+ /* Either we find a closing quote, or we run out of
+ words trying to discover it. We ship whatever we
+ have, otherwise the reason for the failure will not
+ be immediately obvious to the user (ie, missing
+ closing quotes) */
+ if ( (complete->data[complete->len-1] == '"')
+ || (item == words->nelts - 1) )
+ {
+ word->data = complete->data;
+ goto check_done;
+ }
+ svn_stringbuf_appendcstr(complete, " ");
+ item++;
+ }
+ }
+
+ /* First character must be ';' since all delimiters start thus */
+ if (word->data[0] == ';')
+ {
+ int last_letter = word->len - 1;
- /* Test that the first character is ';' and the string is a delimiter */
- if (word->data[j] != ';') /* this excludes switches etc, eg -u */
- goto end_of_isalnum_if; /* this spares the code another indent */
-
- /* there are some cases where a '+' or other non-alphanumeric
- character can be appended to a file name. It's simpler if
- this is removed for the check and added back onto the result. */
- if (!isalnum(word->data[word->len-1]))
+ /* there are some cases where a '+' or other
+ non-alphanumeric character can be appended to a file
+ name. It's simpler if this is removed for the check
+ and added back onto the result. */
+ if (!isalnum(word->data[last_letter]))
{
- special_end_marker = word->data[word->len-1];
- svn_stringbuf_remove(word, word->len-1, 1);
+ special_end_marker = word->data[last_letter];
+ svn_stringbuf_remove(word, last_letter, 1);
}
- /* A ';' in second place could be a protected delimiter */
- if (word->data[++j] == ';')
+ /* A ';' in second place could be a protected delimiter */
+ if (word->data[1] == ';')
{
+ int j = 1;
+
/* ensure that there is an unbroken line of ';' */
while (j < word->len && word->data[j++] == ';') ;
/* ensure that the end characters are [f|l][1-3]. */
- if ( (j == (word->len - 1))
+ if ( (j == last_letter)
/* check the letters */
&& (word->data[j-1] == 'f' || word->data[j-1] == 'l')
@@ -3197,7 +3235,7 @@ __create_custom_diff_cmd(const char *lab
/*check that next char is 1,2 or 3 */
&& (word->data[j] > 48) && (word->data[j] < 52) )
{
- /* it's a protected delimiter, so we consume one ';' */
+ /* it's a protected delimiter, so we consume one ';' */
svn_stringbuf_remove(word, 0, 1);
}
}
@@ -3211,21 +3249,20 @@ __create_custom_diff_cmd(const char *lab
&& (word->data[2] > 48) && (word->data[2] < 52) )
{
/* extract the delimiter's integer 1,2 or 3 */
- j = (int)word->data[2]-49;
+ int j = (int)word->data[2]-49;
/* if it's 'l' it will be in position 4,5 or 6 */
if (word->data[1] == 'l')
j+=3;
- /* pick the correct string parameter out of the tokens_tab */
+ /* pick the correct string parameter in the tokens_tab */
svn_stringbuf_replace(word, 0,
3, /* delimiter is always length 3 */
tokens_tab[j].token,
strlen(tokens_tab[j].token));
}
}
- end_of_isalnum_if:
-
+
/* put the special start character back if it exists */
if (special_start_marker)
svn_stringbuf_insert(word, 0, &special_start_marker, 1);
@@ -3233,7 +3270,8 @@ __create_custom_diff_cmd(const char *lab
/* put the special end character back if it exists */
if (special_end_marker)
svn_stringbuf_appendbyte(word, special_end_marker);
-
+
+ check_done:
result[argv] = word->data;
}
result[argv] = NULL;
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/diff_tests.py?rev=1531371&r1=1531370&r2=1531371&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/diff_tests.py Fri Oct 11 17:41:19 2013
@@ -3223,6 +3223,7 @@ def diff_wrong_extension_type(sbox):
svntest.actions.run_and_verify_svn(None, [], err.INVALID_DIFF_OPTION,
'diff', '-x', sbox.wc_dir, '-r', '1')
+#----------------------------------------------------------------------
# Check the order of the arguments for an external diff tool
def diff_external_diffcmd(sbox):
"svn diff --diff-cmd provides the correct arguments"
@@ -3302,19 +3303,20 @@ def diff_invoke_external_diffcmd(sbox):
# special start and end char are retained +;f1+ -> +file+
"+"+os.path.abspath(svntest.wc.text_base_path("iota")) + "+\n",
- ";f1\n", # removal of ';' @ lower boundary '1' ;;f1 -> ;f1
- ";;l3\n", # removal of ';' @ high boundary '3' ;;;l3 -> ;;l3
- ";;fo\n", # only eligible delimiters are modified ;;fo -> ;;fo
- ";f1o\n", # correct length test of delimiter ;f1o -> ;f1o
- ";f15+\n",# non-modification of ineligble delimiter ;f15+ -> ;f15+
- "-u\n" # non-modification of ineligble element -u -> -u
+ ";f1\n", # removal of ';' @ lower boundary '1' ;;f1 -> ;f1
+ ";;l3\n", # removal of ';' @ high boundary '3' ;;;l3 -> ;;l3
+ "\"A B\"\n", # non-modification of 1st quoted element "A B"-> "A B"
+ ";;fo\n", # only eligible delimiters are modified ;;fo -> ;;fo
+ ";f1o\n", # correct length test of delimiter ;f1o -> ;f1o
+ "-u\n", # non-modification of ineligble element -u -> -u
+ "\"X Y Z\"\n",# non-modification of 2nd quoted element "X Y Z"-> "X Y Z"
])
-
+
svntest.actions.run_and_verify_svn(None, expected_output, [],
'diff',
'--invoke-diff-cmd='+diff_script_path+
- ' ;l1 ;f1 ;l2 ;f2 +;f1 ;f1+ +;f1+ ;;f1 ;;;l3 ;;fo ;f1o ;f15+ -u',
- iota_path)
+ ' ;l1 ;f1 ;l2 ;f2 +;f1 ;f1+ +;f1+ ;;f1 ;;;l3 \"A B\" ;;fo ;f1o -u \"X Y Z\"',
+ iota_path)
#----------------------------------------------------------------------