28f1b13b384dc122daf2b16574536e944b0f6291
   1/*
   2 * GIT - The information manager from hell
   3 *
   4 * Copyright (C) Linus Torvalds, 2005
   5 */
   6#include "cache.h"
   7#include "diff.h"
   8
   9static const char *diff_files_usage =
  10"diff-files [-p] [-q] [-r] [-z] [paths...]";
  11
  12static int generate_patch = 0;
  13static int line_termination = '\n';
  14static int silent = 0;
  15
  16static int matches_pathspec(struct cache_entry *ce, char **spec, int cnt)
  17{
  18        int i;
  19        int namelen = ce_namelen(ce);
  20        for (i = 0; i < cnt; i++) {
  21                int speclen = strlen(spec[i]);
  22                if (! strncmp(spec[i], ce->name, speclen) &&
  23                    speclen <= namelen &&
  24                    (ce->name[speclen] == 0 ||
  25                     ce->name[speclen] == '/'))
  26                        return 1;
  27        }
  28        return 0;
  29}
  30
  31static void show_unmerge(const char *path)
  32{
  33        if (generate_patch)
  34                diff_unmerge(path);
  35        else
  36                printf("U %s%c", path, line_termination);
  37}
  38
  39static void show_file(int pfx, struct cache_entry *ce)
  40{
  41        if (generate_patch)
  42                diff_addremove(pfx, ntohl(ce->ce_mode), ce->sha1,
  43                               ce->name, NULL);
  44        else
  45                printf("%c%06o\t%s\t%s\t%s%c",
  46                       pfx, ntohl(ce->ce_mode), "blob",
  47                       sha1_to_hex(ce->sha1), ce->name, line_termination);
  48}
  49
  50static void show_modified(int oldmode, int mode,
  51                          const char *old_sha1, const char *sha1,
  52                          char *path)
  53{
  54        char old_sha1_hex[41];
  55        strcpy(old_sha1_hex, sha1_to_hex(old_sha1));
  56
  57        if (generate_patch)
  58                diff_change(oldmode, mode, old_sha1, sha1, path, NULL);
  59        else
  60                printf("*%06o->%06o\tblob\t%s->%s\t%s%c",
  61                       oldmode, mode, old_sha1_hex, sha1_to_hex(sha1), path,
  62                       line_termination);
  63}
  64
  65int main(int argc, char **argv)
  66{
  67        static const char null_sha1[20] = { 0, };
  68        int entries = read_cache();
  69        int i;
  70
  71        while (1 < argc && argv[1][0] == '-') {
  72                if (!strcmp(argv[1], "-p"))
  73                        generate_patch = 1;
  74                else if (!strcmp(argv[1], "-q"))
  75                        silent = 1;
  76                else if (!strcmp(argv[1], "-r"))
  77                        ; /* no-op */
  78                else if (!strcmp(argv[1], "-s"))
  79                        ; /* no-op */
  80                else if (!strcmp(argv[1], "-z"))
  81                        line_termination = 0;
  82                else
  83                        usage(diff_files_usage);
  84                argv++; argc--;
  85        }
  86
  87        /* At this point, if argc == 1, then we are doing everything.
  88         * Otherwise argv[1] .. argv[argc-1] have the explicit paths.
  89         */
  90        if (entries < 0) {
  91                perror("read_cache");
  92                exit(1);
  93        }
  94
  95        for (i = 0; i < entries; i++) {
  96                struct stat st;
  97                unsigned int oldmode, mode;
  98                struct cache_entry *ce = active_cache[i];
  99                int changed;
 100
 101                if (1 < argc &&
 102                    ! matches_pathspec(ce, argv+1, argc-1))
 103                        continue;
 104
 105                if (ce_stage(ce)) {
 106                        show_unmerge(ce->name);
 107                        while (i < entries &&
 108                               !strcmp(ce->name, active_cache[i]->name))
 109                                i++;
 110                        i--; /* compensate for loop control increments */
 111                        continue;
 112                }
 113 
 114                if (lstat(ce->name, &st) < 0) {
 115                        if (errno != ENOENT) {
 116                                perror(ce->name);
 117                                continue;
 118                        }       
 119                        if (silent)
 120                                continue;
 121                        show_file('-', ce);
 122                        continue;
 123                }
 124                changed = cache_match_stat(ce, &st);
 125                if (!changed)
 126                        continue;
 127
 128                oldmode = ntohl(ce->ce_mode);
 129                mode = (S_ISLNK(st.st_mode) ? S_IFLNK :
 130                        S_IFREG | ce_permissions(st.st_mode));
 131
 132                show_modified(oldmode, mode, ce->sha1, null_sha1,
 133                              ce->name);
 134        }
 135        return 0;
 136}