commit.con commit Merge branch 'master' into pb/gitpm (d7b6c3c)
   1#include "cache.h"
   2#include "tag.h"
   3#include "commit.h"
   4
   5int save_commit_buffer = 1;
   6
   7struct sort_node
   8{
   9        /*
  10         * the number of children of the associated commit
  11         * that also occur in the list being sorted.
  12         */
  13        unsigned int indegree;
  14
  15        /*
  16         * reference to original list item that we will re-use
  17         * on output.
  18         */
  19        struct commit_list * list_item;
  20
  21};
  22
  23const char *commit_type = "commit";
  24
  25struct cmt_fmt_map {
  26        const char *n;
  27        size_t cmp_len;
  28        enum cmit_fmt v;
  29} cmt_fmts[] = {
  30        { "raw",        1,      CMIT_FMT_RAW },
  31        { "medium",     1,      CMIT_FMT_MEDIUM },
  32        { "short",      1,      CMIT_FMT_SHORT },
  33        { "email",      1,      CMIT_FMT_EMAIL },
  34        { "full",       5,      CMIT_FMT_FULL },
  35        { "fuller",     5,      CMIT_FMT_FULLER },
  36        { "oneline",    1,      CMIT_FMT_ONELINE },
  37};
  38
  39enum cmit_fmt get_commit_format(const char *arg)
  40{
  41        int i;
  42
  43        if (!arg || !*arg)
  44                return CMIT_FMT_DEFAULT;
  45        if (*arg == '=')
  46                arg++;
  47        for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
  48                if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len))
  49                        return cmt_fmts[i].v;
  50        }
  51
  52        die("invalid --pretty format: %s", arg);
  53}
  54
  55static struct commit *check_commit(struct object *obj,
  56                                   const unsigned char *sha1,
  57                                   int quiet)
  58{
  59        if (obj->type != OBJ_COMMIT) {
  60                if (!quiet)
  61                        error("Object %s is a %s, not a commit",
  62                              sha1_to_hex(sha1), typename(obj->type));
  63                return NULL;
  64        }
  65        return (struct commit *) obj;
  66}
  67
  68struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
  69                                              int quiet)
  70{
  71        struct object *obj = deref_tag(parse_object(sha1), NULL, 0);
  72
  73        if (!obj)
  74                return NULL;
  75        return check_commit(obj, sha1, quiet);
  76}
  77
  78struct commit *lookup_commit_reference(const unsigned char *sha1)
  79{
  80        return lookup_commit_reference_gently(sha1, 0);
  81}
  82
  83struct commit *lookup_commit(const unsigned char *sha1)
  84{
  85        struct object *obj = lookup_object(sha1);
  86        if (!obj) {
  87                struct commit *ret = alloc_commit_node();
  88                created_object(sha1, &ret->object);
  89                ret->object.type = OBJ_COMMIT;
  90                return ret;
  91        }
  92        if (!obj->type)
  93                obj->type = OBJ_COMMIT;
  94        return check_commit(obj, sha1, 0);
  95}
  96
  97static unsigned long parse_commit_date(const char *buf)
  98{
  99        unsigned long date;
 100
 101        if (memcmp(buf, "author", 6))
 102                return 0;
 103        while (*buf++ != '\n')
 104                /* nada */;
 105        if (memcmp(buf, "committer", 9))
 106                return 0;
 107        while (*buf++ != '>')
 108                /* nada */;
 109        date = strtoul(buf, NULL, 10);
 110        if (date == ULONG_MAX)
 111                date = 0;
 112        return date;
 113}
 114
 115static struct commit_graft **commit_graft;
 116static int commit_graft_alloc, commit_graft_nr;
 117
 118static int commit_graft_pos(const unsigned char *sha1)
 119{
 120        int lo, hi;
 121        lo = 0;
 122        hi = commit_graft_nr;
 123        while (lo < hi) {
 124                int mi = (lo + hi) / 2;
 125                struct commit_graft *graft = commit_graft[mi];
 126                int cmp = memcmp(sha1, graft->sha1, 20);
 127                if (!cmp)
 128                        return mi;
 129                if (cmp < 0)
 130                        hi = mi;
 131                else
 132                        lo = mi + 1;
 133        }
 134        return -lo - 1;
 135}
 136
 137int register_commit_graft(struct commit_graft *graft, int ignore_dups)
 138{
 139        int pos = commit_graft_pos(graft->sha1);
 140        
 141        if (0 <= pos) {
 142                if (ignore_dups)
 143                        free(graft);
 144                else {
 145                        free(commit_graft[pos]);
 146                        commit_graft[pos] = graft;
 147                }
 148                return 1;
 149        }
 150        pos = -pos - 1;
 151        if (commit_graft_alloc <= ++commit_graft_nr) {
 152                commit_graft_alloc = alloc_nr(commit_graft_alloc);
 153                commit_graft = xrealloc(commit_graft,
 154                                        sizeof(*commit_graft) *
 155                                        commit_graft_alloc);
 156        }
 157        if (pos < commit_graft_nr)
 158                memmove(commit_graft + pos + 1,
 159                        commit_graft + pos,
 160                        (commit_graft_nr - pos - 1) *
 161                        sizeof(*commit_graft));
 162        commit_graft[pos] = graft;
 163        return 0;
 164}
 165
 166void free_commit_grafts(void)
 167{
 168        int pos = commit_graft_nr;
 169        while (pos >= 0)
 170                free(commit_graft[pos--]);
 171        commit_graft_nr = 0;
 172}
 173
 174struct commit_graft *read_graft_line(char *buf, int len)
 175{
 176        /* The format is just "Commit Parent1 Parent2 ...\n" */
 177        int i;
 178        struct commit_graft *graft = NULL;
 179
 180        if (buf[len-1] == '\n')
 181                buf[--len] = 0;
 182        if (buf[0] == '#' || buf[0] == '\0')
 183                return NULL;
 184        if ((len + 1) % 41) {
 185        bad_graft_data:
 186                error("bad graft data: %s", buf);
 187                free(graft);
 188                return NULL;
 189        }
 190        i = (len + 1) / 41 - 1;
 191        graft = xmalloc(sizeof(*graft) + 20 * i);
 192        graft->nr_parent = i;
 193        if (get_sha1_hex(buf, graft->sha1))
 194                goto bad_graft_data;
 195        for (i = 40; i < len; i += 41) {
 196                if (buf[i] != ' ')
 197                        goto bad_graft_data;
 198                if (get_sha1_hex(buf + i + 1, graft->parent[i/41]))
 199                        goto bad_graft_data;
 200        }
 201        return graft;
 202}
 203
 204int read_graft_file(const char *graft_file)
 205{
 206        FILE *fp = fopen(graft_file, "r");
 207        char buf[1024];
 208        if (!fp)
 209                return -1;
 210        while (fgets(buf, sizeof(buf), fp)) {
 211                /* The format is just "Commit Parent1 Parent2 ...\n" */
 212                int len = strlen(buf);
 213                struct commit_graft *graft = read_graft_line(buf, len);
 214                if (!graft)
 215                        continue;
 216                if (register_commit_graft(graft, 1))
 217                        error("duplicate graft data: %s", buf);
 218        }
 219        fclose(fp);
 220        return 0;
 221}
 222
 223static void prepare_commit_graft(void)
 224{
 225        static int commit_graft_prepared;
 226        static char *last_graft_file;
 227        char *graft_file = get_graft_file();
 228
 229        if (last_graft_file) {
 230                if (!strcmp(graft_file, last_graft_file))
 231                        return;
 232                free_commit_grafts();
 233        }
 234        if (last_graft_file)
 235                free(last_graft_file);
 236        last_graft_file = strdup(graft_file);
 237
 238        read_graft_file(graft_file);
 239        commit_graft_prepared = 1;
 240}
 241
 242static struct commit_graft *lookup_commit_graft(const unsigned char *sha1)
 243{
 244        int pos;
 245        prepare_commit_graft();
 246        pos = commit_graft_pos(sha1);
 247        if (pos < 0)
 248                return NULL;
 249        return commit_graft[pos];
 250}
 251
 252int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
 253{
 254        char *tail = buffer;
 255        char *bufptr = buffer;
 256        unsigned char parent[20];
 257        struct commit_list **pptr;
 258        struct commit_graft *graft;
 259        unsigned n_refs = 0;
 260
 261        if (item->object.parsed)
 262                return 0;
 263        item->object.parsed = 1;
 264        tail += size;
 265        if (tail <= bufptr + 5 || memcmp(bufptr, "tree ", 5))
 266                return error("bogus commit object %s", sha1_to_hex(item->object.sha1));
 267        if (tail <= bufptr + 45 || get_sha1_hex(bufptr + 5, parent) < 0)
 268                return error("bad tree pointer in commit %s",
 269                             sha1_to_hex(item->object.sha1));
 270        item->tree = lookup_tree(parent);
 271        if (item->tree)
 272                n_refs++;
 273        bufptr += 46; /* "tree " + "hex sha1" + "\n" */
 274        pptr = &item->parents;
 275
 276        graft = lookup_commit_graft(item->object.sha1);
 277        while (bufptr + 48 < tail && !memcmp(bufptr, "parent ", 7)) {
 278                struct commit *new_parent;
 279
 280                if (tail <= bufptr + 48 ||
 281                    get_sha1_hex(bufptr + 7, parent) ||
 282                    bufptr[47] != '\n')
 283                        return error("bad parents in commit %s", sha1_to_hex(item->object.sha1));
 284                bufptr += 48;
 285                if (graft)
 286                        continue;
 287                new_parent = lookup_commit(parent);
 288                if (new_parent) {
 289                        pptr = &commit_list_insert(new_parent, pptr)->next;
 290                        n_refs++;
 291                }
 292        }
 293        if (graft) {
 294                int i;
 295                struct commit *new_parent;
 296                for (i = 0; i < graft->nr_parent; i++) {
 297                        new_parent = lookup_commit(graft->parent[i]);
 298                        if (!new_parent)
 299                                continue;
 300                        pptr = &commit_list_insert(new_parent, pptr)->next;
 301                        n_refs++;
 302                }
 303        }
 304        item->date = parse_commit_date(bufptr);
 305
 306        if (track_object_refs) {
 307                unsigned i = 0;
 308                struct commit_list *p;
 309                struct object_refs *refs = alloc_object_refs(n_refs);
 310                if (item->tree)
 311                        refs->ref[i++] = &item->tree->object;
 312                for (p = item->parents; p; p = p->next)
 313                        refs->ref[i++] = &p->item->object;
 314                set_object_refs(&item->object, refs);
 315        }
 316
 317        return 0;
 318}
 319
 320int parse_commit(struct commit *item)
 321{
 322        char type[20];
 323        void *buffer;
 324        unsigned long size;
 325        int ret;
 326
 327        if (item->object.parsed)
 328                return 0;
 329        buffer = read_sha1_file(item->object.sha1, type, &size);
 330        if (!buffer)
 331                return error("Could not read %s",
 332                             sha1_to_hex(item->object.sha1));
 333        if (strcmp(type, commit_type)) {
 334                free(buffer);
 335                return error("Object %s not a commit",
 336                             sha1_to_hex(item->object.sha1));
 337        }
 338        ret = parse_commit_buffer(item, buffer, size);
 339        if (save_commit_buffer && !ret) {
 340                item->buffer = buffer;
 341                return 0;
 342        }
 343        free(buffer);
 344        return ret;
 345}
 346
 347struct commit_list *commit_list_insert(struct commit *item, struct commit_list **list_p)
 348{
 349        struct commit_list *new_list = xmalloc(sizeof(struct commit_list));
 350        new_list->item = item;
 351        new_list->next = *list_p;
 352        *list_p = new_list;
 353        return new_list;
 354}
 355
 356void free_commit_list(struct commit_list *list)
 357{
 358        while (list) {
 359                struct commit_list *temp = list;
 360                list = temp->next;
 361                free(temp);
 362        }
 363}
 364
 365struct commit_list * insert_by_date(struct commit *item, struct commit_list **list)
 366{
 367        struct commit_list **pp = list;
 368        struct commit_list *p;
 369        while ((p = *pp) != NULL) {
 370                if (p->item->date < item->date) {
 371                        break;
 372                }
 373                pp = &p->next;
 374        }
 375        return commit_list_insert(item, pp);
 376}
 377
 378        
 379void sort_by_date(struct commit_list **list)
 380{
 381        struct commit_list *ret = NULL;
 382        while (*list) {
 383                insert_by_date((*list)->item, &ret);
 384                *list = (*list)->next;
 385        }
 386        *list = ret;
 387}
 388
 389struct commit *pop_most_recent_commit(struct commit_list **list,
 390                                      unsigned int mark)
 391{
 392        struct commit *ret = (*list)->item;
 393        struct commit_list *parents = ret->parents;
 394        struct commit_list *old = *list;
 395
 396        *list = (*list)->next;
 397        free(old);
 398
 399        while (parents) {
 400                struct commit *commit = parents->item;
 401                parse_commit(commit);
 402                if (!(commit->object.flags & mark)) {
 403                        commit->object.flags |= mark;
 404                        insert_by_date(commit, list);
 405                }
 406                parents = parents->next;
 407        }
 408        return ret;
 409}
 410
 411void clear_commit_marks(struct commit *commit, unsigned int mark)
 412{
 413        struct commit_list *parents;
 414
 415        commit->object.flags &= ~mark;
 416        parents = commit->parents;
 417        while (parents) {
 418                struct commit *parent = parents->item;
 419
 420                /* Have we already cleared this? */
 421                if (mark & parent->object.flags)
 422                        clear_commit_marks(parent, mark);
 423                parents = parents->next;
 424        }
 425}
 426
 427/*
 428 * Generic support for pretty-printing the header
 429 */
 430static int get_one_line(const char *msg, unsigned long len)
 431{
 432        int ret = 0;
 433
 434        while (len--) {
 435                char c = *msg++;
 436                if (!c)
 437                        break;
 438                ret++;
 439                if (c == '\n')
 440                        break;
 441        }
 442        return ret;
 443}
 444
 445static int is_rfc2047_special(char ch)
 446{
 447        return ((ch & 0x80) || (ch == '=') || (ch == '?') || (ch == '_'));
 448}
 449
 450static int add_rfc2047(char *buf, const char *line, int len)
 451{
 452        char *bp = buf;
 453        int i, needquote;
 454        static const char q_utf8[] = "=?utf-8?q?";
 455
 456        for (i = needquote = 0; !needquote && i < len; i++) {
 457                unsigned ch = line[i];
 458                if (ch & 0x80)
 459                        needquote++;
 460                if ((i + 1 < len) &&
 461                    (ch == '=' && line[i+1] == '?'))
 462                        needquote++;
 463        }
 464        if (!needquote)
 465                return sprintf(buf, "%.*s", len, line);
 466
 467        memcpy(bp, q_utf8, sizeof(q_utf8)-1);
 468        bp += sizeof(q_utf8)-1;
 469        for (i = 0; i < len; i++) {
 470                unsigned ch = line[i] & 0xFF;
 471                if (is_rfc2047_special(ch)) {
 472                        sprintf(bp, "=%02X", ch);
 473                        bp += 3;
 474                }
 475                else if (ch == ' ')
 476                        *bp++ = '_';
 477                else
 478                        *bp++ = ch;
 479        }
 480        memcpy(bp, "?=", 2);
 481        bp += 2;
 482        return bp - buf;
 483}
 484
 485static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, const char *line)
 486{
 487        char *date;
 488        int namelen;
 489        unsigned long time;
 490        int tz, ret;
 491        const char *filler = "    ";
 492
 493        if (fmt == CMIT_FMT_ONELINE)
 494                return 0;
 495        date = strchr(line, '>');
 496        if (!date)
 497                return 0;
 498        namelen = ++date - line;
 499        time = strtoul(date, &date, 10);
 500        tz = strtol(date, NULL, 10);
 501
 502        if (fmt == CMIT_FMT_EMAIL) {
 503                char *name_tail = strchr(line, '<');
 504                int display_name_length;
 505                if (!name_tail)
 506                        return 0;
 507                while (line < name_tail && isspace(name_tail[-1]))
 508                        name_tail--;
 509                display_name_length = name_tail - line;
 510                filler = "";
 511                strcpy(buf, "From: ");
 512                ret = strlen(buf);
 513                ret += add_rfc2047(buf + ret, line, display_name_length);
 514                memcpy(buf + ret, name_tail, namelen - display_name_length);
 515                ret += namelen - display_name_length;
 516                buf[ret++] = '\n';
 517        }
 518        else {
 519                ret = sprintf(buf, "%s: %.*s%.*s\n", what,
 520                              (fmt == CMIT_FMT_FULLER) ? 4 : 0,
 521                              filler, namelen, line);
 522        }
 523        switch (fmt) {
 524        case CMIT_FMT_MEDIUM:
 525                ret += sprintf(buf + ret, "Date:   %s\n", show_date(time, tz));
 526                break;
 527        case CMIT_FMT_EMAIL:
 528                ret += sprintf(buf + ret, "Date: %s\n",
 529                               show_rfc2822_date(time, tz));
 530                break;
 531        case CMIT_FMT_FULLER:
 532                ret += sprintf(buf + ret, "%sDate: %s\n", what, show_date(time, tz));
 533                break;
 534        default:
 535                /* notin' */
 536                break;
 537        }
 538        return ret;
 539}
 540
 541static int is_empty_line(const char *line, int *len_p)
 542{
 543        int len = *len_p;
 544        while (len && isspace(line[len-1]))
 545                len--;
 546        *len_p = len;
 547        return !len;
 548}
 549
 550static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *commit, int abbrev)
 551{
 552        struct commit_list *parent = commit->parents;
 553        int offset;
 554
 555        if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) ||
 556            !parent || !parent->next)
 557                return 0;
 558
 559        offset = sprintf(buf, "Merge:");
 560
 561        while (parent) {
 562                struct commit *p = parent->item;
 563                const char *hex = abbrev
 564                        ? find_unique_abbrev(p->object.sha1, abbrev)
 565                        : sha1_to_hex(p->object.sha1);
 566                const char *dots = (abbrev && strlen(hex) != 40) ? "..." : "";
 567                parent = parent->next;
 568
 569                offset += sprintf(buf + offset, " %s%s", hex, dots);
 570        }
 571        buf[offset++] = '\n';
 572        return offset;
 573}
 574
 575unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject)
 576{
 577        int hdr = 1, body = 0;
 578        unsigned long offset = 0;
 579        int indent = 4;
 580        int parents_shown = 0;
 581        const char *msg = commit->buffer;
 582        int plain_non_ascii = 0;
 583
 584        if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
 585                indent = 0;
 586
 587        /* After-subject is used to pass in Content-Type: multipart
 588         * MIME header; in that case we do not have to do the
 589         * plaintext content type even if the commit message has
 590         * non 7-bit ASCII character.  Otherwise, check if we need
 591         * to say this is not a 7-bit ASCII.
 592         */
 593        if (fmt == CMIT_FMT_EMAIL && !after_subject) {
 594                int i, ch, in_body;
 595
 596                for (in_body = i = 0; (ch = msg[i]) && i < len; i++) {
 597                        if (!in_body) {
 598                                /* author could be non 7-bit ASCII but
 599                                 * the log may so; skip over the
 600                                 * header part first.
 601                                 */
 602                                if (ch == '\n' &&
 603                                    i + 1 < len && msg[i+1] == '\n')
 604                                        in_body = 1;
 605                        }
 606                        else if (ch & 0x80) {
 607                                plain_non_ascii = 1;
 608                                break;
 609                        }
 610                }
 611        }
 612
 613        for (;;) {
 614                const char *line = msg;
 615                int linelen = get_one_line(msg, len);
 616
 617                if (!linelen)
 618                        break;
 619
 620                /*
 621                 * We want some slop for indentation and a possible
 622                 * final "...". Thus the "+ 20".
 623                 */
 624                if (offset + linelen + 20 > space) {
 625                        memcpy(buf + offset, "    ...\n", 8);
 626                        offset += 8;
 627                        break;
 628                }
 629
 630                msg += linelen;
 631                len -= linelen;
 632                if (hdr) {
 633                        if (linelen == 1) {
 634                                hdr = 0;
 635                                if ((fmt != CMIT_FMT_ONELINE) && !subject)
 636                                        buf[offset++] = '\n';
 637                                continue;
 638                        }
 639                        if (fmt == CMIT_FMT_RAW) {
 640                                memcpy(buf + offset, line, linelen);
 641                                offset += linelen;
 642                                continue;
 643                        }
 644                        if (!memcmp(line, "parent ", 7)) {
 645                                if (linelen != 48)
 646                                        die("bad parent line in commit");
 647                                continue;
 648                        }
 649
 650                        if (!parents_shown) {
 651                                offset += add_merge_info(fmt, buf + offset,
 652                                                         commit, abbrev);
 653                                parents_shown = 1;
 654                                continue;
 655                        }
 656                        /*
 657                         * MEDIUM == DEFAULT shows only author with dates.
 658                         * FULL shows both authors but not dates.
 659                         * FULLER shows both authors and dates.
 660                         */
 661                        if (!memcmp(line, "author ", 7))
 662                                offset += add_user_info("Author", fmt,
 663                                                        buf + offset,
 664                                                        line + 7);
 665                        if (!memcmp(line, "committer ", 10) &&
 666                            (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER))
 667                                offset += add_user_info("Commit", fmt,
 668                                                        buf + offset,
 669                                                        line + 10);
 670                        continue;
 671                }
 672
 673                if (!subject)
 674                        body = 1;
 675
 676                if (is_empty_line(line, &linelen)) {
 677                        if (!body)
 678                                continue;
 679                        if (subject)
 680                                continue;
 681                        if (fmt == CMIT_FMT_SHORT)
 682                                break;
 683                }
 684
 685                if (subject) {
 686                        int slen = strlen(subject);
 687                        memcpy(buf + offset, subject, slen);
 688                        offset += slen;
 689                        offset += add_rfc2047(buf + offset, line, linelen);
 690                }
 691                else {
 692                        memset(buf + offset, ' ', indent);
 693                        memcpy(buf + offset + indent, line, linelen);
 694                        offset += linelen + indent;
 695                }
 696                buf[offset++] = '\n';
 697                if (fmt == CMIT_FMT_ONELINE)
 698                        break;
 699                if (subject && plain_non_ascii) {
 700                        static const char header[] =
 701                                "Content-Type: text/plain; charset=UTF-8\n"
 702                                "Content-Transfer-Encoding: 8bit\n";
 703                        memcpy(buf + offset, header, sizeof(header)-1);
 704                        offset += sizeof(header)-1;
 705                }
 706                if (after_subject) {
 707                        int slen = strlen(after_subject);
 708                        if (slen > space - offset - 1)
 709                                slen = space - offset - 1;
 710                        memcpy(buf + offset, after_subject, slen);
 711                        offset += slen;
 712                        after_subject = NULL;
 713                }
 714                subject = NULL;
 715        }
 716        while (offset && isspace(buf[offset-1]))
 717                offset--;
 718        /* Make sure there is an EOLN for the non-oneline case */
 719        if (fmt != CMIT_FMT_ONELINE)
 720                buf[offset++] = '\n';
 721        /*
 722         * make sure there is another EOLN to separate the headers from whatever
 723         * body the caller appends if we haven't already written a body
 724         */
 725        if (fmt == CMIT_FMT_EMAIL && !body)
 726                buf[offset++] = '\n';
 727        buf[offset] = '\0';
 728        return offset;
 729}
 730
 731struct commit *pop_commit(struct commit_list **stack)
 732{
 733        struct commit_list *top = *stack;
 734        struct commit *item = top ? top->item : NULL;
 735
 736        if (top) {
 737                *stack = top->next;
 738                free(top);
 739        }
 740        return item;
 741}
 742
 743int count_parents(struct commit * commit)
 744{
 745        int count = 0;
 746        struct commit_list * parents = commit->parents;
 747        for (count=0;parents; parents=parents->next,count++)
 748          ;
 749        return count;
 750}
 751
 752void topo_sort_default_setter(struct commit *c, void *data)
 753{
 754        c->util = data;
 755}
 756
 757void *topo_sort_default_getter(struct commit *c)
 758{
 759        return c->util;
 760}
 761
 762/*
 763 * Performs an in-place topological sort on the list supplied.
 764 */
 765void sort_in_topological_order(struct commit_list ** list, int lifo)
 766{
 767        sort_in_topological_order_fn(list, lifo, topo_sort_default_setter,
 768                                     topo_sort_default_getter);
 769}
 770
 771void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
 772                                  topo_sort_set_fn_t setter,
 773                                  topo_sort_get_fn_t getter)
 774{
 775        struct commit_list * next = *list;
 776        struct commit_list * work = NULL, **insert;
 777        struct commit_list ** pptr = list;
 778        struct sort_node * nodes;
 779        struct sort_node * next_nodes;
 780        int count = 0;
 781
 782        /* determine the size of the list */
 783        while (next) {
 784                next = next->next;
 785                count++;
 786        }
 787        
 788        if (!count)
 789                return;
 790        /* allocate an array to help sort the list */
 791        nodes = xcalloc(count, sizeof(*nodes));
 792        /* link the list to the array */
 793        next_nodes = nodes;
 794        next=*list;
 795        while (next) {
 796                next_nodes->list_item = next;
 797                setter(next->item, next_nodes);
 798                next_nodes++;
 799                next = next->next;
 800        }
 801        /* update the indegree */
 802        next=*list;
 803        while (next) {
 804                struct commit_list * parents = next->item->parents;
 805                while (parents) {
 806                        struct commit * parent=parents->item;
 807                        struct sort_node * pn = (struct sort_node *) getter(parent);
 808
 809                        if (pn)
 810                                pn->indegree++;
 811                        parents=parents->next;
 812                }
 813                next=next->next;
 814        }
 815        /* 
 816         * find the tips
 817         *
 818         * tips are nodes not reachable from any other node in the list 
 819         * 
 820         * the tips serve as a starting set for the work queue.
 821         */
 822        next=*list;
 823        insert = &work;
 824        while (next) {
 825                struct sort_node * node = (struct sort_node *) getter(next->item);
 826
 827                if (node->indegree == 0) {
 828                        insert = &commit_list_insert(next->item, insert)->next;
 829                }
 830                next=next->next;
 831        }
 832
 833        /* process the list in topological order */
 834        if (!lifo)
 835                sort_by_date(&work);
 836        while (work) {
 837                struct commit * work_item = pop_commit(&work);
 838                struct sort_node * work_node = (struct sort_node *) getter(work_item);
 839                struct commit_list * parents = work_item->parents;
 840
 841                while (parents) {
 842                        struct commit * parent=parents->item;
 843                        struct sort_node * pn = (struct sort_node *) getter(parent);
 844
 845                        if (pn) {
 846                                /*
 847                                 * parents are only enqueued for emission 
 848                                 * when all their children have been emitted thereby
 849                                 * guaranteeing topological order.
 850                                 */
 851                                pn->indegree--;
 852                                if (!pn->indegree) {
 853                                        if (!lifo)
 854                                                insert_by_date(parent, &work);
 855                                        else
 856                                                commit_list_insert(parent, &work);
 857                                }
 858                        }
 859                        parents=parents->next;
 860                }
 861                /*
 862                 * work_item is a commit all of whose children
 863                 * have already been emitted. we can emit it now.
 864                 */
 865                *pptr = work_node->list_item;
 866                pptr = &(*pptr)->next;
 867                *pptr = NULL;
 868                setter(work_item, NULL);
 869        }
 870        free(nodes);
 871}
 872
 873/* merge-rebase stuff */
 874
 875/* bits #0..7 in revision.h */
 876#define PARENT1         (1u<< 8)
 877#define PARENT2         (1u<< 9)
 878#define STALE           (1u<<10)
 879#define RESULT          (1u<<11)
 880
 881static struct commit *interesting(struct commit_list *list)
 882{
 883        while (list) {
 884                struct commit *commit = list->item;
 885                list = list->next;
 886                if (commit->object.flags & STALE)
 887                        continue;
 888                return commit;
 889        }
 890        return NULL;
 891}
 892
 893static struct commit_list *merge_bases(struct commit *one, struct commit *two)
 894{
 895        struct commit_list *list = NULL;
 896        struct commit_list *result = NULL;
 897
 898        if (one == two)
 899                /* We do not mark this even with RESULT so we do not
 900                 * have to clean it up.
 901                 */
 902                return commit_list_insert(one, &result);
 903
 904        parse_commit(one);
 905        parse_commit(two);
 906
 907        one->object.flags |= PARENT1;
 908        two->object.flags |= PARENT2;
 909        insert_by_date(one, &list);
 910        insert_by_date(two, &list);
 911
 912        while (interesting(list)) {
 913                struct commit *commit;
 914                struct commit_list *parents;
 915                struct commit_list *n;
 916                int flags;
 917
 918                commit = list->item;
 919                n = list->next;
 920                free(list);
 921                list = n;
 922
 923                flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
 924                if (flags == (PARENT1 | PARENT2)) {
 925                        if (!(commit->object.flags & RESULT)) {
 926                                commit->object.flags |= RESULT;
 927                                insert_by_date(commit, &result);
 928                        }
 929                        /* Mark parents of a found merge stale */
 930                        flags |= STALE;
 931                }
 932                parents = commit->parents;
 933                while (parents) {
 934                        struct commit *p = parents->item;
 935                        parents = parents->next;
 936                        if ((p->object.flags & flags) == flags)
 937                                continue;
 938                        parse_commit(p);
 939                        p->object.flags |= flags;
 940                        insert_by_date(p, &list);
 941                }
 942        }
 943
 944        /* Clean up the result to remove stale ones */
 945        list = result; result = NULL;
 946        while (list) {
 947                struct commit_list *n = list->next;
 948                if (!(list->item->object.flags & STALE))
 949                        insert_by_date(list->item, &result);
 950                free(list);
 951                list = n;
 952        }
 953        return result;
 954}
 955
 956struct commit_list *get_merge_bases(struct commit *one,
 957                                    struct commit *two,
 958                                    int cleanup)
 959{
 960        const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
 961        struct commit_list *list;
 962        struct commit **rslt;
 963        struct commit_list *result;
 964        int cnt, i, j;
 965
 966        result = merge_bases(one, two);
 967        if (one == two)
 968                return result;
 969        if (!result || !result->next) {
 970                if (cleanup) {
 971                        clear_commit_marks(one, all_flags);
 972                        clear_commit_marks(two, all_flags);
 973                }
 974                return result;
 975        }
 976
 977        /* There are more than one */
 978        cnt = 0;
 979        list = result;
 980        while (list) {
 981                list = list->next;
 982                cnt++;
 983        }
 984        rslt = xcalloc(cnt, sizeof(*rslt));
 985        for (list = result, i = 0; list; list = list->next)
 986                rslt[i++] = list->item;
 987        free_commit_list(result);
 988
 989        clear_commit_marks(one, all_flags);
 990        clear_commit_marks(two, all_flags);
 991        for (i = 0; i < cnt - 1; i++) {
 992                for (j = i+1; j < cnt; j++) {
 993                        if (!rslt[i] || !rslt[j])
 994                                continue;
 995                        result = merge_bases(rslt[i], rslt[j]);
 996                        clear_commit_marks(rslt[i], all_flags);
 997                        clear_commit_marks(rslt[j], all_flags);
 998                        for (list = result; list; list = list->next) {
 999                                if (rslt[i] == list->item)
1000                                        rslt[i] = NULL;
1001                                if (rslt[j] == list->item)
1002                                        rslt[j] = NULL;
1003                        }
1004                }
1005        }
1006
1007        /* Surviving ones in rslt[] are the independent results */
1008        result = NULL;
1009        for (i = 0; i < cnt; i++) {
1010                if (rslt[i])
1011                        insert_by_date(rslt[i], &result);
1012        }
1013        free(rslt);
1014        return result;
1015}