receive-pack.c: use a reference transaction for updating the refs
[gitweb.git] / builtin / patch-id.c
index 3cfe02d5a5716de1a3aaa5edc1ca0e3d74c03b03..77db8739b5165f15a437651b0803711f6e019839 100644 (file)
@@ -1,17 +1,14 @@
 #include "builtin.h"
 
-static void flush_current_id(int patchlen, unsigned char *id, git_SHA_CTX *c)
+static void flush_current_id(int patchlen, unsigned char *id, unsigned char *result)
 {
-       unsigned char result[20];
        char name[50];
 
        if (!patchlen)
                return;
 
-       git_SHA1_Final(result, c);
        memcpy(name, sha1_to_hex(id), 41);
        printf("%s %s\n", sha1_to_hex(result), name);
-       git_SHA1_Init(c);
 }
 
 static int remove_space(char *line)
@@ -56,10 +53,31 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
        return 1;
 }
 
-static int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx, struct strbuf *line_buf)
+static void flush_one_hunk(unsigned char *result, git_SHA_CTX *ctx)
+{
+       unsigned char hash[20];
+       unsigned short carry = 0;
+       int i;
+
+       git_SHA1_Final(hash, ctx);
+       git_SHA1_Init(ctx);
+       /* 20-byte sum, with carry */
+       for (i = 0; i < 20; ++i) {
+               carry += result[i] + hash[i];
+               result[i] = carry;
+               carry >>= 8;
+       }
+}
+
+static int get_one_patchid(unsigned char *next_sha1, unsigned char *result,
+                          struct strbuf *line_buf, int stable)
 {
        int patchlen = 0, found_next = 0;
        int before = -1, after = -1;
+       git_SHA_CTX ctx;
+
+       git_SHA1_Init(&ctx);
+       hashclr(result);
 
        while (strbuf_getwholeline(line_buf, stdin, '\n') != EOF) {
                char *line = line_buf->buf;
@@ -107,6 +125,8 @@ static int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx, struct st
                                break;
 
                        /* Else we're parsing another header.  */
+                       if (stable)
+                               flush_one_hunk(result, &ctx);
                        before = after = -1;
                }
 
@@ -119,39 +139,63 @@ static int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx, struct st
                /* Compute the sha without whitespace */
                len = remove_space(line);
                patchlen += len;
-               git_SHA1_Update(ctx, line, len);
+               git_SHA1_Update(&ctx, line, len);
        }
 
        if (!found_next)
                hashclr(next_sha1);
 
+       flush_one_hunk(result, &ctx);
+
        return patchlen;
 }
 
-static void generate_id_list(void)
+static void generate_id_list(int stable)
 {
-       unsigned char sha1[20], n[20];
-       git_SHA_CTX ctx;
+       unsigned char sha1[20], n[20], result[20];
        int patchlen;
        struct strbuf line_buf = STRBUF_INIT;
 
-       git_SHA1_Init(&ctx);
        hashclr(sha1);
        while (!feof(stdin)) {
-               patchlen = get_one_patchid(n, &ctx, &line_buf);
-               flush_current_id(patchlen, sha1, &ctx);
+               patchlen = get_one_patchid(n, result, &line_buf, stable);
+               flush_current_id(patchlen, sha1, result);
                hashcpy(sha1, n);
        }
        strbuf_release(&line_buf);
 }
 
-static const char patch_id_usage[] = "git patch-id < patch";
+static const char patch_id_usage[] = "git patch-id [--stable | --unstable] < patch";
+
+static int git_patch_id_config(const char *var, const char *value, void *cb)
+{
+       int *stable = cb;
+
+       if (!strcmp(var, "patchid.stable")) {
+               *stable = git_config_bool(var, value);
+               return 0;
+       }
+
+       return git_default_config(var, value, cb);
+}
 
 int cmd_patch_id(int argc, const char **argv, const char *prefix)
 {
-       if (argc != 1)
+       int stable = -1;
+
+       git_config(git_patch_id_config, &stable);
+
+       /* If nothing is set, default to unstable. */
+       if (stable < 0)
+               stable = 0;
+
+       if (argc == 2 && !strcmp(argv[1], "--stable"))
+               stable = 1;
+       else if (argc == 2 && !strcmp(argv[1], "--unstable"))
+               stable = 0;
+       else if (argc != 1)
                usage(patch_id_usage);
 
-       generate_id_list();
+       generate_id_list(stable);
        return 0;
 }