bcf89a57892ac3601ac268b08c7f28d443c75108
   1/*
   2 * Copyright (C) 2005 Junio C Hamano
   3 */
   4#include "cache.h"
   5#include "strbuf.h"
   6#include "diff.h"
   7
   8static int matches_pathspec(const char *name, char **spec, int cnt)
   9{
  10        int i;
  11        int namelen = strlen(name);
  12        for (i = 0; i < cnt; i++) {
  13                int speclen = strlen(spec[i]);
  14                if (! strncmp(spec[i], name, speclen) &&
  15                    speclen <= namelen &&
  16                    (name[speclen] == 0 ||
  17                     name[speclen] == '/'))
  18                        return 1;
  19        }
  20        return 0;
  21}
  22
  23static int parse_oneside_change(const char *cp, struct diff_spec *one,
  24                                char *path)
  25{
  26        int ch;
  27
  28        one->file_valid = one->sha1_valid = 1;
  29        one->mode = 0;
  30        while ((ch = *cp) && '0' <= ch && ch <= '7') {
  31                one->mode = (one->mode << 3) | (ch - '0');
  32                cp++;
  33        }
  34
  35        if (strncmp(cp, "\tblob\t", 6))
  36                return -1;
  37        cp += 6;
  38        if (get_sha1_hex(cp, one->u.sha1))
  39                return -1;
  40        cp += 40;
  41        if (*cp++ != '\t')
  42                return -1;
  43        strcpy(path, cp);
  44        return 0;
  45}
  46
  47static int parse_diff_tree_output(const char *buf,
  48                                  struct diff_spec *old,
  49                                  struct diff_spec *new,
  50                                  char *path) {
  51        const char *cp = buf;
  52        int ch;
  53
  54        switch (*cp++) {
  55        case '+':
  56                old->file_valid = 0;
  57                return parse_oneside_change(cp, new, path);
  58        case '-':
  59                new->file_valid = 0;
  60                return parse_oneside_change(cp, old, path);
  61        case '*':
  62                break;
  63        default:
  64                return -1;
  65        }
  66        
  67        /* This is for '*' entries */
  68        old->file_valid = old->sha1_valid = 1;
  69        new->file_valid = new->sha1_valid = 1;
  70
  71        old->mode = new->mode = 0;
  72        while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
  73                old->mode = (old->mode << 3) | (ch - '0');
  74                cp++;
  75        }
  76        if (strncmp(cp, "->", 2))
  77                return -1;
  78        cp += 2;
  79        while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
  80                new->mode = (new->mode << 3) | (ch - '0');
  81                cp++;
  82        }
  83        if (strncmp(cp, "\tblob\t", 6))
  84                return -1;
  85        cp += 6;
  86        if (get_sha1_hex(cp, old->u.sha1))
  87                return -1;
  88        cp += 40;
  89        if (strncmp(cp, "->", 2))
  90                return -1;
  91        cp += 2;
  92        if (get_sha1_hex(cp, new->u.sha1))
  93                return -1;
  94        cp += 40;
  95        if (*cp++ != '\t')
  96                return -1;
  97        strcpy(path, cp);
  98        return 0;
  99}
 100
 101static const char *diff_tree_helper_usage =
 102"diff-tree-helper [-R] [-z] paths...";
 103
 104int main(int ac, char **av) {
 105        struct strbuf sb;
 106        int reverse_diff = 0;
 107        int line_termination = '\n';
 108
 109        strbuf_init(&sb);
 110
 111        while (1 < ac && av[1][0] == '-') {
 112                if (av[1][1] == 'R')
 113                        reverse_diff = 1;
 114                else if (av[1][1] == 'z')
 115                        line_termination = 0;
 116                else
 117                        usage(diff_tree_helper_usage);
 118                ac--; av++;
 119        }
 120        /* the remaining parameters are paths patterns */
 121
 122        while (1) {
 123                struct diff_spec old, new;
 124                char path[PATH_MAX];
 125                read_line(&sb, stdin, line_termination);
 126                if (sb.eof)
 127                        break;
 128                if (parse_diff_tree_output(sb.buf, &old, &new, path)) { 
 129                        fprintf(stderr, "cannot parse %s\n", sb.buf);
 130                        continue;
 131                }
 132                if (1 < ac && !matches_pathspec(path, av+1, ac-1))
 133                        continue;
 134
 135                run_external_diff(path, &old, &new);
 136        }
 137        return 0;
 138}