diff: restrict pathspec limitations to diff b/f case only
[gitweb.git] / builtin / diff.c
index abdd613a83f60bc9a7fc395e421d09a672bb5c59..2af254222593883e9ea0b7288e016dd0aba7102f 100644 (file)
@@ -64,15 +64,18 @@ static void stuff_change(struct diff_options *opt,
 
 static int builtin_diff_b_f(struct rev_info *revs,
                            int argc, const char **argv,
-                           struct blobinfo *blob,
-                           const char *path)
+                           struct blobinfo *blob)
 {
        /* Blob vs file in the working tree*/
        struct stat st;
+       const char *path;
 
        if (argc > 1)
                usage(builtin_diff_usage);
 
+       GUARD_PATHSPEC(&revs->prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
+       path = revs->prune_data.items[0].match;
+
        if (lstat(path, &st))
                die_errno(_("failed to stat '%s'"), path);
        if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
@@ -140,7 +143,7 @@ static int builtin_diff_index(struct rev_info *revs,
                usage(builtin_diff_usage);
        if (!cached) {
                setup_work_tree();
-               if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
+               if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
                        perror("read_cache_preload");
                        return -1;
                }
@@ -242,7 +245,7 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
                revs->combine_merges = revs->dense_combined_merges = 1;
 
        setup_work_tree();
-       if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
+       if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
                perror("read_cache_preload");
                return -1;
        }
@@ -253,9 +256,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
 {
        int i;
        struct rev_info rev;
-       struct object_array_entry ent[100];
-       int ents = 0, blobs = 0, paths = 0;
-       const char *path = NULL;
+       struct object_array ent = OBJECT_ARRAY_INIT;
+       int blobs = 0, paths = 0;
        struct blobinfo blob[2];
        int nongit;
        int result = 0;
@@ -339,9 +341,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        }
 
        for (i = 0; i < rev.pending.nr; i++) {
-               struct object_array_entry *list = rev.pending.objects+i;
-               struct object *obj = list->item;
-               const char *name = list->name;
+               struct object_array_entry *entry = &rev.pending.objects[i];
+               struct object *obj = entry->item;
+               const char *name = entry->name;
                int flags = (obj->flags & UNINTERESTING);
                if (!obj->parsed)
                        obj = parse_object(obj->sha1);
@@ -350,38 +352,29 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                        die(_("invalid object '%s' given."), name);
                if (obj->type == OBJ_COMMIT)
                        obj = &((struct commit *)obj)->tree->object;
+
                if (obj->type == OBJ_TREE) {
-                       if (ARRAY_SIZE(ent) <= ents)
-                               die(_("more than %d trees given: '%s'"),
-                                   (int) ARRAY_SIZE(ent), name);
                        obj->flags |= flags;
-                       ent[ents].item = obj;
-                       ent[ents].name = name;
-                       ents++;
-                       continue;
-               }
-               if (obj->type == OBJ_BLOB) {
+                       add_object_array(obj, name, &ent);
+               } else if (obj->type == OBJ_BLOB) {
                        if (2 <= blobs)
                                die(_("more than two blobs given: '%s'"), name);
                        hashcpy(blob[blobs].sha1, obj->sha1);
                        blob[blobs].name = name;
-                       blob[blobs].mode = list->mode;
+                       blob[blobs].mode = entry->mode;
                        blobs++;
-                       continue;
 
+               } else {
+                       die(_("unhandled object '%s' given."), name);
                }
-               die(_("unhandled object '%s' given."), name);
        }
-       if (rev.prune_data.nr) {
-               if (!path)
-                       path = rev.prune_data.items[0].match;
+       if (rev.prune_data.nr)
                paths += rev.prune_data.nr;
-       }
 
        /*
         * Now, do the arguments look reasonable?
         */
-       if (!ents) {
+       if (!ent.nr) {
                switch (blobs) {
                case 0:
                        result = builtin_diff_files(&rev, argc, argv);
@@ -389,7 +382,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                case 1:
                        if (paths != 1)
                                usage(builtin_diff_usage);
-                       result = builtin_diff_b_f(&rev, argc, argv, blob, path);
+                       result = builtin_diff_b_f(&rev, argc, argv, blob);
                        break;
                case 2:
                        if (paths)
@@ -402,22 +395,26 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        }
        else if (blobs)
                usage(builtin_diff_usage);
-       else if (ents == 1)
+       else if (ent.nr == 1)
                result = builtin_diff_index(&rev, argc, argv);
-       else if (ents == 2)
-               result = builtin_diff_tree(&rev, argc, argv, &ent[0], &ent[1]);
-       else if (ent[0].item->flags & UNINTERESTING) {
+       else if (ent.nr == 2)
+               result = builtin_diff_tree(&rev, argc, argv,
+                                          &ent.objects[0], &ent.objects[1]);
+       else if (ent.objects[0].item->flags & UNINTERESTING) {
                /*
                 * diff A...B where there is at least one merge base
-                * between A and B.  We have ent[0] == merge-base,
-                * ent[ents-2] == A, and ent[ents-1] == B.  Show diff
-                * between the base and B.  Note that we pick one
-                * merge base at random if there are more than one.
+                * between A and B.  We have ent.objects[0] ==
+                * merge-base, ent.objects[ents-2] == A, and
+                * ent.objects[ents-1] == B.  Show diff between the
+                * base and B.  Note that we pick one merge base at
+                * random if there are more than one.
                 */
-               result = builtin_diff_tree(&rev, argc, argv, &ent[0], &ent[ents-1]);
+               result = builtin_diff_tree(&rev, argc, argv,
+                                          &ent.objects[0],
+                                          &ent.objects[ent.nr-1]);
        } else
                result = builtin_diff_combined(&rev, argc, argv,
-                                              ent, ents);
+                                              ent.objects, ent.nr);
        result = diff_result_code(&rev.diffopt, result);
        if (1 < rev.diffopt.skip_stat_unmatch)
                refresh_index_quietly();