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