3 #include "parse-options.h"
11 #include "ref-filter.h"
14 #include "git-compat-util.h"
17 #include "wt-status.h"
19 typedef enum { FIELD_STR
, FIELD_ULONG
, FIELD_TIME
} cmp_type
;
20 typedef enum { COMPARE_EQUAL
, COMPARE_UNEQUAL
, COMPARE_NONE
} cmp_status
;
28 cmp_status cmp_status
;
30 unsigned int then_atom_seen
: 1,
32 condition_satisfied
: 1;
36 enum { R_NORMAL
, R_SHORT
, R_STRIP
} option
;
41 * An atom is a valid field atom listed below, possibly prefixed with
42 * a "*" to denote deref_tag().
44 * We parse given format string and sort specifiers, and make a list
45 * of properties that we need to extract out of objects. ref_array_item
46 * structure will hold an array of values extracted that can be
47 * indexed with the "atom number", which is an index into this
50 static struct used_atom
{
54 char color
[COLOR_MAXLEN
];
57 enum { RR_NORMAL
, RR_SHORTEN
, RR_TRACK
, RR_TRACKSHORT
} option
;
58 unsigned int nobracket
: 1;
61 enum { C_BARE
, C_BODY
, C_BODY_DEP
, C_LINES
, C_SIG
, C_SUB
, C_TRAILERS
} option
;
65 cmp_status cmp_status
;
69 enum { O_FULL
, O_LENGTH
, O_SHORT
} option
;
72 struct refname_atom refname
;
75 static int used_atom_cnt
, need_tagged
, need_symref
;
76 static int need_color_reset_at_eol
;
78 static void color_atom_parser(struct used_atom
*atom
, const char *color_value
)
81 die(_("expected format: %%(color:<color>)"));
82 if (color_parse(color_value
, atom
->u
.color
) < 0)
83 die(_("unrecognized color: %%(color:%s)"), color_value
);
86 static void refname_atom_parser_internal(struct refname_atom
*atom
,
87 const char *arg
, const char *name
)
90 atom
->option
= R_NORMAL
;
91 else if (!strcmp(arg
, "short"))
92 atom
->option
= R_SHORT
;
93 else if (skip_prefix(arg
, "strip=", &arg
)) {
94 atom
->option
= R_STRIP
;
95 if (strtoul_ui(arg
, 10, &atom
->strip
) || atom
->strip
<= 0)
96 die(_("positive value expected refname:strip=%s"), arg
);
98 die(_("unrecognized %%(%s) argument: %s"), name
, arg
);
101 static void remote_ref_atom_parser(struct used_atom
*atom
, const char *arg
)
103 struct string_list params
= STRING_LIST_INIT_DUP
;
107 atom
->u
.remote_ref
.option
= RR_NORMAL
;
111 atom
->u
.remote_ref
.nobracket
= 0;
112 string_list_split(¶ms
, arg
, ',', -1);
114 for (i
= 0; i
< params
.nr
; i
++) {
115 const char *s
= params
.items
[i
].string
;
117 if (!strcmp(s
, "short"))
118 atom
->u
.remote_ref
.option
= RR_SHORTEN
;
119 else if (!strcmp(s
, "track"))
120 atom
->u
.remote_ref
.option
= RR_TRACK
;
121 else if (!strcmp(s
, "trackshort"))
122 atom
->u
.remote_ref
.option
= RR_TRACKSHORT
;
123 else if (!strcmp(s
, "nobracket"))
124 atom
->u
.remote_ref
.nobracket
= 1;
126 die(_("unrecognized format: %%(%s)"), atom
->name
);
129 string_list_clear(¶ms
, 0);
132 static void body_atom_parser(struct used_atom
*atom
, const char *arg
)
135 die(_("%%(body) does not take arguments"));
136 atom
->u
.contents
.option
= C_BODY_DEP
;
139 static void subject_atom_parser(struct used_atom
*atom
, const char *arg
)
142 die(_("%%(subject) does not take arguments"));
143 atom
->u
.contents
.option
= C_SUB
;
146 static void trailers_atom_parser(struct used_atom
*atom
, const char *arg
)
149 die(_("%%(trailers) does not take arguments"));
150 atom
->u
.contents
.option
= C_TRAILERS
;
153 static void contents_atom_parser(struct used_atom
*atom
, const char *arg
)
156 atom
->u
.contents
.option
= C_BARE
;
157 else if (!strcmp(arg
, "body"))
158 atom
->u
.contents
.option
= C_BODY
;
159 else if (!strcmp(arg
, "signature"))
160 atom
->u
.contents
.option
= C_SIG
;
161 else if (!strcmp(arg
, "subject"))
162 atom
->u
.contents
.option
= C_SUB
;
163 else if (!strcmp(arg
, "trailers"))
164 atom
->u
.contents
.option
= C_TRAILERS
;
165 else if (skip_prefix(arg
, "lines=", &arg
)) {
166 atom
->u
.contents
.option
= C_LINES
;
167 if (strtoul_ui(arg
, 10, &atom
->u
.contents
.nlines
))
168 die(_("positive value expected contents:lines=%s"), arg
);
170 die(_("unrecognized %%(contents) argument: %s"), arg
);
173 static void objectname_atom_parser(struct used_atom
*atom
, const char *arg
)
176 atom
->u
.objectname
.option
= O_FULL
;
177 else if (!strcmp(arg
, "short"))
178 atom
->u
.objectname
.option
= O_SHORT
;
179 else if (skip_prefix(arg
, "short=", &arg
)) {
180 atom
->u
.objectname
.option
= O_LENGTH
;
181 if (strtoul_ui(arg
, 10, &atom
->u
.objectname
.length
) ||
182 atom
->u
.objectname
.length
== 0)
183 die(_("positive value expected objectname:short=%s"), arg
);
184 if (atom
->u
.objectname
.length
< MINIMUM_ABBREV
)
185 atom
->u
.objectname
.length
= MINIMUM_ABBREV
;
187 die(_("unrecognized %%(objectname) argument: %s"), arg
);
190 static void refname_atom_parser(struct used_atom
*atom
, const char *arg
)
192 return refname_atom_parser_internal(&atom
->u
.refname
, arg
, atom
->name
);
195 static align_type
parse_align_position(const char *s
)
197 if (!strcmp(s
, "right"))
199 else if (!strcmp(s
, "middle"))
201 else if (!strcmp(s
, "left"))
206 static void align_atom_parser(struct used_atom
*atom
, const char *arg
)
208 struct align
*align
= &atom
->u
.align
;
209 struct string_list params
= STRING_LIST_INIT_DUP
;
211 unsigned int width
= ~0U;
214 die(_("expected format: %%(align:<width>,<position>)"));
216 align
->position
= ALIGN_LEFT
;
218 string_list_split(¶ms
, arg
, ',', -1);
219 for (i
= 0; i
< params
.nr
; i
++) {
220 const char *s
= params
.items
[i
].string
;
223 if (skip_prefix(s
, "position=", &s
)) {
224 position
= parse_align_position(s
);
226 die(_("unrecognized position:%s"), s
);
227 align
->position
= position
;
228 } else if (skip_prefix(s
, "width=", &s
)) {
229 if (strtoul_ui(s
, 10, &width
))
230 die(_("unrecognized width:%s"), s
);
231 } else if (!strtoul_ui(s
, 10, &width
))
233 else if ((position
= parse_align_position(s
)) >= 0)
234 align
->position
= position
;
236 die(_("unrecognized %%(align) argument: %s"), s
);
240 die(_("positive width expected with the %%(align) atom"));
241 align
->width
= width
;
242 string_list_clear(¶ms
, 0);
245 static void if_atom_parser(struct used_atom
*atom
, const char *arg
)
248 atom
->u
.if_then_else
.cmp_status
= COMPARE_NONE
;
250 } else if (skip_prefix(arg
, "equals=", &atom
->u
.if_then_else
.str
)) {
251 atom
->u
.if_then_else
.cmp_status
= COMPARE_EQUAL
;
252 } else if (skip_prefix(arg
, "notequals=", &atom
->u
.if_then_else
.str
)) {
253 atom
->u
.if_then_else
.cmp_status
= COMPARE_UNEQUAL
;
255 die(_("unrecognized %%(if) argument: %s"), arg
);
263 void (*parser
)(struct used_atom
*atom
, const char *arg
);
265 { "refname" , FIELD_STR
, refname_atom_parser
},
267 { "objectsize", FIELD_ULONG
},
268 { "objectname", FIELD_STR
, objectname_atom_parser
},
271 { "numparent", FIELD_ULONG
},
278 { "authordate", FIELD_TIME
},
281 { "committeremail" },
282 { "committerdate", FIELD_TIME
},
286 { "taggerdate", FIELD_TIME
},
288 { "creatordate", FIELD_TIME
},
289 { "subject", FIELD_STR
, subject_atom_parser
},
290 { "body", FIELD_STR
, body_atom_parser
},
291 { "trailers", FIELD_STR
, trailers_atom_parser
},
292 { "contents", FIELD_STR
, contents_atom_parser
},
293 { "upstream", FIELD_STR
, remote_ref_atom_parser
},
294 { "push", FIELD_STR
, remote_ref_atom_parser
},
295 { "symref", FIELD_STR
, refname_atom_parser
},
298 { "color", FIELD_STR
, color_atom_parser
},
299 { "align", FIELD_STR
, align_atom_parser
},
301 { "if", FIELD_STR
, if_atom_parser
},
306 #define REF_FORMATTING_STATE_INIT { 0, NULL }
308 struct ref_formatting_stack
{
309 struct ref_formatting_stack
*prev
;
310 struct strbuf output
;
311 void (*at_end
)(struct ref_formatting_stack
**stack
);
315 struct ref_formatting_state
{
317 struct ref_formatting_stack
*stack
;
322 void (*handler
)(struct atom_value
*atomv
, struct ref_formatting_state
*state
);
323 unsigned long ul
; /* used for sorting when not FIELD_STR */
324 struct used_atom
*atom
;
328 * Used to parse format string and sort specifiers
330 int parse_ref_filter_atom(const char *atom
, const char *ep
)
337 if (*sp
== '*' && sp
< ep
)
340 die(_("malformed field name: %.*s"), (int)(ep
-atom
), atom
);
342 /* Do we have the atom already used elsewhere? */
343 for (i
= 0; i
< used_atom_cnt
; i
++) {
344 int len
= strlen(used_atom
[i
].name
);
345 if (len
== ep
- atom
&& !memcmp(used_atom
[i
].name
, atom
, len
))
350 * If the atom name has a colon, strip it and everything after
351 * it off - it specifies the format for this entry, and
352 * shouldn't be used for checking against the valid_atom
355 arg
= memchr(sp
, ':', ep
- sp
);
356 atom_len
= (arg
? arg
: ep
) - sp
;
358 /* Is the atom a valid one? */
359 for (i
= 0; i
< ARRAY_SIZE(valid_atom
); i
++) {
360 int len
= strlen(valid_atom
[i
].name
);
361 if (len
== atom_len
&& !memcmp(valid_atom
[i
].name
, sp
, len
))
365 if (ARRAY_SIZE(valid_atom
) <= i
)
366 die(_("unknown field name: %.*s"), (int)(ep
-atom
), atom
);
368 /* Add it in, including the deref prefix */
371 REALLOC_ARRAY(used_atom
, used_atom_cnt
);
372 used_atom
[at
].name
= xmemdupz(atom
, ep
- atom
);
373 used_atom
[at
].type
= valid_atom
[i
].cmp_type
;
375 arg
= used_atom
[at
].name
+ (arg
- atom
) + 1;
376 memset(&used_atom
[at
].u
, 0, sizeof(used_atom
[at
].u
));
377 if (valid_atom
[i
].parser
)
378 valid_atom
[i
].parser(&used_atom
[at
], arg
);
381 if (!strcmp(valid_atom
[i
].name
, "symref"))
386 static void quote_formatting(struct strbuf
*s
, const char *str
, int quote_style
)
388 switch (quote_style
) {
390 strbuf_addstr(s
, str
);
393 sq_quote_buf(s
, str
);
396 perl_quote_buf(s
, str
);
399 python_quote_buf(s
, str
);
402 tcl_quote_buf(s
, str
);
407 static void append_atom(struct atom_value
*v
, struct ref_formatting_state
*state
)
410 * Quote formatting is only done when the stack has a single
411 * element. Otherwise quote formatting is done on the
412 * element's entire output strbuf when the %(end) atom is
415 if (!state
->stack
->prev
)
416 quote_formatting(&state
->stack
->output
, v
->s
, state
->quote_style
);
418 strbuf_addstr(&state
->stack
->output
, v
->s
);
421 static void push_stack_element(struct ref_formatting_stack
**stack
)
423 struct ref_formatting_stack
*s
= xcalloc(1, sizeof(struct ref_formatting_stack
));
425 strbuf_init(&s
->output
, 0);
430 static void pop_stack_element(struct ref_formatting_stack
**stack
)
432 struct ref_formatting_stack
*current
= *stack
;
433 struct ref_formatting_stack
*prev
= current
->prev
;
436 strbuf_addbuf(&prev
->output
, ¤t
->output
);
437 strbuf_release(¤t
->output
);
442 static void end_align_handler(struct ref_formatting_stack
**stack
)
444 struct ref_formatting_stack
*cur
= *stack
;
445 struct align
*align
= (struct align
*)cur
->at_end_data
;
446 struct strbuf s
= STRBUF_INIT
;
448 strbuf_utf8_align(&s
, align
->position
, align
->width
, cur
->output
.buf
);
449 strbuf_swap(&cur
->output
, &s
);
453 static void align_atom_handler(struct atom_value
*atomv
, struct ref_formatting_state
*state
)
455 struct ref_formatting_stack
*new;
457 push_stack_element(&state
->stack
);
459 new->at_end
= end_align_handler
;
460 new->at_end_data
= &atomv
->atom
->u
.align
;
463 static void if_then_else_handler(struct ref_formatting_stack
**stack
)
465 struct ref_formatting_stack
*cur
= *stack
;
466 struct ref_formatting_stack
*prev
= cur
->prev
;
467 struct if_then_else
*if_then_else
= (struct if_then_else
*)cur
->at_end_data
;
469 if (!if_then_else
->then_atom_seen
)
470 die(_("format: %%(if) atom used without a %%(then) atom"));
472 if (if_then_else
->else_atom_seen
) {
474 * There is an %(else) atom: we need to drop one state from the
475 * stack, either the %(else) branch if the condition is satisfied, or
476 * the %(then) branch if it isn't.
478 if (if_then_else
->condition_satisfied
) {
479 strbuf_reset(&cur
->output
);
480 pop_stack_element(&cur
);
482 strbuf_swap(&cur
->output
, &prev
->output
);
483 strbuf_reset(&cur
->output
);
484 pop_stack_element(&cur
);
486 } else if (!if_then_else
->condition_satisfied
) {
488 * No %(else) atom: just drop the %(then) branch if the
489 * condition is not satisfied.
491 strbuf_reset(&cur
->output
);
498 static void if_atom_handler(struct atom_value
*atomv
, struct ref_formatting_state
*state
)
500 struct ref_formatting_stack
*new;
501 struct if_then_else
*if_then_else
= xcalloc(sizeof(struct if_then_else
), 1);
503 if_then_else
->str
= atomv
->atom
->u
.if_then_else
.str
;
504 if_then_else
->cmp_status
= atomv
->atom
->u
.if_then_else
.cmp_status
;
506 push_stack_element(&state
->stack
);
508 new->at_end
= if_then_else_handler
;
509 new->at_end_data
= if_then_else
;
512 static int is_empty(const char *s
)
522 static void then_atom_handler(struct atom_value
*atomv
, struct ref_formatting_state
*state
)
524 struct ref_formatting_stack
*cur
= state
->stack
;
525 struct if_then_else
*if_then_else
= NULL
;
527 if (cur
->at_end
== if_then_else_handler
)
528 if_then_else
= (struct if_then_else
*)cur
->at_end_data
;
530 die(_("format: %%(then) atom used without an %%(if) atom"));
531 if (if_then_else
->then_atom_seen
)
532 die(_("format: %%(then) atom used more than once"));
533 if (if_then_else
->else_atom_seen
)
534 die(_("format: %%(then) atom used after %%(else)"));
535 if_then_else
->then_atom_seen
= 1;
537 * If the 'equals' or 'notequals' attribute is used then
538 * perform the required comparison. If not, only non-empty
539 * strings satisfy the 'if' condition.
541 if (if_then_else
->cmp_status
== COMPARE_EQUAL
) {
542 if (!strcmp(if_then_else
->str
, cur
->output
.buf
))
543 if_then_else
->condition_satisfied
= 1;
544 } else if (if_then_else
->cmp_status
== COMPARE_UNEQUAL
) {
545 if (strcmp(if_then_else
->str
, cur
->output
.buf
))
546 if_then_else
->condition_satisfied
= 1;
547 } else if (cur
->output
.len
&& !is_empty(cur
->output
.buf
))
548 if_then_else
->condition_satisfied
= 1;
549 strbuf_reset(&cur
->output
);
552 static void else_atom_handler(struct atom_value
*atomv
, struct ref_formatting_state
*state
)
554 struct ref_formatting_stack
*prev
= state
->stack
;
555 struct if_then_else
*if_then_else
= NULL
;
557 if (prev
->at_end
== if_then_else_handler
)
558 if_then_else
= (struct if_then_else
*)prev
->at_end_data
;
560 die(_("format: %%(else) atom used without an %%(if) atom"));
561 if (!if_then_else
->then_atom_seen
)
562 die(_("format: %%(else) atom used without a %%(then) atom"));
563 if (if_then_else
->else_atom_seen
)
564 die(_("format: %%(else) atom used more than once"));
565 if_then_else
->else_atom_seen
= 1;
566 push_stack_element(&state
->stack
);
567 state
->stack
->at_end_data
= prev
->at_end_data
;
568 state
->stack
->at_end
= prev
->at_end
;
571 static void end_atom_handler(struct atom_value
*atomv
, struct ref_formatting_state
*state
)
573 struct ref_formatting_stack
*current
= state
->stack
;
574 struct strbuf s
= STRBUF_INIT
;
576 if (!current
->at_end
)
577 die(_("format: %%(end) atom used without corresponding atom"));
578 current
->at_end(&state
->stack
);
580 /* Stack may have been popped within at_end(), hence reset the current pointer */
581 current
= state
->stack
;
584 * Perform quote formatting when the stack element is that of
585 * a supporting atom. If nested then perform quote formatting
586 * only on the topmost supporting atom.
588 if (!current
->prev
->prev
) {
589 quote_formatting(&s
, current
->output
.buf
, state
->quote_style
);
590 strbuf_swap(¤t
->output
, &s
);
593 pop_stack_element(&state
->stack
);
597 * In a format string, find the next occurrence of %(atom).
599 static const char *find_next(const char *cp
)
604 * %( is the start of an atom;
605 * %% is a quoted per-cent.
609 else if (cp
[1] == '%')
610 cp
++; /* skip over two % */
611 /* otherwise this is a singleton, literal % */
619 * Make sure the format string is well formed, and parse out
622 int verify_ref_format(const char *format
)
626 need_color_reset_at_eol
= 0;
627 for (cp
= format
; *cp
&& (sp
= find_next(cp
)); ) {
628 const char *color
, *ep
= strchr(sp
, ')');
632 return error(_("malformed format string %s"), sp
);
633 /* sp points at "%(" and ep points at the closing ")" */
634 at
= parse_ref_filter_atom(sp
+ 2, ep
);
637 if (skip_prefix(used_atom
[at
].name
, "color:", &color
))
638 need_color_reset_at_eol
= !!strcmp(color
, "reset");
644 * Given an object name, read the object data and size, and return a
645 * "struct object". If the object data we are returning is also borrowed
646 * by the "struct object" representation, set *eaten as well---it is a
647 * signal from parse_object_buffer to us not to free the buffer.
649 static void *get_obj(const unsigned char *sha1
, struct object
**obj
, unsigned long *sz
, int *eaten
)
651 enum object_type type
;
652 void *buf
= read_sha1_file(sha1
, &type
, sz
);
655 *obj
= parse_object_buffer(sha1
, type
, *sz
, buf
, eaten
);
661 static int grab_objectname(const char *name
, const unsigned char *sha1
,
662 struct atom_value
*v
, struct used_atom
*atom
)
664 if (starts_with(name
, "objectname")) {
665 if (atom
->u
.objectname
.option
== O_SHORT
) {
666 v
->s
= xstrdup(find_unique_abbrev(sha1
, DEFAULT_ABBREV
));
668 } else if (atom
->u
.objectname
.option
== O_FULL
) {
669 v
->s
= xstrdup(sha1_to_hex(sha1
));
671 } else if (atom
->u
.objectname
.option
== O_LENGTH
) {
672 v
->s
= xstrdup(find_unique_abbrev(sha1
, atom
->u
.objectname
.length
));
675 die("BUG: unknown %%(objectname) option");
680 /* See grab_values */
681 static void grab_common_values(struct atom_value
*val
, int deref
, struct object
*obj
, void *buf
, unsigned long sz
)
685 for (i
= 0; i
< used_atom_cnt
; i
++) {
686 const char *name
= used_atom
[i
].name
;
687 struct atom_value
*v
= &val
[i
];
688 if (!!deref
!= (*name
== '*'))
692 if (!strcmp(name
, "objecttype"))
693 v
->s
= typename(obj
->type
);
694 else if (!strcmp(name
, "objectsize")) {
696 v
->s
= xstrfmt("%lu", sz
);
699 grab_objectname(name
, obj
->oid
.hash
, v
, &used_atom
[i
]);
703 /* See grab_values */
704 static void grab_tag_values(struct atom_value
*val
, int deref
, struct object
*obj
, void *buf
, unsigned long sz
)
707 struct tag
*tag
= (struct tag
*) obj
;
709 for (i
= 0; i
< used_atom_cnt
; i
++) {
710 const char *name
= used_atom
[i
].name
;
711 struct atom_value
*v
= &val
[i
];
712 if (!!deref
!= (*name
== '*'))
716 if (!strcmp(name
, "tag"))
718 else if (!strcmp(name
, "type") && tag
->tagged
)
719 v
->s
= typename(tag
->tagged
->type
);
720 else if (!strcmp(name
, "object") && tag
->tagged
)
721 v
->s
= xstrdup(oid_to_hex(&tag
->tagged
->oid
));
725 /* See grab_values */
726 static void grab_commit_values(struct atom_value
*val
, int deref
, struct object
*obj
, void *buf
, unsigned long sz
)
729 struct commit
*commit
= (struct commit
*) obj
;
731 for (i
= 0; i
< used_atom_cnt
; i
++) {
732 const char *name
= used_atom
[i
].name
;
733 struct atom_value
*v
= &val
[i
];
734 if (!!deref
!= (*name
== '*'))
738 if (!strcmp(name
, "tree")) {
739 v
->s
= xstrdup(oid_to_hex(&commit
->tree
->object
.oid
));
741 else if (!strcmp(name
, "numparent")) {
742 v
->ul
= commit_list_count(commit
->parents
);
743 v
->s
= xstrfmt("%lu", v
->ul
);
745 else if (!strcmp(name
, "parent")) {
746 struct commit_list
*parents
;
747 struct strbuf s
= STRBUF_INIT
;
748 for (parents
= commit
->parents
; parents
; parents
= parents
->next
) {
749 struct commit
*parent
= parents
->item
;
750 if (parents
!= commit
->parents
)
751 strbuf_addch(&s
, ' ');
752 strbuf_addstr(&s
, oid_to_hex(&parent
->object
.oid
));
754 v
->s
= strbuf_detach(&s
, NULL
);
759 static const char *find_wholine(const char *who
, int wholen
, const char *buf
, unsigned long sz
)
763 if (!strncmp(buf
, who
, wholen
) &&
765 return buf
+ wholen
+ 1;
766 eol
= strchr(buf
, '\n');
771 return ""; /* end of header */
777 static const char *copy_line(const char *buf
)
779 const char *eol
= strchrnul(buf
, '\n');
780 return xmemdupz(buf
, eol
- buf
);
783 static const char *copy_name(const char *buf
)
786 for (cp
= buf
; *cp
&& *cp
!= '\n'; cp
++) {
787 if (!strncmp(cp
, " <", 2))
788 return xmemdupz(buf
, cp
- buf
);
793 static const char *copy_email(const char *buf
)
795 const char *email
= strchr(buf
, '<');
799 eoemail
= strchr(email
, '>');
802 return xmemdupz(email
, eoemail
+ 1 - email
);
805 static char *copy_subject(const char *buf
, unsigned long len
)
807 char *r
= xmemdupz(buf
, len
);
810 for (i
= 0; i
< len
; i
++)
817 static void grab_date(const char *buf
, struct atom_value
*v
, const char *atomname
)
819 const char *eoemail
= strstr(buf
, "> ");
821 unsigned long timestamp
;
823 struct date_mode date_mode
= { DATE_NORMAL
};
827 * We got here because atomname ends in "date" or "date<something>";
828 * it's not possible that <something> is not ":<format>" because
829 * parse_ref_filter_atom() wouldn't have allowed it, so we can assume that no
830 * ":" means no format is specified, and use the default.
832 formatp
= strchr(atomname
, ':');
833 if (formatp
!= NULL
) {
835 parse_date_format(formatp
, &date_mode
);
840 timestamp
= strtoul(eoemail
+ 2, &zone
, 10);
841 if (timestamp
== ULONG_MAX
)
843 tz
= strtol(zone
, NULL
, 10);
844 if ((tz
== LONG_MIN
|| tz
== LONG_MAX
) && errno
== ERANGE
)
846 v
->s
= xstrdup(show_date(timestamp
, tz
, &date_mode
));
854 /* See grab_values */
855 static void grab_person(const char *who
, struct atom_value
*val
, int deref
, struct object
*obj
, void *buf
, unsigned long sz
)
858 int wholen
= strlen(who
);
859 const char *wholine
= NULL
;
861 for (i
= 0; i
< used_atom_cnt
; i
++) {
862 const char *name
= used_atom
[i
].name
;
863 struct atom_value
*v
= &val
[i
];
864 if (!!deref
!= (*name
== '*'))
868 if (strncmp(who
, name
, wholen
))
870 if (name
[wholen
] != 0 &&
871 strcmp(name
+ wholen
, "name") &&
872 strcmp(name
+ wholen
, "email") &&
873 !starts_with(name
+ wholen
, "date"))
876 wholine
= find_wholine(who
, wholen
, buf
, sz
);
878 return; /* no point looking for it */
879 if (name
[wholen
] == 0)
880 v
->s
= copy_line(wholine
);
881 else if (!strcmp(name
+ wholen
, "name"))
882 v
->s
= copy_name(wholine
);
883 else if (!strcmp(name
+ wholen
, "email"))
884 v
->s
= copy_email(wholine
);
885 else if (starts_with(name
+ wholen
, "date"))
886 grab_date(wholine
, v
, name
);
890 * For a tag or a commit object, if "creator" or "creatordate" is
891 * requested, do something special.
893 if (strcmp(who
, "tagger") && strcmp(who
, "committer"))
894 return; /* "author" for commit object is not wanted */
896 wholine
= find_wholine(who
, wholen
, buf
, sz
);
899 for (i
= 0; i
< used_atom_cnt
; i
++) {
900 const char *name
= used_atom
[i
].name
;
901 struct atom_value
*v
= &val
[i
];
902 if (!!deref
!= (*name
== '*'))
907 if (starts_with(name
, "creatordate"))
908 grab_date(wholine
, v
, name
);
909 else if (!strcmp(name
, "creator"))
910 v
->s
= copy_line(wholine
);
914 static void find_subpos(const char *buf
, unsigned long sz
,
915 const char **sub
, unsigned long *sublen
,
916 const char **body
, unsigned long *bodylen
,
917 unsigned long *nonsiglen
,
918 const char **sig
, unsigned long *siglen
)
921 /* skip past header until we hit empty line */
922 while (*buf
&& *buf
!= '\n') {
923 eol
= strchrnul(buf
, '\n');
928 /* skip any empty lines */
932 /* parse signature first; we might not even have a subject line */
933 *sig
= buf
+ parse_signature(buf
, strlen(buf
));
934 *siglen
= strlen(*sig
);
936 /* subject is first non-empty line */
938 /* subject goes to first empty line */
939 while (buf
< *sig
&& *buf
&& *buf
!= '\n') {
940 eol
= strchrnul(buf
, '\n');
945 *sublen
= buf
- *sub
;
946 /* drop trailing newline, if present */
947 if (*sublen
&& (*sub
)[*sublen
- 1] == '\n')
950 /* skip any empty lines */
954 *bodylen
= strlen(buf
);
955 *nonsiglen
= *sig
- buf
;
959 * If 'lines' is greater than 0, append that many lines from the given
960 * 'buf' of length 'size' to the given strbuf.
962 static void append_lines(struct strbuf
*out
, const char *buf
, unsigned long size
, int lines
)
965 const char *sp
, *eol
;
970 for (i
= 0; i
< lines
&& sp
< buf
+ size
; i
++) {
972 strbuf_addstr(out
, "\n ");
973 eol
= memchr(sp
, '\n', size
- (sp
- buf
));
974 len
= eol
? eol
- sp
: size
- (sp
- buf
);
975 strbuf_add(out
, sp
, len
);
982 /* See grab_values */
983 static void grab_sub_body_contents(struct atom_value
*val
, int deref
, struct object
*obj
, void *buf
, unsigned long sz
)
986 const char *subpos
= NULL
, *bodypos
= NULL
, *sigpos
= NULL
;
987 unsigned long sublen
= 0, bodylen
= 0, nonsiglen
= 0, siglen
= 0;
989 for (i
= 0; i
< used_atom_cnt
; i
++) {
990 struct used_atom
*atom
= &used_atom
[i
];
991 const char *name
= atom
->name
;
992 struct atom_value
*v
= &val
[i
];
993 if (!!deref
!= (*name
== '*'))
997 if (strcmp(name
, "subject") &&
998 strcmp(name
, "body") &&
999 strcmp(name
, "trailers") &&
1000 !starts_with(name
, "contents"))
1003 find_subpos(buf
, sz
,
1005 &bodypos
, &bodylen
, &nonsiglen
,
1008 if (atom
->u
.contents
.option
== C_SUB
)
1009 v
->s
= copy_subject(subpos
, sublen
);
1010 else if (atom
->u
.contents
.option
== C_BODY_DEP
)
1011 v
->s
= xmemdupz(bodypos
, bodylen
);
1012 else if (atom
->u
.contents
.option
== C_BODY
)
1013 v
->s
= xmemdupz(bodypos
, nonsiglen
);
1014 else if (atom
->u
.contents
.option
== C_SIG
)
1015 v
->s
= xmemdupz(sigpos
, siglen
);
1016 else if (atom
->u
.contents
.option
== C_LINES
) {
1017 struct strbuf s
= STRBUF_INIT
;
1018 const char *contents_end
= bodylen
+ bodypos
- siglen
;
1020 /* Size is the length of the message after removing the signature */
1021 append_lines(&s
, subpos
, contents_end
- subpos
, atom
->u
.contents
.nlines
);
1022 v
->s
= strbuf_detach(&s
, NULL
);
1023 } else if (atom
->u
.contents
.option
== C_TRAILERS
) {
1024 struct trailer_info info
;
1026 /* Search for trailer info */
1027 trailer_info_get(&info
, subpos
);
1028 v
->s
= xmemdupz(info
.trailer_start
,
1029 info
.trailer_end
- info
.trailer_start
);
1030 trailer_info_release(&info
);
1031 } else if (atom
->u
.contents
.option
== C_BARE
)
1032 v
->s
= xstrdup(subpos
);
1037 * We want to have empty print-string for field requests
1038 * that do not apply (e.g. "authordate" for a tag object)
1040 static void fill_missing_values(struct atom_value
*val
)
1043 for (i
= 0; i
< used_atom_cnt
; i
++) {
1044 struct atom_value
*v
= &val
[i
];
1051 * val is a list of atom_value to hold returned values. Extract
1052 * the values for atoms in used_atom array out of (obj, buf, sz).
1053 * when deref is false, (obj, buf, sz) is the object that is
1054 * pointed at by the ref itself; otherwise it is the object the
1055 * ref (which is a tag) refers to.
1057 static void grab_values(struct atom_value
*val
, int deref
, struct object
*obj
, void *buf
, unsigned long sz
)
1059 grab_common_values(val
, deref
, obj
, buf
, sz
);
1060 switch (obj
->type
) {
1062 grab_tag_values(val
, deref
, obj
, buf
, sz
);
1063 grab_sub_body_contents(val
, deref
, obj
, buf
, sz
);
1064 grab_person("tagger", val
, deref
, obj
, buf
, sz
);
1067 grab_commit_values(val
, deref
, obj
, buf
, sz
);
1068 grab_sub_body_contents(val
, deref
, obj
, buf
, sz
);
1069 grab_person("author", val
, deref
, obj
, buf
, sz
);
1070 grab_person("committer", val
, deref
, obj
, buf
, sz
);
1073 /* grab_tree_values(val, deref, obj, buf, sz); */
1076 /* grab_blob_values(val, deref, obj, buf, sz); */
1079 die("Eh? Object of type %d?", obj
->type
);
1083 static inline char *copy_advance(char *dst
, const char *src
)
1090 static const char *strip_ref_components(const char *refname
, unsigned int len
)
1092 long remaining
= len
;
1093 const char *start
= refname
;
1098 die(_("ref '%s' does not have %ud components to :strip"),
1108 static const char *show_ref(struct refname_atom
*atom
, const char *refname
)
1110 if (atom
->option
== R_SHORT
)
1111 return shorten_unambiguous_ref(refname
, warn_ambiguous_refs
);
1112 else if (atom
->option
== R_STRIP
)
1113 return strip_ref_components(refname
, atom
->strip
);
1118 static void fill_remote_ref_details(struct used_atom
*atom
, const char *refname
,
1119 struct branch
*branch
, const char **s
)
1121 int num_ours
, num_theirs
;
1122 if (atom
->u
.remote_ref
.option
== RR_SHORTEN
)
1123 *s
= shorten_unambiguous_ref(refname
, warn_ambiguous_refs
);
1124 else if (atom
->u
.remote_ref
.option
== RR_TRACK
) {
1125 if (stat_tracking_info(branch
, &num_ours
,
1126 &num_theirs
, NULL
)) {
1127 *s
= xstrdup("gone");
1128 } else if (!num_ours
&& !num_theirs
)
1131 *s
= xstrfmt("behind %d", num_theirs
);
1132 else if (!num_theirs
)
1133 *s
= xstrfmt("ahead %d", num_ours
);
1135 *s
= xstrfmt("ahead %d, behind %d",
1136 num_ours
, num_theirs
);
1137 if (!atom
->u
.remote_ref
.nobracket
&& *s
[0]) {
1138 const char *to_free
= *s
;
1139 *s
= xstrfmt("[%s]", *s
);
1140 free((void *)to_free
);
1142 } else if (atom
->u
.remote_ref
.option
== RR_TRACKSHORT
) {
1143 if (stat_tracking_info(branch
, &num_ours
,
1147 if (!num_ours
&& !num_theirs
)
1151 else if (!num_theirs
)
1155 } else /* RR_NORMAL */
1159 char *get_head_description(void)
1161 struct strbuf desc
= STRBUF_INIT
;
1162 struct wt_status_state state
;
1163 memset(&state
, 0, sizeof(state
));
1164 wt_status_get_state(&state
, 1);
1165 if (state
.rebase_in_progress
||
1166 state
.rebase_interactive_in_progress
)
1167 strbuf_addf(&desc
, _("(no branch, rebasing %s)"),
1169 else if (state
.bisect_in_progress
)
1170 strbuf_addf(&desc
, _("(no branch, bisect started on %s)"),
1172 else if (state
.detached_from
) {
1173 /* TRANSLATORS: make sure these match _("HEAD detached at ")
1174 and _("HEAD detached from ") in wt-status.c */
1175 if (state
.detached_at
)
1176 strbuf_addf(&desc
, _("(HEAD detached at %s)"),
1177 state
.detached_from
);
1179 strbuf_addf(&desc
, _("(HEAD detached from %s)"),
1180 state
.detached_from
);
1183 strbuf_addstr(&desc
, _("(no branch)"));
1186 free(state
.detached_from
);
1187 return strbuf_detach(&desc
, NULL
);
1190 static const char *get_symref(struct used_atom
*atom
, struct ref_array_item
*ref
)
1195 return show_ref(&atom
->u
.refname
, ref
->symref
);
1198 static const char *get_refname(struct used_atom
*atom
, struct ref_array_item
*ref
)
1200 if (ref
->kind
& FILTER_REFS_DETACHED_HEAD
)
1201 return get_head_description();
1202 return show_ref(&atom
->u
.refname
, ref
->refname
);
1206 * Parse the object referred by ref, and grab needed value.
1208 static void populate_value(struct ref_array_item
*ref
)
1214 const unsigned char *tagged
;
1216 ref
->value
= xcalloc(used_atom_cnt
, sizeof(struct atom_value
));
1218 if (need_symref
&& (ref
->flag
& REF_ISSYMREF
) && !ref
->symref
) {
1219 unsigned char unused1
[20];
1220 ref
->symref
= resolve_refdup(ref
->refname
, RESOLVE_REF_READING
,
1226 /* Fill in specials first */
1227 for (i
= 0; i
< used_atom_cnt
; i
++) {
1228 struct used_atom
*atom
= &used_atom
[i
];
1229 const char *name
= used_atom
[i
].name
;
1230 struct atom_value
*v
= &ref
->value
[i
];
1232 const char *refname
;
1233 struct branch
*branch
= NULL
;
1235 v
->handler
= append_atom
;
1243 if (starts_with(name
, "refname"))
1244 refname
= get_refname(atom
, ref
);
1245 else if (starts_with(name
, "symref"))
1246 refname
= get_symref(atom
, ref
);
1247 else if (starts_with(name
, "upstream")) {
1248 const char *branch_name
;
1249 /* only local branches may have an upstream */
1250 if (!skip_prefix(ref
->refname
, "refs/heads/",
1253 branch
= branch_get(branch_name
);
1255 refname
= branch_get_upstream(branch
, NULL
);
1257 fill_remote_ref_details(atom
, refname
, branch
, &v
->s
);
1259 } else if (starts_with(name
, "push")) {
1260 const char *branch_name
;
1261 if (!skip_prefix(ref
->refname
, "refs/heads/",
1264 branch
= branch_get(branch_name
);
1266 refname
= branch_get_push(branch
, NULL
);
1269 fill_remote_ref_details(atom
, refname
, branch
, &v
->s
);
1271 } else if (starts_with(name
, "color:")) {
1272 v
->s
= atom
->u
.color
;
1274 } else if (!strcmp(name
, "flag")) {
1275 char buf
[256], *cp
= buf
;
1276 if (ref
->flag
& REF_ISSYMREF
)
1277 cp
= copy_advance(cp
, ",symref");
1278 if (ref
->flag
& REF_ISPACKED
)
1279 cp
= copy_advance(cp
, ",packed");
1284 v
->s
= xstrdup(buf
+ 1);
1287 } else if (!deref
&& grab_objectname(name
, ref
->objectname
, v
, atom
)) {
1289 } else if (!strcmp(name
, "HEAD")) {
1291 unsigned char sha1
[20];
1293 head
= resolve_ref_unsafe("HEAD", RESOLVE_REF_READING
,
1295 if (head
&& !strcmp(ref
->refname
, head
))
1300 } else if (starts_with(name
, "align")) {
1301 v
->handler
= align_atom_handler
;
1303 } else if (!strcmp(name
, "end")) {
1304 v
->handler
= end_atom_handler
;
1306 } else if (starts_with(name
, "if")) {
1309 if (skip_prefix(name
, "if:", &s
))
1311 v
->handler
= if_atom_handler
;
1313 } else if (!strcmp(name
, "then")) {
1314 v
->handler
= then_atom_handler
;
1316 } else if (!strcmp(name
, "else")) {
1317 v
->handler
= else_atom_handler
;
1325 v
->s
= xstrfmt("%s^{}", refname
);
1328 for (i
= 0; i
< used_atom_cnt
; i
++) {
1329 struct atom_value
*v
= &ref
->value
[i
];
1336 buf
= get_obj(ref
->objectname
, &obj
, &size
, &eaten
);
1338 die(_("missing object %s for %s"),
1339 sha1_to_hex(ref
->objectname
), ref
->refname
);
1341 die(_("parse_object_buffer failed on %s for %s"),
1342 sha1_to_hex(ref
->objectname
), ref
->refname
);
1344 grab_values(ref
->value
, 0, obj
, buf
, size
);
1349 * If there is no atom that wants to know about tagged
1350 * object, we are done.
1352 if (!need_tagged
|| (obj
->type
!= OBJ_TAG
))
1356 * If it is a tag object, see if we use a value that derefs
1357 * the object, and if we do grab the object it refers to.
1359 tagged
= ((struct tag
*)obj
)->tagged
->oid
.hash
;
1362 * NEEDSWORK: This derefs tag only once, which
1363 * is good to deal with chains of trust, but
1364 * is not consistent with what deref_tag() does
1365 * which peels the onion to the core.
1367 buf
= get_obj(tagged
, &obj
, &size
, &eaten
);
1369 die(_("missing object %s for %s"),
1370 sha1_to_hex(tagged
), ref
->refname
);
1372 die(_("parse_object_buffer failed on %s for %s"),
1373 sha1_to_hex(tagged
), ref
->refname
);
1374 grab_values(ref
->value
, 1, obj
, buf
, size
);
1380 * Given a ref, return the value for the atom. This lazily gets value
1381 * out of the object by calling populate value.
1383 static void get_ref_atom_value(struct ref_array_item
*ref
, int atom
, struct atom_value
**v
)
1386 populate_value(ref
);
1387 fill_missing_values(ref
->value
);
1389 *v
= &ref
->value
[atom
];
1392 enum contains_result
{
1393 CONTAINS_UNKNOWN
= -1,
1399 * Mimicking the real stack, this stack lives on the heap, avoiding stack
1402 * At each recursion step, the stack items points to the commits whose
1403 * ancestors are to be inspected.
1405 struct contains_stack
{
1407 struct contains_stack_entry
{
1408 struct commit
*commit
;
1409 struct commit_list
*parents
;
1413 static int in_commit_list(const struct commit_list
*want
, struct commit
*c
)
1415 for (; want
; want
= want
->next
)
1416 if (!oidcmp(&want
->item
->object
.oid
, &c
->object
.oid
))
1422 * Test whether the candidate or one of its parents is contained in the list.
1423 * Do not recurse to find out, though, but return -1 if inconclusive.
1425 static enum contains_result
contains_test(struct commit
*candidate
,
1426 const struct commit_list
*want
)
1428 /* was it previously marked as containing a want commit? */
1429 if (candidate
->object
.flags
& TMP_MARK
)
1431 /* or marked as not possibly containing a want commit? */
1432 if (candidate
->object
.flags
& UNINTERESTING
)
1435 if (in_commit_list(want
, candidate
)) {
1436 candidate
->object
.flags
|= TMP_MARK
;
1440 if (parse_commit(candidate
) < 0)
1446 static void push_to_contains_stack(struct commit
*candidate
, struct contains_stack
*contains_stack
)
1448 ALLOC_GROW(contains_stack
->contains_stack
, contains_stack
->nr
+ 1, contains_stack
->alloc
);
1449 contains_stack
->contains_stack
[contains_stack
->nr
].commit
= candidate
;
1450 contains_stack
->contains_stack
[contains_stack
->nr
++].parents
= candidate
->parents
;
1453 static enum contains_result
contains_tag_algo(struct commit
*candidate
,
1454 const struct commit_list
*want
)
1456 struct contains_stack contains_stack
= { 0, 0, NULL
};
1457 int result
= contains_test(candidate
, want
);
1459 if (result
!= CONTAINS_UNKNOWN
)
1462 push_to_contains_stack(candidate
, &contains_stack
);
1463 while (contains_stack
.nr
) {
1464 struct contains_stack_entry
*entry
= &contains_stack
.contains_stack
[contains_stack
.nr
- 1];
1465 struct commit
*commit
= entry
->commit
;
1466 struct commit_list
*parents
= entry
->parents
;
1469 commit
->object
.flags
|= UNINTERESTING
;
1470 contains_stack
.nr
--;
1473 * If we just popped the stack, parents->item has been marked,
1474 * therefore contains_test will return a meaningful 0 or 1.
1476 else switch (contains_test(parents
->item
, want
)) {
1478 commit
->object
.flags
|= TMP_MARK
;
1479 contains_stack
.nr
--;
1482 entry
->parents
= parents
->next
;
1484 case CONTAINS_UNKNOWN
:
1485 push_to_contains_stack(parents
->item
, &contains_stack
);
1489 free(contains_stack
.contains_stack
);
1490 return contains_test(candidate
, want
);
1493 static int commit_contains(struct ref_filter
*filter
, struct commit
*commit
)
1495 if (filter
->with_commit_tag_algo
)
1496 return contains_tag_algo(commit
, filter
->with_commit
);
1497 return is_descendant_of(commit
, filter
->with_commit
);
1501 * Return 1 if the refname matches one of the patterns, otherwise 0.
1502 * A pattern can be a literal prefix (e.g. a refname "refs/heads/master"
1503 * matches a pattern "refs/heads/mas") or a wildcard (e.g. the same ref
1504 * matches "refs/heads/mas*", too).
1506 static int match_pattern(const struct ref_filter
*filter
, const char *refname
)
1508 const char **patterns
= filter
->name_patterns
;
1511 if (filter
->ignore_case
)
1512 flags
|= WM_CASEFOLD
;
1515 * When no '--format' option is given we need to skip the prefix
1516 * for matching refs of tags and branches.
1518 (void)(skip_prefix(refname
, "refs/tags/", &refname
) ||
1519 skip_prefix(refname
, "refs/heads/", &refname
) ||
1520 skip_prefix(refname
, "refs/remotes/", &refname
) ||
1521 skip_prefix(refname
, "refs/", &refname
));
1523 for (; *patterns
; patterns
++) {
1524 if (!wildmatch(*patterns
, refname
, flags
, NULL
))
1531 * Return 1 if the refname matches one of the patterns, otherwise 0.
1532 * A pattern can be path prefix (e.g. a refname "refs/heads/master"
1533 * matches a pattern "refs/heads/" but not "refs/heads/m") or a
1534 * wildcard (e.g. the same ref matches "refs/heads/m*", too).
1536 static int match_name_as_path(const struct ref_filter
*filter
, const char *refname
)
1538 const char **pattern
= filter
->name_patterns
;
1539 int namelen
= strlen(refname
);
1540 unsigned flags
= WM_PATHNAME
;
1542 if (filter
->ignore_case
)
1543 flags
|= WM_CASEFOLD
;
1545 for (; *pattern
; pattern
++) {
1546 const char *p
= *pattern
;
1547 int plen
= strlen(p
);
1549 if ((plen
<= namelen
) &&
1550 !strncmp(refname
, p
, plen
) &&
1551 (refname
[plen
] == '\0' ||
1552 refname
[plen
] == '/' ||
1555 if (!wildmatch(p
, refname
, WM_PATHNAME
, NULL
))
1561 /* Return 1 if the refname matches one of the patterns, otherwise 0. */
1562 static int filter_pattern_match(struct ref_filter
*filter
, const char *refname
)
1564 if (!*filter
->name_patterns
)
1565 return 1; /* No pattern always matches */
1566 if (filter
->match_as_path
)
1567 return match_name_as_path(filter
, refname
);
1568 return match_pattern(filter
, refname
);
1572 * Given a ref (sha1, refname), check if the ref belongs to the array
1573 * of sha1s. If the given ref is a tag, check if the given tag points
1574 * at one of the sha1s in the given sha1 array.
1575 * the given sha1_array.
1577 * 1. Only a single level of inderection is obtained, we might want to
1578 * change this to account for multiple levels (e.g. annotated tags
1579 * pointing to annotated tags pointing to a commit.)
1580 * 2. As the refs are cached we might know what refname peels to without
1581 * the need to parse the object via parse_object(). peel_ref() might be a
1582 * more efficient alternative to obtain the pointee.
1584 static const unsigned char *match_points_at(struct sha1_array
*points_at
,
1585 const unsigned char *sha1
,
1586 const char *refname
)
1588 const unsigned char *tagged_sha1
= NULL
;
1591 if (sha1_array_lookup(points_at
, sha1
) >= 0)
1593 obj
= parse_object(sha1
);
1595 die(_("malformed object at '%s'"), refname
);
1596 if (obj
->type
== OBJ_TAG
)
1597 tagged_sha1
= ((struct tag
*)obj
)->tagged
->oid
.hash
;
1598 if (tagged_sha1
&& sha1_array_lookup(points_at
, tagged_sha1
) >= 0)
1603 /* Allocate space for a new ref_array_item and copy the objectname and flag to it */
1604 static struct ref_array_item
*new_ref_array_item(const char *refname
,
1605 const unsigned char *objectname
,
1608 struct ref_array_item
*ref
;
1609 FLEX_ALLOC_STR(ref
, refname
, refname
);
1610 hashcpy(ref
->objectname
, objectname
);
1616 static int filter_ref_kind(struct ref_filter
*filter
, const char *refname
)
1624 { "refs/heads/" , FILTER_REFS_BRANCHES
},
1625 { "refs/remotes/" , FILTER_REFS_REMOTES
},
1626 { "refs/tags/", FILTER_REFS_TAGS
}
1629 if (filter
->kind
== FILTER_REFS_BRANCHES
||
1630 filter
->kind
== FILTER_REFS_REMOTES
||
1631 filter
->kind
== FILTER_REFS_TAGS
)
1632 return filter
->kind
;
1633 else if (!strcmp(refname
, "HEAD"))
1634 return FILTER_REFS_DETACHED_HEAD
;
1636 for (i
= 0; i
< ARRAY_SIZE(ref_kind
); i
++) {
1637 if (starts_with(refname
, ref_kind
[i
].prefix
))
1638 return ref_kind
[i
].kind
;
1641 return FILTER_REFS_OTHERS
;
1645 * A call-back given to for_each_ref(). Filter refs and keep them for
1646 * later object processing.
1648 static int ref_filter_handler(const char *refname
, const struct object_id
*oid
, int flag
, void *cb_data
)
1650 struct ref_filter_cbdata
*ref_cbdata
= cb_data
;
1651 struct ref_filter
*filter
= ref_cbdata
->filter
;
1652 struct ref_array_item
*ref
;
1653 struct commit
*commit
= NULL
;
1656 if (flag
& REF_BAD_NAME
) {
1657 warning(_("ignoring ref with broken name %s"), refname
);
1661 if (flag
& REF_ISBROKEN
) {
1662 warning(_("ignoring broken ref %s"), refname
);
1666 /* Obtain the current ref kind from filter_ref_kind() and ignore unwanted refs. */
1667 kind
= filter_ref_kind(filter
, refname
);
1668 if (!(kind
& filter
->kind
))
1671 if (!filter_pattern_match(filter
, refname
))
1674 if (filter
->points_at
.nr
&& !match_points_at(&filter
->points_at
, oid
->hash
, refname
))
1678 * A merge filter is applied on refs pointing to commits. Hence
1679 * obtain the commit using the 'oid' available and discard all
1680 * non-commits early. The actual filtering is done later.
1682 if (filter
->merge_commit
|| filter
->with_commit
|| filter
->verbose
) {
1683 commit
= lookup_commit_reference_gently(oid
->hash
, 1);
1686 /* We perform the filtering for the '--contains' option */
1687 if (filter
->with_commit
&&
1688 !commit_contains(filter
, commit
))
1693 * We do not open the object yet; sort may only need refname
1694 * to do its job and the resulting list may yet to be pruned
1695 * by maxcount logic.
1697 ref
= new_ref_array_item(refname
, oid
->hash
, flag
);
1698 ref
->commit
= commit
;
1700 REALLOC_ARRAY(ref_cbdata
->array
->items
, ref_cbdata
->array
->nr
+ 1);
1701 ref_cbdata
->array
->items
[ref_cbdata
->array
->nr
++] = ref
;
1706 /* Free memory allocated for a ref_array_item */
1707 static void free_array_item(struct ref_array_item
*item
)
1709 free((char *)item
->symref
);
1713 /* Free all memory allocated for ref_array */
1714 void ref_array_clear(struct ref_array
*array
)
1718 for (i
= 0; i
< array
->nr
; i
++)
1719 free_array_item(array
->items
[i
]);
1721 array
->items
= NULL
;
1722 array
->nr
= array
->alloc
= 0;
1725 static void do_merge_filter(struct ref_filter_cbdata
*ref_cbdata
)
1727 struct rev_info revs
;
1729 struct ref_filter
*filter
= ref_cbdata
->filter
;
1730 struct ref_array
*array
= ref_cbdata
->array
;
1731 struct commit
**to_clear
= xcalloc(sizeof(struct commit
*), array
->nr
);
1733 init_revisions(&revs
, NULL
);
1735 for (i
= 0; i
< array
->nr
; i
++) {
1736 struct ref_array_item
*item
= array
->items
[i
];
1737 add_pending_object(&revs
, &item
->commit
->object
, item
->refname
);
1738 to_clear
[i
] = item
->commit
;
1741 filter
->merge_commit
->object
.flags
|= UNINTERESTING
;
1742 add_pending_object(&revs
, &filter
->merge_commit
->object
, "");
1745 if (prepare_revision_walk(&revs
))
1746 die(_("revision walk setup failed"));
1751 for (i
= 0; i
< old_nr
; i
++) {
1752 struct ref_array_item
*item
= array
->items
[i
];
1753 struct commit
*commit
= item
->commit
;
1755 int is_merged
= !!(commit
->object
.flags
& UNINTERESTING
);
1757 if (is_merged
== (filter
->merge
== REF_FILTER_MERGED_INCLUDE
))
1758 array
->items
[array
->nr
++] = array
->items
[i
];
1760 free_array_item(item
);
1763 for (i
= 0; i
< old_nr
; i
++)
1764 clear_commit_marks(to_clear
[i
], ALL_REV_FLAGS
);
1765 clear_commit_marks(filter
->merge_commit
, ALL_REV_FLAGS
);
1770 * API for filtering a set of refs. Based on the type of refs the user
1771 * has requested, we iterate through those refs and apply filters
1772 * as per the given ref_filter structure and finally store the
1773 * filtered refs in the ref_array structure.
1775 int filter_refs(struct ref_array
*array
, struct ref_filter
*filter
, unsigned int type
)
1777 struct ref_filter_cbdata ref_cbdata
;
1779 unsigned int broken
= 0;
1781 ref_cbdata
.array
= array
;
1782 ref_cbdata
.filter
= filter
;
1784 if (type
& FILTER_REFS_INCLUDE_BROKEN
)
1786 filter
->kind
= type
& FILTER_REFS_KIND_MASK
;
1788 /* Simple per-ref filtering */
1790 die("filter_refs: invalid type");
1793 * For common cases where we need only branches or remotes or tags,
1794 * we only iterate through those refs. If a mix of refs is needed,
1795 * we iterate over all refs and filter out required refs with the help
1796 * of filter_ref_kind().
1798 if (filter
->kind
== FILTER_REFS_BRANCHES
)
1799 ret
= for_each_fullref_in("refs/heads/", ref_filter_handler
, &ref_cbdata
, broken
);
1800 else if (filter
->kind
== FILTER_REFS_REMOTES
)
1801 ret
= for_each_fullref_in("refs/remotes/", ref_filter_handler
, &ref_cbdata
, broken
);
1802 else if (filter
->kind
== FILTER_REFS_TAGS
)
1803 ret
= for_each_fullref_in("refs/tags/", ref_filter_handler
, &ref_cbdata
, broken
);
1804 else if (filter
->kind
& FILTER_REFS_ALL
)
1805 ret
= for_each_fullref_in("", ref_filter_handler
, &ref_cbdata
, broken
);
1806 if (!ret
&& (filter
->kind
& FILTER_REFS_DETACHED_HEAD
))
1807 head_ref(ref_filter_handler
, &ref_cbdata
);
1811 /* Filters that need revision walking */
1812 if (filter
->merge_commit
)
1813 do_merge_filter(&ref_cbdata
);
1818 static int cmp_ref_sorting(struct ref_sorting
*s
, struct ref_array_item
*a
, struct ref_array_item
*b
)
1820 struct atom_value
*va
, *vb
;
1822 cmp_type cmp_type
= used_atom
[s
->atom
].type
;
1823 int (*cmp_fn
)(const char *, const char *);
1825 get_ref_atom_value(a
, s
->atom
, &va
);
1826 get_ref_atom_value(b
, s
->atom
, &vb
);
1827 cmp_fn
= s
->ignore_case
? strcasecmp
: strcmp
;
1829 cmp
= versioncmp(va
->s
, vb
->s
);
1830 else if (cmp_type
== FIELD_STR
)
1831 cmp
= cmp_fn(va
->s
, vb
->s
);
1833 if (va
->ul
< vb
->ul
)
1835 else if (va
->ul
== vb
->ul
)
1836 cmp
= cmp_fn(a
->refname
, b
->refname
);
1841 return (s
->reverse
) ? -cmp
: cmp
;
1844 static struct ref_sorting
*ref_sorting
;
1845 static int compare_refs(const void *a_
, const void *b_
)
1847 struct ref_array_item
*a
= *((struct ref_array_item
**)a_
);
1848 struct ref_array_item
*b
= *((struct ref_array_item
**)b_
);
1849 struct ref_sorting
*s
;
1851 for (s
= ref_sorting
; s
; s
= s
->next
) {
1852 int cmp
= cmp_ref_sorting(s
, a
, b
);
1859 void ref_array_sort(struct ref_sorting
*sorting
, struct ref_array
*array
)
1861 ref_sorting
= sorting
;
1862 QSORT(array
->items
, array
->nr
, compare_refs
);
1865 static void append_literal(const char *cp
, const char *ep
, struct ref_formatting_state
*state
)
1867 struct strbuf
*s
= &state
->stack
->output
;
1869 while (*cp
&& (!ep
|| cp
< ep
)) {
1874 int ch
= hex2chr(cp
+ 1);
1876 strbuf_addch(s
, ch
);
1882 strbuf_addch(s
, *cp
);
1887 void format_ref_array_item(struct ref_array_item
*info
, const char *format
,
1888 int quote_style
, struct strbuf
*final_buf
)
1890 const char *cp
, *sp
, *ep
;
1891 struct ref_formatting_state state
= REF_FORMATTING_STATE_INIT
;
1893 state
.quote_style
= quote_style
;
1894 push_stack_element(&state
.stack
);
1896 for (cp
= format
; *cp
&& (sp
= find_next(cp
)); cp
= ep
+ 1) {
1897 struct atom_value
*atomv
;
1899 ep
= strchr(sp
, ')');
1901 append_literal(cp
, sp
, &state
);
1902 get_ref_atom_value(info
, parse_ref_filter_atom(sp
+ 2, ep
), &atomv
);
1903 atomv
->handler(atomv
, &state
);
1906 sp
= cp
+ strlen(cp
);
1907 append_literal(cp
, sp
, &state
);
1909 if (need_color_reset_at_eol
) {
1910 struct atom_value resetv
;
1911 char color
[COLOR_MAXLEN
] = "";
1913 if (color_parse("reset", color
) < 0)
1914 die("BUG: couldn't parse 'reset' as a color");
1916 append_atom(&resetv
, &state
);
1918 if (state
.stack
->prev
)
1919 die(_("format: %%(end) atom missing"));
1920 strbuf_addbuf(final_buf
, &state
.stack
->output
);
1921 pop_stack_element(&state
.stack
);
1924 void show_ref_array_item(struct ref_array_item
*info
, const char *format
, int quote_style
)
1926 struct strbuf final_buf
= STRBUF_INIT
;
1928 format_ref_array_item(info
, format
, quote_style
, &final_buf
);
1929 fwrite(final_buf
.buf
, 1, final_buf
.len
, stdout
);
1930 strbuf_release(&final_buf
);
1934 /* If no sorting option is given, use refname to sort as default */
1935 struct ref_sorting
*ref_default_sorting(void)
1937 static const char cstr_name
[] = "refname";
1939 struct ref_sorting
*sorting
= xcalloc(1, sizeof(*sorting
));
1941 sorting
->next
= NULL
;
1942 sorting
->atom
= parse_ref_filter_atom(cstr_name
, cstr_name
+ strlen(cstr_name
));
1946 int parse_opt_ref_sorting(const struct option
*opt
, const char *arg
, int unset
)
1948 struct ref_sorting
**sorting_tail
= opt
->value
;
1949 struct ref_sorting
*s
;
1952 if (!arg
) /* should --no-sort void the list ? */
1955 s
= xcalloc(1, sizeof(*s
));
1956 s
->next
= *sorting_tail
;
1963 if (skip_prefix(arg
, "version:", &arg
) ||
1964 skip_prefix(arg
, "v:", &arg
))
1967 s
->atom
= parse_ref_filter_atom(arg
, arg
+len
);
1971 int parse_opt_merge_filter(const struct option
*opt
, const char *arg
, int unset
)
1973 struct ref_filter
*rf
= opt
->value
;
1974 unsigned char sha1
[20];
1976 rf
->merge
= starts_with(opt
->long_name
, "no")
1977 ? REF_FILTER_MERGED_OMIT
1978 : REF_FILTER_MERGED_INCLUDE
;
1980 if (get_sha1(arg
, sha1
))
1981 die(_("malformed object name %s"), arg
);
1983 rf
->merge_commit
= lookup_commit_reference_gently(sha1
, 0);
1984 if (!rf
->merge_commit
)
1985 return opterror(opt
, "must point to a commit", 0);