ref-filter: move code from 'for-each-ref'

Move most of the code from 'for-each-ref' to 'ref-filter' to make it publicly available to other commands, this is to unify the code of 'tag -l', 'branch -l' and 'for-each-ref' so that they can share their implementations with each other. Add 'ref-filter' to the Makefile, this completes the movement of code from 'for-each-ref' to 'ref-filter'. Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr> Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Reviewed-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>

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