notes.con commit Add flags to get_commit_notes() to control the format of the note string (c56fcc8)
   1#include "cache.h"
   2#include "commit.h"
   3#include "notes.h"
   4#include "refs.h"
   5#include "utf8.h"
   6#include "strbuf.h"
   7#include "tree-walk.h"
   8
   9struct entry {
  10        unsigned char commit_sha1[20];
  11        unsigned char notes_sha1[20];
  12};
  13
  14struct hash_map {
  15        struct entry *entries;
  16        off_t count, size;
  17};
  18
  19static int initialized;
  20static struct hash_map hash_map;
  21
  22static int hash_index(struct hash_map *map, const unsigned char *sha1)
  23{
  24        int i = ((*(unsigned int *)sha1) % map->size);
  25
  26        for (;;) {
  27                unsigned char *current = map->entries[i].commit_sha1;
  28
  29                if (!hashcmp(sha1, current))
  30                        return i;
  31
  32                if (is_null_sha1(current))
  33                        return -1 - i;
  34
  35                if (++i == map->size)
  36                        i = 0;
  37        }
  38}
  39
  40static void add_entry(const unsigned char *commit_sha1,
  41                const unsigned char *notes_sha1)
  42{
  43        int index;
  44
  45        if (hash_map.count + 1 > hash_map.size >> 1) {
  46                int i, old_size = hash_map.size;
  47                struct entry *old = hash_map.entries;
  48
  49                hash_map.size = old_size ? old_size << 1 : 64;
  50                hash_map.entries = (struct entry *)
  51                        xcalloc(sizeof(struct entry), hash_map.size);
  52
  53                for (i = 0; i < old_size; i++)
  54                        if (!is_null_sha1(old[i].commit_sha1)) {
  55                                index = -1 - hash_index(&hash_map,
  56                                                old[i].commit_sha1);
  57                                memcpy(hash_map.entries + index, old + i,
  58                                        sizeof(struct entry));
  59                        }
  60                free(old);
  61        }
  62
  63        index = hash_index(&hash_map, commit_sha1);
  64        if (index < 0) {
  65                index = -1 - index;
  66                hash_map.count++;
  67        }
  68
  69        hashcpy(hash_map.entries[index].commit_sha1, commit_sha1);
  70        hashcpy(hash_map.entries[index].notes_sha1, notes_sha1);
  71}
  72
  73static void initialize_hash_map(const char *notes_ref_name)
  74{
  75        unsigned char sha1[20], commit_sha1[20];
  76        unsigned mode;
  77        struct tree_desc desc;
  78        struct name_entry entry;
  79        void *buf;
  80
  81        if (!notes_ref_name || read_ref(notes_ref_name, commit_sha1) ||
  82            get_tree_entry(commit_sha1, "", sha1, &mode))
  83                return;
  84
  85        buf = fill_tree_descriptor(&desc, sha1);
  86        if (!buf)
  87                die("Could not read %s for notes-index", sha1_to_hex(sha1));
  88
  89        while (tree_entry(&desc, &entry))
  90                if (!get_sha1(entry.path, commit_sha1))
  91                        add_entry(commit_sha1, entry.sha1);
  92        free(buf);
  93}
  94
  95static unsigned char *lookup_notes(const unsigned char *commit_sha1)
  96{
  97        int index;
  98
  99        if (!hash_map.size)
 100                return NULL;
 101
 102        index = hash_index(&hash_map, commit_sha1);
 103        if (index < 0)
 104                return NULL;
 105        return hash_map.entries[index].notes_sha1;
 106}
 107
 108void get_commit_notes(const struct commit *commit, struct strbuf *sb,
 109                const char *output_encoding, int flags)
 110{
 111        static const char utf8[] = "utf-8";
 112        unsigned char *sha1;
 113        char *msg, *msg_p;
 114        unsigned long linelen, msglen;
 115        enum object_type type;
 116
 117        if (!initialized) {
 118                const char *env = getenv(GIT_NOTES_REF_ENVIRONMENT);
 119                if (env)
 120                        notes_ref_name = getenv(GIT_NOTES_REF_ENVIRONMENT);
 121                else if (!notes_ref_name)
 122                        notes_ref_name = GIT_NOTES_DEFAULT_REF;
 123                initialize_hash_map(notes_ref_name);
 124                initialized = 1;
 125        }
 126
 127        sha1 = lookup_notes(commit->object.sha1);
 128        if (!sha1)
 129                return;
 130
 131        if (!(msg = read_sha1_file(sha1, &type, &msglen)) || !msglen ||
 132                        type != OBJ_BLOB) {
 133                free(msg);
 134                return;
 135        }
 136
 137        if (output_encoding && *output_encoding &&
 138                        strcmp(utf8, output_encoding)) {
 139                char *reencoded = reencode_string(msg, output_encoding, utf8);
 140                if (reencoded) {
 141                        free(msg);
 142                        msg = reencoded;
 143                        msglen = strlen(msg);
 144                }
 145        }
 146
 147        /* we will end the annotation by a newline anyway */
 148        if (msglen && msg[msglen - 1] == '\n')
 149                msglen--;
 150
 151        if (flags & NOTES_SHOW_HEADER)
 152                strbuf_addstr(sb, "\nNotes:\n");
 153
 154        for (msg_p = msg; msg_p < msg + msglen; msg_p += linelen + 1) {
 155                linelen = strchrnul(msg_p, '\n') - msg_p;
 156
 157                if (flags & NOTES_INDENT)
 158                        strbuf_addstr(sb, "    ");
 159                strbuf_add(sb, msg_p, linelen);
 160                strbuf_addch(sb, '\n');
 161        }
 162
 163        free(msg);
 164}