]> git.ipfire.org Git - thirdparty/git.git/blame - ref-filter.c
ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>)
[thirdparty/git.git] / ref-filter.c
CommitLineData
c95b7585
KN
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"
35257aa0 12#include "revision.h"
ce592082 13#include "utf8.h"
90c00408
KN
14#include "git-compat-util.h"
15#include "version.h"
b1d31c89 16#include "trailer.h"
c95b7585
KN
17
18typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
4f3e3b37 19typedef enum { COMPARE_EQUAL, COMPARE_UNEQUAL, COMPARE_NONE } cmp_status;
c95b7585 20
5bd881d9
KN
21struct align {
22 align_type position;
23 unsigned int width;
24};
25
c58492d4 26struct if_then_else {
4f3e3b37
KN
27 cmp_status cmp_status;
28 const char *str;
c58492d4
KN
29 unsigned int then_atom_seen : 1,
30 else_atom_seen : 1,
31 condition_satisfied : 1;
32};
33
50cd83dc
KN
34/*
35 * An atom is a valid field atom listed below, possibly prefixed with
36 * a "*" to denote deref_tag().
37 *
38 * We parse given format string and sort specifiers, and make a list
39 * of properties that we need to extract out of objects. ref_array_item
40 * structure will hold an array of values extracted that can be
41 * indexed with the "atom number", which is an index into this
42 * array.
43 */
b072add7
KN
44static struct used_atom {
45 const char *name;
46 cmp_type type;
fd935cc7
KN
47 union {
48 char color[COLOR_MAXLEN];
5bd881d9 49 struct align align;
5339bdad
KN
50 enum { RR_NORMAL, RR_SHORTEN, RR_TRACK, RR_TRACKSHORT }
51 remote_ref;
452db397 52 struct {
b1d31c89 53 enum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB, C_TRAILERS } option;
452db397
KN
54 unsigned int nlines;
55 } contents;
4f3e3b37
KN
56 struct {
57 cmp_status cmp_status;
58 const char *str;
59 } if_then_else;
fe63c4d1 60 enum { O_FULL, O_SHORT } objectname;
fd935cc7 61 } u;
b072add7 62} *used_atom;
50cd83dc
KN
63static int used_atom_cnt, need_tagged, need_symref;
64static int need_color_reset_at_eol;
65
fd935cc7
KN
66static void color_atom_parser(struct used_atom *atom, const char *color_value)
67{
68 if (!color_value)
69 die(_("expected format: %%(color:<color>)"));
70 if (color_parse(color_value, atom->u.color) < 0)
71 die(_("unrecognized color: %%(color:%s)"), color_value);
72}
73
5339bdad
KN
74static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
75{
76 if (!arg)
77 atom->u.remote_ref = RR_NORMAL;
78 else if (!strcmp(arg, "short"))
79 atom->u.remote_ref = RR_SHORTEN;
80 else if (!strcmp(arg, "track"))
81 atom->u.remote_ref = RR_TRACK;
82 else if (!strcmp(arg, "trackshort"))
83 atom->u.remote_ref = RR_TRACKSHORT;
84 else
85 die(_("unrecognized format: %%(%s)"), atom->name);
86}
87
452db397
KN
88static void body_atom_parser(struct used_atom *atom, const char *arg)
89{
90 if (arg)
1823c619 91 die(_("%%(body) does not take arguments"));
452db397
KN
92 atom->u.contents.option = C_BODY_DEP;
93}
94
95static void subject_atom_parser(struct used_atom *atom, const char *arg)
96{
97 if (arg)
1823c619 98 die(_("%%(subject) does not take arguments"));
452db397
KN
99 atom->u.contents.option = C_SUB;
100}
101
b1d31c89
JK
102static void trailers_atom_parser(struct used_atom *atom, const char *arg)
103{
104 if (arg)
105 die(_("%%(trailers) does not take arguments"));
106 atom->u.contents.option = C_TRAILERS;
107}
108
452db397
KN
109static void contents_atom_parser(struct used_atom *atom, const char *arg)
110{
111 if (!arg)
112 atom->u.contents.option = C_BARE;
113 else if (!strcmp(arg, "body"))
114 atom->u.contents.option = C_BODY;
115 else if (!strcmp(arg, "signature"))
116 atom->u.contents.option = C_SIG;
117 else if (!strcmp(arg, "subject"))
118 atom->u.contents.option = C_SUB;
b1d31c89
JK
119 else if (!strcmp(arg, "trailers"))
120 atom->u.contents.option = C_TRAILERS;
452db397
KN
121 else if (skip_prefix(arg, "lines=", &arg)) {
122 atom->u.contents.option = C_LINES;
123 if (strtoul_ui(arg, 10, &atom->u.contents.nlines))
124 die(_("positive value expected contents:lines=%s"), arg);
125 } else
126 die(_("unrecognized %%(contents) argument: %s"), arg);
127}
128
fe63c4d1
KN
129static void objectname_atom_parser(struct used_atom *atom, const char *arg)
130{
131 if (!arg)
132 atom->u.objectname = O_FULL;
133 else if (!strcmp(arg, "short"))
134 atom->u.objectname = O_SHORT;
135 else
136 die(_("unrecognized %%(objectname) argument: %s"), arg);
137}
138
25a8d79e
KN
139static align_type parse_align_position(const char *s)
140{
141 if (!strcmp(s, "right"))
142 return ALIGN_RIGHT;
143 else if (!strcmp(s, "middle"))
144 return ALIGN_MIDDLE;
145 else if (!strcmp(s, "left"))
146 return ALIGN_LEFT;
147 return -1;
148}
149
5bd881d9
KN
150static void align_atom_parser(struct used_atom *atom, const char *arg)
151{
152 struct align *align = &atom->u.align;
153 struct string_list params = STRING_LIST_INIT_DUP;
154 int i;
155 unsigned int width = ~0U;
156
157 if (!arg)
158 die(_("expected format: %%(align:<width>,<position>)"));
159
160 align->position = ALIGN_LEFT;
161
162 string_list_split(&params, arg, ',', -1);
163 for (i = 0; i < params.nr; i++) {
164 const char *s = params.items[i].string;
165 int position;
166
395fb8f9
KN
167 if (skip_prefix(s, "position=", &s)) {
168 position = parse_align_position(s);
169 if (position < 0)
170 die(_("unrecognized position:%s"), s);
171 align->position = position;
172 } else if (skip_prefix(s, "width=", &s)) {
173 if (strtoul_ui(s, 10, &width))
174 die(_("unrecognized width:%s"), s);
175 } else if (!strtoul_ui(s, 10, &width))
5bd881d9
KN
176 ;
177 else if ((position = parse_align_position(s)) >= 0)
178 align->position = position;
179 else
180 die(_("unrecognized %%(align) argument: %s"), s);
181 }
182
183 if (width == ~0U)
184 die(_("positive width expected with the %%(align) atom"));
185 align->width = width;
186 string_list_clear(&params, 0);
187}
188
4f3e3b37
KN
189static void if_atom_parser(struct used_atom *atom, const char *arg)
190{
191 if (!arg) {
192 atom->u.if_then_else.cmp_status = COMPARE_NONE;
193 return;
194 } else if (skip_prefix(arg, "equals=", &atom->u.if_then_else.str)) {
195 atom->u.if_then_else.cmp_status = COMPARE_EQUAL;
196 } else if (skip_prefix(arg, "notequals=", &atom->u.if_then_else.str)) {
197 atom->u.if_then_else.cmp_status = COMPARE_UNEQUAL;
198 } else {
199 die(_("unrecognized %%(if) argument: %s"), arg);
200 }
201}
202
203
c95b7585
KN
204static struct {
205 const char *name;
206 cmp_type cmp_type;
4de707ea 207 void (*parser)(struct used_atom *atom, const char *arg);
c95b7585
KN
208} valid_atom[] = {
209 { "refname" },
210 { "objecttype" },
211 { "objectsize", FIELD_ULONG },
fe63c4d1 212 { "objectname", FIELD_STR, objectname_atom_parser },
c95b7585
KN
213 { "tree" },
214 { "parent" },
215 { "numparent", FIELD_ULONG },
216 { "object" },
217 { "type" },
218 { "tag" },
219 { "author" },
220 { "authorname" },
221 { "authoremail" },
222 { "authordate", FIELD_TIME },
223 { "committer" },
224 { "committername" },
225 { "committeremail" },
226 { "committerdate", FIELD_TIME },
227 { "tagger" },
228 { "taggername" },
229 { "taggeremail" },
230 { "taggerdate", FIELD_TIME },
231 { "creator" },
232 { "creatordate", FIELD_TIME },
452db397
KN
233 { "subject", FIELD_STR, subject_atom_parser },
234 { "body", FIELD_STR, body_atom_parser },
b1d31c89 235 { "trailers", FIELD_STR, trailers_atom_parser },
452db397 236 { "contents", FIELD_STR, contents_atom_parser },
5339bdad
KN
237 { "upstream", FIELD_STR, remote_ref_atom_parser },
238 { "push", FIELD_STR, remote_ref_atom_parser },
c95b7585
KN
239 { "symref" },
240 { "flag" },
241 { "HEAD" },
fd935cc7 242 { "color", FIELD_STR, color_atom_parser },
5bd881d9 243 { "align", FIELD_STR, align_atom_parser },
ce592082 244 { "end" },
4f3e3b37 245 { "if", FIELD_STR, if_atom_parser },
c58492d4
KN
246 { "then" },
247 { "else" },
c95b7585
KN
248};
249
574e96a2
KN
250#define REF_FORMATTING_STATE_INIT { 0, NULL }
251
252struct ref_formatting_stack {
253 struct ref_formatting_stack *prev;
254 struct strbuf output;
c58492d4 255 void (*at_end)(struct ref_formatting_stack **stack);
ce592082 256 void *at_end_data;
574e96a2
KN
257};
258
259struct ref_formatting_state {
260 int quote_style;
261 struct ref_formatting_stack *stack;
262};
263
3a25761a
KN
264struct atom_value {
265 const char *s;
63d89fbc 266 void (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);
3a25761a 267 unsigned long ul; /* used for sorting when not FIELD_STR */
c58fc856 268 struct used_atom *atom;
3a25761a
KN
269};
270
c95b7585
KN
271/*
272 * Used to parse format string and sort specifiers
273 */
274int parse_ref_filter_atom(const char *atom, const char *ep)
275{
276 const char *sp;
4de707ea 277 const char *arg;
e94ce139 278 int i, at, atom_len;
c95b7585
KN
279
280 sp = atom;
281 if (*sp == '*' && sp < ep)
282 sp++; /* deref */
283 if (ep <= sp)
1823c619 284 die(_("malformed field name: %.*s"), (int)(ep-atom), atom);
c95b7585
KN
285
286 /* Do we have the atom already used elsewhere? */
287 for (i = 0; i < used_atom_cnt; i++) {
b072add7
KN
288 int len = strlen(used_atom[i].name);
289 if (len == ep - atom && !memcmp(used_atom[i].name, atom, len))
c95b7585
KN
290 return i;
291 }
292
e94ce139
SG
293 /*
294 * If the atom name has a colon, strip it and everything after
295 * it off - it specifies the format for this entry, and
296 * shouldn't be used for checking against the valid_atom
297 * table.
298 */
299 arg = memchr(sp, ':', ep - sp);
300 atom_len = (arg ? arg : ep) - sp;
301
c95b7585
KN
302 /* Is the atom a valid one? */
303 for (i = 0; i < ARRAY_SIZE(valid_atom); i++) {
304 int len = strlen(valid_atom[i].name);
e94ce139 305 if (len == atom_len && !memcmp(valid_atom[i].name, sp, len))
c95b7585
KN
306 break;
307 }
308
309 if (ARRAY_SIZE(valid_atom) <= i)
1823c619 310 die(_("unknown field name: %.*s"), (int)(ep-atom), atom);
c95b7585
KN
311
312 /* Add it in, including the deref prefix */
313 at = used_atom_cnt;
314 used_atom_cnt++;
315 REALLOC_ARRAY(used_atom, used_atom_cnt);
b072add7
KN
316 used_atom[at].name = xmemdupz(atom, ep - atom);
317 used_atom[at].type = valid_atom[i].cmp_type;
4de707ea
KN
318 if (arg)
319 arg = used_atom[at].name + (arg - atom) + 1;
fd935cc7 320 memset(&used_atom[at].u, 0, sizeof(used_atom[at].u));
4de707ea
KN
321 if (valid_atom[i].parser)
322 valid_atom[i].parser(&used_atom[at], arg);
c95b7585
KN
323 if (*atom == '*')
324 need_tagged = 1;
b072add7 325 if (!strcmp(used_atom[at].name, "symref"))
c95b7585
KN
326 need_symref = 1;
327 return at;
328}
329
63d89fbc
KN
330static void quote_formatting(struct strbuf *s, const char *str, int quote_style)
331{
332 switch (quote_style) {
333 case QUOTE_NONE:
334 strbuf_addstr(s, str);
335 break;
336 case QUOTE_SHELL:
337 sq_quote_buf(s, str);
338 break;
339 case QUOTE_PERL:
340 perl_quote_buf(s, str);
341 break;
342 case QUOTE_PYTHON:
343 python_quote_buf(s, str);
344 break;
345 case QUOTE_TCL:
346 tcl_quote_buf(s, str);
347 break;
348 }
349}
350
351static void append_atom(struct atom_value *v, struct ref_formatting_state *state)
352{
ce592082
KN
353 /*
354 * Quote formatting is only done when the stack has a single
355 * element. Otherwise quote formatting is done on the
356 * element's entire output strbuf when the %(end) atom is
357 * encountered.
358 */
359 if (!state->stack->prev)
360 quote_formatting(&state->stack->output, v->s, state->quote_style);
361 else
362 strbuf_addstr(&state->stack->output, v->s);
63d89fbc
KN
363}
364
574e96a2
KN
365static void push_stack_element(struct ref_formatting_stack **stack)
366{
367 struct ref_formatting_stack *s = xcalloc(1, sizeof(struct ref_formatting_stack));
368
369 strbuf_init(&s->output, 0);
370 s->prev = *stack;
371 *stack = s;
372}
373
374static void pop_stack_element(struct ref_formatting_stack **stack)
375{
376 struct ref_formatting_stack *current = *stack;
377 struct ref_formatting_stack *prev = current->prev;
378
379 if (prev)
380 strbuf_addbuf(&prev->output, &current->output);
381 strbuf_release(&current->output);
382 free(current);
383 *stack = prev;
384}
385
c58492d4 386static void end_align_handler(struct ref_formatting_stack **stack)
ce592082 387{
c58492d4
KN
388 struct ref_formatting_stack *cur = *stack;
389 struct align *align = (struct align *)cur->at_end_data;
ce592082
KN
390 struct strbuf s = STRBUF_INIT;
391
c58492d4
KN
392 strbuf_utf8_align(&s, align->position, align->width, cur->output.buf);
393 strbuf_swap(&cur->output, &s);
ce592082
KN
394 strbuf_release(&s);
395}
396
397static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
398{
399 struct ref_formatting_stack *new;
400
401 push_stack_element(&state->stack);
402 new = state->stack;
403 new->at_end = end_align_handler;
c58fc856 404 new->at_end_data = &atomv->atom->u.align;
ce592082
KN
405}
406
c58492d4
KN
407static void if_then_else_handler(struct ref_formatting_stack **stack)
408{
409 struct ref_formatting_stack *cur = *stack;
410 struct ref_formatting_stack *prev = cur->prev;
411 struct if_then_else *if_then_else = (struct if_then_else *)cur->at_end_data;
412
413 if (!if_then_else->then_atom_seen)
414 die(_("format: %%(if) atom used without a %%(then) atom"));
415
416 if (if_then_else->else_atom_seen) {
417 /*
418 * There is an %(else) atom: we need to drop one state from the
419 * stack, either the %(else) branch if the condition is satisfied, or
420 * the %(then) branch if it isn't.
421 */
422 if (if_then_else->condition_satisfied) {
423 strbuf_reset(&cur->output);
424 pop_stack_element(&cur);
425 } else {
426 strbuf_swap(&cur->output, &prev->output);
427 strbuf_reset(&cur->output);
428 pop_stack_element(&cur);
429 }
430 } else if (!if_then_else->condition_satisfied) {
431 /*
432 * No %(else) atom: just drop the %(then) branch if the
433 * condition is not satisfied.
434 */
435 strbuf_reset(&cur->output);
436 }
437
438 *stack = cur;
439 free(if_then_else);
440}
441
442static void if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
443{
444 struct ref_formatting_stack *new;
445 struct if_then_else *if_then_else = xcalloc(sizeof(struct if_then_else), 1);
446
4f3e3b37
KN
447 if_then_else->str = atomv->atom->u.if_then_else.str;
448 if_then_else->cmp_status = atomv->atom->u.if_then_else.cmp_status;
449
c58492d4
KN
450 push_stack_element(&state->stack);
451 new = state->stack;
452 new->at_end = if_then_else_handler;
453 new->at_end_data = if_then_else;
454}
455
456static int is_empty(const char *s)
457{
458 while (*s != '\0') {
459 if (!isspace(*s))
460 return 0;
461 s++;
462 }
463 return 1;
464}
465
466static void then_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
467{
468 struct ref_formatting_stack *cur = state->stack;
469 struct if_then_else *if_then_else = NULL;
470
471 if (cur->at_end == if_then_else_handler)
472 if_then_else = (struct if_then_else *)cur->at_end_data;
473 if (!if_then_else)
474 die(_("format: %%(then) atom used without an %%(if) atom"));
475 if (if_then_else->then_atom_seen)
476 die(_("format: %%(then) atom used more than once"));
477 if (if_then_else->else_atom_seen)
478 die(_("format: %%(then) atom used after %%(else)"));
479 if_then_else->then_atom_seen = 1;
480 /*
4f3e3b37
KN
481 * If the 'equals' or 'notequals' attribute is used then
482 * perform the required comparison. If not, only non-empty
483 * strings satisfy the 'if' condition.
c58492d4 484 */
4f3e3b37
KN
485 if (if_then_else->cmp_status == COMPARE_EQUAL) {
486 if (!strcmp(if_then_else->str, cur->output.buf))
487 if_then_else->condition_satisfied = 1;
488 } else if (if_then_else->cmp_status == COMPARE_UNEQUAL) {
489 if (strcmp(if_then_else->str, cur->output.buf))
490 if_then_else->condition_satisfied = 1;
491 } else if (cur->output.len && !is_empty(cur->output.buf))
c58492d4
KN
492 if_then_else->condition_satisfied = 1;
493 strbuf_reset(&cur->output);
494}
495
496static void else_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
497{
498 struct ref_formatting_stack *prev = state->stack;
499 struct if_then_else *if_then_else = NULL;
500
501 if (prev->at_end == if_then_else_handler)
502 if_then_else = (struct if_then_else *)prev->at_end_data;
503 if (!if_then_else)
504 die(_("format: %%(else) atom used without an %%(if) atom"));
505 if (!if_then_else->then_atom_seen)
506 die(_("format: %%(else) atom used without a %%(then) atom"));
507 if (if_then_else->else_atom_seen)
508 die(_("format: %%(else) atom used more than once"));
509 if_then_else->else_atom_seen = 1;
510 push_stack_element(&state->stack);
511 state->stack->at_end_data = prev->at_end_data;
512 state->stack->at_end = prev->at_end;
513}
514
ce592082
KN
515static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
516{
517 struct ref_formatting_stack *current = state->stack;
518 struct strbuf s = STRBUF_INIT;
519
520 if (!current->at_end)
521 die(_("format: %%(end) atom used without corresponding atom"));
c58492d4
KN
522 current->at_end(&state->stack);
523
524 /* Stack may have been popped within at_end(), hence reset the current pointer */
525 current = state->stack;
ce592082
KN
526
527 /*
528 * Perform quote formatting when the stack element is that of
529 * a supporting atom. If nested then perform quote formatting
530 * only on the topmost supporting atom.
531 */
c58492d4 532 if (!current->prev->prev) {
ce592082
KN
533 quote_formatting(&s, current->output.buf, state->quote_style);
534 strbuf_swap(&current->output, &s);
535 }
536 strbuf_release(&s);
537 pop_stack_element(&state->stack);
538}
539
c95b7585
KN
540/*
541 * In a format string, find the next occurrence of %(atom).
542 */
543static const char *find_next(const char *cp)
544{
545 while (*cp) {
546 if (*cp == '%') {
547 /*
548 * %( is the start of an atom;
549 * %% is a quoted per-cent.
550 */
551 if (cp[1] == '(')
552 return cp;
553 else if (cp[1] == '%')
554 cp++; /* skip over two % */
555 /* otherwise this is a singleton, literal % */
556 }
557 cp++;
558 }
559 return NULL;
560}
561
562/*
563 * Make sure the format string is well formed, and parse out
564 * the used atoms.
565 */
566int verify_ref_format(const char *format)
567{
568 const char *cp, *sp;
569
570 need_color_reset_at_eol = 0;
571 for (cp = format; *cp && (sp = find_next(cp)); ) {
572 const char *color, *ep = strchr(sp, ')');
573 int at;
574
575 if (!ep)
1823c619 576 return error(_("malformed format string %s"), sp);
c95b7585
KN
577 /* sp points at "%(" and ep points at the closing ")" */
578 at = parse_ref_filter_atom(sp + 2, ep);
579 cp = ep + 1;
580
b072add7 581 if (skip_prefix(used_atom[at].name, "color:", &color))
c95b7585
KN
582 need_color_reset_at_eol = !!strcmp(color, "reset");
583 }
584 return 0;
585}
586
587/*
588 * Given an object name, read the object data and size, and return a
589 * "struct object". If the object data we are returning is also borrowed
590 * by the "struct object" representation, set *eaten as well---it is a
591 * signal from parse_object_buffer to us not to free the buffer.
592 */
593static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned long *sz, int *eaten)
594{
595 enum object_type type;
596 void *buf = read_sha1_file(sha1, &type, sz);
597
598 if (buf)
599 *obj = parse_object_buffer(sha1, type, *sz, buf, eaten);
600 else
601 *obj = NULL;
602 return buf;
603}
604
605static int grab_objectname(const char *name, const unsigned char *sha1,
fe63c4d1 606 struct atom_value *v, struct used_atom *atom)
c95b7585 607{
fe63c4d1
KN
608 if (starts_with(name, "objectname")) {
609 if (atom->u.objectname == O_SHORT) {
610 v->s = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV));
611 return 1;
612 } else if (atom->u.objectname == O_FULL) {
613 v->s = xstrdup(sha1_to_hex(sha1));
614 return 1;
615 } else
616 die("BUG: unknown %%(objectname) option");
c95b7585
KN
617 }
618 return 0;
619}
620
621/* See grab_values */
622static void grab_common_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
623{
624 int i;
625
626 for (i = 0; i < used_atom_cnt; i++) {
b072add7 627 const char *name = used_atom[i].name;
c95b7585
KN
628 struct atom_value *v = &val[i];
629 if (!!deref != (*name == '*'))
630 continue;
631 if (deref)
632 name++;
633 if (!strcmp(name, "objecttype"))
634 v->s = typename(obj->type);
635 else if (!strcmp(name, "objectsize")) {
c95b7585 636 v->ul = sz;
a5e03bf5 637 v->s = xstrfmt("%lu", sz);
c95b7585
KN
638 }
639 else if (deref)
fe63c4d1 640 grab_objectname(name, obj->oid.hash, v, &used_atom[i]);
c95b7585
KN
641 }
642}
643
644/* See grab_values */
645static void grab_tag_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
646{
647 int i;
648 struct tag *tag = (struct tag *) obj;
649
650 for (i = 0; i < used_atom_cnt; i++) {
b072add7 651 const char *name = used_atom[i].name;
c95b7585
KN
652 struct atom_value *v = &val[i];
653 if (!!deref != (*name == '*'))
654 continue;
655 if (deref)
656 name++;
657 if (!strcmp(name, "tag"))
658 v->s = tag->tag;
659 else if (!strcmp(name, "type") && tag->tagged)
660 v->s = typename(tag->tagged->type);
a5e03bf5 661 else if (!strcmp(name, "object") && tag->tagged)
f2fd0760 662 v->s = xstrdup(oid_to_hex(&tag->tagged->oid));
c95b7585
KN
663 }
664}
665
666/* See grab_values */
667static void grab_commit_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
668{
669 int i;
670 struct commit *commit = (struct commit *) obj;
671
672 for (i = 0; i < used_atom_cnt; i++) {
b072add7 673 const char *name = used_atom[i].name;
c95b7585
KN
674 struct atom_value *v = &val[i];
675 if (!!deref != (*name == '*'))
676 continue;
677 if (deref)
678 name++;
679 if (!strcmp(name, "tree")) {
f2fd0760 680 v->s = xstrdup(oid_to_hex(&commit->tree->object.oid));
c95b7585 681 }
a5e03bf5 682 else if (!strcmp(name, "numparent")) {
c95b7585 683 v->ul = commit_list_count(commit->parents);
a5e03bf5 684 v->s = xstrfmt("%lu", v->ul);
c95b7585
KN
685 }
686 else if (!strcmp(name, "parent")) {
c95b7585 687 struct commit_list *parents;
a5e03bf5
JK
688 struct strbuf s = STRBUF_INIT;
689 for (parents = commit->parents; parents; parents = parents->next) {
c95b7585 690 struct commit *parent = parents->item;
a5e03bf5
JK
691 if (parents != commit->parents)
692 strbuf_addch(&s, ' ');
f2fd0760 693 strbuf_addstr(&s, oid_to_hex(&parent->object.oid));
c95b7585 694 }
a5e03bf5 695 v->s = strbuf_detach(&s, NULL);
c95b7585
KN
696 }
697 }
698}
699
700static const char *find_wholine(const char *who, int wholen, const char *buf, unsigned long sz)
701{
702 const char *eol;
703 while (*buf) {
704 if (!strncmp(buf, who, wholen) &&
705 buf[wholen] == ' ')
706 return buf + wholen + 1;
707 eol = strchr(buf, '\n');
708 if (!eol)
709 return "";
710 eol++;
711 if (*eol == '\n')
712 return ""; /* end of header */
713 buf = eol;
714 }
715 return "";
716}
717
718static const char *copy_line(const char *buf)
719{
720 const char *eol = strchrnul(buf, '\n');
721 return xmemdupz(buf, eol - buf);
722}
723
724static const char *copy_name(const char *buf)
725{
726 const char *cp;
727 for (cp = buf; *cp && *cp != '\n'; cp++) {
728 if (!strncmp(cp, " <", 2))
729 return xmemdupz(buf, cp - buf);
730 }
731 return "";
732}
733
734static const char *copy_email(const char *buf)
735{
736 const char *email = strchr(buf, '<');
737 const char *eoemail;
738 if (!email)
739 return "";
740 eoemail = strchr(email, '>');
741 if (!eoemail)
742 return "";
743 return xmemdupz(email, eoemail + 1 - email);
744}
745
746static char *copy_subject(const char *buf, unsigned long len)
747{
748 char *r = xmemdupz(buf, len);
749 int i;
750
751 for (i = 0; i < len; i++)
752 if (r[i] == '\n')
753 r[i] = ' ';
754
755 return r;
756}
757
758static void grab_date(const char *buf, struct atom_value *v, const char *atomname)
759{
760 const char *eoemail = strstr(buf, "> ");
761 char *zone;
762 unsigned long timestamp;
763 long tz;
d939af12 764 struct date_mode date_mode = { DATE_NORMAL };
c95b7585
KN
765 const char *formatp;
766
767 /*
768 * We got here because atomname ends in "date" or "date<something>";
769 * it's not possible that <something> is not ":<format>" because
770 * parse_ref_filter_atom() wouldn't have allowed it, so we can assume that no
771 * ":" means no format is specified, and use the default.
772 */
773 formatp = strchr(atomname, ':');
774 if (formatp != NULL) {
775 formatp++;
d939af12 776 parse_date_format(formatp, &date_mode);
c95b7585
KN
777 }
778
779 if (!eoemail)
780 goto bad;
781 timestamp = strtoul(eoemail + 2, &zone, 10);
782 if (timestamp == ULONG_MAX)
783 goto bad;
784 tz = strtol(zone, NULL, 10);
785 if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)
786 goto bad;
d939af12 787 v->s = xstrdup(show_date(timestamp, tz, &date_mode));
c95b7585
KN
788 v->ul = timestamp;
789 return;
790 bad:
791 v->s = "";
792 v->ul = 0;
793}
794
795/* See grab_values */
796static void grab_person(const char *who, struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
797{
798 int i;
799 int wholen = strlen(who);
800 const char *wholine = NULL;
801
802 for (i = 0; i < used_atom_cnt; i++) {
b072add7 803 const char *name = used_atom[i].name;
c95b7585
KN
804 struct atom_value *v = &val[i];
805 if (!!deref != (*name == '*'))
806 continue;
807 if (deref)
808 name++;
809 if (strncmp(who, name, wholen))
810 continue;
811 if (name[wholen] != 0 &&
812 strcmp(name + wholen, "name") &&
813 strcmp(name + wholen, "email") &&
814 !starts_with(name + wholen, "date"))
815 continue;
816 if (!wholine)
817 wholine = find_wholine(who, wholen, buf, sz);
818 if (!wholine)
819 return; /* no point looking for it */
820 if (name[wholen] == 0)
821 v->s = copy_line(wholine);
822 else if (!strcmp(name + wholen, "name"))
823 v->s = copy_name(wholine);
824 else if (!strcmp(name + wholen, "email"))
825 v->s = copy_email(wholine);
826 else if (starts_with(name + wholen, "date"))
827 grab_date(wholine, v, name);
828 }
829
830 /*
831 * For a tag or a commit object, if "creator" or "creatordate" is
832 * requested, do something special.
833 */
834 if (strcmp(who, "tagger") && strcmp(who, "committer"))
835 return; /* "author" for commit object is not wanted */
836 if (!wholine)
837 wholine = find_wholine(who, wholen, buf, sz);
838 if (!wholine)
839 return;
840 for (i = 0; i < used_atom_cnt; i++) {
b072add7 841 const char *name = used_atom[i].name;
c95b7585
KN
842 struct atom_value *v = &val[i];
843 if (!!deref != (*name == '*'))
844 continue;
845 if (deref)
846 name++;
847
848 if (starts_with(name, "creatordate"))
849 grab_date(wholine, v, name);
850 else if (!strcmp(name, "creator"))
851 v->s = copy_line(wholine);
852 }
853}
854
855static void find_subpos(const char *buf, unsigned long sz,
856 const char **sub, unsigned long *sublen,
857 const char **body, unsigned long *bodylen,
858 unsigned long *nonsiglen,
859 const char **sig, unsigned long *siglen)
860{
861 const char *eol;
862 /* skip past header until we hit empty line */
863 while (*buf && *buf != '\n') {
864 eol = strchrnul(buf, '\n');
865 if (*eol)
866 eol++;
867 buf = eol;
868 }
869 /* skip any empty lines */
870 while (*buf == '\n')
871 buf++;
872
873 /* parse signature first; we might not even have a subject line */
874 *sig = buf + parse_signature(buf, strlen(buf));
875 *siglen = strlen(*sig);
876
877 /* subject is first non-empty line */
878 *sub = buf;
879 /* subject goes to first empty line */
880 while (buf < *sig && *buf && *buf != '\n') {
881 eol = strchrnul(buf, '\n');
882 if (*eol)
883 eol++;
884 buf = eol;
885 }
886 *sublen = buf - *sub;
887 /* drop trailing newline, if present */
888 if (*sublen && (*sub)[*sublen - 1] == '\n')
889 *sublen -= 1;
890
891 /* skip any empty lines */
892 while (*buf == '\n')
893 buf++;
894 *body = buf;
895 *bodylen = strlen(buf);
896 *nonsiglen = *sig - buf;
897}
898
1bb38e5a
KN
899/*
900 * If 'lines' is greater than 0, append that many lines from the given
901 * 'buf' of length 'size' to the given strbuf.
902 */
903static void append_lines(struct strbuf *out, const char *buf, unsigned long size, int lines)
904{
905 int i;
906 const char *sp, *eol;
907 size_t len;
908
909 sp = buf;
910
911 for (i = 0; i < lines && sp < buf + size; i++) {
912 if (i)
913 strbuf_addstr(out, "\n ");
914 eol = memchr(sp, '\n', size - (sp - buf));
915 len = eol ? eol - sp : size - (sp - buf);
916 strbuf_add(out, sp, len);
917 if (!eol)
918 break;
919 sp = eol + 1;
920 }
921}
922
c95b7585
KN
923/* See grab_values */
924static void grab_sub_body_contents(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
925{
926 int i;
927 const char *subpos = NULL, *bodypos = NULL, *sigpos = NULL;
928 unsigned long sublen = 0, bodylen = 0, nonsiglen = 0, siglen = 0;
929
930 for (i = 0; i < used_atom_cnt; i++) {
452db397
KN
931 struct used_atom *atom = &used_atom[i];
932 const char *name = atom->name;
c95b7585
KN
933 struct atom_value *v = &val[i];
934 if (!!deref != (*name == '*'))
935 continue;
936 if (deref)
937 name++;
938 if (strcmp(name, "subject") &&
939 strcmp(name, "body") &&
b1d31c89 940 strcmp(name, "trailers") &&
452db397 941 !starts_with(name, "contents"))
c95b7585
KN
942 continue;
943 if (!subpos)
944 find_subpos(buf, sz,
945 &subpos, &sublen,
946 &bodypos, &bodylen, &nonsiglen,
947 &sigpos, &siglen);
948
452db397 949 if (atom->u.contents.option == C_SUB)
c95b7585 950 v->s = copy_subject(subpos, sublen);
452db397 951 else if (atom->u.contents.option == C_BODY_DEP)
c95b7585 952 v->s = xmemdupz(bodypos, bodylen);
452db397 953 else if (atom->u.contents.option == C_BODY)
c95b7585 954 v->s = xmemdupz(bodypos, nonsiglen);
452db397 955 else if (atom->u.contents.option == C_SIG)
c95b7585 956 v->s = xmemdupz(sigpos, siglen);
452db397 957 else if (atom->u.contents.option == C_LINES) {
1bb38e5a
KN
958 struct strbuf s = STRBUF_INIT;
959 const char *contents_end = bodylen + bodypos - siglen;
960
1bb38e5a 961 /* Size is the length of the message after removing the signature */
452db397 962 append_lines(&s, subpos, contents_end - subpos, atom->u.contents.nlines);
1bb38e5a 963 v->s = strbuf_detach(&s, NULL);
b1d31c89
JK
964 } else if (atom->u.contents.option == C_TRAILERS) {
965 struct trailer_info info;
966
967 /* Search for trailer info */
968 trailer_info_get(&info, subpos);
969 v->s = xmemdupz(info.trailer_start,
970 info.trailer_end - info.trailer_start);
971 trailer_info_release(&info);
452db397
KN
972 } else if (atom->u.contents.option == C_BARE)
973 v->s = xstrdup(subpos);
c95b7585
KN
974 }
975}
976
977/*
978 * We want to have empty print-string for field requests
979 * that do not apply (e.g. "authordate" for a tag object)
980 */
981static void fill_missing_values(struct atom_value *val)
982{
983 int i;
984 for (i = 0; i < used_atom_cnt; i++) {
985 struct atom_value *v = &val[i];
986 if (v->s == NULL)
987 v->s = "";
988 }
989}
990
991/*
992 * val is a list of atom_value to hold returned values. Extract
993 * the values for atoms in used_atom array out of (obj, buf, sz).
994 * when deref is false, (obj, buf, sz) is the object that is
995 * pointed at by the ref itself; otherwise it is the object the
996 * ref (which is a tag) refers to.
997 */
998static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
999{
1000 grab_common_values(val, deref, obj, buf, sz);
1001 switch (obj->type) {
1002 case OBJ_TAG:
1003 grab_tag_values(val, deref, obj, buf, sz);
1004 grab_sub_body_contents(val, deref, obj, buf, sz);
1005 grab_person("tagger", val, deref, obj, buf, sz);
1006 break;
1007 case OBJ_COMMIT:
1008 grab_commit_values(val, deref, obj, buf, sz);
1009 grab_sub_body_contents(val, deref, obj, buf, sz);
1010 grab_person("author", val, deref, obj, buf, sz);
1011 grab_person("committer", val, deref, obj, buf, sz);
1012 break;
1013 case OBJ_TREE:
1014 /* grab_tree_values(val, deref, obj, buf, sz); */
1015 break;
1016 case OBJ_BLOB:
1017 /* grab_blob_values(val, deref, obj, buf, sz); */
1018 break;
1019 default:
1020 die("Eh? Object of type %d?", obj->type);
1021 }
1022}
1023
1024static inline char *copy_advance(char *dst, const char *src)
1025{
1026 while (*src)
1027 *dst++ = *src++;
1028 return dst;
1029}
1030
0571979b
JK
1031static const char *strip_ref_components(const char *refname, const char *nr_arg)
1032{
1033 char *end;
1034 long nr = strtol(nr_arg, &end, 10);
1035 long remaining = nr;
1036 const char *start = refname;
1037
1038 if (nr < 1 || *end != '\0')
1823c619 1039 die(_(":strip= requires a positive integer argument"));
0571979b
JK
1040
1041 while (remaining) {
1042 switch (*start++) {
1043 case '\0':
1823c619 1044 die(_("ref '%s' does not have %ld components to :strip"),
0571979b
JK
1045 refname, nr);
1046 case '/':
1047 remaining--;
1048 break;
1049 }
1050 }
1051 return start;
1052}
1053
5339bdad
KN
1054static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
1055 struct branch *branch, const char **s)
1056{
1057 int num_ours, num_theirs;
1058 if (atom->u.remote_ref == RR_SHORTEN)
1059 *s = shorten_unambiguous_ref(refname, warn_ambiguous_refs);
1060 else if (atom->u.remote_ref == RR_TRACK) {
1061 if (stat_tracking_info(branch, &num_ours,
1062 &num_theirs, NULL))
1063 return;
1064
1065 if (!num_ours && !num_theirs)
1066 *s = "";
1067 else if (!num_ours)
1068 *s = xstrfmt("[behind %d]", num_theirs);
1069 else if (!num_theirs)
1070 *s = xstrfmt("[ahead %d]", num_ours);
1071 else
1072 *s = xstrfmt("[ahead %d, behind %d]",
1073 num_ours, num_theirs);
1074 } else if (atom->u.remote_ref == RR_TRACKSHORT) {
1075 if (stat_tracking_info(branch, &num_ours,
1076 &num_theirs, NULL))
1077 return;
1078
1079 if (!num_ours && !num_theirs)
1080 *s = "=";
1081 else if (!num_ours)
1082 *s = "<";
1083 else if (!num_theirs)
1084 *s = ">";
1085 else
1086 *s = "<>";
1087 } else /* RR_NORMAL */
1088 *s = refname;
1089}
1090
c95b7585
KN
1091/*
1092 * Parse the object referred by ref, and grab needed value.
1093 */
1094static void populate_value(struct ref_array_item *ref)
1095{
1096 void *buf;
1097 struct object *obj;
1098 int eaten, i;
1099 unsigned long size;
1100 const unsigned char *tagged;
1101
1102 ref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value));
1103
1104 if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {
1105 unsigned char unused1[20];
1106 ref->symref = resolve_refdup(ref->refname, RESOLVE_REF_READING,
1107 unused1, NULL);
1108 if (!ref->symref)
1109 ref->symref = "";
1110 }
1111
1112 /* Fill in specials first */
1113 for (i = 0; i < used_atom_cnt; i++) {
fd935cc7 1114 struct used_atom *atom = &used_atom[i];
b072add7 1115 const char *name = used_atom[i].name;
c95b7585
KN
1116 struct atom_value *v = &ref->value[i];
1117 int deref = 0;
1118 const char *refname;
1119 const char *formatp;
1120 struct branch *branch = NULL;
1121
63d89fbc 1122 v->handler = append_atom;
c58fc856 1123 v->atom = atom;
63d89fbc 1124
c95b7585
KN
1125 if (*name == '*') {
1126 deref = 1;
1127 name++;
1128 }
1129
1130 if (starts_with(name, "refname"))
1131 refname = ref->refname;
1132 else if (starts_with(name, "symref"))
1133 refname = ref->symref ? ref->symref : "";
1134 else if (starts_with(name, "upstream")) {
1135 const char *branch_name;
1136 /* only local branches may have an upstream */
1137 if (!skip_prefix(ref->refname, "refs/heads/",
1138 &branch_name))
1139 continue;
1140 branch = branch_get(branch_name);
1141
1142 refname = branch_get_upstream(branch, NULL);
5339bdad
KN
1143 if (refname)
1144 fill_remote_ref_details(atom, refname, branch, &v->s);
1145 continue;
c95b7585
KN
1146 } else if (starts_with(name, "push")) {
1147 const char *branch_name;
1148 if (!skip_prefix(ref->refname, "refs/heads/",
1149 &branch_name))
1150 continue;
1151 branch = branch_get(branch_name);
1152
1153 refname = branch_get_push(branch, NULL);
1154 if (!refname)
1155 continue;
5339bdad
KN
1156 fill_remote_ref_details(atom, refname, branch, &v->s);
1157 continue;
fd935cc7
KN
1158 } else if (starts_with(name, "color:")) {
1159 v->s = atom->u.color;
c95b7585
KN
1160 continue;
1161 } else if (!strcmp(name, "flag")) {
1162 char buf[256], *cp = buf;
1163 if (ref->flag & REF_ISSYMREF)
1164 cp = copy_advance(cp, ",symref");
1165 if (ref->flag & REF_ISPACKED)
1166 cp = copy_advance(cp, ",packed");
1167 if (cp == buf)
1168 v->s = "";
1169 else {
1170 *cp = '\0';
1171 v->s = xstrdup(buf + 1);
1172 }
1173 continue;
fe63c4d1 1174 } else if (!deref && grab_objectname(name, ref->objectname, v, atom)) {
c95b7585
KN
1175 continue;
1176 } else if (!strcmp(name, "HEAD")) {
1177 const char *head;
1178 unsigned char sha1[20];
1179
1180 head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
1181 sha1, NULL);
84679d47 1182 if (head && !strcmp(ref->refname, head))
c95b7585
KN
1183 v->s = "*";
1184 else
1185 v->s = " ";
1186 continue;
5bd881d9 1187 } else if (starts_with(name, "align")) {
ce592082
KN
1188 v->handler = align_atom_handler;
1189 continue;
1190 } else if (!strcmp(name, "end")) {
1191 v->handler = end_atom_handler;
1192 continue;
4f3e3b37
KN
1193 } else if (starts_with(name, "if")) {
1194 const char *s;
1195
1196 if (skip_prefix(name, "if:", &s))
1197 v->s = xstrdup(s);
c58492d4
KN
1198 v->handler = if_atom_handler;
1199 continue;
1200 } else if (!strcmp(name, "then")) {
1201 v->handler = then_atom_handler;
1202 continue;
1203 } else if (!strcmp(name, "else")) {
1204 v->handler = else_atom_handler;
1205 continue;
c95b7585
KN
1206 } else
1207 continue;
1208
1209 formatp = strchr(name, ':');
1210 if (formatp) {
0571979b 1211 const char *arg;
c95b7585
KN
1212
1213 formatp++;
1214 if (!strcmp(formatp, "short"))
1215 refname = shorten_unambiguous_ref(refname,
1216 warn_ambiguous_refs);
0571979b
JK
1217 else if (skip_prefix(formatp, "strip=", &arg))
1218 refname = strip_ref_components(refname, arg);
5339bdad 1219 else
1823c619 1220 die(_("unknown %.*s format %s"),
c95b7585
KN
1221 (int)(formatp - name), name, formatp);
1222 }
1223
1224 if (!deref)
1225 v->s = refname;
a5e03bf5
JK
1226 else
1227 v->s = xstrfmt("%s^{}", refname);
c95b7585
KN
1228 }
1229
1230 for (i = 0; i < used_atom_cnt; i++) {
1231 struct atom_value *v = &ref->value[i];
1232 if (v->s == NULL)
1233 goto need_obj;
1234 }
1235 return;
1236
1237 need_obj:
1238 buf = get_obj(ref->objectname, &obj, &size, &eaten);
1239 if (!buf)
1823c619 1240 die(_("missing object %s for %s"),
c95b7585
KN
1241 sha1_to_hex(ref->objectname), ref->refname);
1242 if (!obj)
1823c619 1243 die(_("parse_object_buffer failed on %s for %s"),
c95b7585
KN
1244 sha1_to_hex(ref->objectname), ref->refname);
1245
1246 grab_values(ref->value, 0, obj, buf, size);
1247 if (!eaten)
1248 free(buf);
1249
1250 /*
1251 * If there is no atom that wants to know about tagged
1252 * object, we are done.
1253 */
1254 if (!need_tagged || (obj->type != OBJ_TAG))
1255 return;
1256
1257 /*
1258 * If it is a tag object, see if we use a value that derefs
1259 * the object, and if we do grab the object it refers to.
1260 */
ed1c9977 1261 tagged = ((struct tag *)obj)->tagged->oid.hash;
c95b7585
KN
1262
1263 /*
1264 * NEEDSWORK: This derefs tag only once, which
1265 * is good to deal with chains of trust, but
1266 * is not consistent with what deref_tag() does
1267 * which peels the onion to the core.
1268 */
1269 buf = get_obj(tagged, &obj, &size, &eaten);
1270 if (!buf)
1823c619 1271 die(_("missing object %s for %s"),
c95b7585
KN
1272 sha1_to_hex(tagged), ref->refname);
1273 if (!obj)
1823c619 1274 die(_("parse_object_buffer failed on %s for %s"),
c95b7585
KN
1275 sha1_to_hex(tagged), ref->refname);
1276 grab_values(ref->value, 1, obj, buf, size);
1277 if (!eaten)
1278 free(buf);
1279}
1280
1281/*
1282 * Given a ref, return the value for the atom. This lazily gets value
1283 * out of the object by calling populate value.
1284 */
1285static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct atom_value **v)
1286{
1287 if (!ref->value) {
1288 populate_value(ref);
1289 fill_missing_values(ref->value);
1290 }
1291 *v = &ref->value[atom];
1292}
1293
ee2bd06b
KN
1294enum contains_result {
1295 CONTAINS_UNKNOWN = -1,
1296 CONTAINS_NO = 0,
1297 CONTAINS_YES = 1
1298};
1299
1300/*
1301 * Mimicking the real stack, this stack lives on the heap, avoiding stack
1302 * overflows.
1303 *
1304 * At each recursion step, the stack items points to the commits whose
1305 * ancestors are to be inspected.
1306 */
1307struct contains_stack {
1308 int nr, alloc;
1309 struct contains_stack_entry {
1310 struct commit *commit;
1311 struct commit_list *parents;
1312 } *contains_stack;
1313};
1314
1315static int in_commit_list(const struct commit_list *want, struct commit *c)
1316{
1317 for (; want; want = want->next)
f2fd0760 1318 if (!oidcmp(&want->item->object.oid, &c->object.oid))
ee2bd06b
KN
1319 return 1;
1320 return 0;
1321}
1322
1323/*
1324 * Test whether the candidate or one of its parents is contained in the list.
1325 * Do not recurse to find out, though, but return -1 if inconclusive.
1326 */
1327static enum contains_result contains_test(struct commit *candidate,
1328 const struct commit_list *want)
1329{
1330 /* was it previously marked as containing a want commit? */
1331 if (candidate->object.flags & TMP_MARK)
1332 return 1;
1333 /* or marked as not possibly containing a want commit? */
1334 if (candidate->object.flags & UNINTERESTING)
1335 return 0;
1336 /* or are we it? */
1337 if (in_commit_list(want, candidate)) {
1338 candidate->object.flags |= TMP_MARK;
1339 return 1;
1340 }
1341
1342 if (parse_commit(candidate) < 0)
1343 return 0;
1344
1345 return -1;
1346}
1347
1348static void push_to_contains_stack(struct commit *candidate, struct contains_stack *contains_stack)
1349{
1350 ALLOC_GROW(contains_stack->contains_stack, contains_stack->nr + 1, contains_stack->alloc);
1351 contains_stack->contains_stack[contains_stack->nr].commit = candidate;
1352 contains_stack->contains_stack[contains_stack->nr++].parents = candidate->parents;
1353}
1354
1355static enum contains_result contains_tag_algo(struct commit *candidate,
1356 const struct commit_list *want)
1357{
1358 struct contains_stack contains_stack = { 0, 0, NULL };
1359 int result = contains_test(candidate, want);
1360
1361 if (result != CONTAINS_UNKNOWN)
1362 return result;
1363
1364 push_to_contains_stack(candidate, &contains_stack);
1365 while (contains_stack.nr) {
1366 struct contains_stack_entry *entry = &contains_stack.contains_stack[contains_stack.nr - 1];
1367 struct commit *commit = entry->commit;
1368 struct commit_list *parents = entry->parents;
1369
1370 if (!parents) {
1371 commit->object.flags |= UNINTERESTING;
1372 contains_stack.nr--;
1373 }
1374 /*
1375 * If we just popped the stack, parents->item has been marked,
1376 * therefore contains_test will return a meaningful 0 or 1.
1377 */
1378 else switch (contains_test(parents->item, want)) {
1379 case CONTAINS_YES:
1380 commit->object.flags |= TMP_MARK;
1381 contains_stack.nr--;
1382 break;
1383 case CONTAINS_NO:
1384 entry->parents = parents->next;
1385 break;
1386 case CONTAINS_UNKNOWN:
1387 push_to_contains_stack(parents->item, &contains_stack);
1388 break;
1389 }
1390 }
1391 free(contains_stack.contains_stack);
1392 return contains_test(candidate, want);
1393}
1394
1395static int commit_contains(struct ref_filter *filter, struct commit *commit)
1396{
1397 if (filter->with_commit_tag_algo)
1398 return contains_tag_algo(commit, filter->with_commit);
1399 return is_descendant_of(commit, filter->with_commit);
1400}
1401
bef0e12b
KN
1402/*
1403 * Return 1 if the refname matches one of the patterns, otherwise 0.
1404 * A pattern can be a literal prefix (e.g. a refname "refs/heads/master"
1405 * matches a pattern "refs/heads/mas") or a wildcard (e.g. the same ref
1406 * matches "refs/heads/mas*", too).
1407 */
3bb16a8b 1408static int match_pattern(const struct ref_filter *filter, const char *refname)
bef0e12b 1409{
3bb16a8b
NTND
1410 const char **patterns = filter->name_patterns;
1411 unsigned flags = 0;
1412
1413 if (filter->ignore_case)
1414 flags |= WM_CASEFOLD;
1415
bef0e12b
KN
1416 /*
1417 * When no '--format' option is given we need to skip the prefix
1418 * for matching refs of tags and branches.
1419 */
1420 (void)(skip_prefix(refname, "refs/tags/", &refname) ||
1421 skip_prefix(refname, "refs/heads/", &refname) ||
1422 skip_prefix(refname, "refs/remotes/", &refname) ||
1423 skip_prefix(refname, "refs/", &refname));
1424
1425 for (; *patterns; patterns++) {
3bb16a8b 1426 if (!wildmatch(*patterns, refname, flags, NULL))
bef0e12b
KN
1427 return 1;
1428 }
1429 return 0;
1430}
1431
c95b7585
KN
1432/*
1433 * Return 1 if the refname matches one of the patterns, otherwise 0.
1434 * A pattern can be path prefix (e.g. a refname "refs/heads/master"
bef0e12b
KN
1435 * matches a pattern "refs/heads/" but not "refs/heads/m") or a
1436 * wildcard (e.g. the same ref matches "refs/heads/m*", too).
c95b7585 1437 */
3bb16a8b 1438static int match_name_as_path(const struct ref_filter *filter, const char *refname)
c95b7585 1439{
3bb16a8b 1440 const char **pattern = filter->name_patterns;
c95b7585 1441 int namelen = strlen(refname);
3bb16a8b
NTND
1442 unsigned flags = WM_PATHNAME;
1443
1444 if (filter->ignore_case)
1445 flags |= WM_CASEFOLD;
1446
c95b7585
KN
1447 for (; *pattern; pattern++) {
1448 const char *p = *pattern;
1449 int plen = strlen(p);
1450
1451 if ((plen <= namelen) &&
1452 !strncmp(refname, p, plen) &&
1453 (refname[plen] == '\0' ||
1454 refname[plen] == '/' ||
1455 p[plen-1] == '/'))
1456 return 1;
1457 if (!wildmatch(p, refname, WM_PATHNAME, NULL))
1458 return 1;
1459 }
1460 return 0;
1461}
1462
bef0e12b
KN
1463/* Return 1 if the refname matches one of the patterns, otherwise 0. */
1464static int filter_pattern_match(struct ref_filter *filter, const char *refname)
1465{
1466 if (!*filter->name_patterns)
1467 return 1; /* No pattern always matches */
1468 if (filter->match_as_path)
3bb16a8b
NTND
1469 return match_name_as_path(filter, refname);
1470 return match_pattern(filter, refname);
bef0e12b
KN
1471}
1472
68411046
KN
1473/*
1474 * Given a ref (sha1, refname), check if the ref belongs to the array
1475 * of sha1s. If the given ref is a tag, check if the given tag points
1476 * at one of the sha1s in the given sha1 array.
1477 * the given sha1_array.
1478 * NEEDSWORK:
1479 * 1. Only a single level of inderection is obtained, we might want to
1480 * change this to account for multiple levels (e.g. annotated tags
1481 * pointing to annotated tags pointing to a commit.)
1482 * 2. As the refs are cached we might know what refname peels to without
1483 * the need to parse the object via parse_object(). peel_ref() might be a
1484 * more efficient alternative to obtain the pointee.
1485 */
1486static const unsigned char *match_points_at(struct sha1_array *points_at,
1487 const unsigned char *sha1,
1488 const char *refname)
1489{
1490 const unsigned char *tagged_sha1 = NULL;
1491 struct object *obj;
1492
1493 if (sha1_array_lookup(points_at, sha1) >= 0)
1494 return sha1;
1495 obj = parse_object(sha1);
1496 if (!obj)
1497 die(_("malformed object at '%s'"), refname);
1498 if (obj->type == OBJ_TAG)
ed1c9977 1499 tagged_sha1 = ((struct tag *)obj)->tagged->oid.hash;
68411046
KN
1500 if (tagged_sha1 && sha1_array_lookup(points_at, tagged_sha1) >= 0)
1501 return tagged_sha1;
1502 return NULL;
1503}
1504
c95b7585
KN
1505/* Allocate space for a new ref_array_item and copy the objectname and flag to it */
1506static struct ref_array_item *new_ref_array_item(const char *refname,
1507 const unsigned char *objectname,
1508 int flag)
1509{
96ffc06f
JK
1510 struct ref_array_item *ref;
1511 FLEX_ALLOC_STR(ref, refname, refname);
c95b7585
KN
1512 hashcpy(ref->objectname, objectname);
1513 ref->flag = flag;
1514
1515 return ref;
1516}
1517
5b4f2851
KN
1518static int filter_ref_kind(struct ref_filter *filter, const char *refname)
1519{
1520 unsigned int i;
1521
1522 static struct {
1523 const char *prefix;
1524 unsigned int kind;
1525 } ref_kind[] = {
1526 { "refs/heads/" , FILTER_REFS_BRANCHES },
1527 { "refs/remotes/" , FILTER_REFS_REMOTES },
1528 { "refs/tags/", FILTER_REFS_TAGS}
1529 };
1530
1531 if (filter->kind == FILTER_REFS_BRANCHES ||
1532 filter->kind == FILTER_REFS_REMOTES ||
1533 filter->kind == FILTER_REFS_TAGS)
1534 return filter->kind;
1535 else if (!strcmp(refname, "HEAD"))
1536 return FILTER_REFS_DETACHED_HEAD;
1537
1538 for (i = 0; i < ARRAY_SIZE(ref_kind); i++) {
1539 if (starts_with(refname, ref_kind[i].prefix))
1540 return ref_kind[i].kind;
1541 }
1542
1543 return FILTER_REFS_OTHERS;
1544}
1545
c95b7585
KN
1546/*
1547 * A call-back given to for_each_ref(). Filter refs and keep them for
1548 * later object processing.
1549 */
14de7fba 1550static int ref_filter_handler(const char *refname, const struct object_id *oid, int flag, void *cb_data)
c95b7585
KN
1551{
1552 struct ref_filter_cbdata *ref_cbdata = cb_data;
14de7fba 1553 struct ref_filter *filter = ref_cbdata->filter;
c95b7585 1554 struct ref_array_item *ref;
35257aa0 1555 struct commit *commit = NULL;
5b4f2851 1556 unsigned int kind;
c95b7585
KN
1557
1558 if (flag & REF_BAD_NAME) {
1823c619 1559 warning(_("ignoring ref with broken name %s"), refname);
c95b7585
KN
1560 return 0;
1561 }
1562
7ebc8cbe 1563 if (flag & REF_ISBROKEN) {
1823c619 1564 warning(_("ignoring broken ref %s"), refname);
7ebc8cbe
JH
1565 return 0;
1566 }
1567
5b4f2851
KN
1568 /* Obtain the current ref kind from filter_ref_kind() and ignore unwanted refs. */
1569 kind = filter_ref_kind(filter, refname);
1570 if (!(kind & filter->kind))
1571 return 0;
1572
bef0e12b 1573 if (!filter_pattern_match(filter, refname))
c95b7585
KN
1574 return 0;
1575
68411046
KN
1576 if (filter->points_at.nr && !match_points_at(&filter->points_at, oid->hash, refname))
1577 return 0;
1578
35257aa0
KN
1579 /*
1580 * A merge filter is applied on refs pointing to commits. Hence
1581 * obtain the commit using the 'oid' available and discard all
1582 * non-commits early. The actual filtering is done later.
1583 */
aedcb7dc 1584 if (filter->merge_commit || filter->with_commit || filter->verbose) {
35257aa0
KN
1585 commit = lookup_commit_reference_gently(oid->hash, 1);
1586 if (!commit)
1587 return 0;
ee2bd06b
KN
1588 /* We perform the filtering for the '--contains' option */
1589 if (filter->with_commit &&
1590 !commit_contains(filter, commit))
1591 return 0;
35257aa0
KN
1592 }
1593
c95b7585
KN
1594 /*
1595 * We do not open the object yet; sort may only need refname
1596 * to do its job and the resulting list may yet to be pruned
1597 * by maxcount logic.
1598 */
1599 ref = new_ref_array_item(refname, oid->hash, flag);
35257aa0 1600 ref->commit = commit;
c95b7585 1601
14de7fba
KN
1602 REALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);
1603 ref_cbdata->array->items[ref_cbdata->array->nr++] = ref;
5b4f2851 1604 ref->kind = kind;
c95b7585
KN
1605 return 0;
1606}
1607
1608/* Free memory allocated for a ref_array_item */
1609static void free_array_item(struct ref_array_item *item)
1610{
1611 free((char *)item->symref);
c95b7585
KN
1612 free(item);
1613}
1614
1615/* Free all memory allocated for ref_array */
1616void ref_array_clear(struct ref_array *array)
1617{
1618 int i;
1619
1620 for (i = 0; i < array->nr; i++)
1621 free_array_item(array->items[i]);
1622 free(array->items);
1623 array->items = NULL;
1624 array->nr = array->alloc = 0;
1625}
1626
35257aa0
KN
1627static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
1628{
1629 struct rev_info revs;
1630 int i, old_nr;
1631 struct ref_filter *filter = ref_cbdata->filter;
1632 struct ref_array *array = ref_cbdata->array;
1633 struct commit **to_clear = xcalloc(sizeof(struct commit *), array->nr);
1634
1635 init_revisions(&revs, NULL);
1636
1637 for (i = 0; i < array->nr; i++) {
1638 struct ref_array_item *item = array->items[i];
1639 add_pending_object(&revs, &item->commit->object, item->refname);
1640 to_clear[i] = item->commit;
1641 }
1642
1643 filter->merge_commit->object.flags |= UNINTERESTING;
1644 add_pending_object(&revs, &filter->merge_commit->object, "");
1645
1646 revs.limited = 1;
1647 if (prepare_revision_walk(&revs))
1648 die(_("revision walk setup failed"));
1649
1650 old_nr = array->nr;
1651 array->nr = 0;
1652
1653 for (i = 0; i < old_nr; i++) {
1654 struct ref_array_item *item = array->items[i];
1655 struct commit *commit = item->commit;
1656
1657 int is_merged = !!(commit->object.flags & UNINTERESTING);
1658
1659 if (is_merged == (filter->merge == REF_FILTER_MERGED_INCLUDE))
1660 array->items[array->nr++] = array->items[i];
1661 else
1662 free_array_item(item);
1663 }
1664
1665 for (i = 0; i < old_nr; i++)
1666 clear_commit_marks(to_clear[i], ALL_REV_FLAGS);
1667 clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);
1668 free(to_clear);
1669}
1670
14de7fba
KN
1671/*
1672 * API for filtering a set of refs. Based on the type of refs the user
1673 * has requested, we iterate through those refs and apply filters
1674 * as per the given ref_filter structure and finally store the
1675 * filtered refs in the ref_array structure.
1676 */
1677int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type)
1678{
1679 struct ref_filter_cbdata ref_cbdata;
35257aa0 1680 int ret = 0;
5b4f2851 1681 unsigned int broken = 0;
14de7fba
KN
1682
1683 ref_cbdata.array = array;
1684 ref_cbdata.filter = filter;
1685
5b4f2851
KN
1686 if (type & FILTER_REFS_INCLUDE_BROKEN)
1687 broken = 1;
1688 filter->kind = type & FILTER_REFS_KIND_MASK;
1689
35257aa0 1690 /* Simple per-ref filtering */
5b4f2851 1691 if (!filter->kind)
14de7fba 1692 die("filter_refs: invalid type");
5b4f2851
KN
1693 else {
1694 /*
1695 * For common cases where we need only branches or remotes or tags,
1696 * we only iterate through those refs. If a mix of refs is needed,
1697 * we iterate over all refs and filter out required refs with the help
1698 * of filter_ref_kind().
1699 */
1700 if (filter->kind == FILTER_REFS_BRANCHES)
1701 ret = for_each_fullref_in("refs/heads/", ref_filter_handler, &ref_cbdata, broken);
1702 else if (filter->kind == FILTER_REFS_REMOTES)
1703 ret = for_each_fullref_in("refs/remotes/", ref_filter_handler, &ref_cbdata, broken);
1704 else if (filter->kind == FILTER_REFS_TAGS)
1705 ret = for_each_fullref_in("refs/tags/", ref_filter_handler, &ref_cbdata, broken);
1706 else if (filter->kind & FILTER_REFS_ALL)
1707 ret = for_each_fullref_in("", ref_filter_handler, &ref_cbdata, broken);
1708 if (!ret && (filter->kind & FILTER_REFS_DETACHED_HEAD))
1709 head_ref(ref_filter_handler, &ref_cbdata);
1710 }
1711
35257aa0
KN
1712
1713 /* Filters that need revision walking */
1714 if (filter->merge_commit)
1715 do_merge_filter(&ref_cbdata);
1716
1717 return ret;
14de7fba
KN
1718}
1719
c95b7585
KN
1720static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, struct ref_array_item *b)
1721{
1722 struct atom_value *va, *vb;
1723 int cmp;
b072add7 1724 cmp_type cmp_type = used_atom[s->atom].type;
3bb16a8b 1725 int (*cmp_fn)(const char *, const char *);
c95b7585
KN
1726
1727 get_ref_atom_value(a, s->atom, &va);
1728 get_ref_atom_value(b, s->atom, &vb);
3bb16a8b 1729 cmp_fn = s->ignore_case ? strcasecmp : strcmp;
90c00408
KN
1730 if (s->version)
1731 cmp = versioncmp(va->s, vb->s);
1732 else if (cmp_type == FIELD_STR)
3bb16a8b 1733 cmp = cmp_fn(va->s, vb->s);
90c00408 1734 else {
c95b7585
KN
1735 if (va->ul < vb->ul)
1736 cmp = -1;
1737 else if (va->ul == vb->ul)
3bb16a8b 1738 cmp = cmp_fn(a->refname, b->refname);
c95b7585
KN
1739 else
1740 cmp = 1;
c95b7585 1741 }
90c00408 1742
c95b7585
KN
1743 return (s->reverse) ? -cmp : cmp;
1744}
1745
1746static struct ref_sorting *ref_sorting;
1747static int compare_refs(const void *a_, const void *b_)
1748{
1749 struct ref_array_item *a = *((struct ref_array_item **)a_);
1750 struct ref_array_item *b = *((struct ref_array_item **)b_);
1751 struct ref_sorting *s;
1752
1753 for (s = ref_sorting; s; s = s->next) {
1754 int cmp = cmp_ref_sorting(s, a, b);
1755 if (cmp)
1756 return cmp;
1757 }
1758 return 0;
1759}
1760
1761void ref_array_sort(struct ref_sorting *sorting, struct ref_array *array)
1762{
1763 ref_sorting = sorting;
9ed0d8d6 1764 QSORT(array->items, array->nr, compare_refs);
c95b7585
KN
1765}
1766
574e96a2 1767static void append_literal(const char *cp, const char *ep, struct ref_formatting_state *state)
c95b7585 1768{
574e96a2
KN
1769 struct strbuf *s = &state->stack->output;
1770
c95b7585
KN
1771 while (*cp && (!ep || cp < ep)) {
1772 if (*cp == '%') {
1773 if (cp[1] == '%')
1774 cp++;
1775 else {
d2330973 1776 int ch = hex2chr(cp + 1);
c95b7585 1777 if (0 <= ch) {
574e96a2 1778 strbuf_addch(s, ch);
c95b7585
KN
1779 cp += 3;
1780 continue;
1781 }
1782 }
1783 }
574e96a2 1784 strbuf_addch(s, *cp);
c95b7585
KN
1785 cp++;
1786 }
1787}
1788
1789void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)
1790{
1791 const char *cp, *sp, *ep;
574e96a2
KN
1792 struct strbuf *final_buf;
1793 struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
1794
1795 state.quote_style = quote_style;
1796 push_stack_element(&state.stack);
c95b7585
KN
1797
1798 for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {
1799 struct atom_value *atomv;
1800
1801 ep = strchr(sp, ')');
1802 if (cp < sp)
574e96a2 1803 append_literal(cp, sp, &state);
c95b7585 1804 get_ref_atom_value(info, parse_ref_filter_atom(sp + 2, ep), &atomv);
63d89fbc 1805 atomv->handler(atomv, &state);
c95b7585
KN
1806 }
1807 if (*cp) {
1808 sp = cp + strlen(cp);
574e96a2 1809 append_literal(cp, sp, &state);
c95b7585
KN
1810 }
1811 if (need_color_reset_at_eol) {
1812 struct atom_value resetv;
1813 char color[COLOR_MAXLEN] = "";
1814
1815 if (color_parse("reset", color) < 0)
1816 die("BUG: couldn't parse 'reset' as a color");
1817 resetv.s = color;
574e96a2 1818 append_atom(&resetv, &state);
c95b7585 1819 }
ce592082
KN
1820 if (state.stack->prev)
1821 die(_("format: %%(end) atom missing"));
574e96a2
KN
1822 final_buf = &state.stack->output;
1823 fwrite(final_buf->buf, 1, final_buf->len, stdout);
1824 pop_stack_element(&state.stack);
c95b7585
KN
1825 putchar('\n');
1826}
1827
1828/* If no sorting option is given, use refname to sort as default */
1829struct ref_sorting *ref_default_sorting(void)
1830{
1831 static const char cstr_name[] = "refname";
1832
1833 struct ref_sorting *sorting = xcalloc(1, sizeof(*sorting));
1834
1835 sorting->next = NULL;
1836 sorting->atom = parse_ref_filter_atom(cstr_name, cstr_name + strlen(cstr_name));
1837 return sorting;
1838}
1839
1840int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset)
1841{
1842 struct ref_sorting **sorting_tail = opt->value;
1843 struct ref_sorting *s;
1844 int len;
1845
1846 if (!arg) /* should --no-sort void the list ? */
1847 return -1;
1848
1849 s = xcalloc(1, sizeof(*s));
1850 s->next = *sorting_tail;
1851 *sorting_tail = s;
1852
1853 if (*arg == '-') {
1854 s->reverse = 1;
1855 arg++;
1856 }
90c00408
KN
1857 if (skip_prefix(arg, "version:", &arg) ||
1858 skip_prefix(arg, "v:", &arg))
1859 s->version = 1;
c95b7585
KN
1860 len = strlen(arg);
1861 s->atom = parse_ref_filter_atom(arg, arg+len);
1862 return 0;
1863}
5afcb905
KN
1864
1865int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)
1866{
1867 struct ref_filter *rf = opt->value;
1868 unsigned char sha1[20];
1869
1870 rf->merge = starts_with(opt->long_name, "no")
1871 ? REF_FILTER_MERGED_OMIT
1872 : REF_FILTER_MERGED_INCLUDE;
1873
1874 if (get_sha1(arg, sha1))
1875 die(_("malformed object name %s"), arg);
1876
1877 rf->merge_commit = lookup_commit_reference_gently(sha1, 0);
1878 if (!rf->merge_commit)
1879 return opterror(opt, "must point to a commit", 0);
1880
1881 return 0;
1882}