Merge branch 'jc/apply-ws-fix-tab-in-indent' into maint
authorJunio C Hamano <gitster@pobox.com>
Mon, 22 Apr 2013 18:26:56 +0000 (11:26 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 22 Apr 2013 18:26:56 +0000 (11:26 -0700)
* jc/apply-ws-fix-tab-in-indent:
test: resurrect q_to_tab
apply --whitespace=fix: avoid running over the postimage buffer

1  2 
builtin/apply.c
t/t4124-apply-ws-rule.sh
t/test-lib-functions.sh
diff --combined builtin/apply.c
index f6a3c97dd5903a8b7d42383da370428067c3e14e,df773c75b9833038327b9411d6d2e3b950f96c0f..30eefc3c7b390800e9452a06da18208d2fef4f11
@@@ -1041,17 -1041,15 +1041,17 @@@ static int gitdiff_renamedst(const cha
  
  static int gitdiff_similarity(const char *line, struct patch *patch)
  {
 -      if ((patch->score = strtoul(line, NULL, 10)) == ULONG_MAX)
 -              patch->score = 0;
 +      unsigned long val = strtoul(line, NULL, 10);
 +      if (val <= 100)
 +              patch->score = val;
        return 0;
  }
  
  static int gitdiff_dissimilarity(const char *line, struct patch *patch)
  {
 -      if ((patch->score = strtoul(line, NULL, 10)) == ULONG_MAX)
 -              patch->score = 0;
 +      unsigned long val = strtoul(line, NULL, 10);
 +      if (val <= 100)
 +              patch->score = val;
        return 0;
  }
  
@@@ -1921,7 -1919,7 +1921,7 @@@ static int parse_binary(char *buffer, u
  }
  
  /*
 - * Read the patch text in "buffer" taht extends for "size" bytes; stop
 + * Read the patch text in "buffer" that extends for "size" bytes; stop
   * reading after seeing a single patch (i.e. changes to a single file).
   * Create fragments (i.e. patch hunks) and hang them to the given patch.
   * Return the number of bytes consumed, so that the caller can call us
@@@ -2097,7 -2095,7 +2097,7 @@@ static void update_pre_post_images(stru
                                   char *buf,
                                   size_t len, size_t postlen)
  {
 -      int i, ctx;
 +      int i, ctx, reduced;
        char *new, *old, *fixed;
        struct image fixed_preimage;
  
         * free "oldlines".
         */
        prepare_image(&fixed_preimage, buf, len, 1);
 -      assert(fixed_preimage.nr == preimage->nr);
 -      for (i = 0; i < preimage->nr; i++)
 +      assert(postlen
 +             ? fixed_preimage.nr == preimage->nr
 +             : fixed_preimage.nr <= preimage->nr);
 +      for (i = 0; i < fixed_preimage.nr; i++)
                fixed_preimage.line[i].flag = preimage->line[i].flag;
        free(preimage->line_allocated);
        *preimage = fixed_preimage;
  
        /*
         * Adjust the common context lines in postimage. This can be
-        * done in-place when we are just doing whitespace fixing,
-        * which does not make the string grow, but needs a new buffer
-        * when ignoring whitespace causes the update, since in this case
-        * we could have e.g. tabs converted to multiple spaces.
+        * done in-place when we are shrinking it with whitespace
+        * fixing, but needs a new buffer when ignoring whitespace or
+        * expanding leading tabs to spaces.
+        *
         * We trust the caller to tell us if the update can be done
         * in place (postlen==0) or not.
         */
        else
                new = old;
        fixed = preimage->buf;
 -      for (i = ctx = 0; i < postimage->nr; i++) {
 +
 +      for (i = reduced = ctx = 0; i < postimage->nr; i++) {
                size_t len = postimage->line[i].len;
                if (!(postimage->line[i].flag & LINE_COMMON)) {
                        /* an added line -- no counterparts in preimage */
                        fixed += preimage->line[ctx].len;
                        ctx++;
                }
 -              if (preimage->nr <= ctx)
 -                      die(_("oops"));
 +
 +              /*
 +               * preimage is expected to run out, if the caller
 +               * fixed addition of trailing blank lines.
 +               */
 +              if (preimage->nr <= ctx) {
 +                      reduced++;
 +                      continue;
 +              }
  
                /* and copy it in, while fixing the line length */
                len = preimage->line[ctx].len;
  
        /* Fix the length of the whole thing */
        postimage->len = new - postimage->buf;
 +      postimage->nr -= reduced;
  }
  
  static int match_fragment(struct image *img,
        int i;
        char *fixed_buf, *buf, *orig, *target;
        struct strbuf fixed;
-       size_t fixed_len;
+       size_t fixed_len, postlen;
        int preimage_limit;
  
        if (preimage->nr + try_lno <= img->nr) {
        strbuf_init(&fixed, preimage->len + 1);
        orig = preimage->buf;
        target = img->buf + try;
+       postlen = 0;
        for (i = 0; i < preimage_limit; i++) {
                size_t oldlen = preimage->line[i].len;
                size_t tgtlen = img->line[try_lno + i].len;
                match = (tgtfix.len == fixed.len - fixstart &&
                         !memcmp(tgtfix.buf, fixed.buf + fixstart,
                                             fixed.len - fixstart));
+               postlen += tgtfix.len;
  
                strbuf_release(&tgtfix);
                if (!match)
         * hunk match.  Update the context lines in the postimage.
         */
        fixed_buf = strbuf_detach(&fixed, &fixed_len);
+       if (postlen < postimage->len)
+               postlen = 0;
        update_pre_post_images(preimage, postimage,
-                              fixed_buf, fixed_len, 0);
+                              fixed_buf, fixed_len, postlen);
        return 1;
  
   unmatch_exit:
@@@ -3025,7 -3016,7 +3029,7 @@@ static struct patch *in_fn_table(const 
   *
   * The latter is needed to deal with a case where two paths A and B
   * are swapped by first renaming A to B and then renaming B to A;
 - * moving A to B should not be prevented due to presense of B as we
 + * moving A to B should not be prevented due to presence of B as we
   * will remove it in a later patch.
   */
  #define PATH_TO_BE_DELETED ((struct patch *) -2)
@@@ -3509,7 -3500,7 +3513,7 @@@ static int check_patch(struct patch *pa
         *
         * A patch to swap-rename between A and B would first rename A
         * to B and then rename B to A.  While applying the first one,
 -       * the presense of B should not stop A from getting renamed to
 +       * the presence of B should not stop A from getting renamed to
         * B; ask to_be_deleted() about the later rename.  Removal of
         * B and rename from A to B is handled the same way by asking
         * was_deleted().
@@@ -3600,40 -3591,6 +3604,40 @@@ static int get_current_sha1(const char 
        return 0;
  }
  
 +static int preimage_sha1_in_gitlink_patch(struct patch *p, unsigned char sha1[20])
 +{
 +      /*
 +       * A usable gitlink patch has only one fragment (hunk) that looks like:
 +       * @@ -1 +1 @@
 +       * -Subproject commit <old sha1>
 +       * +Subproject commit <new sha1>
 +       * or
 +       * @@ -1 +0,0 @@
 +       * -Subproject commit <old sha1>
 +       * for a removal patch.
 +       */
 +      struct fragment *hunk = p->fragments;
 +      static const char heading[] = "-Subproject commit ";
 +      char *preimage;
 +
 +      if (/* does the patch have only one hunk? */
 +          hunk && !hunk->next &&
 +          /* is its preimage one line? */
 +          hunk->oldpos == 1 && hunk->oldlines == 1 &&
 +          /* does preimage begin with the heading? */
 +          (preimage = memchr(hunk->patch, '\n', hunk->size)) != NULL &&
 +          !prefixcmp(++preimage, heading) &&
 +          /* does it record full SHA-1? */
 +          !get_sha1_hex(preimage + sizeof(heading) - 1, sha1) &&
 +          preimage[sizeof(heading) + 40 - 1] == '\n' &&
 +          /* does the abbreviated name on the index line agree with it? */
 +          !prefixcmp(preimage + sizeof(heading) - 1, p->old_sha1_prefix))
 +              return 0; /* it all looks fine */
 +
 +      /* we may have full object name on the index line */
 +      return get_sha1_hex(p->old_sha1_prefix, sha1);
 +}
 +
  /* Build an index that contains the just the files needed for a 3way merge */
  static void build_fake_ancestor(struct patch *list, const char *filename)
  {
         * worth showing the new sha1 prefix, but until then...
         */
        for (patch = list; patch; patch = patch->next) {
 -              const unsigned char *sha1_ptr;
                unsigned char sha1[20];
                struct cache_entry *ce;
                const char *name;
                name = patch->old_name ? patch->old_name : patch->new_name;
                if (0 < patch->is_new)
                        continue;
 -              else if (get_sha1_blob(patch->old_sha1_prefix, sha1))
 -                      /* git diff has no index line for mode/type changes */
 -                      if (!patch->lines_added && !patch->lines_deleted) {
 -                              if (get_current_sha1(patch->old_name, sha1))
 -                                      die("mode change for %s, which is not "
 -                                              "in current HEAD", name);
 -                              sha1_ptr = sha1;
 -                      } else
 -                              die("sha1 information is lacking or useless "
 -                                      "(%s).", name);
 -              else
 -                      sha1_ptr = sha1;
  
 -              ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0);
 +              if (S_ISGITLINK(patch->old_mode)) {
 +                      if (!preimage_sha1_in_gitlink_patch(patch, sha1))
 +                              ; /* ok, the textual part looks sane */
 +                      else
 +                              die("sha1 information is lacking or useless for submoule %s",
 +                                  name);
 +              } else if (!get_sha1_blob(patch->old_sha1_prefix, sha1)) {
 +                      ; /* ok */
 +              } else if (!patch->lines_added && !patch->lines_deleted) {
 +                      /* mode-only change: update the current */
 +                      if (get_current_sha1(patch->old_name, sha1))
 +                              die("mode change for %s, which is not "
 +                                  "in current HEAD", name);
 +              } else
 +                      die("sha1 information is lacking or useless "
 +                          "(%s).", name);
 +
 +              ce = make_cache_entry(patch->old_mode, sha1, name, 0, 0);
                if (!ce)
                        die(_("make_cache_entry failed for path '%s'"), name);
                if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD))
diff --combined t/t4124-apply-ws-rule.sh
index 581a801649f20a74e81c32f9503f233c3cd3d507,0bbcf0603d20380e71ef27cec654ec6c604561d1..5d0c5983381b4072d915de0f8d75053b19172d66
@@@ -47,7 -47,7 +47,7 @@@ test_fix () 
        # find touched lines
        $DIFF file target | sed -n -e "s/^> //p" >fixed
  
 -      # the changed lines are all expeced to change
 +      # the changed lines are all expected to change
        fixed_cnt=$(wc -l <fixed)
        case "$1" in
        '') expect_cnt=$fixed_cnt ;;
@@@ -486,4 -486,30 +486,30 @@@ test_expect_success 'same, but with CR-
        test_cmp one expect
  '
  
+ test_expect_success 'whitespace=fix to expand' '
+       qz_to_tab_space >preimage <<-\EOF &&
+       QQa
+       QQb
+       QQc
+       ZZZZZZZZZZZZZZZZd
+       QQe
+       QQf
+       QQg
+       EOF
+       qz_to_tab_space >patch <<-\EOF &&
+       diff --git a/preimage b/preimage
+       --- a/preimage
+       +++ b/preimage
+       @@ -1,7 +1,6 @@
+        QQa
+        QQb
+        QQc
+       -QQd
+        QQe
+        QQf
+        QQg
+       EOF
+       git -c core.whitespace=tab-in-indent apply --whitespace=fix patch
+ '
  test_done
diff --combined t/test-lib-functions.sh
index fa62d010f68e3ee97e6754687ad4d08564d3c96b,4a8bac282bee1253fe9b26e78c1cf3bfc0d7fec0..3fc9cc92884bd03f1d4f6a2b543b4c0e0fb55959
@@@ -91,6 -91,10 +91,10 @@@ q_to_tab () 
        tr Q '\011'
  }
  
+ qz_to_tab_space () {
+       tr QZ '\011\040'
+ }
  append_cr () {
        sed -e 's/$/Q/' | tr Q '\015'
  }
@@@ -275,15 -279,6 +279,15 @@@ test_have_prereq () 
  
        for prerequisite
        do
 +              case "$prerequisite" in
 +              !*)
 +                      negative_prereq=t
 +                      prerequisite=${prerequisite#!}
 +                      ;;
 +              *)
 +                      negative_prereq=
 +              esac
 +
                case " $lazily_tested_prereq " in
                *" $prerequisite "*)
                        ;;
                total_prereq=$(($total_prereq + 1))
                case "$satisfied_prereq" in
                *" $prerequisite "*)
 +                      satisfied_this_prereq=t
 +                      ;;
 +              *)
 +                      satisfied_this_prereq=
 +              esac
 +
 +              case "$satisfied_this_prereq,$negative_prereq" in
 +              t,|,t)
                        ok_prereq=$(($ok_prereq + 1))
                        ;;
                *)
 -                      # Keep a list of missing prerequisites
 +                      # Keep a list of missing prerequisites; restore
 +                      # the negative marker if necessary.
 +                      prerequisite=${negative_prereq:+!}$prerequisite
                        if test -z "$missing_prereq"
                        then
                                missing_prereq=$prerequisite
@@@ -602,13 -587,6 +606,13 @@@ test_cmp() 
        $GIT_TEST_CMP "$@"
  }
  
 +# Tests that its two parameters refer to the same revision
 +test_cmp_rev () {
 +      git rev-parse --verify "$1" >expect.rev &&
 +      git rev-parse --verify "$2" >actual.rev &&
 +      test_cmp expect.rev actual.rev
 +}
 +
  # Print a sequence of numbers or letters in increasing order.  This is
  # similar to GNU seq(1), but the latter might not be available
  # everywhere (and does not do letters).  It may be used like: