4221d3ae4c7a844627cd72c3f4772bbe94abda16
   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] [-z] [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 machine_readable = 0;
  80        int entries = read_cache();
  81        int i;
  82
  83        while (1 < argc && argv[1][0] == '-') {
  84                if (!strcmp(argv[1], "-s"))
  85                        silent_on_nonexisting_files = silent = 1;
  86                else if (!strcmp(argv[1], "-q"))
  87                        silent_on_nonexisting_files = 1;
  88                else if (!strcmp(argv[1], "-z")) {
  89                        machine_readable = 1;
  90                }
  91                else
  92                        usage(show_diff_usage);
  93                argv++; argc--;
  94        }
  95
  96        /* At this point, if argc == 1, then we are doing everything.
  97         * Otherwise argv[1] .. argv[argc-1] have the explicit paths.
  98         */
  99        if (entries < 0) {
 100                perror("read_cache");
 101                exit(1);
 102        }
 103        for (i = 0; i < entries; i++) {
 104                struct stat st;
 105                struct cache_entry *ce = active_cache[i];
 106                int changed;
 107                unsigned long size;
 108                char type[20];
 109                void *new;
 110
 111                if (1 <argc &&
 112                    ! matches_pathspec(ce, argv+1, argc-1))
 113                        continue;
 114
 115                if (stat(ce->name, &st) < 0) {
 116                        if (errno == ENOENT && silent_on_nonexisting_files)
 117                                continue;
 118                        if (machine_readable)
 119                                printf("X %s%c", ce->name, 0);
 120                        else {
 121                                printf("%s: %s\n", ce->name, strerror(errno));
 122                                if (errno == ENOENT)
 123                                        show_diff_empty(ce);
 124                        }
 125                        continue;
 126                }
 127                changed = cache_match_stat(ce, &st);
 128                if (!changed)
 129                        continue;
 130                if (!machine_readable)
 131                        printf("%s: %s\n", ce->name, sha1_to_hex(ce->sha1));
 132                else {
 133                        printf("%s %s%c", sha1_to_hex(ce->sha1), ce->name, 0);
 134                        continue;
 135                }
 136                fflush(stdout);
 137                if (silent)
 138                        continue;
 139
 140                new = read_sha1_file(ce->sha1, type, &size);
 141                show_differences(ce->name, new, size);
 142                free(new);
 143        }
 144        return 0;
 145}