sha1_name.con commit show-branch: optionally use unique prefix as name. (013f276)
   1#include "cache.h"
   2#include "commit.h"
   3
   4static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
   5{
   6        struct alternate_object_database *alt;
   7        char hex[40];
   8        int found = 0;
   9        static struct alternate_object_database *fakeent;
  10
  11        if (!fakeent) {
  12                const char *objdir = get_object_directory();
  13                int objdir_len = strlen(objdir);
  14                int entlen = objdir_len + 43;
  15                fakeent = xmalloc(sizeof(*fakeent) + entlen);
  16                memcpy(fakeent->base, objdir, objdir_len);
  17                fakeent->name = fakeent->base + objdir_len + 1;
  18                fakeent->name[-1] = '/';
  19        }
  20        fakeent->next = alt_odb_list;
  21
  22        sprintf(hex, "%.2s", name);
  23        for (alt = fakeent; alt && found < 2; alt = alt->next) {
  24                struct dirent *de;
  25                DIR *dir;
  26                sprintf(alt->name, "%.2s/", name);
  27                dir = opendir(alt->base);
  28                if (!dir)
  29                        continue;
  30                while ((de = readdir(dir)) != NULL) {
  31                        if (strlen(de->d_name) != 38)
  32                                continue;
  33                        if (memcmp(de->d_name, name + 2, len - 2))
  34                                continue;
  35                        if (!found) {
  36                                memcpy(hex + 2, de->d_name, 38);
  37                                found++;
  38                        }
  39                        else if (memcmp(hex + 2, de->d_name, 38)) {
  40                                found = 2;
  41                                break;
  42                        }
  43                }
  44                closedir(dir);
  45        }
  46        if (found == 1)
  47                return get_sha1_hex(hex, sha1) == 0;
  48        return found;
  49}
  50
  51static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b)
  52{
  53        do {
  54                if (*a != *b)
  55                        return 0;
  56                a++;
  57                b++;
  58                len -= 2;
  59        } while (len > 1);
  60        if (len)
  61                if ((*a ^ *b) & 0xf0)
  62                        return 0;
  63        return 1;
  64}
  65
  66static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1)
  67{
  68        struct packed_git *p;
  69        unsigned char found_sha1[20];
  70        int found = 0;
  71
  72        prepare_packed_git();
  73        for (p = packed_git; p && found < 2; p = p->next) {
  74                unsigned num = num_packed_objects(p);
  75                unsigned first = 0, last = num;
  76                while (first < last) {
  77                        unsigned mid = (first + last) / 2;
  78                        unsigned char now[20];
  79                        int cmp;
  80
  81                        nth_packed_object_sha1(p, mid, now);
  82                        cmp = memcmp(match, now, 20);
  83                        if (!cmp) {
  84                                first = mid;
  85                                break;
  86                        }
  87                        if (cmp > 0) {
  88                                first = mid+1;
  89                                continue;
  90                        }
  91                        last = mid;
  92                }
  93                if (first < num) {
  94                        unsigned char now[20], next[20];
  95                        nth_packed_object_sha1(p, first, now);
  96                        if (match_sha(len, match, now)) {
  97                                if (nth_packed_object_sha1(p, first+1, next) ||
  98                                    !match_sha(len, match, next)) {
  99                                        /* unique within this pack */
 100                                        if (!found) {
 101                                                memcpy(found_sha1, now, 20);
 102                                                found++;
 103                                        }
 104                                        else if (memcmp(found_sha1, now, 20)) {
 105                                                found = 2;
 106                                                break;
 107                                        }
 108                                }
 109                                else {
 110                                        /* not even unique within this pack */
 111                                        found = 2;
 112                                        break;
 113                                }
 114                        }
 115                }
 116        }
 117        if (found == 1)
 118                memcpy(sha1, found_sha1, 20);
 119        return found;
 120}
 121
 122#define SHORT_NAME_NOT_FOUND (-1)
 123#define SHORT_NAME_AMBIGUOUS (-2)
 124
 125static int find_unique_short_object(int len, char *canonical,
 126                                    unsigned char *res, unsigned char *sha1)
 127{
 128        int has_unpacked, has_packed;
 129        unsigned char unpacked_sha1[20], packed_sha1[20];
 130
 131        has_unpacked = find_short_object_filename(len, canonical, unpacked_sha1);
 132        has_packed = find_short_packed_object(len, res, packed_sha1);
 133        if (!has_unpacked && !has_packed)
 134                return SHORT_NAME_NOT_FOUND;
 135        if (1 < has_unpacked || 1 < has_packed)
 136                return SHORT_NAME_AMBIGUOUS;
 137        if (has_unpacked != has_packed) {
 138                memcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1), 20);
 139                return 0;
 140        }
 141        /* Both have unique ones -- do they match? */
 142        if (memcmp(packed_sha1, unpacked_sha1, 20))
 143                return -2;
 144        memcpy(sha1, packed_sha1, 20);
 145        return 0;
 146}
 147
 148static int get_short_sha1(const char *name, int len, unsigned char *sha1,
 149                          int quietly)
 150{
 151        int i, status;
 152        char canonical[40];
 153        unsigned char res[20];
 154
 155        if (len < 4)
 156                return -1;
 157        memset(res, 0, 20);
 158        memset(canonical, 'x', 40);
 159        for (i = 0; i < len ;i++) {
 160                unsigned char c = name[i];
 161                unsigned char val;
 162                if (c >= '0' && c <= '9')
 163                        val = c - '0';
 164                else if (c >= 'a' && c <= 'f')
 165                        val = c - 'a' + 10;
 166                else if (c >= 'A' && c <='F') {
 167                        val = c - 'A' + 10;
 168                        c -= 'A' - 'a';
 169                }
 170                else
 171                        return -1;
 172                canonical[i] = c;
 173                if (!(i & 1))
 174                        val <<= 4;
 175                res[i >> 1] |= val;
 176        }
 177
 178        status = find_unique_short_object(i, canonical, res, sha1);
 179        if (!quietly && (status == SHORT_NAME_AMBIGUOUS))
 180                return error("short SHA1 %.*s is ambiguous.", len, canonical);
 181        return status;
 182}
 183
 184const char *find_unique_abbrev(const unsigned char *sha1, int len)
 185{
 186        int status;
 187        static char hex[41];
 188        memcpy(hex, sha1_to_hex(sha1), 40);
 189        while (len < 40) {
 190                unsigned char sha1_ret[20];
 191                status = get_short_sha1(hex, len, sha1_ret, 1);
 192                if (!status) {
 193                        hex[len] = 0;
 194                        return hex;
 195                }
 196                if (status != SHORT_NAME_AMBIGUOUS)
 197                        return NULL;
 198                len++;
 199        }
 200        return NULL;
 201}
 202
 203static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
 204{
 205        static const char *prefix[] = {
 206                "",
 207                "refs",
 208                "refs/tags",
 209                "refs/heads",
 210                NULL
 211        };
 212        const char **p;
 213
 214        if (len == 40 && !get_sha1_hex(str, sha1))
 215                return 0;
 216
 217        for (p = prefix; *p; p++) {
 218                char *pathname = git_path("%s/%.*s", *p, len, str);
 219                if (!read_ref(pathname, sha1))
 220                        return 0;
 221        }
 222
 223        return -1;
 224}
 225
 226static int get_sha1_1(const char *name, int len, unsigned char *sha1);
 227
 228static int get_parent(const char *name, int len,
 229                      unsigned char *result, int idx)
 230{
 231        unsigned char sha1[20];
 232        int ret = get_sha1_1(name, len, sha1);
 233        struct commit *commit;
 234        struct commit_list *p;
 235
 236        if (ret)
 237                return ret;
 238        commit = lookup_commit_reference(sha1);
 239        if (!commit)
 240                return -1;
 241        if (parse_commit(commit))
 242                return -1;
 243        if (!idx) {
 244                memcpy(result, commit->object.sha1, 20);
 245                return 0;
 246        }
 247        p = commit->parents;
 248        while (p) {
 249                if (!--idx) {
 250                        memcpy(result, p->item->object.sha1, 20);
 251                        return 0;
 252                }
 253                p = p->next;
 254        }
 255        return -1;
 256}
 257
 258static int get_nth_ancestor(const char *name, int len,
 259                            unsigned char *result, int generation)
 260{
 261        unsigned char sha1[20];
 262        int ret = get_sha1_1(name, len, sha1);
 263        if (ret)
 264                return ret;
 265
 266        while (generation--) {
 267                struct commit *commit = lookup_commit_reference(sha1);
 268
 269                if (!commit || parse_commit(commit) || !commit->parents)
 270                        return -1;
 271                memcpy(sha1, commit->parents->item->object.sha1, 20);
 272        }
 273        memcpy(result, sha1, 20);
 274        return 0;
 275}
 276
 277static int get_sha1_1(const char *name, int len, unsigned char *sha1)
 278{
 279        int parent, ret;
 280        const char *cp;
 281
 282        /* foo^[0-9] or foo^ (== foo^1); we do not do more than 9 parents. */
 283        if (len > 2 && name[len-2] == '^' &&
 284            name[len-1] >= '0' && name[len-1] <= '9') {
 285                parent = name[len-1] - '0';
 286                len -= 2;
 287        }
 288        else if (len > 1 && name[len-1] == '^') {
 289                parent = 1;
 290                len--;
 291        } else
 292                parent = -1;
 293
 294        if (parent >= 0)
 295                return get_parent(name, len, sha1, parent);
 296
 297        /* "name~3" is "name^^^",
 298         * "name~12" is "name^^^^^^^^^^^^", and
 299         * "name~" and "name~0" are name -- not "name^0"!
 300         */
 301        parent = 0;
 302        for (cp = name + len - 1; name <= cp; cp--) {
 303                int ch = *cp;
 304                if ('0' <= ch && ch <= '9')
 305                        continue;
 306                if (ch != '~')
 307                        parent = -1;
 308                break;
 309        }
 310        if (!parent && *cp == '~') {
 311                int len1 = cp - name;
 312                cp++;
 313                while (cp < name + len)
 314                        parent = parent * 10 + *cp++ - '0';
 315                return get_nth_ancestor(name, len1, sha1, parent);
 316        }
 317
 318        ret = get_sha1_basic(name, len, sha1);
 319        if (!ret)
 320                return 0;
 321        return get_short_sha1(name, len, sha1, 0);
 322}
 323
 324/*
 325 * This is like "get_sha1_basic()", except it allows "sha1 expressions",
 326 * notably "xyz^" for "parent of xyz"
 327 */
 328int get_sha1(const char *name, unsigned char *sha1)
 329{
 330        prepare_alt_odb();
 331        return get_sha1_1(name, strlen(name), sha1);
 332}