gitweb: Remove superfluous "|" in "commit" view
[git/jnareb-git.git] / builtin-for-each-ref.c
blobaf72a12a5798265cece6c7b72582fd3672421394
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"
10 /* Quoting styles */
11 #define QUOTE_NONE 0
12 #define QUOTE_SHELL 1
13 #define QUOTE_PERL 2
14 #define QUOTE_PYTHON 3
16 typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
18 struct atom_value {
19 const char *s;
20 unsigned long ul; /* used for sorting when not FIELD_STR */
23 struct ref_sort {
24 struct ref_sort *next;
25 int atom; /* index into used_atom array */
26 unsigned reverse : 1;
29 struct refinfo {
30 char *refname;
31 unsigned char objectname[20];
32 struct atom_value *value;
35 static 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" },
69 * An atom is a valid field atom listed above, possibly prefixed with
70 * a "*" to denote deref_tag().
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.
78 static const char **used_atom;
79 static cmp_type *used_atom_type;
80 static int used_atom_cnt, sort_atom_limit, need_tagged;
83 * Used to parse format string and sort specifiers
85 static int parse_atom(const char *atom, const char *ep)
87 const char *sp;
88 char *n;
89 int i, at;
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);
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;
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;
111 if (ARRAY_SIZE(valid_atom) <= i)
112 die("unknown field name: %.*s", (int)(ep-atom), atom);
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;
130 * In a format string, find the next occurrence of %(atom).
132 static const char *find_next(const char *cp)
134 while (*cp) {
135 if (*cp == '%') {
136 /* %( is the start of an atom;
137 * %% is a quoteed per-cent.
139 if (cp[1] == '(')
140 return cp;
141 else if (cp[1] == '%')
142 cp++; /* skip over two % */
143 /* otherwise this is a singleton, literal % */
145 cp++;
147 return NULL;
151 * Make sure the format string is well formed, and parse out
152 * the used atoms.
154 static void verify_format(const char *format)
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;
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.
173 static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned long *sz, int *eaten)
175 char type[20];
176 void *buf = read_sha1_file(sha1, type, sz);
178 if (buf)
179 *obj = parse_object_buffer(sha1, type, *sz, buf, eaten);
180 else
181 *obj = NULL;
182 return buf;
185 /* See grab_values */
186 static void grab_common_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
188 int i;
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;
205 else if (!strcmp(name, "objectname")) {
206 char *s = xmalloc(41);
207 strcpy(s, sha1_to_hex(obj->sha1));
208 v->s = s;
213 /* See grab_values */
214 static void grab_tag_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
216 int i;
217 struct tag *tag = (struct tag *) obj;
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;
231 static int num_parents(struct commit *commit)
233 struct commit_list *parents;
234 int i;
236 for (i = 0, parents = commit->parents;
237 parents;
238 parents = parents->next)
239 i++;
240 return i;
243 /* See grab_values */
244 static void grab_commit_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
246 int i;
247 struct commit *commit = (struct commit *) obj;
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;
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);
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] = ' ';
285 static const char *find_wholine(const char *who, int wholen, const char *buf, unsigned long sz)
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;
300 return "";
303 static char *copy_line(const char *buf)
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;
317 static char *copy_name(const char *buf)
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;
332 static char *copy_email(const char *buf)
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;
348 static void grab_date(const char *buf, struct atom_value *v)
350 const char *eoemail = strstr(buf, "> ");
351 char *zone;
352 unsigned long timestamp;
353 long tz;
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;
371 /* See grab_values */
372 static void grab_person(const char *who, struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
374 int i;
375 int wholen = strlen(who);
376 const char *wholine = NULL;
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);
406 /* For a tag or a commit object, if "creator" or "creatordate" is
407 * requested, do something special.
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++;
423 if (!strcmp(name, "creatordate"))
424 grab_date(wholine, v);
425 else if (!strcmp(name, "creator"))
426 v->s = copy_line(wholine);
430 static void find_subpos(const char *buf, unsigned long sz, const char **sub, const char **body)
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 */
440 buf = eol + 1;
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;
455 /* See grab_values */
456 static void grab_sub_body_contents(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
458 int i;
459 const char *subpos = NULL, *bodypos = NULL;
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;
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);
486 /* We want to have empty print-string for field requests
487 * that do not apply (e.g. "authordate" for a tag object)
489 static void fill_missing_values(struct atom_value *val)
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 = "";
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.
506 static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
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);
533 * Parse the object referred by ref, and grab needed value.
535 static void populate_value(struct refinfo *ref)
537 void *buf;
538 struct object *obj;
539 int eaten, i;
540 unsigned long size;
541 const unsigned char *tagged;
543 ref->value = xcalloc(sizeof(struct atom_value), used_atom_cnt);
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);
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;
567 grab_values(ref->value, 0, obj, buf, size);
568 if (!eaten)
569 free(buf);
571 /* If there is no atom that wants to know about tagged
572 * object, we are done.
574 if (!need_tagged || (obj->type != OBJ_TAG))
575 return;
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.
580 tagged = ((struct tag *)obj)->tagged->sha1;
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.
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);
600 * Given a ref, return the value for the atom. This lazily gets value
601 * out of the object by calling populate value.
603 static void get_value(struct refinfo *ref, int atom, struct atom_value **v)
605 if (!ref->value) {
606 populate_value(ref);
607 fill_missing_values(ref->value);
609 *v = &ref->value[atom];
612 struct grab_ref_cbdata {
613 struct refinfo **grab_array;
614 const char **grab_pattern;
615 int grab_cnt;
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.
623 static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
625 struct grab_ref_cbdata *cb = cb_data;
626 struct refinfo *ref;
627 int cnt;
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);
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;
644 if (!*pattern)
645 return 0;
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.
652 ref = xcalloc(1, sizeof(*ref));
653 ref->refname = xstrdup(refname);
654 hashcpy(ref->objectname, sha1);
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;
664 static int cmp_ref_sort(struct ref_sort *s, struct refinfo *a, struct refinfo *b)
666 struct atom_value *va, *vb;
667 int cmp;
668 cmp_type cmp_type = used_atom_type[s->atom];
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;
685 return (s->reverse) ? -cmp : cmp;
688 static struct ref_sort *ref_sort;
689 static int compare_refs(const void *a_, const void *b_)
691 struct refinfo *a = *((struct refinfo **)a_);
692 struct refinfo *b = *((struct refinfo **)b_);
693 struct ref_sort *s;
695 for (s = ref_sort; s; s = s->next) {
696 int cmp = cmp_ref_sort(s, a, b);
697 if (cmp)
698 return cmp;
700 return 0;
703 static void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs)
705 ref_sort = sort;
706 qsort(refs, num_refs, sizeof(struct refinfo *), compare_refs);
709 static void print_value(struct refinfo *ref, int atom, int quote_style)
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;
729 static int hex1(char ch)
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;
739 static int hex2(const char *cp)
741 if (cp[0] && cp[1])
742 return (hex1(cp[0]) << 4) | hex1(cp[1]);
743 else
744 return -1;
747 static void emit(const char *cp, const char *ep)
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;
762 putchar(*cp);
763 cp++;
767 static void show_ref(struct refinfo *info, const char *format, int quote_style)
769 const char *cp, *sp, *ep;
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);
777 if (*cp) {
778 sp = cp + strlen(cp);
779 emit(cp, sp);
781 putchar('\n');
784 static struct ref_sort *default_sort(void)
786 static const char cstr_name[] = "refname";
788 struct ref_sort *sort = xcalloc(1, sizeof(*sort));
790 sort->next = NULL;
791 sort->atom = parse_atom(cstr_name, cstr_name + strlen(cstr_name));
792 return sort;
795 int cmd_for_each_ref(int ac, const char **av, char *prefix)
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;
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;
813 if (!strncmp(arg, "--format=", 9)) {
814 if (format)
815 die("more than one --format?");
816 format = arg + 9;
817 continue;
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;
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;
831 if (!strcmp(arg, "--python") ) {
832 if (0 <= quote_style)
833 die("more than one quoting style?");
834 quote_style = QUOTE_PYTHON;
835 continue;
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;
845 if (!strncmp(arg, "--sort=", 7)) {
846 struct ref_sort *s = xcalloc(1, sizeof(*s));
847 int len;
849 s->next = NULL;
850 *sort_tail = s;
851 sort_tail = &s->next;
853 arg += 7;
854 if (*arg == '-') {
855 s->reverse = 1;
856 arg++;
858 len = strlen(arg);
859 sort->atom = parse_atom(arg, arg+len);
860 continue;
862 break;
864 if (quote_style < 0)
865 quote_style = QUOTE_NONE;
867 if (!sort)
868 sort = default_sort();
869 sort_atom_limit = used_atom_cnt;
870 if (!format)
871 format = "%(objectname) %(objecttype)\t%(refname)";
873 verify_format(format);
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;
881 for (i = 0; i < used_atom_cnt; i++) {
882 if (used_atom[i][0] == '*') {
883 need_tagged = 1;
884 break;
888 sort_refs(sort, refs, num_refs);
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;