diff-tree-helper.con commit diff-cache: handle modified new files correctly (c9cddab)
   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
  47#define PLEASE_WARN -1
  48#define WARNED_OURSELVES -2
  49 
  50static int parse_diff_tree_output(const char *buf,
  51                                  struct diff_spec *old,
  52                                  struct diff_spec *new,
  53                                  char *path) {
  54        const char *cp = buf;
  55        int ch;
  56
  57        switch (*cp++) {
  58        case 'U':
  59                diff_unmerge(cp + 1);
  60                return WARNED_OURSELVES;
  61        case '+':
  62                old->file_valid = 0;
  63                return parse_oneside_change(cp, new, path);
  64        case '-':
  65                new->file_valid = 0;
  66                return parse_oneside_change(cp, old, path);
  67        case '*':
  68                break;
  69        default:
  70                return PLEASE_WARN;
  71        }
  72        
  73        /* This is for '*' entries */
  74        old->file_valid = old->sha1_valid = 1;
  75        new->file_valid = new->sha1_valid = 1;
  76
  77        old->mode = new->mode = 0;
  78        while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
  79                old->mode = (old->mode << 3) | (ch - '0');
  80                cp++;
  81        }
  82        if (strncmp(cp, "->", 2))
  83                return PLEASE_WARN;
  84        cp += 2;
  85        while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
  86                new->mode = (new->mode << 3) | (ch - '0');
  87                cp++;
  88        }
  89        if (strncmp(cp, "\tblob\t", 6))
  90                return PLEASE_WARN;
  91        cp += 6;
  92        if (get_sha1_hex(cp, old->u.sha1))
  93                return PLEASE_WARN;
  94        cp += 40;
  95        if (strncmp(cp, "->", 2))
  96                return PLEASE_WARN;
  97        cp += 2;
  98        if (get_sha1_hex(cp, new->u.sha1))
  99                return PLEASE_WARN;
 100        cp += 40;
 101        if (*cp++ != '\t')
 102                return PLEASE_WARN;
 103        strcpy(path, cp);
 104        return 0;
 105}
 106
 107static const char *diff_tree_helper_usage =
 108"diff-tree-helper [-R] [-z] paths...";
 109
 110int main(int ac, char **av) {
 111        struct strbuf sb;
 112        int reverse_diff = 0;
 113        int line_termination = '\n';
 114
 115        strbuf_init(&sb);
 116
 117        while (1 < ac && av[1][0] == '-') {
 118                if (av[1][1] == 'R')
 119                        reverse_diff = 1;
 120                else if (av[1][1] == 'z')
 121                        line_termination = 0;
 122                else
 123                        usage(diff_tree_helper_usage);
 124                ac--; av++;
 125        }
 126        /* the remaining parameters are paths patterns */
 127
 128        while (1) {
 129                int status;
 130                struct diff_spec old, new;
 131                char path[PATH_MAX];
 132                read_line(&sb, stdin, line_termination);
 133                if (sb.eof)
 134                        break;
 135                status = parse_diff_tree_output(sb.buf, &old, &new, path);
 136                if (status) {
 137                        if (status == PLEASE_WARN)
 138                                fprintf(stderr, "cannot parse %s\n", sb.buf);
 139                        continue;
 140                }
 141                if (1 < ac && !matches_pathspec(path, av+1, ac-1))
 142                        continue;
 143
 144                run_external_diff(path, &old, &new);
 145        }
 146        return 0;
 147}