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)
 
 
 #----------------------------------------------------------------------