diff-cache.con commit Make "cat-file" use "read_object_with_reference()" (11e7d5c)
   1#include "cache.h"
   2#include "diff.h"
   3
   4static int cached_only = 0;
   5static int generate_patch = 0;
   6static int line_termination = '\n';
   7
   8/* A file entry went away or appeared */
   9static void show_file(const char *prefix, struct cache_entry *ce, unsigned char *sha1, unsigned int mode)
  10{
  11        if (generate_patch)
  12                diff_addremove(prefix[0], ntohl(mode), sha1, ce->name, NULL);
  13        else
  14                printf("%s%06o\tblob\t%s\t%s%c", prefix, ntohl(mode),
  15                       sha1_to_hex(sha1), ce->name, line_termination);
  16}
  17
  18static int get_stat_data(struct cache_entry *ce, unsigned char **sha1p, unsigned int *modep)
  19{
  20        unsigned char *sha1 = ce->sha1;
  21        unsigned int mode = ce->ce_mode;
  22
  23        if (!cached_only) {
  24                static unsigned char no_sha1[20];
  25                int changed;
  26                struct stat st;
  27                if (stat(ce->name, &st) < 0)
  28                        return -1;
  29                changed = cache_match_stat(ce, &st);
  30                if (changed) {
  31                        mode = create_ce_mode(st.st_mode);
  32                        sha1 = no_sha1;
  33                }
  34        }
  35
  36        *sha1p = sha1;
  37        *modep = mode;
  38        return 0;
  39}
  40
  41static void show_new_file(struct cache_entry *new)
  42{
  43        unsigned char *sha1;
  44        unsigned int mode;
  45
  46        /* New file in the index: it might actually be different in the working copy */
  47        if (get_stat_data(new, &sha1, &mode) < 0)
  48                return;
  49
  50        show_file("+", new, sha1, mode);
  51}
  52
  53static int show_modified(struct cache_entry *old, struct cache_entry *new)
  54{
  55        unsigned int mode, oldmode;
  56        unsigned char *sha1;
  57        unsigned char old_sha1_hex[60];
  58
  59        if (get_stat_data(new, &sha1, &mode) < 0) {
  60                show_file("-", old, old->sha1, old->ce_mode);
  61                return -1;
  62        }
  63
  64        oldmode = old->ce_mode;
  65        if (mode == oldmode && !memcmp(sha1, old->sha1, 20))
  66                return 0;
  67
  68        mode = ntohl(mode);
  69        oldmode = ntohl(oldmode);
  70
  71        if (generate_patch)
  72                diff_change(oldmode, mode,
  73                            old->sha1, sha1, old->name, NULL);
  74        else {
  75                strcpy(old_sha1_hex, sha1_to_hex(old->sha1));
  76                printf("*%06o->%06o\tblob\t%s->%s\t%s%c", oldmode, mode,
  77                       old_sha1_hex, sha1_to_hex(sha1),
  78                       old->name, line_termination);
  79        }
  80        return 0;
  81}
  82
  83static int diff_cache(struct cache_entry **ac, int entries)
  84{
  85        while (entries) {
  86                struct cache_entry *ce = *ac;
  87                int same = (entries > 1) && same_name(ce, ac[1]);
  88
  89                switch (ce_stage(ce)) {
  90                case 0:
  91                        /* No stage 1 entry? That means it's a new file */
  92                        if (!same) {
  93                                show_new_file(ce);
  94                                break;
  95                        }
  96                        /* Show difference between old and new */
  97                        show_modified(ac[1], ce);
  98                        break;
  99                case 1:
 100                        /* No stage 3 (merge) entry? That means it's been deleted */
 101                        if (!same) {
 102                                show_file("-", ce, ce->sha1, ce->ce_mode);
 103                                break;
 104                        }
 105                        /* Otherwise we fall through to the "unmerged" case */
 106                case 3:
 107                        if (generate_patch)
 108                                diff_unmerge(ce->name);
 109                        else
 110                                printf("U %s%c", ce->name, line_termination);
 111                        break;
 112
 113                default:
 114                        die("impossible cache entry stage");
 115                }
 116
 117                /*
 118                 * Ignore all the different stages for this file,
 119                 * we've handled the relevant cases now.
 120                 */
 121                do {
 122                        ac++;
 123                        entries--;
 124                } while (entries && same_name(ce, ac[0]));
 125        }
 126        return 0;
 127}
 128
 129/*
 130 * This turns all merge entries into "stage 3". That guarantees that
 131 * when we read in the new tree (into "stage 1"), we won't lose sight
 132 * of the fact that we had unmerged entries.
 133 */
 134static void mark_merge_entries(void)
 135{
 136        int i;
 137        for (i = 0; i < active_nr; i++) {
 138                struct cache_entry *ce = active_cache[i];
 139                if (!ce_stage(ce))
 140                        continue;
 141                ce->ce_flags |= htons(CE_STAGEMASK);
 142        }
 143}
 144
 145static char *diff_cache_usage =
 146"diff-cache [-r] [-z] [-p] [--cached] <tree sha1>";
 147
 148int main(int argc, char **argv)
 149{
 150        unsigned char tree_sha1[20];
 151        void *tree;
 152        unsigned long size;
 153
 154        read_cache();
 155        while (argc > 2) {
 156                char *arg = argv[1];
 157                argv++;
 158                argc--;
 159                if (!strcmp(arg, "-r")) {
 160                        /* We accept the -r flag just to look like diff-tree */
 161                        continue;
 162                }
 163                if (!strcmp(arg, "-p")) {
 164                        generate_patch = 1;
 165                        continue;
 166                }
 167                if (!strcmp(arg, "-z")) {
 168                        line_termination = '\0';
 169                        continue;
 170                }
 171                if (!strcmp(arg, "--cached")) {
 172                        cached_only = 1;
 173                        continue;
 174                }
 175                usage(diff_cache_usage);
 176        }
 177
 178        if (argc != 2 || get_sha1(argv[1], tree_sha1))
 179                usage(diff_cache_usage);
 180
 181        mark_merge_entries();
 182
 183        tree = read_object_with_reference(tree_sha1, "tree", &size, 0);
 184        if (!tree)
 185                die("bad tree object %s", argv[1]);
 186        if (read_tree(tree, size, 1))
 187                die("unable to read tree object %s", argv[1]);
 188
 189        return diff_cache(active_cache, active_nr);
 190}