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