40bc187bdc201c6d5b7df0eb7144d98760b72bdd
   1/*
   2 * GIT - The information manager from hell
   3 *
   4 * Copyright (C) Linus Torvalds, 2005
   5 */
   6#include "cache.h"
   7
   8static char *diff_cmd = "diff -L '%s' -u -N  - '%s'";
   9
  10/* Help to copy the thing properly quoted for the shell safety.
  11 * any single quote is replaced with '\'', and the caller is
  12 * expected to enclose the result within a single quote pair.
  13 *
  14 * E.g.
  15 *  original     sq_expand     result
  16 *  name     ==> name      ==> 'name'
  17 *  a b      ==> a b       ==> 'a b'
  18 *  a'b      ==> a'\''b    ==> 'a'\''b'
  19 *
  20 * NOTE! The returned memory belongs to this function so
  21 * do not free it.
  22 */
  23static char *sq_expand(char *src)
  24{
  25        static char *buf = NULL;
  26        int cnt, c;
  27        char *cp;
  28
  29        /* count bytes needed to store the quoted string. */ 
  30        for (cnt = 1, cp = src; *cp; cnt++, cp++)
  31                if (*cp == '\'')
  32                        cnt += 3;
  33
  34        if (! (buf = malloc(cnt)))
  35            return buf;
  36        cp = buf;
  37        while ((c = *src++)) {
  38                if (c != '\'')
  39                        *cp++ = c;
  40                else {
  41                        cp = strcpy(cp, "'\\''");
  42                        cp += 4;
  43                }
  44        }
  45        *cp = 0;
  46        return buf;
  47}
  48
  49static void show_differences(char *name, char *label, void *old_contents,
  50                             unsigned long long old_size)
  51{
  52        FILE *f;
  53        char *name_sq = sq_expand(name);
  54        char *label_sq = (name != label) ? sq_expand(label) : name_sq;
  55        int cmd_size = strlen(name_sq) + strlen(label_sq) + strlen(diff_cmd);
  56        char *cmd = malloc(cmd_size);
  57
  58        fflush(stdout);
  59        snprintf(cmd, cmd_size, diff_cmd, label_sq, name_sq);
  60        f = popen(cmd, "w");
  61        if (old_size)
  62                fwrite(old_contents, old_size, 1, f);
  63        pclose(f);
  64        if (label_sq != name_sq)
  65                free(label_sq);
  66        free(name_sq);
  67        free(cmd);
  68}
  69
  70static void show_diff_empty(struct cache_entry *ce)
  71{
  72        char *old;
  73        unsigned long int size;
  74        unsigned char type[20];
  75
  76        old = read_sha1_file(ce->sha1, type, &size);
  77        if (! old) {
  78                error("unable to read blob object for %s (%s)", ce->name,
  79                      sha1_to_hex(ce->sha1));
  80                return;
  81        }
  82        show_differences("/dev/null", ce->name, old, size);
  83}
  84
  85static const char *show_diff_usage = "show-diff [-q] [-s] [-z] [paths...]";
  86
  87static int matches_pathspec(struct cache_entry *ce, char **spec, int cnt)
  88{
  89        int i;
  90        int namelen = ce_namelen(ce);
  91        for (i = 0; i < cnt; i++) {
  92                int speclen = strlen(spec[i]);
  93                if (! strncmp(spec[i], ce->name, speclen) &&
  94                    speclen <= namelen &&
  95                    (ce->name[speclen] == 0 ||
  96                     ce->name[speclen] == '/'))
  97                        return 1;
  98        }
  99        return 0;
 100}
 101
 102int main(int argc, char **argv)
 103{
 104        int silent = 0;
 105        int silent_on_nonexisting_files = 0;
 106        int machine_readable = 0;
 107        int entries = read_cache();
 108        int i;
 109
 110        while (1 < argc && argv[1][0] == '-') {
 111                if (!strcmp(argv[1], "-s"))
 112                        silent_on_nonexisting_files = silent = 1;
 113                else if (!strcmp(argv[1], "-q"))
 114                        silent_on_nonexisting_files = 1;
 115                else if (!strcmp(argv[1], "-z"))
 116                        machine_readable = 1;
 117                else
 118                        usage(show_diff_usage);
 119                argv++; argc--;
 120        }
 121
 122        /* At this point, if argc == 1, then we are doing everything.
 123         * Otherwise argv[1] .. argv[argc-1] have the explicit paths.
 124         */
 125        if (entries < 0) {
 126                perror("read_cache");
 127                exit(1);
 128        }
 129        for (i = 0; i < entries; i++) {
 130                struct stat st;
 131                struct cache_entry *ce = active_cache[i];
 132                int changed;
 133                unsigned long size;
 134                char type[20];
 135                void *old;
 136
 137                if (1 < argc &&
 138                    ! matches_pathspec(ce, argv+1, argc-1))
 139                        continue;
 140
 141                if (ce_stage(ce)) {
 142                        if (machine_readable)
 143                                printf("U %s%c", ce->name, 0);
 144                        else
 145                                printf("%s: Unmerged\n",
 146                                       ce->name);
 147                        while (i < entries &&
 148                               !strcmp(ce->name, active_cache[i]->name))
 149                                i++;
 150                        i--; /* compensate for loop control increments */
 151                        continue;
 152                }
 153 
 154                if (stat(ce->name, &st) < 0) {
 155                        if (errno == ENOENT && silent_on_nonexisting_files)
 156                                continue;
 157                        if (machine_readable)
 158                                printf("X %s%c", ce->name, 0);
 159                        else {
 160                                printf("%s: %s\n", ce->name, strerror(errno));
 161                                if (errno == ENOENT)
 162                                        show_diff_empty(ce);
 163                        }
 164                        continue;
 165                }
 166                changed = cache_match_stat(ce, &st);
 167                if (!changed)
 168                        continue;
 169                if (!machine_readable)
 170                        printf("%s: %s\n", ce->name, sha1_to_hex(ce->sha1));
 171                else {
 172                        printf("%s %s%c", sha1_to_hex(ce->sha1), ce->name, 0);
 173                        continue;
 174                }
 175                if (silent)
 176                        continue;
 177
 178                old = read_sha1_file(ce->sha1, type, &size);
 179                if (! old)
 180                        error("unable to read blob object for %s (%s)",
 181                              ce->name, sha1_to_hex(ce->sha1));
 182                else
 183                        show_differences(ce->name, ce->name, old, size);
 184                free(old);
 185        }
 186        return 0;
 187}