ref-filter.con commit for-each-ref: add '--merged' and '--no-merged' options (7c32834)
   1#include "builtin.h"
   2#include "cache.h"
   3#include "parse-options.h"
   4#include "refs.h"
   5#include "wildmatch.h"
   6#include "commit.h"
   7#include "remote.h"
   8#include "color.h"
   9#include "tag.h"
  10#include "quote.h"
  11#include "ref-filter.h"
  12#include "revision.h"
  13
  14typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
  15
  16static struct {
  17        const char *name;
  18        cmp_type cmp_type;
  19} valid_atom[] = {
  20        { "refname" },
  21        { "objecttype" },
  22        { "objectsize", FIELD_ULONG },
  23        { "objectname" },
  24        { "tree" },
  25        { "parent" },
  26        { "numparent", FIELD_ULONG },
  27        { "object" },
  28        { "type" },
  29        { "tag" },
  30        { "author" },
  31        { "authorname" },
  32        { "authoremail" },
  33        { "authordate", FIELD_TIME },
  34        { "committer" },
  35        { "committername" },
  36        { "committeremail" },
  37        { "committerdate", FIELD_TIME },
  38        { "tagger" },
  39        { "taggername" },
  40        { "taggeremail" },
  41        { "taggerdate", FIELD_TIME },
  42        { "creator" },
  43        { "creatordate", FIELD_TIME },
  44        { "subject" },
  45        { "body" },
  46        { "contents" },
  47        { "contents:subject" },
  48        { "contents:body" },
  49        { "contents:signature" },
  50        { "upstream" },
  51        { "push" },
  52        { "symref" },
  53        { "flag" },
  54        { "HEAD" },
  55        { "color" },
  56};
  57
  58/*
  59 * An atom is a valid field atom listed above, possibly prefixed with
  60 * a "*" to denote deref_tag().
  61 *
  62 * We parse given format string and sort specifiers, and make a list
  63 * of properties that we need to extract out of objects.  ref_array_item
  64 * structure will hold an array of values extracted that can be
  65 * indexed with the "atom number", which is an index into this
  66 * array.
  67 */
  68static const char **used_atom;
  69static cmp_type *used_atom_type;
  70static int used_atom_cnt, need_tagged, need_symref;
  71static int need_color_reset_at_eol;
  72
  73/*
  74 * Used to parse format string and sort specifiers
  75 */
  76int parse_ref_filter_atom(const char *atom, const char *ep)
  77{
  78        const char *sp;
  79        int i, at;
  80
  81        sp = atom;
  82        if (*sp == '*' && sp < ep)
  83                sp++; /* deref */
  84        if (ep <= sp)
  85                die("malformed field name: %.*s", (int)(ep-atom), atom);
  86
  87        /* Do we have the atom already used elsewhere? */
  88        for (i = 0; i < used_atom_cnt; i++) {
  89                int len = strlen(used_atom[i]);
  90                if (len == ep - atom && !memcmp(used_atom[i], atom, len))
  91                        return i;
  92        }
  93
  94        /* Is the atom a valid one? */
  95        for (i = 0; i < ARRAY_SIZE(valid_atom); i++) {
  96                int len = strlen(valid_atom[i].name);
  97                /*
  98                 * If the atom name has a colon, strip it and everything after
  99                 * it off - it specifies the format for this entry, and
 100                 * shouldn't be used for checking against the valid_atom
 101                 * table.
 102                 */
 103                const char *formatp = strchr(sp, ':');
 104                if (!formatp || ep < formatp)
 105                        formatp = ep;
 106                if (len == formatp - sp && !memcmp(valid_atom[i].name, sp, len))
 107                        break;
 108        }
 109
 110        if (ARRAY_SIZE(valid_atom) <= i)
 111                die("unknown field name: %.*s", (int)(ep-atom), atom);
 112
 113        /* Add it in, including the deref prefix */
 114        at = used_atom_cnt;
 115        used_atom_cnt++;
 116        REALLOC_ARRAY(used_atom, used_atom_cnt);
 117        REALLOC_ARRAY(used_atom_type, used_atom_cnt);
 118        used_atom[at] = xmemdupz(atom, ep - atom);
 119        used_atom_type[at] = valid_atom[i].cmp_type;
 120        if (*atom == '*')
 121                need_tagged = 1;
 122        if (!strcmp(used_atom[at], "symref"))
 123                need_symref = 1;
 124        return at;
 125}
 126
 127/*
 128 * In a format string, find the next occurrence of %(atom).
 129 */
 130static const char *find_next(const char *cp)
 131{
 132        while (*cp) {
 133                if (*cp == '%') {
 134                        /*
 135                         * %( is the start of an atom;
 136                         * %% is a quoted per-cent.
 137                         */
 138                        if (cp[1] == '(')
 139                                return cp;
 140                        else if (cp[1] == '%')
 141                                cp++; /* skip over two % */
 142                        /* otherwise this is a singleton, literal % */
 143                }
 144                cp++;
 145        }
 146        return NULL;
 147}
 148
 149/*
 150 * Make sure the format string is well formed, and parse out
 151 * the used atoms.
 152 */
 153int verify_ref_format(const char *format)
 154{
 155        const char *cp, *sp;
 156
 157        need_color_reset_at_eol = 0;
 158        for (cp = format; *cp && (sp = find_next(cp)); ) {
 159                const char *color, *ep = strchr(sp, ')');
 160                int at;
 161
 162                if (!ep)
 163                        return error("malformed format string %s", sp);
 164                /* sp points at "%(" and ep points at the closing ")" */
 165                at = parse_ref_filter_atom(sp + 2, ep);
 166                cp = ep + 1;
 167
 168                if (skip_prefix(used_atom[at], "color:", &color))
 169                        need_color_reset_at_eol = !!strcmp(color, "reset");
 170        }
 171        return 0;
 172}
 173
 174/*
 175 * Given an object name, read the object data and size, and return a
 176 * "struct object".  If the object data we are returning is also borrowed
 177 * by the "struct object" representation, set *eaten as well---it is a
 178 * signal from parse_object_buffer to us not to free the buffer.
 179 */
 180static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned long *sz, int *eaten)
 181{
 182        enum object_type type;
 183        void *buf = read_sha1_file(sha1, &type, sz);
 184
 185        if (buf)
 186                *obj = parse_object_buffer(sha1, type, *sz, buf, eaten);
 187        else
 188                *obj = NULL;
 189        return buf;
 190}
 191
 192static int grab_objectname(const char *name, const unsigned char *sha1,
 193                            struct atom_value *v)
 194{
 195        if (!strcmp(name, "objectname")) {
 196                char *s = xmalloc(41);
 197                strcpy(s, sha1_to_hex(sha1));
 198                v->s = s;
 199                return 1;
 200        }
 201        if (!strcmp(name, "objectname:short")) {
 202                v->s = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV));
 203                return 1;
 204        }
 205        return 0;
 206}
 207
 208/* See grab_values */
 209static void grab_common_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
 210{
 211        int i;
 212
 213        for (i = 0; i < used_atom_cnt; i++) {
 214                const char *name = used_atom[i];
 215                struct atom_value *v = &val[i];
 216                if (!!deref != (*name == '*'))
 217                        continue;
 218                if (deref)
 219                        name++;
 220                if (!strcmp(name, "objecttype"))
 221                        v->s = typename(obj->type);
 222                else if (!strcmp(name, "objectsize")) {
 223                        char *s = xmalloc(40);
 224                        sprintf(s, "%lu", sz);
 225                        v->ul = sz;
 226                        v->s = s;
 227                }
 228                else if (deref)
 229                        grab_objectname(name, obj->sha1, v);
 230        }
 231}
 232
 233/* See grab_values */
 234static void grab_tag_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
 235{
 236        int i;
 237        struct tag *tag = (struct tag *) obj;
 238
 239        for (i = 0; i < used_atom_cnt; i++) {
 240                const char *name = used_atom[i];
 241                struct atom_value *v = &val[i];
 242                if (!!deref != (*name == '*'))
 243                        continue;
 244                if (deref)
 245                        name++;
 246                if (!strcmp(name, "tag"))
 247                        v->s = tag->tag;
 248                else if (!strcmp(name, "type") && tag->tagged)
 249                        v->s = typename(tag->tagged->type);
 250                else if (!strcmp(name, "object") && tag->tagged) {
 251                        char *s = xmalloc(41);
 252                        strcpy(s, sha1_to_hex(tag->tagged->sha1));
 253                        v->s = s;
 254                }
 255        }
 256}
 257
 258/* See grab_values */
 259static void grab_commit_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
 260{
 261        int i;
 262        struct commit *commit = (struct commit *) obj;
 263
 264        for (i = 0; i < used_atom_cnt; i++) {
 265                const char *name = used_atom[i];
 266                struct atom_value *v = &val[i];
 267                if (!!deref != (*name == '*'))
 268                        continue;
 269                if (deref)
 270                        name++;
 271                if (!strcmp(name, "tree")) {
 272                        char *s = xmalloc(41);
 273                        strcpy(s, sha1_to_hex(commit->tree->object.sha1));
 274                        v->s = s;
 275                }
 276                if (!strcmp(name, "numparent")) {
 277                        char *s = xmalloc(40);
 278                        v->ul = commit_list_count(commit->parents);
 279                        sprintf(s, "%lu", v->ul);
 280                        v->s = s;
 281                }
 282                else if (!strcmp(name, "parent")) {
 283                        int num = commit_list_count(commit->parents);
 284                        int i;
 285                        struct commit_list *parents;
 286                        char *s = xmalloc(41 * num + 1);
 287                        v->s = s;
 288                        for (i = 0, parents = commit->parents;
 289                             parents;
 290                             parents = parents->next, i = i + 41) {
 291                                struct commit *parent = parents->item;
 292                                strcpy(s+i, sha1_to_hex(parent->object.sha1));
 293                                if (parents->next)
 294                                        s[i+40] = ' ';
 295                        }
 296                        if (!i)
 297                                *s = '\0';
 298                }
 299        }
 300}
 301
 302static const char *find_wholine(const char *who, int wholen, const char *buf, unsigned long sz)
 303{
 304        const char *eol;
 305        while (*buf) {
 306                if (!strncmp(buf, who, wholen) &&
 307                    buf[wholen] == ' ')
 308                        return buf + wholen + 1;
 309                eol = strchr(buf, '\n');
 310                if (!eol)
 311                        return "";
 312                eol++;
 313                if (*eol == '\n')
 314                        return ""; /* end of header */
 315                buf = eol;
 316        }
 317        return "";
 318}
 319
 320static const char *copy_line(const char *buf)
 321{
 322        const char *eol = strchrnul(buf, '\n');
 323        return xmemdupz(buf, eol - buf);
 324}
 325
 326static const char *copy_name(const char *buf)
 327{
 328        const char *cp;
 329        for (cp = buf; *cp && *cp != '\n'; cp++) {
 330                if (!strncmp(cp, " <", 2))
 331                        return xmemdupz(buf, cp - buf);
 332        }
 333        return "";
 334}
 335
 336static const char *copy_email(const char *buf)
 337{
 338        const char *email = strchr(buf, '<');
 339        const char *eoemail;
 340        if (!email)
 341                return "";
 342        eoemail = strchr(email, '>');
 343        if (!eoemail)
 344                return "";
 345        return xmemdupz(email, eoemail + 1 - email);
 346}
 347
 348static char *copy_subject(const char *buf, unsigned long len)
 349{
 350        char *r = xmemdupz(buf, len);
 351        int i;
 352
 353        for (i = 0; i < len; i++)
 354                if (r[i] == '\n')
 355                        r[i] = ' ';
 356
 357        return r;
 358}
 359
 360static void grab_date(const char *buf, struct atom_value *v, const char *atomname)
 361{
 362        const char *eoemail = strstr(buf, "> ");
 363        char *zone;
 364        unsigned long timestamp;
 365        long tz;
 366        enum date_mode date_mode = DATE_NORMAL;
 367        const char *formatp;
 368
 369        /*
 370         * We got here because atomname ends in "date" or "date<something>";
 371         * it's not possible that <something> is not ":<format>" because
 372         * parse_ref_filter_atom() wouldn't have allowed it, so we can assume that no
 373         * ":" means no format is specified, and use the default.
 374         */
 375        formatp = strchr(atomname, ':');
 376        if (formatp != NULL) {
 377                formatp++;
 378                date_mode = parse_date_format(formatp);
 379        }
 380
 381        if (!eoemail)
 382                goto bad;
 383        timestamp = strtoul(eoemail + 2, &zone, 10);
 384        if (timestamp == ULONG_MAX)
 385                goto bad;
 386        tz = strtol(zone, NULL, 10);
 387        if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)
 388                goto bad;
 389        v->s = xstrdup(show_date(timestamp, tz, date_mode));
 390        v->ul = timestamp;
 391        return;
 392 bad:
 393        v->s = "";
 394        v->ul = 0;
 395}
 396
 397/* See grab_values */
 398static void grab_person(const char *who, struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
 399{
 400        int i;
 401        int wholen = strlen(who);
 402        const char *wholine = NULL;
 403
 404        for (i = 0; i < used_atom_cnt; i++) {
 405                const char *name = used_atom[i];
 406                struct atom_value *v = &val[i];
 407                if (!!deref != (*name == '*'))
 408                        continue;
 409                if (deref)
 410                        name++;
 411                if (strncmp(who, name, wholen))
 412                        continue;
 413                if (name[wholen] != 0 &&
 414                    strcmp(name + wholen, "name") &&
 415                    strcmp(name + wholen, "email") &&
 416                    !starts_with(name + wholen, "date"))
 417                        continue;
 418                if (!wholine)
 419                        wholine = find_wholine(who, wholen, buf, sz);
 420                if (!wholine)
 421                        return; /* no point looking for it */
 422                if (name[wholen] == 0)
 423                        v->s = copy_line(wholine);
 424                else if (!strcmp(name + wholen, "name"))
 425                        v->s = copy_name(wholine);
 426                else if (!strcmp(name + wholen, "email"))
 427                        v->s = copy_email(wholine);
 428                else if (starts_with(name + wholen, "date"))
 429                        grab_date(wholine, v, name);
 430        }
 431
 432        /*
 433         * For a tag or a commit object, if "creator" or "creatordate" is
 434         * requested, do something special.
 435         */
 436        if (strcmp(who, "tagger") && strcmp(who, "committer"))
 437                return; /* "author" for commit object is not wanted */
 438        if (!wholine)
 439                wholine = find_wholine(who, wholen, buf, sz);
 440        if (!wholine)
 441                return;
 442        for (i = 0; i < used_atom_cnt; i++) {
 443                const char *name = used_atom[i];
 444                struct atom_value *v = &val[i];
 445                if (!!deref != (*name == '*'))
 446                        continue;
 447                if (deref)
 448                        name++;
 449
 450                if (starts_with(name, "creatordate"))
 451                        grab_date(wholine, v, name);
 452                else if (!strcmp(name, "creator"))
 453                        v->s = copy_line(wholine);
 454        }
 455}
 456
 457static void find_subpos(const char *buf, unsigned long sz,
 458                        const char **sub, unsigned long *sublen,
 459                        const char **body, unsigned long *bodylen,
 460                        unsigned long *nonsiglen,
 461                        const char **sig, unsigned long *siglen)
 462{
 463        const char *eol;
 464        /* skip past header until we hit empty line */
 465        while (*buf && *buf != '\n') {
 466                eol = strchrnul(buf, '\n');
 467                if (*eol)
 468                        eol++;
 469                buf = eol;
 470        }
 471        /* skip any empty lines */
 472        while (*buf == '\n')
 473                buf++;
 474
 475        /* parse signature first; we might not even have a subject line */
 476        *sig = buf + parse_signature(buf, strlen(buf));
 477        *siglen = strlen(*sig);
 478
 479        /* subject is first non-empty line */
 480        *sub = buf;
 481        /* subject goes to first empty line */
 482        while (buf < *sig && *buf && *buf != '\n') {
 483                eol = strchrnul(buf, '\n');
 484                if (*eol)
 485                        eol++;
 486                buf = eol;
 487        }
 488        *sublen = buf - *sub;
 489        /* drop trailing newline, if present */
 490        if (*sublen && (*sub)[*sublen - 1] == '\n')
 491                *sublen -= 1;
 492
 493        /* skip any empty lines */
 494        while (*buf == '\n')
 495                buf++;
 496        *body = buf;
 497        *bodylen = strlen(buf);
 498        *nonsiglen = *sig - buf;
 499}
 500
 501/* See grab_values */
 502static void grab_sub_body_contents(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
 503{
 504        int i;
 505        const char *subpos = NULL, *bodypos = NULL, *sigpos = NULL;
 506        unsigned long sublen = 0, bodylen = 0, nonsiglen = 0, siglen = 0;
 507
 508        for (i = 0; i < used_atom_cnt; i++) {
 509                const char *name = used_atom[i];
 510                struct atom_value *v = &val[i];
 511                if (!!deref != (*name == '*'))
 512                        continue;
 513                if (deref)
 514                        name++;
 515                if (strcmp(name, "subject") &&
 516                    strcmp(name, "body") &&
 517                    strcmp(name, "contents") &&
 518                    strcmp(name, "contents:subject") &&
 519                    strcmp(name, "contents:body") &&
 520                    strcmp(name, "contents:signature"))
 521                        continue;
 522                if (!subpos)
 523                        find_subpos(buf, sz,
 524                                    &subpos, &sublen,
 525                                    &bodypos, &bodylen, &nonsiglen,
 526                                    &sigpos, &siglen);
 527
 528                if (!strcmp(name, "subject"))
 529                        v->s = copy_subject(subpos, sublen);
 530                else if (!strcmp(name, "contents:subject"))
 531                        v->s = copy_subject(subpos, sublen);
 532                else if (!strcmp(name, "body"))
 533                        v->s = xmemdupz(bodypos, bodylen);
 534                else if (!strcmp(name, "contents:body"))
 535                        v->s = xmemdupz(bodypos, nonsiglen);
 536                else if (!strcmp(name, "contents:signature"))
 537                        v->s = xmemdupz(sigpos, siglen);
 538                else if (!strcmp(name, "contents"))
 539                        v->s = xstrdup(subpos);
 540        }
 541}
 542
 543/*
 544 * We want to have empty print-string for field requests
 545 * that do not apply (e.g. "authordate" for a tag object)
 546 */
 547static void fill_missing_values(struct atom_value *val)
 548{
 549        int i;
 550        for (i = 0; i < used_atom_cnt; i++) {
 551                struct atom_value *v = &val[i];
 552                if (v->s == NULL)
 553                        v->s = "";
 554        }
 555}
 556
 557/*
 558 * val is a list of atom_value to hold returned values.  Extract
 559 * the values for atoms in used_atom array out of (obj, buf, sz).
 560 * when deref is false, (obj, buf, sz) is the object that is
 561 * pointed at by the ref itself; otherwise it is the object the
 562 * ref (which is a tag) refers to.
 563 */
 564static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
 565{
 566        grab_common_values(val, deref, obj, buf, sz);
 567        switch (obj->type) {
 568        case OBJ_TAG:
 569                grab_tag_values(val, deref, obj, buf, sz);
 570                grab_sub_body_contents(val, deref, obj, buf, sz);
 571                grab_person("tagger", val, deref, obj, buf, sz);
 572                break;
 573        case OBJ_COMMIT:
 574                grab_commit_values(val, deref, obj, buf, sz);
 575                grab_sub_body_contents(val, deref, obj, buf, sz);
 576                grab_person("author", val, deref, obj, buf, sz);
 577                grab_person("committer", val, deref, obj, buf, sz);
 578                break;
 579        case OBJ_TREE:
 580                /* grab_tree_values(val, deref, obj, buf, sz); */
 581                break;
 582        case OBJ_BLOB:
 583                /* grab_blob_values(val, deref, obj, buf, sz); */
 584                break;
 585        default:
 586                die("Eh?  Object of type %d?", obj->type);
 587        }
 588}
 589
 590static inline char *copy_advance(char *dst, const char *src)
 591{
 592        while (*src)
 593                *dst++ = *src++;
 594        return dst;
 595}
 596
 597/*
 598 * Parse the object referred by ref, and grab needed value.
 599 */
 600static void populate_value(struct ref_array_item *ref)
 601{
 602        void *buf;
 603        struct object *obj;
 604        int eaten, i;
 605        unsigned long size;
 606        const unsigned char *tagged;
 607
 608        ref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value));
 609
 610        if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {
 611                unsigned char unused1[20];
 612                ref->symref = resolve_refdup(ref->refname, RESOLVE_REF_READING,
 613                                             unused1, NULL);
 614                if (!ref->symref)
 615                        ref->symref = "";
 616        }
 617
 618        /* Fill in specials first */
 619        for (i = 0; i < used_atom_cnt; i++) {
 620                const char *name = used_atom[i];
 621                struct atom_value *v = &ref->value[i];
 622                int deref = 0;
 623                const char *refname;
 624                const char *formatp;
 625                struct branch *branch = NULL;
 626
 627                if (*name == '*') {
 628                        deref = 1;
 629                        name++;
 630                }
 631
 632                if (starts_with(name, "refname"))
 633                        refname = ref->refname;
 634                else if (starts_with(name, "symref"))
 635                        refname = ref->symref ? ref->symref : "";
 636                else if (starts_with(name, "upstream")) {
 637                        const char *branch_name;
 638                        /* only local branches may have an upstream */
 639                        if (!skip_prefix(ref->refname, "refs/heads/",
 640                                         &branch_name))
 641                                continue;
 642                        branch = branch_get(branch_name);
 643
 644                        refname = branch_get_upstream(branch, NULL);
 645                        if (!refname)
 646                                continue;
 647                } else if (starts_with(name, "push")) {
 648                        const char *branch_name;
 649                        if (!skip_prefix(ref->refname, "refs/heads/",
 650                                         &branch_name))
 651                                continue;
 652                        branch = branch_get(branch_name);
 653
 654                        refname = branch_get_push(branch, NULL);
 655                        if (!refname)
 656                                continue;
 657                } else if (starts_with(name, "color:")) {
 658                        char color[COLOR_MAXLEN] = "";
 659
 660                        if (color_parse(name + 6, color) < 0)
 661                                die(_("unable to parse format"));
 662                        v->s = xstrdup(color);
 663                        continue;
 664                } else if (!strcmp(name, "flag")) {
 665                        char buf[256], *cp = buf;
 666                        if (ref->flag & REF_ISSYMREF)
 667                                cp = copy_advance(cp, ",symref");
 668                        if (ref->flag & REF_ISPACKED)
 669                                cp = copy_advance(cp, ",packed");
 670                        if (cp == buf)
 671                                v->s = "";
 672                        else {
 673                                *cp = '\0';
 674                                v->s = xstrdup(buf + 1);
 675                        }
 676                        continue;
 677                } else if (!deref && grab_objectname(name, ref->objectname, v)) {
 678                        continue;
 679                } else if (!strcmp(name, "HEAD")) {
 680                        const char *head;
 681                        unsigned char sha1[20];
 682
 683                        head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
 684                                                  sha1, NULL);
 685                        if (!strcmp(ref->refname, head))
 686                                v->s = "*";
 687                        else
 688                                v->s = " ";
 689                        continue;
 690                } else
 691                        continue;
 692
 693                formatp = strchr(name, ':');
 694                if (formatp) {
 695                        int num_ours, num_theirs;
 696
 697                        formatp++;
 698                        if (!strcmp(formatp, "short"))
 699                                refname = shorten_unambiguous_ref(refname,
 700                                                      warn_ambiguous_refs);
 701                        else if (!strcmp(formatp, "track") &&
 702                                 (starts_with(name, "upstream") ||
 703                                  starts_with(name, "push"))) {
 704                                char buf[40];
 705
 706                                if (stat_tracking_info(branch, &num_ours,
 707                                                       &num_theirs, NULL))
 708                                        continue;
 709
 710                                if (!num_ours && !num_theirs)
 711                                        v->s = "";
 712                                else if (!num_ours) {
 713                                        sprintf(buf, "[behind %d]", num_theirs);
 714                                        v->s = xstrdup(buf);
 715                                } else if (!num_theirs) {
 716                                        sprintf(buf, "[ahead %d]", num_ours);
 717                                        v->s = xstrdup(buf);
 718                                } else {
 719                                        sprintf(buf, "[ahead %d, behind %d]",
 720                                                num_ours, num_theirs);
 721                                        v->s = xstrdup(buf);
 722                                }
 723                                continue;
 724                        } else if (!strcmp(formatp, "trackshort") &&
 725                                   (starts_with(name, "upstream") ||
 726                                    starts_with(name, "push"))) {
 727                                assert(branch);
 728
 729                                if (stat_tracking_info(branch, &num_ours,
 730                                                        &num_theirs, NULL))
 731                                        continue;
 732
 733                                if (!num_ours && !num_theirs)
 734                                        v->s = "=";
 735                                else if (!num_ours)
 736                                        v->s = "<";
 737                                else if (!num_theirs)
 738                                        v->s = ">";
 739                                else
 740                                        v->s = "<>";
 741                                continue;
 742                        } else
 743                                die("unknown %.*s format %s",
 744                                    (int)(formatp - name), name, formatp);
 745                }
 746
 747                if (!deref)
 748                        v->s = refname;
 749                else {
 750                        int len = strlen(refname);
 751                        char *s = xmalloc(len + 4);
 752                        sprintf(s, "%s^{}", refname);
 753                        v->s = s;
 754                }
 755        }
 756
 757        for (i = 0; i < used_atom_cnt; i++) {
 758                struct atom_value *v = &ref->value[i];
 759                if (v->s == NULL)
 760                        goto need_obj;
 761        }
 762        return;
 763
 764 need_obj:
 765        buf = get_obj(ref->objectname, &obj, &size, &eaten);
 766        if (!buf)
 767                die("missing object %s for %s",
 768                    sha1_to_hex(ref->objectname), ref->refname);
 769        if (!obj)
 770                die("parse_object_buffer failed on %s for %s",
 771                    sha1_to_hex(ref->objectname), ref->refname);
 772
 773        grab_values(ref->value, 0, obj, buf, size);
 774        if (!eaten)
 775                free(buf);
 776
 777        /*
 778         * If there is no atom that wants to know about tagged
 779         * object, we are done.
 780         */
 781        if (!need_tagged || (obj->type != OBJ_TAG))
 782                return;
 783
 784        /*
 785         * If it is a tag object, see if we use a value that derefs
 786         * the object, and if we do grab the object it refers to.
 787         */
 788        tagged = ((struct tag *)obj)->tagged->sha1;
 789
 790        /*
 791         * NEEDSWORK: This derefs tag only once, which
 792         * is good to deal with chains of trust, but
 793         * is not consistent with what deref_tag() does
 794         * which peels the onion to the core.
 795         */
 796        buf = get_obj(tagged, &obj, &size, &eaten);
 797        if (!buf)
 798                die("missing object %s for %s",
 799                    sha1_to_hex(tagged), ref->refname);
 800        if (!obj)
 801                die("parse_object_buffer failed on %s for %s",
 802                    sha1_to_hex(tagged), ref->refname);
 803        grab_values(ref->value, 1, obj, buf, size);
 804        if (!eaten)
 805                free(buf);
 806}
 807
 808/*
 809 * Given a ref, return the value for the atom.  This lazily gets value
 810 * out of the object by calling populate value.
 811 */
 812static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct atom_value **v)
 813{
 814        if (!ref->value) {
 815                populate_value(ref);
 816                fill_missing_values(ref->value);
 817        }
 818        *v = &ref->value[atom];
 819}
 820
 821/*
 822 * Return 1 if the refname matches one of the patterns, otherwise 0.
 823 * A pattern can be path prefix (e.g. a refname "refs/heads/master"
 824 * matches a pattern "refs/heads/") or a wildcard (e.g. the same ref
 825 * matches "refs/heads/m*",too).
 826 */
 827static int match_name_as_path(const char **pattern, const char *refname)
 828{
 829        int namelen = strlen(refname);
 830        for (; *pattern; pattern++) {
 831                const char *p = *pattern;
 832                int plen = strlen(p);
 833
 834                if ((plen <= namelen) &&
 835                    !strncmp(refname, p, plen) &&
 836                    (refname[plen] == '\0' ||
 837                     refname[plen] == '/' ||
 838                     p[plen-1] == '/'))
 839                        return 1;
 840                if (!wildmatch(p, refname, WM_PATHNAME, NULL))
 841                        return 1;
 842        }
 843        return 0;
 844}
 845
 846/*
 847 * Given a ref (sha1, refname), check if the ref belongs to the array
 848 * of sha1s. If the given ref is a tag, check if the given tag points
 849 * at one of the sha1s in the given sha1 array.
 850 * the given sha1_array.
 851 * NEEDSWORK:
 852 * 1. Only a single level of inderection is obtained, we might want to
 853 * change this to account for multiple levels (e.g. annotated tags
 854 * pointing to annotated tags pointing to a commit.)
 855 * 2. As the refs are cached we might know what refname peels to without
 856 * the need to parse the object via parse_object(). peel_ref() might be a
 857 * more efficient alternative to obtain the pointee.
 858 */
 859static const unsigned char *match_points_at(struct sha1_array *points_at,
 860                                            const unsigned char *sha1,
 861                                            const char *refname)
 862{
 863        const unsigned char *tagged_sha1 = NULL;
 864        struct object *obj;
 865
 866        if (sha1_array_lookup(points_at, sha1) >= 0)
 867                return sha1;
 868        obj = parse_object(sha1);
 869        if (!obj)
 870                die(_("malformed object at '%s'"), refname);
 871        if (obj->type == OBJ_TAG)
 872                tagged_sha1 = ((struct tag *)obj)->tagged->sha1;
 873        if (tagged_sha1 && sha1_array_lookup(points_at, tagged_sha1) >= 0)
 874                return tagged_sha1;
 875        return NULL;
 876}
 877
 878/* Allocate space for a new ref_array_item and copy the objectname and flag to it */
 879static struct ref_array_item *new_ref_array_item(const char *refname,
 880                                                 const unsigned char *objectname,
 881                                                 int flag)
 882{
 883        size_t len = strlen(refname);
 884        struct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);
 885        memcpy(ref->refname, refname, len);
 886        ref->refname[len] = '\0';
 887        hashcpy(ref->objectname, objectname);
 888        ref->flag = flag;
 889
 890        return ref;
 891}
 892
 893/*
 894 * A call-back given to for_each_ref().  Filter refs and keep them for
 895 * later object processing.
 896 */
 897static int ref_filter_handler(const char *refname, const struct object_id *oid, int flag, void *cb_data)
 898{
 899        struct ref_filter_cbdata *ref_cbdata = cb_data;
 900        struct ref_filter *filter = ref_cbdata->filter;
 901        struct ref_array_item *ref;
 902        struct commit *commit = NULL;
 903
 904        if (flag & REF_BAD_NAME) {
 905                warning("ignoring ref with broken name %s", refname);
 906                return 0;
 907        }
 908
 909        if (*filter->name_patterns && !match_name_as_path(filter->name_patterns, refname))
 910                return 0;
 911
 912        if (filter->points_at.nr && !match_points_at(&filter->points_at, oid->hash, refname))
 913                return 0;
 914
 915        /*
 916         * A merge filter is applied on refs pointing to commits. Hence
 917         * obtain the commit using the 'oid' available and discard all
 918         * non-commits early. The actual filtering is done later.
 919         */
 920        if (filter->merge_commit) {
 921                commit = lookup_commit_reference_gently(oid->hash, 1);
 922                if (!commit)
 923                        return 0;
 924        }
 925
 926        /*
 927         * We do not open the object yet; sort may only need refname
 928         * to do its job and the resulting list may yet to be pruned
 929         * by maxcount logic.
 930         */
 931        ref = new_ref_array_item(refname, oid->hash, flag);
 932        ref->commit = commit;
 933
 934        REALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);
 935        ref_cbdata->array->items[ref_cbdata->array->nr++] = ref;
 936        return 0;
 937}
 938
 939/*  Free memory allocated for a ref_array_item */
 940static void free_array_item(struct ref_array_item *item)
 941{
 942        free((char *)item->symref);
 943        free(item);
 944}
 945
 946/* Free all memory allocated for ref_array */
 947void ref_array_clear(struct ref_array *array)
 948{
 949        int i;
 950
 951        for (i = 0; i < array->nr; i++)
 952                free_array_item(array->items[i]);
 953        free(array->items);
 954        array->items = NULL;
 955        array->nr = array->alloc = 0;
 956}
 957
 958static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
 959{
 960        struct rev_info revs;
 961        int i, old_nr;
 962        struct ref_filter *filter = ref_cbdata->filter;
 963        struct ref_array *array = ref_cbdata->array;
 964        struct commit **to_clear = xcalloc(sizeof(struct commit *), array->nr);
 965
 966        init_revisions(&revs, NULL);
 967
 968        for (i = 0; i < array->nr; i++) {
 969                struct ref_array_item *item = array->items[i];
 970                add_pending_object(&revs, &item->commit->object, item->refname);
 971                to_clear[i] = item->commit;
 972        }
 973
 974        filter->merge_commit->object.flags |= UNINTERESTING;
 975        add_pending_object(&revs, &filter->merge_commit->object, "");
 976
 977        revs.limited = 1;
 978        if (prepare_revision_walk(&revs))
 979                die(_("revision walk setup failed"));
 980
 981        old_nr = array->nr;
 982        array->nr = 0;
 983
 984        for (i = 0; i < old_nr; i++) {
 985                struct ref_array_item *item = array->items[i];
 986                struct commit *commit = item->commit;
 987
 988                int is_merged = !!(commit->object.flags & UNINTERESTING);
 989
 990                if (is_merged == (filter->merge == REF_FILTER_MERGED_INCLUDE))
 991                        array->items[array->nr++] = array->items[i];
 992                else
 993                        free_array_item(item);
 994        }
 995
 996        for (i = 0; i < old_nr; i++)
 997                clear_commit_marks(to_clear[i], ALL_REV_FLAGS);
 998        clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);
 999        free(to_clear);
1000}
1001
1002/*
1003 * API for filtering a set of refs. Based on the type of refs the user
1004 * has requested, we iterate through those refs and apply filters
1005 * as per the given ref_filter structure and finally store the
1006 * filtered refs in the ref_array structure.
1007 */
1008int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type)
1009{
1010        struct ref_filter_cbdata ref_cbdata;
1011        int ret = 0;
1012
1013        ref_cbdata.array = array;
1014        ref_cbdata.filter = filter;
1015
1016        /*  Simple per-ref filtering */
1017        if (type & (FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN))
1018                ret = for_each_rawref(ref_filter_handler, &ref_cbdata);
1019        else if (type & FILTER_REFS_ALL)
1020                ret = for_each_ref(ref_filter_handler, &ref_cbdata);
1021        else if (type)
1022                die("filter_refs: invalid type");
1023
1024        /*  Filters that need revision walking */
1025        if (filter->merge_commit)
1026                do_merge_filter(&ref_cbdata);
1027
1028        return ret;
1029}
1030
1031static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, struct ref_array_item *b)
1032{
1033        struct atom_value *va, *vb;
1034        int cmp;
1035        cmp_type cmp_type = used_atom_type[s->atom];
1036
1037        get_ref_atom_value(a, s->atom, &va);
1038        get_ref_atom_value(b, s->atom, &vb);
1039        switch (cmp_type) {
1040        case FIELD_STR:
1041                cmp = strcmp(va->s, vb->s);
1042                break;
1043        default:
1044                if (va->ul < vb->ul)
1045                        cmp = -1;
1046                else if (va->ul == vb->ul)
1047                        cmp = 0;
1048                else
1049                        cmp = 1;
1050                break;
1051        }
1052        return (s->reverse) ? -cmp : cmp;
1053}
1054
1055static struct ref_sorting *ref_sorting;
1056static int compare_refs(const void *a_, const void *b_)
1057{
1058        struct ref_array_item *a = *((struct ref_array_item **)a_);
1059        struct ref_array_item *b = *((struct ref_array_item **)b_);
1060        struct ref_sorting *s;
1061
1062        for (s = ref_sorting; s; s = s->next) {
1063                int cmp = cmp_ref_sorting(s, a, b);
1064                if (cmp)
1065                        return cmp;
1066        }
1067        return 0;
1068}
1069
1070void ref_array_sort(struct ref_sorting *sorting, struct ref_array *array)
1071{
1072        ref_sorting = sorting;
1073        qsort(array->items, array->nr, sizeof(struct ref_array_item *), compare_refs);
1074}
1075
1076static void print_value(struct atom_value *v, int quote_style)
1077{
1078        struct strbuf sb = STRBUF_INIT;
1079        switch (quote_style) {
1080        case QUOTE_NONE:
1081                fputs(v->s, stdout);
1082                break;
1083        case QUOTE_SHELL:
1084                sq_quote_buf(&sb, v->s);
1085                break;
1086        case QUOTE_PERL:
1087                perl_quote_buf(&sb, v->s);
1088                break;
1089        case QUOTE_PYTHON:
1090                python_quote_buf(&sb, v->s);
1091                break;
1092        case QUOTE_TCL:
1093                tcl_quote_buf(&sb, v->s);
1094                break;
1095        }
1096        if (quote_style != QUOTE_NONE) {
1097                fputs(sb.buf, stdout);
1098                strbuf_release(&sb);
1099        }
1100}
1101
1102static int hex1(char ch)
1103{
1104        if ('0' <= ch && ch <= '9')
1105                return ch - '0';
1106        else if ('a' <= ch && ch <= 'f')
1107                return ch - 'a' + 10;
1108        else if ('A' <= ch && ch <= 'F')
1109                return ch - 'A' + 10;
1110        return -1;
1111}
1112static int hex2(const char *cp)
1113{
1114        if (cp[0] && cp[1])
1115                return (hex1(cp[0]) << 4) | hex1(cp[1]);
1116        else
1117                return -1;
1118}
1119
1120static void emit(const char *cp, const char *ep)
1121{
1122        while (*cp && (!ep || cp < ep)) {
1123                if (*cp == '%') {
1124                        if (cp[1] == '%')
1125                                cp++;
1126                        else {
1127                                int ch = hex2(cp + 1);
1128                                if (0 <= ch) {
1129                                        putchar(ch);
1130                                        cp += 3;
1131                                        continue;
1132                                }
1133                        }
1134                }
1135                putchar(*cp);
1136                cp++;
1137        }
1138}
1139
1140void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)
1141{
1142        const char *cp, *sp, *ep;
1143
1144        for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {
1145                struct atom_value *atomv;
1146
1147                ep = strchr(sp, ')');
1148                if (cp < sp)
1149                        emit(cp, sp);
1150                get_ref_atom_value(info, parse_ref_filter_atom(sp + 2, ep), &atomv);
1151                print_value(atomv, quote_style);
1152        }
1153        if (*cp) {
1154                sp = cp + strlen(cp);
1155                emit(cp, sp);
1156        }
1157        if (need_color_reset_at_eol) {
1158                struct atom_value resetv;
1159                char color[COLOR_MAXLEN] = "";
1160
1161                if (color_parse("reset", color) < 0)
1162                        die("BUG: couldn't parse 'reset' as a color");
1163                resetv.s = color;
1164                print_value(&resetv, quote_style);
1165        }
1166        putchar('\n');
1167}
1168
1169/*  If no sorting option is given, use refname to sort as default */
1170struct ref_sorting *ref_default_sorting(void)
1171{
1172        static const char cstr_name[] = "refname";
1173
1174        struct ref_sorting *sorting = xcalloc(1, sizeof(*sorting));
1175
1176        sorting->next = NULL;
1177        sorting->atom = parse_ref_filter_atom(cstr_name, cstr_name + strlen(cstr_name));
1178        return sorting;
1179}
1180
1181int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset)
1182{
1183        struct ref_sorting **sorting_tail = opt->value;
1184        struct ref_sorting *s;
1185        int len;
1186
1187        if (!arg) /* should --no-sort void the list ? */
1188                return -1;
1189
1190        s = xcalloc(1, sizeof(*s));
1191        s->next = *sorting_tail;
1192        *sorting_tail = s;
1193
1194        if (*arg == '-') {
1195                s->reverse = 1;
1196                arg++;
1197        }
1198        len = strlen(arg);
1199        s->atom = parse_ref_filter_atom(arg, arg+len);
1200        return 0;
1201}
1202
1203int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)
1204{
1205        struct ref_filter *rf = opt->value;
1206        unsigned char sha1[20];
1207
1208        rf->merge = starts_with(opt->long_name, "no")
1209                ? REF_FILTER_MERGED_OMIT
1210                : REF_FILTER_MERGED_INCLUDE;
1211
1212        if (get_sha1(arg, sha1))
1213                die(_("malformed object name %s"), arg);
1214
1215        rf->merge_commit = lookup_commit_reference_gently(sha1, 0);
1216        if (!rf->merge_commit)
1217                return opterror(opt, "must point to a commit", 0);
1218
1219        return 0;
1220}