f9e8c12f90e793bc039a6181a6b6424b3725f6dc
   1/*
   2 * GIT - The information manager from hell
   3 *
   4 * Copyright (C) Linus Torvalds, 2005
   5 */
   6#include "cache.h"
   7
   8static void show_differences(char *name,
   9        void *old_contents, unsigned long long old_size)
  10{
  11        static char cmd[1000];
  12        FILE *f;
  13
  14        snprintf(cmd, sizeof(cmd), "diff -L %s -u -N  - %s", name, name);
  15        f = popen(cmd, "w");
  16        if (old_size)
  17                fwrite(old_contents, old_size, 1, f);
  18        pclose(f);
  19}
  20
  21static void show_diff_empty(struct cache_entry *ce)
  22{
  23        char *old;
  24        unsigned long int size;
  25        int lines=0;
  26        unsigned char type[20], *p, *end;
  27
  28        old = read_sha1_file(ce->sha1, type, &size);
  29        if (size > 0) {
  30                int startline = 1;
  31                int c = 0;
  32
  33                printf("--- %s\n", ce->name);
  34                printf("+++ /dev/null\n");
  35                p = old;
  36                end = old + size;
  37                while (p < end)
  38                        if (*p++ == '\n')
  39                                lines ++;
  40                printf("@@ -1,%d +0,0 @@\n", lines);
  41                p = old;
  42                while (p < end) {
  43                        c = *p++;
  44                        if (startline) {
  45                                putchar('-');
  46                                startline = 0;
  47                        }
  48                        putchar(c);
  49                        if (c == '\n')
  50                                startline = 1;
  51                }
  52                if (c!='\n')
  53                        printf("\n");
  54                fflush(stdout);
  55        }
  56}
  57
  58static const char *show_diff_usage = "show-diff [-s] [-q] [paths...]";
  59
  60static int matches_pathspec(struct cache_entry *ce, char **spec, int cnt)
  61{
  62        int i;
  63        int namelen = ce_namelen(ce);
  64        for (i = 0; i < cnt; i++) {
  65                int speclen = strlen(spec[i]);
  66                if (! strncmp(spec[i], ce->name, speclen) &&
  67                    speclen <= namelen &&
  68                    (ce->name[speclen] == 0 ||
  69                     ce->name[speclen] == '/'))
  70                        return 1;
  71        }
  72        return 0;
  73}
  74
  75int main(int argc, char **argv)
  76{
  77        int silent = 0;
  78        int silent_on_nonexisting_files = 0;
  79        int entries = read_cache();
  80        int i;
  81
  82        while (1 < argc && argv[1][0] == '-') {
  83                if (!strcmp(argv[1], "-s"))
  84                        silent_on_nonexisting_files = silent = 1;
  85                else if (!strcmp(argv[1], "-q"))
  86                        silent_on_nonexisting_files = 1;
  87                else
  88                        usage(show_diff_usage);
  89                argv++; argc--;
  90        }
  91
  92        /* At this point, if argc == 1, then we are doing everything.
  93         * Otherwise argv[1] .. argv[argc-1] have the explicit paths.
  94         */
  95        if (entries < 0) {
  96                perror("read_cache");
  97                exit(1);
  98        }
  99        for (i = 0; i < entries; i++) {
 100                struct stat st;
 101                struct cache_entry *ce = active_cache[i];
 102                int n, changed;
 103                unsigned long size;
 104                char type[20];
 105                void *new;
 106
 107                if (1 <argc &&
 108                    ! matches_pathspec(ce, argv+1, argc-1))
 109                        continue;
 110
 111                if (stat(ce->name, &st) < 0) {
 112                        if (errno == ENOENT && silent_on_nonexisting_files)
 113                                continue;
 114                        printf("%s: %s\n", ce->name, strerror(errno));
 115                        if (errno == ENOENT)
 116                                show_diff_empty(ce);
 117                        continue;
 118                }
 119                changed = cache_match_stat(ce, &st);
 120                if (!changed)
 121                        continue;
 122                printf("%s:  ", ce->name);
 123                for (n = 0; n < 20; n++)
 124                        printf("%02x", ce->sha1[n]);
 125                printf("\n");
 126                fflush(stdout);
 127                if (silent)
 128                        continue;
 129
 130                new = read_sha1_file(ce->sha1, type, &size);
 131                show_differences(ce->name, new, size);
 132                free(new);
 133        }
 134        return 0;
 135}