builtin-for-each-ref.con commit Revert "prune: --grace=time" (026aa93)
   1#include "cache.h"
   2#include "refs.h"
   3#include "object.h"
   4#include "tag.h"
   5#include "commit.h"
   6#include "tree.h"
   7#include "blob.h"
   8#include "quote.h"
   9
  10/* Quoting styles */
  11#define QUOTE_NONE 0
  12#define QUOTE_SHELL 1
  13#define QUOTE_PERL 2
  14#define QUOTE_PYTHON 3
  15
  16typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
  17
  18struct atom_value {
  19        const char *s;
  20        unsigned long ul; /* used for sorting when not FIELD_STR */
  21};
  22
  23struct ref_sort {
  24        struct ref_sort *next;
  25        int atom; /* index into used_atom array */
  26        unsigned reverse : 1;
  27};
  28
  29struct refinfo {
  30        char *refname;
  31        unsigned char objectname[20];
  32        struct atom_value *value;
  33};
  34
  35static struct {
  36        const char *name;
  37        cmp_type cmp_type;
  38} valid_atom[] = {
  39        { "refname" },
  40        { "objecttype" },
  41        { "objectsize", FIELD_ULONG },
  42        { "objectname" },
  43        { "tree" },
  44        { "parent" }, /* NEEDSWORK: how to address 2nd and later parents? */
  45        { "numparent", FIELD_ULONG },
  46        { "object" },
  47        { "type" },
  48        { "tag" },
  49        { "author" },
  50        { "authorname" },
  51        { "authoremail" },
  52        { "authordate", FIELD_TIME },
  53        { "committer" },
  54        { "committername" },
  55        { "committeremail" },
  56        { "committerdate", FIELD_TIME },
  57        { "tagger" },
  58        { "taggername" },
  59        { "taggeremail" },
  60        { "taggerdate", FIELD_TIME },
  61        { "creator" },
  62        { "creatordate", FIELD_TIME },
  63        { "subject" },
  64        { "body" },
  65        { "contents" },
  66};
  67
  68/*
  69 * An atom is a valid field atom listed above, possibly prefixed with
  70 * a "*" to denote deref_tag().
  71 *
  72 * We parse given format string and sort specifiers, and make a list
  73 * of properties that we need to extract out of objects.  refinfo
  74 * structure will hold an array of values extracted that can be
  75 * indexed with the "atom number", which is an index into this
  76 * array.
  77 */
  78static const char **used_atom;
  79static cmp_type *used_atom_type;
  80static int used_atom_cnt, sort_atom_limit, need_tagged;
  81
  82/*
  83 * Used to parse format string and sort specifiers
  84 */
  85static int parse_atom(const char *atom, const char *ep)
  86{
  87        const char *sp;
  88        char *n;
  89        int i, at;
  90
  91        sp = atom;
  92        if (*sp == '*' && sp < ep)
  93                sp++; /* deref */
  94        if (ep <= sp)
  95                die("malformed field name: %.*s", (int)(ep-atom), atom);
  96
  97        /* Do we have the atom already used elsewhere? */
  98        for (i = 0; i < used_atom_cnt; i++) {
  99                int len = strlen(used_atom[i]);
 100                if (len == ep - atom && !memcmp(used_atom[i], atom, len))
 101                        return i;
 102        }
 103
 104        /* Is the atom a valid one? */
 105        for (i = 0; i < ARRAY_SIZE(valid_atom); i++) {
 106                int len = strlen(valid_atom[i].name);
 107                if (len == ep - sp && !memcmp(valid_atom[i].name, sp, len))
 108                        break;
 109        }
 110
 111        if (ARRAY_SIZE(valid_atom) <= i)
 112                die("unknown field name: %.*s", (int)(ep-atom), atom);
 113
 114        /* Add it in, including the deref prefix */
 115        at = used_atom_cnt;
 116        used_atom_cnt++;
 117        used_atom = xrealloc(used_atom,
 118                             (sizeof *used_atom) * used_atom_cnt);
 119        used_atom_type = xrealloc(used_atom_type,
 120                                  (sizeof(*used_atom_type) * used_atom_cnt));
 121        n = xmalloc(ep - atom + 1);
 122        memcpy(n, atom, ep - atom);
 123        n[ep-atom] = 0;
 124        used_atom[at] = n;
 125        used_atom_type[at] = valid_atom[i].cmp_type;
 126        return at;
 127}
 128
 129/*
 130 * In a format string, find the next occurrence of %(atom).
 131 */
 132static const char *find_next(const char *cp)
 133{
 134        while (*cp) {
 135                if (*cp == '%') {
 136                        /* %( is the start of an atom;
 137                         * %% is a quoteed per-cent.
 138                         */
 139                        if (cp[1] == '(')
 140                                return cp;
 141                        else if (cp[1] == '%')
 142                                cp++; /* skip over two % */
 143                        /* otherwise this is a singleton, literal % */
 144                }
 145                cp++;
 146        }
 147        return NULL;
 148}
 149
 150/*
 151 * Make sure the format string is well formed, and parse out
 152 * the used atoms.
 153 */
 154static void verify_format(const char *format)
 155{
 156        const char *cp, *sp;
 157        for (cp = format; *cp && (sp = find_next(cp)); ) {
 158                const char *ep = strchr(sp, ')');
 159                if (!ep)
 160                        die("malformatted format string %s", sp);
 161                /* sp points at "%(" and ep points at the closing ")" */
 162                parse_atom(sp + 2, ep);
 163                cp = ep + 1;
 164        }
 165}
 166
 167/*
 168 * Given an object name, read the object data and size, and return a
 169 * "struct object".  If the object data we are returning is also borrowed
 170 * by the "struct object" representation, set *eaten as well---it is a
 171 * signal from parse_object_buffer to us not to free the buffer.
 172 */
 173static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned long *sz, int *eaten)
 174{
 175        char type[20];
 176        void *buf = read_sha1_file(sha1, type, sz);
 177
 178        if (buf)
 179                *obj = parse_object_buffer(sha1, type, *sz, buf, eaten);
 180        else
 181                *obj = NULL;
 182        return buf;
 183}
 184
 185/* See grab_values */
 186static void grab_common_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
 187{
 188        int i;
 189
 190        for (i = 0; i < used_atom_cnt; i++) {
 191                const char *name = used_atom[i];
 192                struct atom_value *v = &val[i];
 193                if (!!deref != (*name == '*'))
 194                        continue;
 195                if (deref)
 196                        name++;
 197                if (!strcmp(name, "objecttype"))
 198                        v->s = type_names[obj->type];
 199                else if (!strcmp(name, "objectsize")) {
 200                        char *s = xmalloc(40);
 201                        sprintf(s, "%lu", sz);
 202                        v->ul = sz;
 203                        v->s = s;
 204                }
 205                else if (!strcmp(name, "objectname")) {
 206                        char *s = xmalloc(41);
 207                        strcpy(s, sha1_to_hex(obj->sha1));
 208                        v->s = s;
 209                }
 210        }
 211}
 212
 213/* See grab_values */
 214static void grab_tag_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
 215{
 216        int i;
 217        struct tag *tag = (struct tag *) obj;
 218
 219        for (i = 0; i < used_atom_cnt; i++) {
 220                const char *name = used_atom[i];
 221                struct atom_value *v = &val[i];
 222                if (!!deref != (*name == '*'))
 223                        continue;
 224                if (deref)
 225                        name++;
 226                if (!strcmp(name, "tag"))
 227                        v->s = tag->tag;
 228        }
 229}
 230
 231static int num_parents(struct commit *commit)
 232{
 233        struct commit_list *parents;
 234        int i;
 235
 236        for (i = 0, parents = commit->parents;
 237             parents;
 238             parents = parents->next)
 239                i++;
 240        return i;
 241}
 242
 243/* See grab_values */
 244static void grab_commit_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
 245{
 246        int i;
 247        struct commit *commit = (struct commit *) obj;
 248
 249        for (i = 0; i < used_atom_cnt; i++) {
 250                const char *name = used_atom[i];
 251                struct atom_value *v = &val[i];
 252                if (!!deref != (*name == '*'))
 253                        continue;
 254                if (deref)
 255                        name++;
 256                if (!strcmp(name, "tree")) {
 257                        char *s = xmalloc(41);
 258                        strcpy(s, sha1_to_hex(commit->tree->object.sha1));
 259                        v->s = s;
 260                }
 261                if (!strcmp(name, "numparent")) {
 262                        char *s = xmalloc(40);
 263                        sprintf(s, "%lu", v->ul);
 264                        v->s = s;
 265                        v->ul = num_parents(commit);
 266                }
 267                else if (!strcmp(name, "parent")) {
 268                        int num = num_parents(commit);
 269                        int i;
 270                        struct commit_list *parents;
 271                        char *s = xmalloc(42 * num);
 272                        v->s = s;
 273                        for (i = 0, parents = commit->parents;
 274                             parents;
 275                             parents = parents->next, i = i + 42) {
 276                                struct commit *parent = parents->item;
 277                                strcpy(s+i, sha1_to_hex(parent->object.sha1));
 278                                if (parents->next)
 279                                        s[i+40] = ' ';
 280                        }
 281                }
 282        }
 283}
 284
 285static const char *find_wholine(const char *who, int wholen, const char *buf, unsigned long sz)
 286{
 287        const char *eol;
 288        while (*buf) {
 289                if (!strncmp(buf, who, wholen) &&
 290                    buf[wholen] == ' ')
 291                        return buf + wholen + 1;
 292                eol = strchr(buf, '\n');
 293                if (!eol)
 294                        return "";
 295                eol++;
 296                if (eol[1] == '\n')
 297                        return ""; /* end of header */
 298                buf = eol;
 299        }
 300        return "";
 301}
 302
 303static char *copy_line(const char *buf)
 304{
 305        const char *eol = strchr(buf, '\n');
 306        char *line;
 307        int len;
 308        if (!eol)
 309                return "";
 310        len = eol - buf;
 311        line = xmalloc(len + 1);
 312        memcpy(line, buf, len);
 313        line[len] = 0;
 314        return line;
 315}
 316
 317static char *copy_name(const char *buf)
 318{
 319        const char *eol = strchr(buf, '\n');
 320        const char *eoname = strstr(buf, " <");
 321        char *line;
 322        int len;
 323        if (!(eoname && eol && eoname < eol))
 324                return "";
 325        len = eoname - buf;
 326        line = xmalloc(len + 1);
 327        memcpy(line, buf, len);
 328        line[len] = 0;
 329        return line;
 330}
 331
 332static char *copy_email(const char *buf)
 333{
 334        const char *email = strchr(buf, '<');
 335        const char *eoemail = strchr(email, '>');
 336        char *line;
 337        int len;
 338        if (!email || !eoemail)
 339                return "";
 340        eoemail++;
 341        len = eoemail - email;
 342        line = xmalloc(len + 1);
 343        memcpy(line, email, len);
 344        line[len] = 0;
 345        return line;
 346}
 347
 348static void grab_date(const char *buf, struct atom_value *v)
 349{
 350        const char *eoemail = strstr(buf, "> ");
 351        char *zone;
 352        unsigned long timestamp;
 353        long tz;
 354
 355        if (!eoemail)
 356                goto bad;
 357        timestamp = strtoul(eoemail + 2, &zone, 10);
 358        if (timestamp == ULONG_MAX)
 359                goto bad;
 360        tz = strtol(zone, NULL, 10);
 361        if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)
 362                goto bad;
 363        v->s = xstrdup(show_date(timestamp, tz, 0));
 364        v->ul = timestamp;
 365        return;
 366 bad:
 367        v->s = "";
 368        v->ul = 0;
 369}
 370
 371/* See grab_values */
 372static void grab_person(const char *who, struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
 373{
 374        int i;
 375        int wholen = strlen(who);
 376        const char *wholine = NULL;
 377
 378        for (i = 0; i < used_atom_cnt; i++) {
 379                const char *name = used_atom[i];
 380                struct atom_value *v = &val[i];
 381                if (!!deref != (*name == '*'))
 382                        continue;
 383                if (deref)
 384                        name++;
 385                if (strncmp(who, name, wholen))
 386                        continue;
 387                if (name[wholen] != 0 &&
 388                    strcmp(name + wholen, "name") &&
 389                    strcmp(name + wholen, "email") &&
 390                    strcmp(name + wholen, "date"))
 391                        continue;
 392                if (!wholine)
 393                        wholine = find_wholine(who, wholen, buf, sz);
 394                if (!wholine)
 395                        return; /* no point looking for it */
 396                if (name[wholen] == 0)
 397                        v->s = copy_line(wholine);
 398                else if (!strcmp(name + wholen, "name"))
 399                        v->s = copy_name(wholine);
 400                else if (!strcmp(name + wholen, "email"))
 401                        v->s = copy_email(wholine);
 402                else if (!strcmp(name + wholen, "date"))
 403                        grab_date(wholine, v);
 404        }
 405
 406        /* For a tag or a commit object, if "creator" or "creatordate" is
 407         * requested, do something special.
 408         */
 409        if (strcmp(who, "tagger") && strcmp(who, "committer"))
 410                return; /* "author" for commit object is not wanted */
 411        if (!wholine)
 412                wholine = find_wholine(who, wholen, buf, sz);
 413        if (!wholine)
 414                return;
 415        for (i = 0; i < used_atom_cnt; i++) {
 416                const char *name = used_atom[i];
 417                struct atom_value *v = &val[i];
 418                if (!!deref != (*name == '*'))
 419                        continue;
 420                if (deref)
 421                        name++;
 422
 423                if (!strcmp(name, "creatordate"))
 424                        grab_date(wholine, v);
 425                else if (!strcmp(name, "creator"))
 426                        v->s = copy_line(wholine);
 427        }
 428}
 429
 430static void find_subpos(const char *buf, unsigned long sz, const char **sub, const char **body)
 431{
 432        while (*buf) {
 433                const char *eol = strchr(buf, '\n');
 434                if (!eol)
 435                        return;
 436                if (eol[1] == '\n') {
 437                        buf = eol + 1;
 438                        break; /* found end of header */
 439                }
 440                buf = eol + 1;
 441        }
 442        while (*buf == '\n')
 443                buf++;
 444        if (!*buf)
 445                return;
 446        *sub = buf; /* first non-empty line */
 447        buf = strchr(buf, '\n');
 448        if (!buf)
 449                return; /* no body */
 450        while (*buf == '\n')
 451                buf++; /* skip blank between subject and body */
 452        *body = buf;
 453}
 454
 455/* See grab_values */
 456static void grab_sub_body_contents(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
 457{
 458        int i;
 459        const char *subpos = NULL, *bodypos = NULL;
 460
 461        for (i = 0; i < used_atom_cnt; i++) {
 462                const char *name = used_atom[i];
 463                struct atom_value *v = &val[i];
 464                if (!!deref != (*name == '*'))
 465                        continue;
 466                if (deref)
 467                        name++;
 468                if (strcmp(name, "subject") &&
 469                    strcmp(name, "body") &&
 470                    strcmp(name, "contents"))
 471                        continue;
 472                if (!subpos)
 473                        find_subpos(buf, sz, &subpos, &bodypos);
 474                if (!subpos)
 475                        return;
 476
 477                if (!strcmp(name, "subject"))
 478                        v->s = copy_line(subpos);
 479                else if (!strcmp(name, "body"))
 480                        v->s = xstrdup(bodypos);
 481                else if (!strcmp(name, "contents"))
 482                        v->s = xstrdup(subpos);
 483        }
 484}
 485
 486/* We want to have empty print-string for field requests
 487 * that do not apply (e.g. "authordate" for a tag object)
 488 */
 489static void fill_missing_values(struct atom_value *val)
 490{
 491        int i;
 492        for (i = 0; i < used_atom_cnt; i++) {
 493                struct atom_value *v = &val[i];
 494                if (v->s == NULL)
 495                        v->s = "";
 496        }
 497}
 498
 499/*
 500 * val is a list of atom_value to hold returned values.  Extract
 501 * the values for atoms in used_atom array out of (obj, buf, sz).
 502 * when deref is false, (obj, buf, sz) is the object that is
 503 * pointed at by the ref itself; otherwise it is the object the
 504 * ref (which is a tag) refers to.
 505 */
 506static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
 507{
 508        grab_common_values(val, deref, obj, buf, sz);
 509        switch (obj->type) {
 510        case OBJ_TAG:
 511                grab_tag_values(val, deref, obj, buf, sz);
 512                grab_sub_body_contents(val, deref, obj, buf, sz);
 513                grab_person("tagger", val, deref, obj, buf, sz);
 514                break;
 515        case OBJ_COMMIT:
 516                grab_commit_values(val, deref, obj, buf, sz);
 517                grab_sub_body_contents(val, deref, obj, buf, sz);
 518                grab_person("author", val, deref, obj, buf, sz);
 519                grab_person("committer", val, deref, obj, buf, sz);
 520                break;
 521        case OBJ_TREE:
 522                // grab_tree_values(val, deref, obj, buf, sz);
 523                break;
 524        case OBJ_BLOB:
 525                // grab_blob_values(val, deref, obj, buf, sz);
 526                break;
 527        default:
 528                die("Eh?  Object of type %d?", obj->type);
 529        }
 530}
 531
 532/*
 533 * Parse the object referred by ref, and grab needed value.
 534 */
 535static void populate_value(struct refinfo *ref)
 536{
 537        void *buf;
 538        struct object *obj;
 539        int eaten, i;
 540        unsigned long size;
 541        const unsigned char *tagged;
 542
 543        ref->value = xcalloc(sizeof(struct atom_value), used_atom_cnt);
 544
 545        buf = get_obj(ref->objectname, &obj, &size, &eaten);
 546        if (!buf)
 547                die("missing object %s for %s",
 548                    sha1_to_hex(ref->objectname), ref->refname);
 549        if (!obj)
 550                die("parse_object_buffer failed on %s for %s",
 551                    sha1_to_hex(ref->objectname), ref->refname);
 552
 553        /* Fill in specials first */
 554        for (i = 0; i < used_atom_cnt; i++) {
 555                const char *name = used_atom[i];
 556                struct atom_value *v = &ref->value[i];
 557                if (!strcmp(name, "refname"))
 558                        v->s = ref->refname;
 559                else if (!strcmp(name, "*refname")) {
 560                        int len = strlen(ref->refname);
 561                        char *s = xmalloc(len + 4);
 562                        sprintf(s, "%s^{}", ref->refname);
 563                        v->s = s;
 564                }
 565        }
 566
 567        grab_values(ref->value, 0, obj, buf, size);
 568        if (!eaten)
 569                free(buf);
 570
 571        /* If there is no atom that wants to know about tagged
 572         * object, we are done.
 573         */
 574        if (!need_tagged || (obj->type != OBJ_TAG))
 575                return;
 576
 577        /* If it is a tag object, see if we use a value that derefs
 578         * the object, and if we do grab the object it refers to.
 579         */
 580        tagged = ((struct tag *)obj)->tagged->sha1;
 581
 582        /* NEEDSWORK: This derefs tag only once, which
 583         * is good to deal with chains of trust, but
 584         * is not consistent with what deref_tag() does
 585         * which peels the onion to the core.
 586         */
 587        buf = get_obj(tagged, &obj, &size, &eaten);
 588        if (!buf)
 589                die("missing object %s for %s",
 590                    sha1_to_hex(tagged), ref->refname);
 591        if (!obj)
 592                die("parse_object_buffer failed on %s for %s",
 593                    sha1_to_hex(tagged), ref->refname);
 594        grab_values(ref->value, 1, obj, buf, size);
 595        if (!eaten)
 596                free(buf);
 597}
 598
 599/*
 600 * Given a ref, return the value for the atom.  This lazily gets value
 601 * out of the object by calling populate value.
 602 */
 603static void get_value(struct refinfo *ref, int atom, struct atom_value **v)
 604{
 605        if (!ref->value) {
 606                populate_value(ref);
 607                fill_missing_values(ref->value);
 608        }
 609        *v = &ref->value[atom];
 610}
 611
 612struct grab_ref_cbdata {
 613        struct refinfo **grab_array;
 614        const char **grab_pattern;
 615        int grab_cnt;
 616};
 617
 618/*
 619 * A call-back given to for_each_ref().  It is unfortunate that we
 620 * need to use global variables to pass extra information to this
 621 * function.
 622 */
 623static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 624{
 625        struct grab_ref_cbdata *cb = cb_data;
 626        struct refinfo *ref;
 627        int cnt;
 628
 629        if (*cb->grab_pattern) {
 630                const char **pattern;
 631                int namelen = strlen(refname);
 632                for (pattern = cb->grab_pattern; *pattern; pattern++) {
 633                        const char *p = *pattern;
 634                        int plen = strlen(p);
 635
 636                        if ((plen <= namelen) &&
 637                            !strncmp(refname, p, plen) &&
 638                            (refname[plen] == '\0' ||
 639                             refname[plen] == '/'))
 640                                break;
 641                        if (!fnmatch(p, refname, FNM_PATHNAME))
 642                                break;
 643                }
 644                if (!*pattern)
 645                        return 0;
 646        }
 647
 648        /* We do not open the object yet; sort may only need refname
 649         * to do its job and the resulting list may yet to be pruned
 650         * by maxcount logic.
 651         */
 652        ref = xcalloc(1, sizeof(*ref));
 653        ref->refname = xstrdup(refname);
 654        hashcpy(ref->objectname, sha1);
 655
 656        cnt = cb->grab_cnt;
 657        cb->grab_array = xrealloc(cb->grab_array,
 658                                  sizeof(*cb->grab_array) * (cnt + 1));
 659        cb->grab_array[cnt++] = ref;
 660        cb->grab_cnt = cnt;
 661        return 0;
 662}
 663
 664static int cmp_ref_sort(struct ref_sort *s, struct refinfo *a, struct refinfo *b)
 665{
 666        struct atom_value *va, *vb;
 667        int cmp;
 668        cmp_type cmp_type = used_atom_type[s->atom];
 669
 670        get_value(a, s->atom, &va);
 671        get_value(b, s->atom, &vb);
 672        switch (cmp_type) {
 673        case FIELD_STR:
 674                cmp = strcmp(va->s, vb->s);
 675                break;
 676        default:
 677                if (va->ul < vb->ul)
 678                        cmp = -1;
 679                else if (va->ul == vb->ul)
 680                        cmp = 0;
 681                else
 682                        cmp = 1;
 683                break;
 684        }
 685        return (s->reverse) ? -cmp : cmp;
 686}
 687
 688static struct ref_sort *ref_sort;
 689static int compare_refs(const void *a_, const void *b_)
 690{
 691        struct refinfo *a = *((struct refinfo **)a_);
 692        struct refinfo *b = *((struct refinfo **)b_);
 693        struct ref_sort *s;
 694
 695        for (s = ref_sort; s; s = s->next) {
 696                int cmp = cmp_ref_sort(s, a, b);
 697                if (cmp)
 698                        return cmp;
 699        }
 700        return 0;
 701}
 702
 703static void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs)
 704{
 705        ref_sort = sort;
 706        qsort(refs, num_refs, sizeof(struct refinfo *), compare_refs);
 707}
 708
 709static void print_value(struct refinfo *ref, int atom, int quote_style)
 710{
 711        struct atom_value *v;
 712        get_value(ref, atom, &v);
 713        switch (quote_style) {
 714        case QUOTE_NONE:
 715                fputs(v->s, stdout);
 716                break;
 717        case QUOTE_SHELL:
 718                sq_quote_print(stdout, v->s);
 719                break;
 720        case QUOTE_PERL:
 721                perl_quote_print(stdout, v->s);
 722                break;
 723        case QUOTE_PYTHON:
 724                python_quote_print(stdout, v->s);
 725                break;
 726        }
 727}
 728
 729static int hex1(char ch)
 730{
 731        if ('0' <= ch && ch <= '9')
 732                return ch - '0';
 733        else if ('a' <= ch && ch <= 'f')
 734                return ch - 'a' + 10;
 735        else if ('A' <= ch && ch <= 'F')
 736                return ch - 'A' + 10;
 737        return -1;
 738}
 739static int hex2(const char *cp)
 740{
 741        if (cp[0] && cp[1])
 742                return (hex1(cp[0]) << 4) | hex1(cp[1]);
 743        else
 744                return -1;
 745}
 746
 747static void emit(const char *cp, const char *ep)
 748{
 749        while (*cp && (!ep || cp < ep)) {
 750                if (*cp == '%') {
 751                        if (cp[1] == '%')
 752                                cp++;
 753                        else {
 754                                int ch = hex2(cp + 1);
 755                                if (0 <= ch) {
 756                                        putchar(ch);
 757                                        cp += 3;
 758                                        continue;
 759                                }
 760                        }
 761                }
 762                putchar(*cp);
 763                cp++;
 764        }
 765}
 766
 767static void show_ref(struct refinfo *info, const char *format, int quote_style)
 768{
 769        const char *cp, *sp, *ep;
 770
 771        for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {
 772                ep = strchr(sp, ')');
 773                if (cp < sp)
 774                        emit(cp, sp);
 775                print_value(info, parse_atom(sp + 2, ep), quote_style);
 776        }
 777        if (*cp) {
 778                sp = cp + strlen(cp);
 779                emit(cp, sp);
 780        }
 781        putchar('\n');
 782}
 783
 784static struct ref_sort *default_sort(void)
 785{
 786        static const char cstr_name[] = "refname";
 787
 788        struct ref_sort *sort = xcalloc(1, sizeof(*sort));
 789
 790        sort->next = NULL;
 791        sort->atom = parse_atom(cstr_name, cstr_name + strlen(cstr_name));
 792        return sort;
 793}
 794
 795int cmd_for_each_ref(int ac, const char **av, char *prefix)
 796{
 797        int i, num_refs;
 798        const char *format = NULL;
 799        struct ref_sort *sort = NULL, **sort_tail = &sort;
 800        int maxcount = 0;
 801        int quote_style = -1; /* unspecified yet */
 802        struct refinfo **refs;
 803        struct grab_ref_cbdata cbdata;
 804
 805        for (i = 1; i < ac; i++) {
 806                const char *arg = av[i];
 807                if (arg[0] != '-')
 808                        break;
 809                if (!strcmp(arg, "--")) {
 810                        i++;
 811                        break;
 812                }
 813                if (!strncmp(arg, "--format=", 9)) {
 814                        if (format)
 815                                die("more than one --format?");
 816                        format = arg + 9;
 817                        continue;
 818                }
 819                if (!strcmp(arg, "-s") || !strcmp(arg, "--shell") ) {
 820                        if (0 <= quote_style)
 821                                die("more than one quoting style?");
 822                        quote_style = QUOTE_SHELL;
 823                        continue;
 824                }
 825                if (!strcmp(arg, "-p") || !strcmp(arg, "--perl") ) {
 826                        if (0 <= quote_style)
 827                                die("more than one quoting style?");
 828                        quote_style = QUOTE_PERL;
 829                        continue;
 830                }
 831                if (!strcmp(arg, "--python") ) {
 832                        if (0 <= quote_style)
 833                                die("more than one quoting style?");
 834                        quote_style = QUOTE_PYTHON;
 835                        continue;
 836                }
 837                if (!strncmp(arg, "--count=", 8)) {
 838                        if (maxcount)
 839                                die("more than one --count?");
 840                        maxcount = atoi(arg + 8);
 841                        if (maxcount <= 0)
 842                                die("The number %s did not parse", arg);
 843                        continue;
 844                }
 845                if (!strncmp(arg, "--sort=", 7)) {
 846                        struct ref_sort *s = xcalloc(1, sizeof(*s));
 847                        int len;
 848
 849                        s->next = NULL;
 850                        *sort_tail = s;
 851                        sort_tail = &s->next;
 852
 853                        arg += 7;
 854                        if (*arg == '-') {
 855                                s->reverse = 1;
 856                                arg++;
 857                        }
 858                        len = strlen(arg);
 859                        sort->atom = parse_atom(arg, arg+len);
 860                        continue;
 861                }
 862                break;
 863        }
 864        if (quote_style < 0)
 865                quote_style = QUOTE_NONE;
 866
 867        if (!sort)
 868                sort = default_sort();
 869        sort_atom_limit = used_atom_cnt;
 870        if (!format)
 871                format = "%(objectname) %(objecttype)\t%(refname)";
 872
 873        verify_format(format);
 874
 875        memset(&cbdata, 0, sizeof(cbdata));
 876        cbdata.grab_pattern = av + i;
 877        for_each_ref(grab_single_ref, &cbdata);
 878        refs = cbdata.grab_array;
 879        num_refs = cbdata.grab_cnt;
 880
 881        for (i = 0; i < used_atom_cnt; i++) {
 882                if (used_atom[i][0] == '*') {
 883                        need_tagged = 1;
 884                        break;
 885                }
 886        }
 887
 888        sort_refs(sort, refs, num_refs);
 889
 890        if (!maxcount || num_refs < maxcount)
 891                maxcount = num_refs;
 892        for (i = 0; i < maxcount; i++)
 893                show_ref(refs[i], format, quote_style);
 894        return 0;
 895}