diff-tree.con commit Simplify "diff-tree" output, and only keep track of one single name-base. (eeb7991)
   1#include "cache.h"
   2
   3static int recursive = 0;
   4
   5static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base);
   6
   7static void update_tree_entry(void **bufp, unsigned long *sizep)
   8{
   9        void *buf = *bufp;
  10        unsigned long size = *sizep;
  11        int len = strlen(buf) + 1 + 20;
  12
  13        if (size < len)
  14                usage("corrupt tree file");
  15        *bufp = buf + len;
  16        *sizep = size - len;
  17}
  18
  19static const unsigned char *extract(void *tree, unsigned long size, const char **pathp, unsigned int *modep)
  20{
  21        int len = strlen(tree)+1;
  22        const unsigned char *sha1 = tree + len;
  23        const char *path = strchr(tree, ' ');
  24
  25        if (!path || size < len + 20 || sscanf(tree, "%o", modep) != 1)
  26                usage("corrupt tree file");
  27        *pathp = path+1;
  28        return sha1;
  29}
  30
  31static void show_file(const char *prefix, void *tree, unsigned long size, const char *base)
  32{
  33        unsigned mode;
  34        const char *path;
  35        const unsigned char *sha1 = extract(tree, size, &path, &mode);
  36        printf("%s%o %s %s%s%c", prefix, mode, sha1_to_hex(sha1), base, path, 0);
  37}
  38
  39static int compare_tree_entry(void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
  40{
  41        unsigned mode1, mode2;
  42        const char *path1, *path2;
  43        const unsigned char *sha1, *sha2;
  44        int cmp, pathlen1, pathlen2;
  45        char old_sha1_hex[50];
  46
  47        sha1 = extract(tree1, size1, &path1, &mode1);
  48        sha2 = extract(tree2, size2, &path2, &mode2);
  49
  50        pathlen1 = strlen(path1);
  51        pathlen2 = strlen(path2);
  52        cmp = cache_name_compare(path1, pathlen1, path2, pathlen2);
  53        if (cmp < 0) {
  54                show_file("-", tree1, size1, base);
  55                return -1;
  56        }
  57        if (cmp > 0) {
  58                show_file("+", tree2, size2, base);
  59                return 1;
  60        }
  61        if (!memcmp(sha1, sha2, 20) && mode1 == mode2)
  62                return 0;
  63        if (recursive && S_ISDIR(mode1) && S_ISDIR(mode2)) {
  64                int retval;
  65                int baselen = strlen(base);
  66                char *newbase = malloc(baselen + pathlen1 + 2);
  67                memcpy(newbase, base, baselen);
  68                memcpy(newbase + baselen, path1, pathlen1);
  69                memcpy(newbase + baselen + pathlen1, "/", 2);
  70                retval = diff_tree_sha1(sha1, sha2, newbase);
  71                free(newbase);
  72                return retval;
  73        }
  74
  75        strcpy(old_sha1_hex, sha1_to_hex(sha1));
  76        printf("*%o->%o %s->%s %s%s%c", mode1, mode2, old_sha1_hex, sha1_to_hex(sha2), base, path1, 0);
  77        return 0;
  78}
  79
  80static int diff_tree(void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
  81{
  82        while (size1 | size2) {
  83                if (!size1) {
  84                        show_file("+", tree2, size2, base);
  85                        update_tree_entry(&tree2, &size2);
  86                        continue;
  87                }
  88                if (!size2) {
  89                        show_file("-", tree1, size1, base);
  90                        update_tree_entry(&tree1, &size1);
  91                        continue;
  92                }
  93                switch (compare_tree_entry(tree1, size1, tree2, size2, base)) {
  94                case -1:
  95                        update_tree_entry(&tree1, &size1);
  96                        continue;
  97                case 0:
  98                        update_tree_entry(&tree1, &size1);
  99                        /* Fallthrough */
 100                case 1:
 101                        update_tree_entry(&tree2, &size2);
 102                        continue;
 103                }
 104                usage("diff-tree: internal error");
 105        }
 106        return 0;
 107}
 108
 109static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base)
 110{
 111        void *tree1, *tree2;
 112        unsigned long size1, size2;
 113        char type[20];
 114        int retval;
 115
 116        tree1 = read_sha1_file(old, type, &size1);
 117        if (!tree1 || strcmp(type, "tree"))
 118                usage("unable to read source tree");
 119        tree2 = read_sha1_file(new, type, &size2);
 120        if (!tree2 || strcmp(type, "tree"))
 121                usage("unable to read destination tree");
 122        retval = diff_tree(tree1, size1, tree2, size2, base);
 123        free(tree1);
 124        free(tree2);
 125        return retval;
 126}
 127
 128int main(int argc, char **argv)
 129{
 130        unsigned char old[20], new[20];
 131
 132        while (argc > 3) {
 133                char *arg = argv[1];
 134                argv++;
 135                argc--;
 136                if (!strcmp(arg, "-R")) {
 137                        recursive = 1;
 138                        continue;
 139                }
 140                usage("diff-tree [-R] <tree sha1> <tree sha1>");
 141        }
 142
 143        if (argc != 3 || get_sha1_hex(argv[1], old) || get_sha1_hex(argv[2], new))
 144                usage("diff-tree <tree sha1> <tree sha1>");
 145        return diff_tree_sha1(old, new, "");
 146}