blob: 88b021dd1d0e3050f92dbcc1973f15c70df92bbf [file] [log] [blame]
Elijah Newren5e3f94d2023-04-22 20:17:23 +00001#include "git-compat-util.h"
Elijah Newren32a8f512023-03-21 06:26:03 +00002#include "environment.h"
Elijah Newrenf394e092023-03-21 06:25:54 +00003#include "gettext.h"
Kousik Sanagavarapuf46094a2023-07-23 21:49:58 +05304#include "config.h"
Elijah Newrend4a4f922023-04-22 20:17:26 +00005#include "gpg-interface.h"
Elijah Newren41771fa2023-02-24 00:09:27 +00006#include "hex.h"
Karthik Nayakc95b7582015-06-14 01:07:27 +05307#include "parse-options.h"
Kousik Sanagavarapuf5d18f82023-07-23 21:49:59 +05308#include "run-command.h"
Karthik Nayakc95b7582015-06-14 01:07:27 +05309#include "refs.h"
10#include "wildmatch.h"
Elijah Newrendabab1d2023-04-11 00:41:49 -070011#include "object-name.h"
Elijah Newrena034e912023-05-16 06:34:06 +000012#include "object-store-ll.h"
Elijah Newren6f2d7432023-04-11 03:00:42 +000013#include "oid-array.h"
Stefan Beller109cd762018-06-28 18:21:51 -070014#include "repository.h"
Karthik Nayakc95b7582015-06-14 01:07:27 +053015#include "commit.h"
16#include "remote.h"
17#include "color.h"
18#include "tag.h"
19#include "quote.h"
20#include "ref-filter.h"
Karthik Nayak35257aa2015-07-07 21:36:12 +053021#include "revision.h"
Karthik Nayakce592082015-09-11 20:33:07 +053022#include "utf8.h"
Karthik Nayak90c00402015-09-10 21:18:25 +053023#include "version.h"
Elijah Newren34676632023-04-22 20:17:17 +000024#include "versioncmp.h"
Jacob Kellerb1d31c82016-11-18 16:58:15 -080025#include "trailer.h"
Karthik Nayakd4919bb2017-01-10 14:19:38 +053026#include "wt-status.h"
Jeff Kinga91aca42017-03-09 08:29:49 -050027#include "commit-slab.h"
Derrick Stolee819807b2018-05-01 12:47:15 +000028#include "commit-graph.h"
Derrick Stolee64043552018-07-20 16:33:04 +000029#include "commit-reach.h"
Nickolai Belakovski25820832019-04-28 22:19:42 -070030#include "worktree.h"
31#include "hashmap.h"
Jeff Kingdbbcd442020-07-28 16:23:39 -040032#include "strvec.h"
Karthik Nayakc95b7582015-06-14 01:07:27 +053033
Karthik Nayak6eac70f2017-01-10 14:19:50 +053034static struct ref_msg {
35 const char *gone;
36 const char *ahead;
37 const char *behind;
38 const char *ahead_behind;
39} msgs = {
40 /* Untranslated plumbing messages: */
41 "gone",
42 "ahead %d",
43 "behind %d",
44 "ahead %d, behind %d"
45};
46
47void setup_ref_filter_porcelain_msg(void)
48{
49 msgs.gone = _("gone");
50 msgs.ahead = _("ahead %d");
51 msgs.behind = _("behind %d");
52 msgs.ahead_behind = _("ahead %d, behind %d");
53}
Karthik Nayakc95b7582015-06-14 01:07:27 +053054
55typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
Karthik Nayak4f3e3b32017-01-10 14:19:36 +053056typedef enum { COMPARE_EQUAL, COMPARE_UNEQUAL, COMPARE_NONE } cmp_status;
Olga Telezhnayaa8e7e382018-07-17 08:22:57 +000057typedef enum { SOURCE_NONE = 0, SOURCE_OBJ, SOURCE_OTHER } info_source;
Karthik Nayakc95b7582015-06-14 01:07:27 +053058
Karthik Nayak5bd881d2016-02-17 23:36:15 +053059struct align {
60 align_type position;
61 unsigned int width;
62};
63
Karthik Nayakc58492d2017-01-10 14:19:34 +053064struct if_then_else {
Karthik Nayak4f3e3b32017-01-10 14:19:36 +053065 cmp_status cmp_status;
66 const char *str;
Karthik Nayakc58492d2017-01-10 14:19:34 +053067 unsigned int then_atom_seen : 1,
68 else_atom_seen : 1,
69 condition_satisfied : 1;
70};
71
Karthik Nayakb180e6f2017-01-10 14:19:43 +053072struct refname_atom {
Karthik Nayak1a347282017-01-10 14:19:49 +053073 enum { R_NORMAL, R_SHORT, R_LSTRIP, R_RSTRIP } option;
74 int lstrip, rstrip;
Karthik Nayakb180e6f2017-01-10 14:19:43 +053075};
76
Hariom Vermaee82a482021-02-13 01:52:43 +000077static struct ref_trailer_buf {
78 struct string_list filter_list;
79 struct strbuf sepbuf;
80 struct strbuf kvsepbuf;
81} ref_trailer_buf = {STRING_LIST_INIT_NODUP, STRBUF_INIT, STRBUF_INIT};
82
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +000083static struct expand_data {
84 struct object_id oid;
85 enum object_type type;
86 unsigned long size;
87 off_t disk_size;
88 struct object_id delta_base_oid;
89 void *content;
90
91 struct object_info info;
92} oi, oi_deref;
93
Nickolai Belakovski25820832019-04-28 22:19:42 -070094struct ref_to_worktree_entry {
Eric Wonge2b50382019-10-06 23:30:43 +000095 struct hashmap_entry ent;
Nickolai Belakovski25820832019-04-28 22:19:42 -070096 struct worktree *wt; /* key is wt->head_ref */
97};
98
Ævar Arnfjörð Bjarmason5cf88fd2022-08-25 19:09:48 +020099static int ref_to_worktree_map_cmpfnc(const void *lookupdata UNUSED,
Eric Wong939af162019-10-06 23:30:37 +0000100 const struct hashmap_entry *eptr,
101 const struct hashmap_entry *kptr,
Nickolai Belakovski25820832019-04-28 22:19:42 -0700102 const void *keydata_aka_refname)
103{
Eric Wong939af162019-10-06 23:30:37 +0000104 const struct ref_to_worktree_entry *e, *k;
105
106 e = container_of(eptr, const struct ref_to_worktree_entry, ent);
107 k = container_of(kptr, const struct ref_to_worktree_entry, ent);
108
Nickolai Belakovski25820832019-04-28 22:19:42 -0700109 return strcmp(e->wt->head_ref,
110 keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);
111}
112
113static struct ref_to_worktree_map {
114 struct hashmap map;
115 struct worktree **worktrees;
116} ref_to_worktree_map;
117
Karthik Nayak50cd83d2016-02-17 23:36:10 +0530118/*
ZheNing Hu1197f1a2021-05-13 15:15:38 +0000119 * The enum atom_type is used as the index of valid_atom array.
120 * In the atom parsing stage, it will be passed to used_atom.atom_type
121 * as the identifier of the atom type. We can check the type of used_atom
122 * entry by `if (used_atom[i].atom_type == ATOM_*)`.
123 */
124enum atom_type {
125 ATOM_REFNAME,
126 ATOM_OBJECTTYPE,
127 ATOM_OBJECTSIZE,
128 ATOM_OBJECTNAME,
129 ATOM_DELTABASE,
130 ATOM_TREE,
131 ATOM_PARENT,
132 ATOM_NUMPARENT,
133 ATOM_OBJECT,
134 ATOM_TYPE,
135 ATOM_TAG,
136 ATOM_AUTHOR,
137 ATOM_AUTHORNAME,
138 ATOM_AUTHOREMAIL,
139 ATOM_AUTHORDATE,
140 ATOM_COMMITTER,
141 ATOM_COMMITTERNAME,
142 ATOM_COMMITTEREMAIL,
143 ATOM_COMMITTERDATE,
144 ATOM_TAGGER,
145 ATOM_TAGGERNAME,
146 ATOM_TAGGEREMAIL,
147 ATOM_TAGGERDATE,
148 ATOM_CREATOR,
149 ATOM_CREATORDATE,
Kousik Sanagavarapuf5d18f82023-07-23 21:49:59 +0530150 ATOM_DESCRIBE,
ZheNing Hu1197f1a2021-05-13 15:15:38 +0000151 ATOM_SUBJECT,
152 ATOM_BODY,
153 ATOM_TRAILERS,
154 ATOM_CONTENTS,
Kousik Sanagavarapu26c9c032023-06-04 23:52:47 +0530155 ATOM_SIGNATURE,
ZheNing Hubd0708c2021-07-26 03:26:47 +0000156 ATOM_RAW,
ZheNing Hu1197f1a2021-05-13 15:15:38 +0000157 ATOM_UPSTREAM,
158 ATOM_PUSH,
159 ATOM_SYMREF,
160 ATOM_FLAG,
161 ATOM_HEAD,
162 ATOM_COLOR,
163 ATOM_WORKTREEPATH,
164 ATOM_ALIGN,
165 ATOM_END,
166 ATOM_IF,
167 ATOM_THEN,
168 ATOM_ELSE,
ZheNing Hub9dee072021-07-26 03:26:50 +0000169 ATOM_REST,
Derrick Stolee49abcd22023-03-20 11:26:54 +0000170 ATOM_AHEADBEHIND,
ZheNing Hu1197f1a2021-05-13 15:15:38 +0000171};
172
173/*
Karthik Nayak50cd83d2016-02-17 23:36:10 +0530174 * An atom is a valid field atom listed below, possibly prefixed with
175 * a "*" to denote deref_tag().
176 *
177 * We parse given format string and sort specifiers, and make a list
178 * of properties that we need to extract out of objects. ref_array_item
179 * structure will hold an array of values extracted that can be
180 * indexed with the "atom number", which is an index into this
181 * array.
182 */
Karthik Nayakb072add2016-02-17 23:36:11 +0530183static struct used_atom {
ZheNing Hu1197f1a2021-05-13 15:15:38 +0000184 enum atom_type atom_type;
Karthik Nayakb072add2016-02-17 23:36:11 +0530185 const char *name;
186 cmp_type type;
Olga Telezhnayaa8e7e382018-07-17 08:22:57 +0000187 info_source source;
Karthik Nayakfd935cc2016-02-17 23:36:13 +0530188 union {
189 char color[COLOR_MAXLEN];
Karthik Nayak5bd881d2016-02-17 23:36:15 +0530190 struct align align;
Karthik Nayak7743fcc2017-01-10 14:19:41 +0530191 struct {
Johannes Schindelincc723852017-10-05 14:19:09 +0200192 enum {
J Wyman9700fae2017-11-07 17:31:08 +0100193 RR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME, RR_REMOTE_REF
Johannes Schindelincc723852017-10-05 14:19:09 +0200194 } option;
Karthik Nayak3ba308c2017-01-10 14:19:45 +0530195 struct refname_atom refname;
Johannes Schindelincc723852017-10-05 14:19:09 +0200196 unsigned int nobracket : 1, push : 1, push_remote : 1;
Karthik Nayak7743fcc2017-01-10 14:19:41 +0530197 } remote_ref;
Karthik Nayak452db392016-02-17 23:36:18 +0530198 struct {
Hariom Verma905f0a42020-08-21 21:41:50 +0000199 enum { C_BARE, C_BODY, C_BODY_DEP, C_LENGTH, C_LINES,
200 C_SIG, C_SUB, C_SUB_SANITIZE, C_TRAILERS } option;
Taylor Blau67a20a02017-10-01 22:25:23 -0700201 struct process_trailer_options trailer_opts;
Karthik Nayak452db392016-02-17 23:36:18 +0530202 unsigned int nlines;
203 } contents;
Karthik Nayak4f3e3b32017-01-10 14:19:36 +0530204 struct {
ZheNing Hubd0708c2021-07-26 03:26:47 +0000205 enum { RAW_BARE, RAW_LENGTH } option;
206 } raw_data;
207 struct {
Karthik Nayak4f3e3b32017-01-10 14:19:36 +0530208 cmp_status cmp_status;
209 const char *str;
210 } if_then_else;
Karthik Nayak42d0eb02017-01-10 14:19:37 +0530211 struct {
212 enum { O_FULL, O_LENGTH, O_SHORT } option;
213 unsigned int length;
Hariom Verma87d3beb2020-08-21 21:41:46 +0000214 } oid;
ZheNing Hu0caf20f2021-05-13 15:15:37 +0000215 struct {
216 enum { O_SIZE, O_SIZE_DISK } option;
217 } objectsize;
Hariom Vermab82445d2020-08-21 21:41:43 +0000218 struct email_option {
219 enum { EO_RAW, EO_TRIM, EO_LOCALPART } option;
220 } email_option;
Kousik Sanagavarapu26c9c032023-06-04 23:52:47 +0530221 struct {
222 enum { S_BARE, S_GRADE, S_SIGNER, S_KEY,
223 S_FINGERPRINT, S_PRI_KEY_FP, S_TRUST_LEVEL } option;
224 } signature;
Kousik Sanagavarapuf5d18f82023-07-23 21:49:59 +0530225 const char **describe_args;
Karthik Nayakb180e6f2017-01-10 14:19:43 +0530226 struct refname_atom refname;
Jeff King613a0e52017-05-19 02:12:12 -0400227 char *head;
Karthik Nayakfd935cc2016-02-17 23:36:13 +0530228 } u;
Karthik Nayakb072add2016-02-17 23:36:11 +0530229} *used_atom;
Karthik Nayak50cd83d2016-02-17 23:36:10 +0530230static int used_atom_cnt, need_tagged, need_symref;
Karthik Nayak50cd83d2016-02-17 23:36:10 +0530231
Olga Telezhnayae2e7a242018-03-29 12:49:45 +0000232/*
233 * Expand string, append it to strbuf *sb, then return error code ret.
234 * Allow to save few lines of code.
235 */
Ævar Arnfjörð Bjarmason48ca53c2021-07-13 10:05:18 +0200236__attribute__((format (printf, 3, 4)))
Olga Telezhnayae2e7a242018-03-29 12:49:45 +0000237static int strbuf_addf_ret(struct strbuf *sb, int ret, const char *fmt, ...)
238{
239 va_list ap;
240 va_start(ap, fmt);
241 strbuf_vaddf(sb, fmt, ap);
242 va_end(ap);
243 return ret;
244}
245
Jeff Kinga33d0fa2022-12-14 11:19:43 -0500246static int err_no_arg(struct strbuf *sb, const char *name)
247{
Jeff King1955ef12022-12-14 11:23:53 -0500248 size_t namelen = strchrnul(name, ':') - name;
249 strbuf_addf(sb, _("%%(%.*s) does not take arguments"),
250 (int)namelen, name);
Jeff Kinga33d0fa2022-12-14 11:19:43 -0500251 return -1;
252}
253
Jeff Kingdda4fc12022-12-14 11:20:19 -0500254static int err_bad_arg(struct strbuf *sb, const char *name, const char *arg)
255{
Jeff King1955ef12022-12-14 11:23:53 -0500256 size_t namelen = strchrnul(name, ':') - name;
257 strbuf_addf(sb, _("unrecognized %%(%.*s) argument: %s"),
258 (int)namelen, name, arg);
Jeff Kingdda4fc12022-12-14 11:20:19 -0500259 return -1;
260}
261
Kousik Sanagavarapuf46094a2023-07-23 21:49:58 +0530262/*
263 * Parse option of name "candidate" in the option string "to_parse" of
264 * the form
265 *
266 * "candidate1[=val1],candidate2[=val2],candidate3[=val3],..."
267 *
268 * The remaining part of "to_parse" is stored in "end" (if we are
269 * parsing the last candidate, then this is NULL) and the value of
270 * the candidate is stored in "valuestart" and its length in "valuelen",
271 * that is the portion after "=". Since it is possible for a "candidate"
272 * to not have a value, in such cases, "valuestart" is set to point to
273 * NULL and "valuelen" to 0.
274 *
275 * The function returns 1 on success. It returns 0 if we don't find
276 * "candidate" in "to_parse" or we find "candidate" but it is followed
277 * by more chars (for example, "candidatefoo"), that is, we don't find
278 * an exact match.
279 *
280 * This function only does the above for one "candidate" at a time. So
281 * it has to be called each time trying to parse a "candidate" in the
282 * option string "to_parse".
283 */
284static int match_atom_arg_value(const char *to_parse, const char *candidate,
285 const char **end, const char **valuestart,
286 size_t *valuelen)
287{
288 const char *atom;
289
290 if (!skip_prefix(to_parse, candidate, &atom))
291 return 0; /* definitely not "candidate" */
292
293 if (*atom == '=') {
294 /* we just saw "candidate=" */
295 *valuestart = atom + 1;
296 atom = strchrnul(*valuestart, ',');
297 *valuelen = atom - *valuestart;
298 } else if (*atom != ',' && *atom != '\0') {
299 /* key begins with "candidate" but has more chars */
300 return 0;
301 } else {
302 /* just "candidate" without "=val" */
303 *valuestart = NULL;
304 *valuelen = 0;
305 }
306
307 /* atom points at either the ',' or NUL after this key[=val] */
308 if (*atom == ',')
309 atom++;
310 else if (*atom)
311 BUG("Why is *atom not NULL yet?");
312
313 *end = atom;
314 return 1;
315}
316
317/*
318 * Parse boolean option of name "candidate" in the option list "to_parse"
319 * of the form
320 *
321 * "candidate1[=bool1],candidate2[=bool2],candidate3[=bool3],..."
322 *
323 * The remaining part of "to_parse" is stored in "end" (if we are parsing
324 * the last candidate, then this is NULL) and the value (if given) is
325 * parsed and stored in "val", so "val" always points to either 0 or 1.
326 * If the value is not given, then "val" is set to point to 1.
327 *
328 * The boolean value is parsed using "git_parse_maybe_bool()", so the
329 * accepted values are
330 *
331 * to set true - "1", "yes", "true"
332 * to set false - "0", "no", "false"
333 *
334 * This function returns 1 on success. It returns 0 when we don't find
335 * an exact match for "candidate" or when the boolean value given is
336 * not valid.
337 */
338static int match_atom_bool_arg(const char *to_parse, const char *candidate,
339 const char **end, int *val)
340{
341 const char *argval;
342 char *strval;
343 size_t arglen;
344 int v;
345
346 if (!match_atom_arg_value(to_parse, candidate, end, &argval, &arglen))
347 return 0;
348
349 if (!argval) {
350 *val = 1;
351 return 1;
352 }
353
354 strval = xstrndup(argval, arglen);
355 v = git_parse_maybe_bool(strval);
356 free(strval);
357
358 if (v == -1)
359 return 0;
360
361 *val = v;
362
363 return 1;
364}
365
ZheNing Hue85fcb32021-07-26 03:26:49 +0000366static int color_atom_parser(struct ref_format *format, struct used_atom *atom,
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000367 const char *color_value, struct strbuf *err)
Karthik Nayakfd935cc2016-02-17 23:36:13 +0530368{
369 if (!color_value)
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000370 return strbuf_addf_ret(err, -1, _("expected format: %%(color:<color>)"));
Karthik Nayakfd935cc2016-02-17 23:36:13 +0530371 if (color_parse(color_value, atom->u.color) < 0)
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000372 return strbuf_addf_ret(err, -1, _("unrecognized color: %%(color:%s)"),
373 color_value);
Jeff King11b087a2017-07-13 11:09:32 -0400374 /*
375 * We check this after we've parsed the color, which lets us complain
376 * about syntactically bogus color names even if they won't be used.
377 */
378 if (!want_color(format->use_color))
379 color_parse("", atom->u.color);
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000380 return 0;
Karthik Nayakfd935cc2016-02-17 23:36:13 +0530381}
382
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000383static int refname_atom_parser_internal(struct refname_atom *atom, const char *arg,
384 const char *name, struct strbuf *err)
Karthik Nayak5339bda2016-02-17 23:36:17 +0530385{
386 if (!arg)
Karthik Nayakb180e6f2017-01-10 14:19:43 +0530387 atom->option = R_NORMAL;
Karthik Nayak5339bda2016-02-17 23:36:17 +0530388 else if (!strcmp(arg, "short"))
Karthik Nayakb180e6f2017-01-10 14:19:43 +0530389 atom->option = R_SHORT;
Junio C Hamano44a6b6c2017-02-07 11:50:34 -0800390 else if (skip_prefix(arg, "lstrip=", &arg) ||
391 skip_prefix(arg, "strip=", &arg)) {
Karthik Nayak17938f12017-01-10 14:19:46 +0530392 atom->option = R_LSTRIP;
Karthik Nayak1a0ca5e2017-01-10 14:19:48 +0530393 if (strtol_i(arg, 10, &atom->lstrip))
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000394 return strbuf_addf_ret(err, -1, _("Integer value expected refname:lstrip=%s"), arg);
Karthik Nayak1a347282017-01-10 14:19:49 +0530395 } else if (skip_prefix(arg, "rstrip=", &arg)) {
396 atom->option = R_RSTRIP;
397 if (strtol_i(arg, 10, &atom->rstrip))
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000398 return strbuf_addf_ret(err, -1, _("Integer value expected refname:rstrip=%s"), arg);
Karthik Nayakb180e6f2017-01-10 14:19:43 +0530399 } else
Jeff King1955ef12022-12-14 11:23:53 -0500400 return err_bad_arg(err, name, arg);
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000401 return 0;
Karthik Nayakb180e6f2017-01-10 14:19:43 +0530402}
403
Jeff King5fe9e1c2023-02-24 01:39:06 -0500404static int remote_ref_atom_parser(struct ref_format *format UNUSED,
405 struct used_atom *atom,
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000406 const char *arg, struct strbuf *err)
Karthik Nayak5339bda2016-02-17 23:36:17 +0530407{
Karthik Nayak7743fcc2017-01-10 14:19:41 +0530408 struct string_list params = STRING_LIST_INIT_DUP;
409 int i;
410
Johannes Schindelincc723852017-10-05 14:19:09 +0200411 if (!strcmp(atom->name, "push") || starts_with(atom->name, "push:"))
412 atom->u.remote_ref.push = 1;
413
Karthik Nayak7743fcc2017-01-10 14:19:41 +0530414 if (!arg) {
Karthik Nayak3ba308c2017-01-10 14:19:45 +0530415 atom->u.remote_ref.option = RR_REF;
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000416 return refname_atom_parser_internal(&atom->u.remote_ref.refname,
417 arg, atom->name, err);
Karthik Nayak7743fcc2017-01-10 14:19:41 +0530418 }
419
420 atom->u.remote_ref.nobracket = 0;
421 string_list_split(&params, arg, ',', -1);
422
423 for (i = 0; i < params.nr; i++) {
424 const char *s = params.items[i].string;
425
Karthik Nayak3ba308c2017-01-10 14:19:45 +0530426 if (!strcmp(s, "track"))
Karthik Nayak7743fcc2017-01-10 14:19:41 +0530427 atom->u.remote_ref.option = RR_TRACK;
428 else if (!strcmp(s, "trackshort"))
429 atom->u.remote_ref.option = RR_TRACKSHORT;
430 else if (!strcmp(s, "nobracket"))
431 atom->u.remote_ref.nobracket = 1;
Johannes Schindelincc723852017-10-05 14:19:09 +0200432 else if (!strcmp(s, "remotename")) {
433 atom->u.remote_ref.option = RR_REMOTE_NAME;
434 atom->u.remote_ref.push_remote = 1;
J Wyman9700fae2017-11-07 17:31:08 +0100435 } else if (!strcmp(s, "remoteref")) {
436 atom->u.remote_ref.option = RR_REMOTE_REF;
437 atom->u.remote_ref.push_remote = 1;
Johannes Schindelincc723852017-10-05 14:19:09 +0200438 } else {
Karthik Nayak3ba308c2017-01-10 14:19:45 +0530439 atom->u.remote_ref.option = RR_REF;
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000440 if (refname_atom_parser_internal(&atom->u.remote_ref.refname,
441 arg, atom->name, err)) {
442 string_list_clear(&params, 0);
443 return -1;
444 }
Karthik Nayak3ba308c2017-01-10 14:19:45 +0530445 }
Karthik Nayak7743fcc2017-01-10 14:19:41 +0530446 }
447
448 string_list_clear(&params, 0);
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000449 return 0;
Karthik Nayak5339bda2016-02-17 23:36:17 +0530450}
451
Jeff King5fe9e1c2023-02-24 01:39:06 -0500452static int objecttype_atom_parser(struct ref_format *format UNUSED,
453 struct used_atom *atom,
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +0000454 const char *arg, struct strbuf *err)
455{
456 if (arg)
Jeff Kinga33d0fa2022-12-14 11:19:43 -0500457 return err_no_arg(err, "objecttype");
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +0000458 if (*atom->name == '*')
459 oi_deref.info.typep = &oi_deref.type;
460 else
461 oi.info.typep = &oi.type;
462 return 0;
463}
464
Jeff King5fe9e1c2023-02-24 01:39:06 -0500465static int objectsize_atom_parser(struct ref_format *format UNUSED,
466 struct used_atom *atom,
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +0000467 const char *arg, struct strbuf *err)
468{
Olga Telezhnaya1867ce62018-12-24 13:24:30 +0000469 if (!arg) {
ZheNing Hu0caf20f2021-05-13 15:15:37 +0000470 atom->u.objectsize.option = O_SIZE;
Olga Telezhnaya1867ce62018-12-24 13:24:30 +0000471 if (*atom->name == '*')
472 oi_deref.info.sizep = &oi_deref.size;
473 else
474 oi.info.sizep = &oi.size;
475 } else if (!strcmp(arg, "disk")) {
ZheNing Hu0caf20f2021-05-13 15:15:37 +0000476 atom->u.objectsize.option = O_SIZE_DISK;
Olga Telezhnaya1867ce62018-12-24 13:24:30 +0000477 if (*atom->name == '*')
478 oi_deref.info.disk_sizep = &oi_deref.disk_size;
479 else
480 oi.info.disk_sizep = &oi.disk_size;
481 } else
Jeff Kingdda4fc12022-12-14 11:20:19 -0500482 return err_bad_arg(err, "objectsize", arg);
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +0000483 return 0;
484}
485
Jeff King5fe9e1c2023-02-24 01:39:06 -0500486static int deltabase_atom_parser(struct ref_format *format UNUSED,
487 struct used_atom *atom,
Olga Telezhnaya33311fa2018-12-24 13:24:30 +0000488 const char *arg, struct strbuf *err)
489{
Karthik Nayakc95b7582015-06-14 01:07:27 +0530490 if (arg)
Jeff Kinga33d0fa2022-12-14 11:19:43 -0500491 return err_no_arg(err, "deltabase");
Karthik Nayakc95b7582015-06-14 01:07:27 +0530492 if (*atom->name == '*')
Jeff Kingb99b6bc2020-02-23 23:36:56 -0500493 oi_deref.info.delta_base_oid = &oi_deref.delta_base_oid;
Karthik Nayakc95b7582015-06-14 01:07:27 +0530494 else
Jeff Kingb99b6bc2020-02-23 23:36:56 -0500495 oi.info.delta_base_oid = &oi.delta_base_oid;
Karthik Nayakc95b7582015-06-14 01:07:27 +0530496 return 0;
497}
498
Jeff King5fe9e1c2023-02-24 01:39:06 -0500499static int body_atom_parser(struct ref_format *format UNUSED,
500 struct used_atom *atom,
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000501 const char *arg, struct strbuf *err)
Karthik Nayak452db392016-02-17 23:36:18 +0530502{
503 if (arg)
Jeff Kinga33d0fa2022-12-14 11:19:43 -0500504 return err_no_arg(err, "body");
Karthik Nayak452db392016-02-17 23:36:18 +0530505 atom->u.contents.option = C_BODY_DEP;
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000506 return 0;
Karthik Nayak452db392016-02-17 23:36:18 +0530507}
508
Jeff King5fe9e1c2023-02-24 01:39:06 -0500509static int subject_atom_parser(struct ref_format *format UNUSED,
510 struct used_atom *atom,
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000511 const char *arg, struct strbuf *err)
Karthik Nayak452db392016-02-17 23:36:18 +0530512{
Hariom Verma905f0a42020-08-21 21:41:50 +0000513 if (!arg)
514 atom->u.contents.option = C_SUB;
515 else if (!strcmp(arg, "sanitize"))
516 atom->u.contents.option = C_SUB_SANITIZE;
517 else
Jeff Kingdda4fc12022-12-14 11:20:19 -0500518 return err_bad_arg(err, "subject", arg);
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000519 return 0;
Karthik Nayak452db392016-02-17 23:36:18 +0530520}
521
Kousik Sanagavarapu26c9c032023-06-04 23:52:47 +0530522static int parse_signature_option(const char *arg)
523{
524 if (!arg)
525 return S_BARE;
526 else if (!strcmp(arg, "signer"))
527 return S_SIGNER;
528 else if (!strcmp(arg, "grade"))
529 return S_GRADE;
530 else if (!strcmp(arg, "key"))
531 return S_KEY;
532 else if (!strcmp(arg, "fingerprint"))
533 return S_FINGERPRINT;
534 else if (!strcmp(arg, "primarykeyfingerprint"))
535 return S_PRI_KEY_FP;
536 else if (!strcmp(arg, "trustlevel"))
537 return S_TRUST_LEVEL;
538 return -1;
539}
540
541static int signature_atom_parser(struct ref_format *format UNUSED,
542 struct used_atom *atom,
543 const char *arg, struct strbuf *err)
544{
545 int opt = parse_signature_option(arg);
546 if (opt < 0)
547 return err_bad_arg(err, "signature", arg);
548 atom->u.signature.option = opt;
549 return 0;
550}
551
Jeff King29c9f2c2023-08-29 19:45:06 -0400552static int trailers_atom_parser(struct ref_format *format UNUSED,
553 struct used_atom *atom,
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000554 const char *arg, struct strbuf *err)
Jacob Kellerb1d31c82016-11-18 16:58:15 -0800555{
Jeff Kinge5fba5d2018-08-22 20:50:17 -0400556 atom->u.contents.trailer_opts.no_divider = 1;
557
Taylor Blau67a20a02017-10-01 22:25:23 -0700558 if (arg) {
Hariom Vermaee82a482021-02-13 01:52:43 +0000559 const char *argbuf = xstrfmt("%s)", arg);
560 char *invalid_arg = NULL;
561
562 if (format_set_trailers_options(&atom->u.contents.trailer_opts,
563 &ref_trailer_buf.filter_list,
564 &ref_trailer_buf.sepbuf,
565 &ref_trailer_buf.kvsepbuf,
566 &argbuf, &invalid_arg)) {
567 if (!invalid_arg)
568 strbuf_addf(err, _("expected %%(trailers:key=<value>)"));
569 else
570 strbuf_addf(err, _("unknown %%(trailers) argument: %s"), invalid_arg);
571 free((char *)invalid_arg);
572 return -1;
Taylor Blau67a20a02017-10-01 22:25:23 -0700573 }
574 }
Jacob Kellerb1d31c82016-11-18 16:58:15 -0800575 atom->u.contents.option = C_TRAILERS;
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000576 return 0;
Jacob Kellerb1d31c82016-11-18 16:58:15 -0800577}
578
ZheNing Hue85fcb32021-07-26 03:26:49 +0000579static int contents_atom_parser(struct ref_format *format, struct used_atom *atom,
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000580 const char *arg, struct strbuf *err)
Karthik Nayak452db392016-02-17 23:36:18 +0530581{
582 if (!arg)
583 atom->u.contents.option = C_BARE;
584 else if (!strcmp(arg, "body"))
585 atom->u.contents.option = C_BODY;
Christian Couderb6839fd2020-07-16 14:19:40 +0200586 else if (!strcmp(arg, "size"))
587 atom->u.contents.option = C_LENGTH;
Karthik Nayak452db392016-02-17 23:36:18 +0530588 else if (!strcmp(arg, "signature"))
589 atom->u.contents.option = C_SIG;
590 else if (!strcmp(arg, "subject"))
591 atom->u.contents.option = C_SUB;
Hariom Verma2c22e102020-08-21 21:06:14 +0000592 else if (!strcmp(arg, "trailers")) {
593 if (trailers_atom_parser(format, atom, NULL, err))
594 return -1;
595 } else if (skip_prefix(arg, "trailers:", &arg)) {
596 if (trailers_atom_parser(format, atom, arg, err))
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000597 return -1;
Taylor Blau7a5edbd2017-10-01 22:25:24 -0700598 } else if (skip_prefix(arg, "lines=", &arg)) {
Karthik Nayak452db392016-02-17 23:36:18 +0530599 atom->u.contents.option = C_LINES;
600 if (strtoul_ui(arg, 10, &atom->u.contents.nlines))
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000601 return strbuf_addf_ret(err, -1, _("positive value expected contents:lines=%s"), arg);
Karthik Nayak452db392016-02-17 23:36:18 +0530602 } else
Jeff Kingdda4fc12022-12-14 11:20:19 -0500603 return err_bad_arg(err, "contents", arg);
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000604 return 0;
Karthik Nayak452db392016-02-17 23:36:18 +0530605}
606
Kousik Sanagavarapuf5d18f82023-07-23 21:49:59 +0530607static int describe_atom_option_parser(struct strvec *args, const char **arg,
608 struct strbuf *err)
609{
610 const char *argval;
611 size_t arglen = 0;
612 int optval = 0;
613
614 if (match_atom_bool_arg(*arg, "tags", arg, &optval)) {
615 if (!optval)
616 strvec_push(args, "--no-tags");
617 else
618 strvec_push(args, "--tags");
619 return 1;
620 }
621
622 if (match_atom_arg_value(*arg, "abbrev", arg, &argval, &arglen)) {
623 char *endptr;
624
625 if (!arglen)
626 return strbuf_addf_ret(err, -1,
627 _("argument expected for %s"),
628 "describe:abbrev");
629 if (strtol(argval, &endptr, 10) < 0)
630 return strbuf_addf_ret(err, -1,
631 _("positive value expected %s=%s"),
632 "describe:abbrev", argval);
633 if (endptr - argval != arglen)
634 return strbuf_addf_ret(err, -1,
635 _("cannot fully parse %s=%s"),
636 "describe:abbrev", argval);
637
638 strvec_pushf(args, "--abbrev=%.*s", (int)arglen, argval);
639 return 1;
640 }
641
642 if (match_atom_arg_value(*arg, "match", arg, &argval, &arglen)) {
643 if (!arglen)
644 return strbuf_addf_ret(err, -1,
645 _("value expected %s="),
646 "describe:match");
647
648 strvec_pushf(args, "--match=%.*s", (int)arglen, argval);
649 return 1;
650 }
651
652 if (match_atom_arg_value(*arg, "exclude", arg, &argval, &arglen)) {
653 if (!arglen)
654 return strbuf_addf_ret(err, -1,
655 _("value expected %s="),
656 "describe:exclude");
657
658 strvec_pushf(args, "--exclude=%.*s", (int)arglen, argval);
659 return 1;
660 }
661
662 return 0;
663}
664
665static int describe_atom_parser(struct ref_format *format UNUSED,
666 struct used_atom *atom,
667 const char *arg, struct strbuf *err)
668{
669 struct strvec args = STRVEC_INIT;
670
671 for (;;) {
672 int found = 0;
673 const char *bad_arg = arg;
674
675 if (!arg || !*arg)
676 break;
677
678 found = describe_atom_option_parser(&args, &arg, err);
679 if (found < 0)
680 return found;
681 if (!found)
682 return err_bad_arg(err, "describe", bad_arg);
683 }
684 atom->u.describe_args = strvec_detach(&args);
685 return 0;
686}
687
Jeff King5fe9e1c2023-02-24 01:39:06 -0500688static int raw_atom_parser(struct ref_format *format UNUSED,
689 struct used_atom *atom,
690 const char *arg, struct strbuf *err)
ZheNing Hubd0708c2021-07-26 03:26:47 +0000691{
692 if (!arg)
693 atom->u.raw_data.option = RAW_BARE;
694 else if (!strcmp(arg, "size"))
695 atom->u.raw_data.option = RAW_LENGTH;
696 else
Jeff Kingdda4fc12022-12-14 11:20:19 -0500697 return err_bad_arg(err, "raw", arg);
ZheNing Hubd0708c2021-07-26 03:26:47 +0000698 return 0;
699}
700
Jeff King5fe9e1c2023-02-24 01:39:06 -0500701static int oid_atom_parser(struct ref_format *format UNUSED,
702 struct used_atom *atom,
Hariom Verma87d3beb2020-08-21 21:41:46 +0000703 const char *arg, struct strbuf *err)
Karthik Nayakfe63c4d2016-02-17 23:36:19 +0530704{
705 if (!arg)
Hariom Verma87d3beb2020-08-21 21:41:46 +0000706 atom->u.oid.option = O_FULL;
Karthik Nayakfe63c4d2016-02-17 23:36:19 +0530707 else if (!strcmp(arg, "short"))
Hariom Verma87d3beb2020-08-21 21:41:46 +0000708 atom->u.oid.option = O_SHORT;
Karthik Nayak42d0eb02017-01-10 14:19:37 +0530709 else if (skip_prefix(arg, "short=", &arg)) {
Hariom Verma87d3beb2020-08-21 21:41:46 +0000710 atom->u.oid.option = O_LENGTH;
711 if (strtoul_ui(arg, 10, &atom->u.oid.length) ||
712 atom->u.oid.length == 0)
Hariom Vermae7601eb2020-08-21 21:41:45 +0000713 return strbuf_addf_ret(err, -1, _("positive value expected '%s' in %%(%s)"), arg, atom->name);
Hariom Verma87d3beb2020-08-21 21:41:46 +0000714 if (atom->u.oid.length < MINIMUM_ABBREV)
715 atom->u.oid.length = MINIMUM_ABBREV;
Karthik Nayak42d0eb02017-01-10 14:19:37 +0530716 } else
Jeff King1955ef12022-12-14 11:23:53 -0500717 return err_bad_arg(err, atom->name, arg);
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000718 return 0;
Karthik Nayakfe63c4d2016-02-17 23:36:19 +0530719}
720
Jeff King5fe9e1c2023-02-24 01:39:06 -0500721static int person_email_atom_parser(struct ref_format *format UNUSED,
722 struct used_atom *atom,
Hariom Vermab82445d2020-08-21 21:41:43 +0000723 const char *arg, struct strbuf *err)
724{
725 if (!arg)
726 atom->u.email_option.option = EO_RAW;
727 else if (!strcmp(arg, "trim"))
728 atom->u.email_option.option = EO_TRIM;
729 else if (!strcmp(arg, "localpart"))
730 atom->u.email_option.option = EO_LOCALPART;
731 else
Jeff King285da432022-12-14 11:24:03 -0500732 return err_bad_arg(err, atom->name, arg);
Karthik Nayakc95b7582015-06-14 01:07:27 +0530733 return 0;
734}
735
Jeff King5fe9e1c2023-02-24 01:39:06 -0500736static int refname_atom_parser(struct ref_format *format UNUSED,
737 struct used_atom *atom,
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000738 const char *arg, struct strbuf *err)
Karthik Nayaka7984102017-01-10 14:19:44 +0530739{
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000740 return refname_atom_parser_internal(&atom->u.refname, arg, atom->name, err);
Karthik Nayaka7984102017-01-10 14:19:44 +0530741}
742
Karthik Nayak25a8d792016-02-17 23:36:14 +0530743static align_type parse_align_position(const char *s)
744{
745 if (!strcmp(s, "right"))
746 return ALIGN_RIGHT;
747 else if (!strcmp(s, "middle"))
748 return ALIGN_MIDDLE;
749 else if (!strcmp(s, "left"))
750 return ALIGN_LEFT;
751 return -1;
752}
753
Jeff King5fe9e1c2023-02-24 01:39:06 -0500754static int align_atom_parser(struct ref_format *format UNUSED,
755 struct used_atom *atom,
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000756 const char *arg, struct strbuf *err)
Karthik Nayak5bd881d2016-02-17 23:36:15 +0530757{
758 struct align *align = &atom->u.align;
759 struct string_list params = STRING_LIST_INIT_DUP;
760 int i;
761 unsigned int width = ~0U;
762
763 if (!arg)
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000764 return strbuf_addf_ret(err, -1, _("expected format: %%(align:<width>,<position>)"));
Karthik Nayak5bd881d2016-02-17 23:36:15 +0530765
766 align->position = ALIGN_LEFT;
767
768 string_list_split(&params, arg, ',', -1);
769 for (i = 0; i < params.nr; i++) {
770 const char *s = params.items[i].string;
771 int position;
772
Karthik Nayak395fb8f2016-02-17 23:36:16 +0530773 if (skip_prefix(s, "position=", &s)) {
774 position = parse_align_position(s);
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000775 if (position < 0) {
776 strbuf_addf(err, _("unrecognized position:%s"), s);
777 string_list_clear(&params, 0);
778 return -1;
779 }
Karthik Nayak395fb8f2016-02-17 23:36:16 +0530780 align->position = position;
781 } else if (skip_prefix(s, "width=", &s)) {
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000782 if (strtoul_ui(s, 10, &width)) {
783 strbuf_addf(err, _("unrecognized width:%s"), s);
784 string_list_clear(&params, 0);
785 return -1;
786 }
Karthik Nayak395fb8f2016-02-17 23:36:16 +0530787 } else if (!strtoul_ui(s, 10, &width))
Karthik Nayak5bd881d2016-02-17 23:36:15 +0530788 ;
789 else if ((position = parse_align_position(s)) >= 0)
790 align->position = position;
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000791 else {
Jean-Noël Avila68e2ea02022-01-05 20:02:21 +0000792 strbuf_addf(err, _("unrecognized %%(%s) argument: %s"), "align", s);
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000793 string_list_clear(&params, 0);
794 return -1;
795 }
Karthik Nayak5bd881d2016-02-17 23:36:15 +0530796 }
797
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000798 if (width == ~0U) {
799 string_list_clear(&params, 0);
800 return strbuf_addf_ret(err, -1, _("positive width expected with the %%(align) atom"));
801 }
Karthik Nayak5bd881d2016-02-17 23:36:15 +0530802 align->width = width;
803 string_list_clear(&params, 0);
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000804 return 0;
Karthik Nayak5bd881d2016-02-17 23:36:15 +0530805}
806
Jeff King5fe9e1c2023-02-24 01:39:06 -0500807static int if_atom_parser(struct ref_format *format UNUSED,
808 struct used_atom *atom,
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000809 const char *arg, struct strbuf *err)
Karthik Nayak4f3e3b32017-01-10 14:19:36 +0530810{
811 if (!arg) {
812 atom->u.if_then_else.cmp_status = COMPARE_NONE;
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000813 return 0;
Karthik Nayak4f3e3b32017-01-10 14:19:36 +0530814 } else if (skip_prefix(arg, "equals=", &atom->u.if_then_else.str)) {
815 atom->u.if_then_else.cmp_status = COMPARE_EQUAL;
816 } else if (skip_prefix(arg, "notequals=", &atom->u.if_then_else.str)) {
817 atom->u.if_then_else.cmp_status = COMPARE_UNEQUAL;
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000818 } else
Jeff Kingdda4fc12022-12-14 11:20:19 -0500819 return err_bad_arg(err, "if", arg);
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000820 return 0;
Karthik Nayak4f3e3b32017-01-10 14:19:36 +0530821}
822
Jeff King29c9f2c2023-08-29 19:45:06 -0400823static int rest_atom_parser(struct ref_format *format UNUSED,
Jeff King5fe9e1c2023-02-24 01:39:06 -0500824 struct used_atom *atom UNUSED,
ZheNing Hub9dee072021-07-26 03:26:50 +0000825 const char *arg, struct strbuf *err)
826{
827 if (arg)
Jeff Kinga33d0fa2022-12-14 11:19:43 -0500828 return err_no_arg(err, "rest");
ZheNing Hub9dee072021-07-26 03:26:50 +0000829 return 0;
830}
831
Jeff King29c9f2c2023-08-29 19:45:06 -0400832static int ahead_behind_atom_parser(struct ref_format *format,
833 struct used_atom *atom UNUSED,
Derrick Stolee49abcd22023-03-20 11:26:54 +0000834 const char *arg, struct strbuf *err)
835{
836 struct string_list_item *item;
837
838 if (!arg)
839 return strbuf_addf_ret(err, -1, _("expected format: %%(ahead-behind:<committish>)"));
840
841 item = string_list_append(&format->bases, arg);
842 item->util = lookup_commit_reference_by_name(arg);
843 if (!item->util)
844 die("failed to find '%s'", arg);
845
846 return 0;
847}
848
Jeff King5fe9e1c2023-02-24 01:39:06 -0500849static int head_atom_parser(struct ref_format *format UNUSED,
850 struct used_atom *atom,
Jeff Kingafc1a942022-12-14 11:18:49 -0500851 const char *arg, struct strbuf *err)
Jeff King613a0e52017-05-19 02:12:12 -0400852{
Jeff Kingafc1a942022-12-14 11:18:49 -0500853 if (arg)
Jeff Kinga33d0fa2022-12-14 11:19:43 -0500854 return err_no_arg(err, "HEAD");
René Scharfeefbd4fd2017-10-01 09:29:03 +0200855 atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000856 return 0;
Jeff King613a0e52017-05-19 02:12:12 -0400857}
Karthik Nayak4f3e3b32017-01-10 14:19:36 +0530858
Karthik Nayakc95b7582015-06-14 01:07:27 +0530859static struct {
860 const char *name;
Olga Telezhnayaa8e7e382018-07-17 08:22:57 +0000861 info_source source;
Karthik Nayakc95b7582015-06-14 01:07:27 +0530862 cmp_type cmp_type;
ZheNing Hue85fcb32021-07-26 03:26:49 +0000863 int (*parser)(struct ref_format *format, struct used_atom *atom,
Olga Telezhnaya74efea92018-03-29 12:49:45 +0000864 const char *arg, struct strbuf *err);
Karthik Nayakc95b7582015-06-14 01:07:27 +0530865} valid_atom[] = {
ZheNing Hu1197f1a2021-05-13 15:15:38 +0000866 [ATOM_REFNAME] = { "refname", SOURCE_NONE, FIELD_STR, refname_atom_parser },
867 [ATOM_OBJECTTYPE] = { "objecttype", SOURCE_OTHER, FIELD_STR, objecttype_atom_parser },
868 [ATOM_OBJECTSIZE] = { "objectsize", SOURCE_OTHER, FIELD_ULONG, objectsize_atom_parser },
869 [ATOM_OBJECTNAME] = { "objectname", SOURCE_OTHER, FIELD_STR, oid_atom_parser },
870 [ATOM_DELTABASE] = { "deltabase", SOURCE_OTHER, FIELD_STR, deltabase_atom_parser },
871 [ATOM_TREE] = { "tree", SOURCE_OBJ, FIELD_STR, oid_atom_parser },
872 [ATOM_PARENT] = { "parent", SOURCE_OBJ, FIELD_STR, oid_atom_parser },
873 [ATOM_NUMPARENT] = { "numparent", SOURCE_OBJ, FIELD_ULONG },
874 [ATOM_OBJECT] = { "object", SOURCE_OBJ },
875 [ATOM_TYPE] = { "type", SOURCE_OBJ },
876 [ATOM_TAG] = { "tag", SOURCE_OBJ },
877 [ATOM_AUTHOR] = { "author", SOURCE_OBJ },
878 [ATOM_AUTHORNAME] = { "authorname", SOURCE_OBJ },
879 [ATOM_AUTHOREMAIL] = { "authoremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
880 [ATOM_AUTHORDATE] = { "authordate", SOURCE_OBJ, FIELD_TIME },
881 [ATOM_COMMITTER] = { "committer", SOURCE_OBJ },
882 [ATOM_COMMITTERNAME] = { "committername", SOURCE_OBJ },
883 [ATOM_COMMITTEREMAIL] = { "committeremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
884 [ATOM_COMMITTERDATE] = { "committerdate", SOURCE_OBJ, FIELD_TIME },
885 [ATOM_TAGGER] = { "tagger", SOURCE_OBJ },
886 [ATOM_TAGGERNAME] = { "taggername", SOURCE_OBJ },
887 [ATOM_TAGGEREMAIL] = { "taggeremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
888 [ATOM_TAGGERDATE] = { "taggerdate", SOURCE_OBJ, FIELD_TIME },
889 [ATOM_CREATOR] = { "creator", SOURCE_OBJ },
890 [ATOM_CREATORDATE] = { "creatordate", SOURCE_OBJ, FIELD_TIME },
Kousik Sanagavarapuf5d18f82023-07-23 21:49:59 +0530891 [ATOM_DESCRIBE] = { "describe", SOURCE_OBJ, FIELD_STR, describe_atom_parser },
ZheNing Hu1197f1a2021-05-13 15:15:38 +0000892 [ATOM_SUBJECT] = { "subject", SOURCE_OBJ, FIELD_STR, subject_atom_parser },
893 [ATOM_BODY] = { "body", SOURCE_OBJ, FIELD_STR, body_atom_parser },
894 [ATOM_TRAILERS] = { "trailers", SOURCE_OBJ, FIELD_STR, trailers_atom_parser },
895 [ATOM_CONTENTS] = { "contents", SOURCE_OBJ, FIELD_STR, contents_atom_parser },
Kousik Sanagavarapu26c9c032023-06-04 23:52:47 +0530896 [ATOM_SIGNATURE] = { "signature", SOURCE_OBJ, FIELD_STR, signature_atom_parser },
ZheNing Hubd0708c2021-07-26 03:26:47 +0000897 [ATOM_RAW] = { "raw", SOURCE_OBJ, FIELD_STR, raw_atom_parser },
ZheNing Hu1197f1a2021-05-13 15:15:38 +0000898 [ATOM_UPSTREAM] = { "upstream", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
899 [ATOM_PUSH] = { "push", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
900 [ATOM_SYMREF] = { "symref", SOURCE_NONE, FIELD_STR, refname_atom_parser },
901 [ATOM_FLAG] = { "flag", SOURCE_NONE },
902 [ATOM_HEAD] = { "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
903 [ATOM_COLOR] = { "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
904 [ATOM_WORKTREEPATH] = { "worktreepath", SOURCE_NONE },
905 [ATOM_ALIGN] = { "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
906 [ATOM_END] = { "end", SOURCE_NONE },
907 [ATOM_IF] = { "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
908 [ATOM_THEN] = { "then", SOURCE_NONE },
909 [ATOM_ELSE] = { "else", SOURCE_NONE },
ZheNing Hub9dee072021-07-26 03:26:50 +0000910 [ATOM_REST] = { "rest", SOURCE_NONE, FIELD_STR, rest_atom_parser },
Derrick Stolee49abcd22023-03-20 11:26:54 +0000911 [ATOM_AHEADBEHIND] = { "ahead-behind", SOURCE_OTHER, FIELD_STR, ahead_behind_atom_parser },
Nguyễn Thái Ngọc Duy5a59a232019-02-16 18:24:41 +0700912 /*
913 * Please update $__git_ref_fieldlist in git-completion.bash
914 * when you add new atoms
915 */
Karthik Nayakc95b7582015-06-14 01:07:27 +0530916};
917
Ævar Arnfjörð Bjarmason9865b6e2021-09-27 14:54:25 +0200918#define REF_FORMATTING_STATE_INIT { 0 }
Karthik Nayak574e96a2015-09-10 21:18:18 +0530919
920struct ref_formatting_stack {
921 struct ref_formatting_stack *prev;
922 struct strbuf output;
Karthik Nayakc58492d2017-01-10 14:19:34 +0530923 void (*at_end)(struct ref_formatting_stack **stack);
Karthik Nayakce592082015-09-11 20:33:07 +0530924 void *at_end_data;
Karthik Nayak574e96a2015-09-10 21:18:18 +0530925};
926
927struct ref_formatting_state {
928 int quote_style;
929 struct ref_formatting_stack *stack;
930};
931
Karthik Nayak3a257612015-08-22 09:09:37 +0530932struct atom_value {
933 const char *s;
ZheNing Hubd0708c2021-07-26 03:26:47 +0000934 ssize_t s_size;
Olga Telezhnaya3fc84392018-03-29 12:49:45 +0000935 int (*handler)(struct atom_value *atomv, struct ref_formatting_state *state,
936 struct strbuf *err);
Johannes Schindeline467dc12017-04-20 22:52:09 +0200937 uintmax_t value; /* used for sorting when not FIELD_STR */
Karthik Nayakc58fc852017-01-10 14:19:35 +0530938 struct used_atom *atom;
Karthik Nayak3a257612015-08-22 09:09:37 +0530939};
940
ZheNing Hubd0708c2021-07-26 03:26:47 +0000941#define ATOM_SIZE_UNSPECIFIED (-1)
942
943#define ATOM_VALUE_INIT { \
944 .s_size = ATOM_SIZE_UNSPECIFIED \
945}
946
Karthik Nayakc95b7582015-06-14 01:07:27 +0530947/*
Karthik Nayakc95b7582015-06-14 01:07:27 +0530948 * Used to parse format string and sort specifiers
949 */
ZheNing Hue85fcb32021-07-26 03:26:49 +0000950static int parse_ref_filter_atom(struct ref_format *format,
Olga Telezhnayae6ff7b32018-03-29 12:49:45 +0000951 const char *atom, const char *ep,
952 struct strbuf *err)
Karthik Nayakc95b7582015-06-14 01:07:27 +0530953{
954 const char *sp;
Karthik Nayak4de707e2016-02-17 23:36:12 +0530955 const char *arg;
SZEDER Gábore94ce132016-10-02 18:35:11 +0200956 int i, at, atom_len;
Karthik Nayakc95b7582015-06-14 01:07:27 +0530957
958 sp = atom;
959 if (*sp == '*' && sp < ep)
960 sp++; /* deref */
961 if (ep <= sp)
Olga Telezhnayae6ff7b32018-03-29 12:49:45 +0000962 return strbuf_addf_ret(err, -1, _("malformed field name: %.*s"),
963 (int)(ep-atom), atom);
Karthik Nayakc95b7582015-06-14 01:07:27 +0530964
SZEDER Gábore94ce132016-10-02 18:35:11 +0200965 /*
966 * If the atom name has a colon, strip it and everything after
967 * it off - it specifies the format for this entry, and
968 * shouldn't be used for checking against the valid_atom
969 * table.
970 */
971 arg = memchr(sp, ':', ep - sp);
972 atom_len = (arg ? arg : ep) - sp;
973
ZheNing Hubd0708c2021-07-26 03:26:47 +0000974 /* Do we have the atom already used elsewhere? */
975 for (i = 0; i < used_atom_cnt; i++) {
976 int len = strlen(used_atom[i].name);
977 if (len == ep - atom && !memcmp(used_atom[i].name, atom, len))
978 return i;
979 }
980
Karthik Nayakc95b7582015-06-14 01:07:27 +0530981 /* Is the atom a valid one? */
982 for (i = 0; i < ARRAY_SIZE(valid_atom); i++) {
983 int len = strlen(valid_atom[i].name);
SZEDER Gábore94ce132016-10-02 18:35:11 +0200984 if (len == atom_len && !memcmp(valid_atom[i].name, sp, len))
Karthik Nayakc95b7582015-06-14 01:07:27 +0530985 break;
986 }
987
988 if (ARRAY_SIZE(valid_atom) <= i)
Olga Telezhnayae6ff7b32018-03-29 12:49:45 +0000989 return strbuf_addf_ret(err, -1, _("unknown field name: %.*s"),
990 (int)(ep-atom), atom);
SZEDER Gábor47bd3d02018-11-14 13:27:25 +0100991 if (valid_atom[i].source != SOURCE_NONE && !have_git_dir())
992 return strbuf_addf_ret(err, -1,
993 _("not a git repository, but the field '%.*s' requires access to object data"),
994 (int)(ep-atom), atom);
Karthik Nayakc95b7582015-06-14 01:07:27 +0530995
996 /* Add it in, including the deref prefix */
997 at = used_atom_cnt;
998 used_atom_cnt++;
999 REALLOC_ARRAY(used_atom, used_atom_cnt);
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001000 used_atom[at].atom_type = i;
Karthik Nayakb072add2016-02-17 23:36:11 +05301001 used_atom[at].name = xmemdupz(atom, ep - atom);
1002 used_atom[at].type = valid_atom[i].cmp_type;
Olga Telezhnayaa8e7e382018-07-17 08:22:57 +00001003 used_atom[at].source = valid_atom[i].source;
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00001004 if (used_atom[at].source == SOURCE_OBJ) {
1005 if (*atom == '*')
1006 oi_deref.info.contentp = &oi_deref.content;
1007 else
1008 oi.info.contentp = &oi.content;
1009 }
Taylor Blaubea4dbe2017-10-02 09:10:34 -07001010 if (arg) {
Karthik Nayak4de707e2016-02-17 23:36:12 +05301011 arg = used_atom[at].name + (arg - atom) + 1;
Taylor Blaubea4dbe2017-10-02 09:10:34 -07001012 if (!*arg) {
1013 /*
1014 * Treat empty sub-arguments list as NULL (i.e.,
1015 * "%(atom:)" is equivalent to "%(atom)").
1016 */
1017 arg = NULL;
1018 }
1019 }
Karthik Nayakfd935cc2016-02-17 23:36:13 +05301020 memset(&used_atom[at].u, 0, sizeof(used_atom[at].u));
Olga Telezhnaya74efea92018-03-29 12:49:45 +00001021 if (valid_atom[i].parser && valid_atom[i].parser(format, &used_atom[at], arg, err))
1022 return -1;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301023 if (*atom == '*')
1024 need_tagged = 1;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001025 if (i == ATOM_SYMREF)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301026 need_symref = 1;
1027 return at;
1028}
1029
ZheNing Hubd0708c2021-07-26 03:26:47 +00001030static void quote_formatting(struct strbuf *s, const char *str, ssize_t len, int quote_style)
Karthik Nayak63d89fb2015-09-10 21:18:20 +05301031{
1032 switch (quote_style) {
1033 case QUOTE_NONE:
ZheNing Hubd0708c2021-07-26 03:26:47 +00001034 if (len < 0)
1035 strbuf_addstr(s, str);
1036 else
1037 strbuf_add(s, str, len);
Karthik Nayak63d89fb2015-09-10 21:18:20 +05301038 break;
1039 case QUOTE_SHELL:
1040 sq_quote_buf(s, str);
1041 break;
1042 case QUOTE_PERL:
ZheNing Hu7121c4d2021-07-26 03:26:48 +00001043 if (len < 0)
1044 perl_quote_buf(s, str);
1045 else
1046 perl_quote_buf_with_len(s, str, len);
Karthik Nayak63d89fb2015-09-10 21:18:20 +05301047 break;
1048 case QUOTE_PYTHON:
1049 python_quote_buf(s, str);
1050 break;
1051 case QUOTE_TCL:
1052 tcl_quote_buf(s, str);
1053 break;
1054 }
1055}
1056
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001057static int append_atom(struct atom_value *v, struct ref_formatting_state *state,
Jeff King5fe9e1c2023-02-24 01:39:06 -05001058 struct strbuf *err UNUSED)
Karthik Nayak63d89fb2015-09-10 21:18:20 +05301059{
Karthik Nayakce592082015-09-11 20:33:07 +05301060 /*
1061 * Quote formatting is only done when the stack has a single
1062 * element. Otherwise quote formatting is done on the
1063 * element's entire output strbuf when the %(end) atom is
1064 * encountered.
1065 */
1066 if (!state->stack->prev)
ZheNing Hubd0708c2021-07-26 03:26:47 +00001067 quote_formatting(&state->stack->output, v->s, v->s_size, state->quote_style);
1068 else if (v->s_size < 0)
Karthik Nayakce592082015-09-11 20:33:07 +05301069 strbuf_addstr(&state->stack->output, v->s);
ZheNing Hubd0708c2021-07-26 03:26:47 +00001070 else
1071 strbuf_add(&state->stack->output, v->s, v->s_size);
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001072 return 0;
Karthik Nayak63d89fb2015-09-10 21:18:20 +05301073}
1074
Karthik Nayak574e96a2015-09-10 21:18:18 +05301075static void push_stack_element(struct ref_formatting_stack **stack)
1076{
1077 struct ref_formatting_stack *s = xcalloc(1, sizeof(struct ref_formatting_stack));
1078
1079 strbuf_init(&s->output, 0);
1080 s->prev = *stack;
1081 *stack = s;
1082}
1083
1084static void pop_stack_element(struct ref_formatting_stack **stack)
1085{
1086 struct ref_formatting_stack *current = *stack;
1087 struct ref_formatting_stack *prev = current->prev;
1088
1089 if (prev)
1090 strbuf_addbuf(&prev->output, &current->output);
1091 strbuf_release(&current->output);
1092 free(current);
1093 *stack = prev;
1094}
1095
Karthik Nayakc58492d2017-01-10 14:19:34 +05301096static void end_align_handler(struct ref_formatting_stack **stack)
Karthik Nayakce592082015-09-11 20:33:07 +05301097{
Karthik Nayakc58492d2017-01-10 14:19:34 +05301098 struct ref_formatting_stack *cur = *stack;
1099 struct align *align = (struct align *)cur->at_end_data;
Karthik Nayakce592082015-09-11 20:33:07 +05301100 struct strbuf s = STRBUF_INIT;
1101
Karthik Nayakc58492d2017-01-10 14:19:34 +05301102 strbuf_utf8_align(&s, align->position, align->width, cur->output.buf);
1103 strbuf_swap(&cur->output, &s);
Karthik Nayakce592082015-09-11 20:33:07 +05301104 strbuf_release(&s);
1105}
1106
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001107static int align_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
Jeff King5fe9e1c2023-02-24 01:39:06 -05001108 struct strbuf *err UNUSED)
Karthik Nayakce592082015-09-11 20:33:07 +05301109{
Brandon Williams1472b5b2018-02-14 10:59:46 -08001110 struct ref_formatting_stack *new_stack;
Karthik Nayakce592082015-09-11 20:33:07 +05301111
1112 push_stack_element(&state->stack);
Brandon Williams1472b5b2018-02-14 10:59:46 -08001113 new_stack = state->stack;
1114 new_stack->at_end = end_align_handler;
1115 new_stack->at_end_data = &atomv->atom->u.align;
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001116 return 0;
Karthik Nayakce592082015-09-11 20:33:07 +05301117}
1118
Karthik Nayakc58492d2017-01-10 14:19:34 +05301119static void if_then_else_handler(struct ref_formatting_stack **stack)
1120{
1121 struct ref_formatting_stack *cur = *stack;
1122 struct ref_formatting_stack *prev = cur->prev;
1123 struct if_then_else *if_then_else = (struct if_then_else *)cur->at_end_data;
1124
1125 if (!if_then_else->then_atom_seen)
Jean-Noël Avilad7d30ba2022-01-05 20:02:23 +00001126 die(_("format: %%(%s) atom used without a %%(%s) atom"), "if", "then");
Karthik Nayakc58492d2017-01-10 14:19:34 +05301127
1128 if (if_then_else->else_atom_seen) {
1129 /*
1130 * There is an %(else) atom: we need to drop one state from the
1131 * stack, either the %(else) branch if the condition is satisfied, or
1132 * the %(then) branch if it isn't.
1133 */
1134 if (if_then_else->condition_satisfied) {
1135 strbuf_reset(&cur->output);
1136 pop_stack_element(&cur);
1137 } else {
1138 strbuf_swap(&cur->output, &prev->output);
1139 strbuf_reset(&cur->output);
1140 pop_stack_element(&cur);
1141 }
1142 } else if (!if_then_else->condition_satisfied) {
1143 /*
1144 * No %(else) atom: just drop the %(then) branch if the
1145 * condition is not satisfied.
1146 */
1147 strbuf_reset(&cur->output);
1148 }
1149
1150 *stack = cur;
1151 free(if_then_else);
1152}
1153
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001154static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
Jeff King5fe9e1c2023-02-24 01:39:06 -05001155 struct strbuf *err UNUSED)
Karthik Nayakc58492d2017-01-10 14:19:34 +05301156{
Brandon Williams1472b5b2018-02-14 10:59:46 -08001157 struct ref_formatting_stack *new_stack;
René Scharfe241b5d32021-03-06 12:26:19 +01001158 struct if_then_else *if_then_else = xcalloc(1,
1159 sizeof(struct if_then_else));
Karthik Nayakc58492d2017-01-10 14:19:34 +05301160
Karthik Nayak4f3e3b32017-01-10 14:19:36 +05301161 if_then_else->str = atomv->atom->u.if_then_else.str;
1162 if_then_else->cmp_status = atomv->atom->u.if_then_else.cmp_status;
1163
Karthik Nayakc58492d2017-01-10 14:19:34 +05301164 push_stack_element(&state->stack);
Brandon Williams1472b5b2018-02-14 10:59:46 -08001165 new_stack = state->stack;
1166 new_stack->at_end = if_then_else_handler;
1167 new_stack->at_end_data = if_then_else;
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001168 return 0;
Karthik Nayakc58492d2017-01-10 14:19:34 +05301169}
1170
ZheNing Hubd0708c2021-07-26 03:26:47 +00001171static int is_empty(struct strbuf *buf)
Karthik Nayakc58492d2017-01-10 14:19:34 +05301172{
ZheNing Hubd0708c2021-07-26 03:26:47 +00001173 const char *cur = buf->buf;
1174 const char *end = buf->buf + buf->len;
1175
1176 while (cur != end && (isspace(*cur)))
1177 cur++;
1178
1179 return cur == end;
1180 }
Karthik Nayakc58492d2017-01-10 14:19:34 +05301181
Jeff King5fe9e1c2023-02-24 01:39:06 -05001182static int then_atom_handler(struct atom_value *atomv UNUSED,
1183 struct ref_formatting_state *state,
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001184 struct strbuf *err)
Karthik Nayakc58492d2017-01-10 14:19:34 +05301185{
1186 struct ref_formatting_stack *cur = state->stack;
1187 struct if_then_else *if_then_else = NULL;
ZheNing Hubd0708c2021-07-26 03:26:47 +00001188 size_t str_len = 0;
Karthik Nayakc58492d2017-01-10 14:19:34 +05301189
1190 if (cur->at_end == if_then_else_handler)
1191 if_then_else = (struct if_then_else *)cur->at_end_data;
1192 if (!if_then_else)
Jean-Noël Avilad7d30ba2022-01-05 20:02:23 +00001193 return strbuf_addf_ret(err, -1, _("format: %%(%s) atom used without a %%(%s) atom"), "then", "if");
Karthik Nayakc58492d2017-01-10 14:19:34 +05301194 if (if_then_else->then_atom_seen)
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001195 return strbuf_addf_ret(err, -1, _("format: %%(then) atom used more than once"));
Karthik Nayakc58492d2017-01-10 14:19:34 +05301196 if (if_then_else->else_atom_seen)
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001197 return strbuf_addf_ret(err, -1, _("format: %%(then) atom used after %%(else)"));
Karthik Nayakc58492d2017-01-10 14:19:34 +05301198 if_then_else->then_atom_seen = 1;
ZheNing Hubd0708c2021-07-26 03:26:47 +00001199 if (if_then_else->str)
1200 str_len = strlen(if_then_else->str);
Karthik Nayakc58492d2017-01-10 14:19:34 +05301201 /*
Karthik Nayak4f3e3b32017-01-10 14:19:36 +05301202 * If the 'equals' or 'notequals' attribute is used then
1203 * perform the required comparison. If not, only non-empty
1204 * strings satisfy the 'if' condition.
Karthik Nayakc58492d2017-01-10 14:19:34 +05301205 */
Karthik Nayak4f3e3b32017-01-10 14:19:36 +05301206 if (if_then_else->cmp_status == COMPARE_EQUAL) {
ZheNing Hubd0708c2021-07-26 03:26:47 +00001207 if (str_len == cur->output.len &&
1208 !memcmp(if_then_else->str, cur->output.buf, cur->output.len))
Karthik Nayak4f3e3b32017-01-10 14:19:36 +05301209 if_then_else->condition_satisfied = 1;
1210 } else if (if_then_else->cmp_status == COMPARE_UNEQUAL) {
ZheNing Hubd0708c2021-07-26 03:26:47 +00001211 if (str_len != cur->output.len ||
1212 memcmp(if_then_else->str, cur->output.buf, cur->output.len))
Karthik Nayak4f3e3b32017-01-10 14:19:36 +05301213 if_then_else->condition_satisfied = 1;
ZheNing Hubd0708c2021-07-26 03:26:47 +00001214 } else if (cur->output.len && !is_empty(&cur->output))
Karthik Nayakc58492d2017-01-10 14:19:34 +05301215 if_then_else->condition_satisfied = 1;
1216 strbuf_reset(&cur->output);
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001217 return 0;
Karthik Nayakc58492d2017-01-10 14:19:34 +05301218}
1219
Jeff King5fe9e1c2023-02-24 01:39:06 -05001220static int else_atom_handler(struct atom_value *atomv UNUSED,
1221 struct ref_formatting_state *state,
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001222 struct strbuf *err)
Karthik Nayakc58492d2017-01-10 14:19:34 +05301223{
1224 struct ref_formatting_stack *prev = state->stack;
1225 struct if_then_else *if_then_else = NULL;
1226
1227 if (prev->at_end == if_then_else_handler)
1228 if_then_else = (struct if_then_else *)prev->at_end_data;
1229 if (!if_then_else)
Jean-Noël Avilad7d30ba2022-01-05 20:02:23 +00001230 return strbuf_addf_ret(err, -1, _("format: %%(%s) atom used without a %%(%s) atom"), "else", "if");
Karthik Nayakc58492d2017-01-10 14:19:34 +05301231 if (!if_then_else->then_atom_seen)
Jean-Noël Avilad7d30ba2022-01-05 20:02:23 +00001232 return strbuf_addf_ret(err, -1, _("format: %%(%s) atom used without a %%(%s) atom"), "else", "then");
Karthik Nayakc58492d2017-01-10 14:19:34 +05301233 if (if_then_else->else_atom_seen)
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001234 return strbuf_addf_ret(err, -1, _("format: %%(else) atom used more than once"));
Karthik Nayakc58492d2017-01-10 14:19:34 +05301235 if_then_else->else_atom_seen = 1;
1236 push_stack_element(&state->stack);
1237 state->stack->at_end_data = prev->at_end_data;
1238 state->stack->at_end = prev->at_end;
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001239 return 0;
Karthik Nayakce592082015-09-11 20:33:07 +05301240}
1241
Jeff King5fe9e1c2023-02-24 01:39:06 -05001242static int end_atom_handler(struct atom_value *atomv UNUSED,
1243 struct ref_formatting_state *state,
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001244 struct strbuf *err)
Karthik Nayakce592082015-09-11 20:33:07 +05301245{
1246 struct ref_formatting_stack *current = state->stack;
1247 struct strbuf s = STRBUF_INIT;
1248
1249 if (!current->at_end)
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001250 return strbuf_addf_ret(err, -1, _("format: %%(end) atom used without corresponding atom"));
Karthik Nayakc58492d2017-01-10 14:19:34 +05301251 current->at_end(&state->stack);
1252
1253 /* Stack may have been popped within at_end(), hence reset the current pointer */
1254 current = state->stack;
Karthik Nayakce592082015-09-11 20:33:07 +05301255
1256 /*
1257 * Perform quote formatting when the stack element is that of
1258 * a supporting atom. If nested then perform quote formatting
1259 * only on the topmost supporting atom.
1260 */
Karthik Nayakc58492d2017-01-10 14:19:34 +05301261 if (!current->prev->prev) {
ZheNing Hubd0708c2021-07-26 03:26:47 +00001262 quote_formatting(&s, current->output.buf, current->output.len, state->quote_style);
Karthik Nayakce592082015-09-11 20:33:07 +05301263 strbuf_swap(&current->output, &s);
1264 }
1265 strbuf_release(&s);
1266 pop_stack_element(&state->stack);
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00001267 return 0;
Karthik Nayakce592082015-09-11 20:33:07 +05301268}
1269
Karthik Nayakc95b7582015-06-14 01:07:27 +05301270/*
1271 * In a format string, find the next occurrence of %(atom).
1272 */
1273static const char *find_next(const char *cp)
1274{
1275 while (*cp) {
1276 if (*cp == '%') {
1277 /*
1278 * %( is the start of an atom;
1279 * %% is a quoted per-cent.
1280 */
1281 if (cp[1] == '(')
1282 return cp;
1283 else if (cp[1] == '%')
1284 cp++; /* skip over two % */
1285 /* otherwise this is a singleton, literal % */
1286 }
1287 cp++;
1288 }
1289 return NULL;
1290}
1291
ZheNing Hub9dee072021-07-26 03:26:50 +00001292static int reject_atom(enum atom_type atom_type)
1293{
1294 return atom_type == ATOM_REST;
1295}
1296
Karthik Nayakc95b7582015-06-14 01:07:27 +05301297/*
1298 * Make sure the format string is well formed, and parse out
1299 * the used atoms.
1300 */
Jeff King4a68e362017-07-13 11:01:18 -04001301int verify_ref_format(struct ref_format *format)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301302{
1303 const char *cp, *sp;
1304
Jeff Kingbf285ae2017-07-13 11:02:30 -04001305 format->need_color_reset_at_eol = 0;
Jeff King4a68e362017-07-13 11:01:18 -04001306 for (cp = format->format; *cp && (sp = find_next(cp)); ) {
Olga Telezhnayae6ff7b32018-03-29 12:49:45 +00001307 struct strbuf err = STRBUF_INIT;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301308 const char *color, *ep = strchr(sp, ')');
1309 int at;
1310
1311 if (!ep)
Nguyễn Thái Ngọc Duy1823c612016-02-27 13:42:04 +07001312 return error(_("malformed format string %s"), sp);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301313 /* sp points at "%(" and ep points at the closing ")" */
Olga Telezhnayae6ff7b32018-03-29 12:49:45 +00001314 at = parse_ref_filter_atom(format, sp + 2, ep, &err);
1315 if (at < 0)
1316 die("%s", err.buf);
ZheNing Hub9dee072021-07-26 03:26:50 +00001317 if (reject_atom(used_atom[at].atom_type))
1318 die(_("this command reject atom %%(%.*s)"), (int)(ep - sp - 2), sp + 2);
ZheNing Hu7121c4d2021-07-26 03:26:48 +00001319
1320 if ((format->quote_style == QUOTE_PYTHON ||
1321 format->quote_style == QUOTE_SHELL ||
1322 format->quote_style == QUOTE_TCL) &&
1323 used_atom[at].atom_type == ATOM_RAW &&
1324 used_atom[at].u.raw_data.option == RAW_BARE)
Jiang Xinf7337192021-11-01 10:14:17 +08001325 die(_("--format=%.*s cannot be used with "
ZheNing Hu7121c4d2021-07-26 03:26:48 +00001326 "--python, --shell, --tcl"), (int)(ep - sp - 2), sp + 2);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301327 cp = ep + 1;
1328
Karthik Nayakb072add2016-02-17 23:36:11 +05301329 if (skip_prefix(used_atom[at].name, "color:", &color))
Jeff Kingbf285ae2017-07-13 11:02:30 -04001330 format->need_color_reset_at_eol = !!strcmp(color, "reset");
Olga Telezhnayae6ff7b32018-03-29 12:49:45 +00001331 strbuf_release(&err);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301332 }
Jeff King11b087a2017-07-13 11:09:32 -04001333 if (format->need_color_reset_at_eol && !want_color(format->use_color))
1334 format->need_color_reset_at_eol = 0;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301335 return 0;
1336}
1337
Hariom Verma87d3beb2020-08-21 21:41:46 +00001338static const char *do_grab_oid(const char *field, const struct object_id *oid,
1339 struct used_atom *atom)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301340{
Hariom Verma87d3beb2020-08-21 21:41:46 +00001341 switch (atom->u.oid.option) {
Hariom Verma51011002020-08-21 21:41:44 +00001342 case O_FULL:
1343 return oid_to_hex(oid);
1344 case O_LENGTH:
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02001345 return repo_find_unique_abbrev(the_repository, oid,
1346 atom->u.oid.length);
Hariom Verma51011002020-08-21 21:41:44 +00001347 case O_SHORT:
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02001348 return repo_find_unique_abbrev(the_repository, oid,
1349 DEFAULT_ABBREV);
Hariom Verma51011002020-08-21 21:41:44 +00001350 default:
1351 BUG("unknown %%(%s) option", field);
1352 }
1353}
1354
Hariom Verma87d3beb2020-08-21 21:41:46 +00001355static int grab_oid(const char *name, const char *field, const struct object_id *oid,
1356 struct atom_value *v, struct used_atom *atom)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301357{
Hariom Verma51011002020-08-21 21:41:44 +00001358 if (starts_with(name, field)) {
Hariom Verma87d3beb2020-08-21 21:41:46 +00001359 v->s = xstrdup(do_grab_oid(field, oid, atom));
Hariom Verma51011002020-08-21 21:41:44 +00001360 return 1;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301361 }
1362 return 0;
1363}
1364
1365/* See grab_values */
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00001366static void grab_common_values(struct atom_value *val, int deref, struct expand_data *oi)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301367{
1368 int i;
1369
1370 for (i = 0; i < used_atom_cnt; i++) {
Karthik Nayakb072add2016-02-17 23:36:11 +05301371 const char *name = used_atom[i].name;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001372 enum atom_type atom_type = used_atom[i].atom_type;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301373 struct atom_value *v = &val[i];
1374 if (!!deref != (*name == '*'))
1375 continue;
1376 if (deref)
1377 name++;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001378 if (atom_type == ATOM_OBJECTTYPE)
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00001379 v->s = xstrdup(type_name(oi->type));
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001380 else if (atom_type == ATOM_OBJECTSIZE) {
ZheNing Hu0caf20f2021-05-13 15:15:37 +00001381 if (used_atom[i].u.objectsize.option == O_SIZE_DISK) {
1382 v->value = oi->disk_size;
1383 v->s = xstrfmt("%"PRIuMAX, (uintmax_t)oi->disk_size);
1384 } else if (used_atom[i].u.objectsize.option == O_SIZE) {
1385 v->value = oi->size;
1386 v->s = xstrfmt("%"PRIuMAX , (uintmax_t)oi->size);
1387 }
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001388 } else if (atom_type == ATOM_DELTABASE)
Olga Telezhnaya33311fa2018-12-24 13:24:30 +00001389 v->s = xstrdup(oid_to_hex(&oi->delta_base_oid));
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001390 else if (atom_type == ATOM_OBJECTNAME && deref)
Hariom Verma87d3beb2020-08-21 21:41:46 +00001391 grab_oid(name, "objectname", &oi->oid, v, &used_atom[i]);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301392 }
1393}
1394
1395/* See grab_values */
Jeff Kinge0329192019-02-14 00:50:54 -05001396static void grab_tag_values(struct atom_value *val, int deref, struct object *obj)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301397{
1398 int i;
1399 struct tag *tag = (struct tag *) obj;
1400
1401 for (i = 0; i < used_atom_cnt; i++) {
Karthik Nayakb072add2016-02-17 23:36:11 +05301402 const char *name = used_atom[i].name;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001403 enum atom_type atom_type = used_atom[i].atom_type;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301404 struct atom_value *v = &val[i];
1405 if (!!deref != (*name == '*'))
1406 continue;
1407 if (deref)
1408 name++;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001409 if (atom_type == ATOM_TAG)
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00001410 v->s = xstrdup(tag->tag);
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001411 else if (atom_type == ATOM_TYPE && tag->tagged)
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00001412 v->s = xstrdup(type_name(tag->tagged->type));
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001413 else if (atom_type == ATOM_OBJECT && tag->tagged)
brian m. carlsonf2fd0762015-11-10 02:22:28 +00001414 v->s = xstrdup(oid_to_hex(&tag->tagged->oid));
Karthik Nayakc95b7582015-06-14 01:07:27 +05301415 }
1416}
1417
1418/* See grab_values */
Jeff Kinge0329192019-02-14 00:50:54 -05001419static void grab_commit_values(struct atom_value *val, int deref, struct object *obj)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301420{
1421 int i;
1422 struct commit *commit = (struct commit *) obj;
1423
1424 for (i = 0; i < used_atom_cnt; i++) {
Karthik Nayakb072add2016-02-17 23:36:11 +05301425 const char *name = used_atom[i].name;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001426 enum atom_type atom_type = used_atom[i].atom_type;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301427 struct atom_value *v = &val[i];
1428 if (!!deref != (*name == '*'))
1429 continue;
1430 if (deref)
1431 name++;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001432 if (atom_type == ATOM_TREE &&
1433 grab_oid(name, "tree", get_commit_tree_oid(commit), v, &used_atom[i]))
Hariom Verma837adb12020-08-21 21:41:47 +00001434 continue;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001435 if (atom_type == ATOM_NUMPARENT) {
Johannes Schindeline467dc12017-04-20 22:52:09 +02001436 v->value = commit_list_count(commit->parents);
1437 v->s = xstrfmt("%lu", (unsigned long)v->value);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301438 }
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001439 else if (atom_type == ATOM_PARENT) {
Karthik Nayakc95b7582015-06-14 01:07:27 +05301440 struct commit_list *parents;
Jeff Kinga5e03bf2015-09-24 17:07:12 -04001441 struct strbuf s = STRBUF_INIT;
1442 for (parents = commit->parents; parents; parents = parents->next) {
Hariom Verma26bc0aa2020-08-21 21:41:48 +00001443 struct object_id *oid = &parents->item->object.oid;
Jeff Kinga5e03bf2015-09-24 17:07:12 -04001444 if (parents != commit->parents)
1445 strbuf_addch(&s, ' ');
Hariom Verma26bc0aa2020-08-21 21:41:48 +00001446 strbuf_addstr(&s, do_grab_oid("parent", oid, &used_atom[i]));
Karthik Nayakc95b7582015-06-14 01:07:27 +05301447 }
Jeff Kinga5e03bf2015-09-24 17:07:12 -04001448 v->s = strbuf_detach(&s, NULL);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301449 }
1450 }
1451}
1452
Jeff King5c326d12019-02-14 00:51:03 -05001453static const char *find_wholine(const char *who, int wholen, const char *buf)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301454{
1455 const char *eol;
1456 while (*buf) {
1457 if (!strncmp(buf, who, wholen) &&
1458 buf[wholen] == ' ')
1459 return buf + wholen + 1;
1460 eol = strchr(buf, '\n');
1461 if (!eol)
1462 return "";
1463 eol++;
1464 if (*eol == '\n')
1465 return ""; /* end of header */
1466 buf = eol;
1467 }
1468 return "";
1469}
1470
1471static const char *copy_line(const char *buf)
1472{
1473 const char *eol = strchrnul(buf, '\n');
1474 return xmemdupz(buf, eol - buf);
1475}
1476
1477static const char *copy_name(const char *buf)
1478{
1479 const char *cp;
1480 for (cp = buf; *cp && *cp != '\n'; cp++) {
Jeff King20869d12023-01-07 08:26:18 -05001481 if (starts_with(cp, " <"))
Karthik Nayakc95b7582015-06-14 01:07:27 +05301482 return xmemdupz(buf, cp - buf);
1483 }
Mischa POSLAWSKY8b3f33e2019-08-17 23:51:07 +02001484 return xstrdup("");
Karthik Nayakc95b7582015-06-14 01:07:27 +05301485}
1486
Hariom Vermab82445d2020-08-21 21:41:43 +00001487static const char *copy_email(const char *buf, struct used_atom *atom)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301488{
1489 const char *email = strchr(buf, '<');
1490 const char *eoemail;
1491 if (!email)
Mischa POSLAWSKY8b3f33e2019-08-17 23:51:07 +02001492 return xstrdup("");
Hariom Vermab82445d2020-08-21 21:41:43 +00001493 switch (atom->u.email_option.option) {
1494 case EO_RAW:
1495 eoemail = strchr(email, '>');
1496 if (eoemail)
1497 eoemail++;
1498 break;
1499 case EO_TRIM:
1500 email++;
1501 eoemail = strchr(email, '>');
1502 break;
1503 case EO_LOCALPART:
1504 email++;
1505 eoemail = strchr(email, '@');
1506 if (!eoemail)
1507 eoemail = strchr(email, '>');
1508 break;
1509 default:
1510 BUG("unknown email option");
1511 }
1512
Karthik Nayakc95b7582015-06-14 01:07:27 +05301513 if (!eoemail)
Mischa POSLAWSKY8b3f33e2019-08-17 23:51:07 +02001514 return xstrdup("");
Hariom Vermab82445d2020-08-21 21:41:43 +00001515 return xmemdupz(email, eoemail - email);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301516}
1517
1518static char *copy_subject(const char *buf, unsigned long len)
1519{
Philippe Blain9f75ce32020-10-29 12:48:28 +00001520 struct strbuf sb = STRBUF_INIT;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301521 int i;
1522
Philippe Blain9f75ce32020-10-29 12:48:28 +00001523 for (i = 0; i < len; i++) {
1524 if (buf[i] == '\r' && i + 1 < len && buf[i + 1] == '\n')
1525 continue; /* ignore CR in CRLF */
Karthik Nayakc95b7582015-06-14 01:07:27 +05301526
Philippe Blain9f75ce32020-10-29 12:48:28 +00001527 if (buf[i] == '\n')
1528 strbuf_addch(&sb, ' ');
1529 else
1530 strbuf_addch(&sb, buf[i]);
1531 }
1532 return strbuf_detach(&sb, NULL);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301533}
1534
1535static void grab_date(const char *buf, struct atom_value *v, const char *atomname)
1536{
1537 const char *eoemail = strstr(buf, "> ");
1538 char *zone;
Johannes Schindelindddbad72017-04-26 21:29:31 +02001539 timestamp_t timestamp;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301540 long tz;
Ævar Arnfjörð Bjarmasonf1842892022-02-16 09:14:03 +01001541 struct date_mode date_mode = DATE_MODE_INIT;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301542 const char *formatp;
1543
1544 /*
1545 * We got here because atomname ends in "date" or "date<something>";
1546 * it's not possible that <something> is not ":<format>" because
1547 * parse_ref_filter_atom() wouldn't have allowed it, so we can assume that no
1548 * ":" means no format is specified, and use the default.
1549 */
1550 formatp = strchr(atomname, ':');
Junio C Hamanoafe8a902022-05-02 09:50:37 -07001551 if (formatp) {
Karthik Nayakc95b7582015-06-14 01:07:27 +05301552 formatp++;
Junio C Hamanod939af12015-08-03 11:01:27 -07001553 parse_date_format(formatp, &date_mode);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301554 }
1555
1556 if (!eoemail)
1557 goto bad;
Johannes Schindelin1aeb7e72017-04-21 12:45:44 +02001558 timestamp = parse_timestamp(eoemail + 2, &zone, 10);
Johannes Schindelindddbad72017-04-26 21:29:31 +02001559 if (timestamp == TIME_MAX)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301560 goto bad;
1561 tz = strtol(zone, NULL, 10);
1562 if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)
1563 goto bad;
Junio C Hamanod939af12015-08-03 11:01:27 -07001564 v->s = xstrdup(show_date(timestamp, tz, &date_mode));
Johannes Schindeline467dc12017-04-20 22:52:09 +02001565 v->value = timestamp;
Ævar Arnfjörð Bjarmason974c9192022-02-16 09:14:05 +01001566 date_mode_release(&date_mode);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301567 return;
1568 bad:
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00001569 v->s = xstrdup("");
Johannes Schindeline467dc12017-04-20 22:52:09 +02001570 v->value = 0;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301571}
1572
1573/* See grab_values */
Jeff King5c326d12019-02-14 00:51:03 -05001574static void grab_person(const char *who, struct atom_value *val, int deref, void *buf)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301575{
1576 int i;
1577 int wholen = strlen(who);
1578 const char *wholine = NULL;
1579
1580 for (i = 0; i < used_atom_cnt; i++) {
Karthik Nayakb072add2016-02-17 23:36:11 +05301581 const char *name = used_atom[i].name;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301582 struct atom_value *v = &val[i];
1583 if (!!deref != (*name == '*'))
1584 continue;
1585 if (deref)
1586 name++;
1587 if (strncmp(who, name, wholen))
1588 continue;
1589 if (name[wholen] != 0 &&
1590 strcmp(name + wholen, "name") &&
Hariom Vermab82445d2020-08-21 21:41:43 +00001591 !starts_with(name + wholen, "email") &&
Karthik Nayakc95b7582015-06-14 01:07:27 +05301592 !starts_with(name + wholen, "date"))
1593 continue;
1594 if (!wholine)
Jeff King5c326d12019-02-14 00:51:03 -05001595 wholine = find_wholine(who, wholen, buf);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301596 if (!wholine)
1597 return; /* no point looking for it */
1598 if (name[wholen] == 0)
1599 v->s = copy_line(wholine);
1600 else if (!strcmp(name + wholen, "name"))
1601 v->s = copy_name(wholine);
Hariom Vermab82445d2020-08-21 21:41:43 +00001602 else if (starts_with(name + wholen, "email"))
1603 v->s = copy_email(wholine, &used_atom[i]);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301604 else if (starts_with(name + wholen, "date"))
1605 grab_date(wholine, v, name);
1606 }
1607
1608 /*
1609 * For a tag or a commit object, if "creator" or "creatordate" is
1610 * requested, do something special.
1611 */
1612 if (strcmp(who, "tagger") && strcmp(who, "committer"))
1613 return; /* "author" for commit object is not wanted */
1614 if (!wholine)
Jeff King5c326d12019-02-14 00:51:03 -05001615 wholine = find_wholine(who, wholen, buf);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301616 if (!wholine)
1617 return;
1618 for (i = 0; i < used_atom_cnt; i++) {
Karthik Nayakb072add2016-02-17 23:36:11 +05301619 const char *name = used_atom[i].name;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001620 enum atom_type atom_type = used_atom[i].atom_type;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301621 struct atom_value *v = &val[i];
1622 if (!!deref != (*name == '*'))
1623 continue;
1624 if (deref)
1625 name++;
1626
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001627 if (atom_type == ATOM_CREATORDATE)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301628 grab_date(wholine, v, name);
ZheNing Hu1197f1a2021-05-13 15:15:38 +00001629 else if (atom_type == ATOM_CREATOR)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301630 v->s = copy_line(wholine);
1631 }
1632}
1633
Kousik Sanagavarapu26c9c032023-06-04 23:52:47 +05301634static void grab_signature(struct atom_value *val, int deref, struct object *obj)
1635{
1636 int i;
1637 struct commit *commit = (struct commit *) obj;
1638 struct signature_check sigc = { 0 };
1639 int signature_checked = 0;
1640
1641 for (i = 0; i < used_atom_cnt; i++) {
1642 struct used_atom *atom = &used_atom[i];
1643 const char *name = atom->name;
1644 struct atom_value *v = &val[i];
1645 int opt;
1646
1647 if (!!deref != (*name == '*'))
1648 continue;
1649 if (deref)
1650 name++;
1651
1652 if (!skip_prefix(name, "signature", &name) ||
1653 (*name && *name != ':'))
1654 continue;
1655 if (!*name)
1656 name = NULL;
1657 else
1658 name++;
1659
1660 opt = parse_signature_option(name);
1661 if (opt < 0)
1662 continue;
1663
1664 if (!signature_checked) {
1665 check_commit_signature(commit, &sigc);
1666 signature_checked = 1;
1667 }
1668
1669 switch (opt) {
1670 case S_BARE:
1671 v->s = xstrdup(sigc.output ? sigc.output: "");
1672 break;
1673 case S_SIGNER:
1674 v->s = xstrdup(sigc.signer ? sigc.signer : "");
1675 break;
1676 case S_GRADE:
1677 switch (sigc.result) {
1678 case 'G':
1679 switch (sigc.trust_level) {
1680 case TRUST_UNDEFINED:
1681 case TRUST_NEVER:
1682 v->s = xstrfmt("%c", (char)'U');
1683 break;
1684 default:
1685 v->s = xstrfmt("%c", (char)'G');
1686 break;
1687 }
1688 break;
1689 case 'B':
1690 case 'E':
1691 case 'N':
1692 case 'X':
1693 case 'Y':
1694 case 'R':
1695 v->s = xstrfmt("%c", (char)sigc.result);
1696 break;
1697 }
1698 break;
1699 case S_KEY:
1700 v->s = xstrdup(sigc.key ? sigc.key : "");
1701 break;
1702 case S_FINGERPRINT:
1703 v->s = xstrdup(sigc.fingerprint ?
1704 sigc.fingerprint : "");
1705 break;
1706 case S_PRI_KEY_FP:
1707 v->s = xstrdup(sigc.primary_key_fingerprint ?
1708 sigc.primary_key_fingerprint : "");
1709 break;
1710 case S_TRUST_LEVEL:
1711 v->s = xstrdup(gpg_trust_level_to_str(sigc.trust_level));
1712 break;
1713 }
1714 }
1715
1716 if (signature_checked)
1717 signature_check_clear(&sigc);
1718}
1719
Jeff King5c326d12019-02-14 00:51:03 -05001720static void find_subpos(const char *buf,
brian m. carlson83dff3e2021-01-18 23:49:10 +00001721 const char **sub, size_t *sublen,
1722 const char **body, size_t *bodylen,
1723 size_t *nonsiglen,
1724 const char **sig, size_t *siglen)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301725{
brian m. carlson482c1192021-02-11 02:08:03 +00001726 struct strbuf payload = STRBUF_INIT;
1727 struct strbuf signature = STRBUF_INIT;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301728 const char *eol;
brian m. carlson482c1192021-02-11 02:08:03 +00001729 const char *end = buf + strlen(buf);
1730 const char *sigstart;
1731
brian m. carlson88bce0e2021-02-11 02:08:05 +00001732 /* parse signature first; we might not even have a subject line */
1733 parse_signature(buf, end - buf, &payload, &signature);
Ævar Arnfjörð Bjarmasonb6046ab2022-11-08 19:17:42 +01001734 strbuf_release(&payload);
brian m. carlson482c1192021-02-11 02:08:03 +00001735
Karthik Nayakc95b7582015-06-14 01:07:27 +05301736 /* skip past header until we hit empty line */
1737 while (*buf && *buf != '\n') {
1738 eol = strchrnul(buf, '\n');
1739 if (*eol)
1740 eol++;
1741 buf = eol;
1742 }
1743 /* skip any empty lines */
1744 while (*buf == '\n')
1745 buf++;
brian m. carlson482c1192021-02-11 02:08:03 +00001746 *sig = strbuf_detach(&signature, siglen);
1747 sigstart = buf + parse_signed_buffer(buf, strlen(buf));
Karthik Nayakc95b7582015-06-14 01:07:27 +05301748
1749 /* subject is first non-empty line */
1750 *sub = buf;
Philippe Blain9f75ce32020-10-29 12:48:28 +00001751 /* subject goes to first empty line before signature begins */
Jeff King8e1c5fc2022-11-02 03:44:00 -04001752 if ((eol = strstr(*sub, "\n\n")) ||
1753 (eol = strstr(*sub, "\r\n\r\n"))) {
brian m. carlson482c1192021-02-11 02:08:03 +00001754 eol = eol < sigstart ? eol : sigstart;
Jeff King8e1c5fc2022-11-02 03:44:00 -04001755 } else {
Philippe Blain9f75ce32020-10-29 12:48:28 +00001756 /* treat whole message as subject */
Jeff Kingb01e1c72022-11-02 03:42:07 -04001757 eol = sigstart;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301758 }
Philippe Blain9f75ce32020-10-29 12:48:28 +00001759 buf = eol;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301760 *sublen = buf - *sub;
1761 /* drop trailing newline, if present */
Philippe Blain9f75ce32020-10-29 12:48:28 +00001762 while (*sublen && ((*sub)[*sublen - 1] == '\n' ||
1763 (*sub)[*sublen - 1] == '\r'))
Karthik Nayakc95b7582015-06-14 01:07:27 +05301764 *sublen -= 1;
1765
1766 /* skip any empty lines */
Philippe Blain9f75ce32020-10-29 12:48:28 +00001767 while (*buf == '\n' || *buf == '\r')
Karthik Nayakc95b7582015-06-14 01:07:27 +05301768 buf++;
1769 *body = buf;
1770 *bodylen = strlen(buf);
brian m. carlson482c1192021-02-11 02:08:03 +00001771 *nonsiglen = sigstart - buf;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301772}
1773
Karthik Nayak1bb38e52015-09-11 20:34:16 +05301774/*
1775 * If 'lines' is greater than 0, append that many lines from the given
1776 * 'buf' of length 'size' to the given strbuf.
1777 */
1778static void append_lines(struct strbuf *out, const char *buf, unsigned long size, int lines)
1779{
1780 int i;
1781 const char *sp, *eol;
1782 size_t len;
1783
1784 sp = buf;
1785
1786 for (i = 0; i < lines && sp < buf + size; i++) {
1787 if (i)
1788 strbuf_addstr(out, "\n ");
1789 eol = memchr(sp, '\n', size - (sp - buf));
1790 len = eol ? eol - sp : size - (sp - buf);
1791 strbuf_add(out, sp, len);
1792 if (!eol)
1793 break;
1794 sp = eol + 1;
1795 }
1796}
1797
Kousik Sanagavarapuf5d18f82023-07-23 21:49:59 +05301798static void grab_describe_values(struct atom_value *val, int deref,
1799 struct object *obj)
1800{
1801 struct commit *commit = (struct commit *)obj;
1802 int i;
1803
1804 for (i = 0; i < used_atom_cnt; i++) {
1805 struct used_atom *atom = &used_atom[i];
1806 enum atom_type type = atom->atom_type;
1807 const char *name = atom->name;
1808 struct atom_value *v = &val[i];
1809
1810 struct child_process cmd = CHILD_PROCESS_INIT;
1811 struct strbuf out = STRBUF_INIT;
1812 struct strbuf err = STRBUF_INIT;
1813
1814 if (type != ATOM_DESCRIBE)
1815 continue;
1816
1817 if (!!deref != (*name == '*'))
1818 continue;
1819
1820 cmd.git_cmd = 1;
1821 strvec_push(&cmd.args, "describe");
1822 strvec_pushv(&cmd.args, atom->u.describe_args);
1823 strvec_push(&cmd.args, oid_to_hex(&commit->object.oid));
1824 if (pipe_command(&cmd, NULL, 0, &out, 0, &err, 0) < 0) {
1825 error(_("failed to run 'describe'"));
1826 v->s = xstrdup("");
1827 continue;
1828 }
1829 strbuf_rtrim(&out);
1830 v->s = strbuf_detach(&out, NULL);
1831
1832 strbuf_release(&err);
1833 }
1834}
1835
Karthik Nayakc95b7582015-06-14 01:07:27 +05301836/* See grab_values */
ZheNing Hu311d0b82021-07-26 03:26:46 +00001837static void grab_sub_body_contents(struct atom_value *val, int deref, struct expand_data *data)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301838{
1839 int i;
1840 const char *subpos = NULL, *bodypos = NULL, *sigpos = NULL;
brian m. carlson83dff3e2021-01-18 23:49:10 +00001841 size_t sublen = 0, bodylen = 0, nonsiglen = 0, siglen = 0;
ZheNing Hu311d0b82021-07-26 03:26:46 +00001842 void *buf = data->content;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301843
1844 for (i = 0; i < used_atom_cnt; i++) {
Karthik Nayak452db392016-02-17 23:36:18 +05301845 struct used_atom *atom = &used_atom[i];
1846 const char *name = atom->name;
Karthik Nayakc95b7582015-06-14 01:07:27 +05301847 struct atom_value *v = &val[i];
ZheNing Hubd0708c2021-07-26 03:26:47 +00001848 enum atom_type atom_type = atom->atom_type;
brian m. carlson482c1192021-02-11 02:08:03 +00001849
Karthik Nayakc95b7582015-06-14 01:07:27 +05301850 if (!!deref != (*name == '*'))
1851 continue;
1852 if (deref)
1853 name++;
ZheNing Hu311d0b82021-07-26 03:26:46 +00001854
ZheNing Hubd0708c2021-07-26 03:26:47 +00001855 if (atom_type == ATOM_RAW) {
1856 unsigned long buf_size = data->size;
1857
1858 if (atom->u.raw_data.option == RAW_BARE) {
1859 v->s = xmemdupz(buf, buf_size);
1860 v->s_size = buf_size;
1861 } else if (atom->u.raw_data.option == RAW_LENGTH) {
1862 v->s = xstrfmt("%"PRIuMAX, (uintmax_t)buf_size);
1863 }
1864 continue;
1865 }
1866
ZheNing Hu311d0b82021-07-26 03:26:46 +00001867 if ((data->type != OBJ_TAG &&
1868 data->type != OBJ_COMMIT) ||
1869 (strcmp(name, "body") &&
1870 !starts_with(name, "subject") &&
1871 !starts_with(name, "trailers") &&
1872 !starts_with(name, "contents")))
Karthik Nayakc95b7582015-06-14 01:07:27 +05301873 continue;
1874 if (!subpos)
Jeff King5c326d12019-02-14 00:51:03 -05001875 find_subpos(buf,
Karthik Nayakc95b7582015-06-14 01:07:27 +05301876 &subpos, &sublen,
1877 &bodypos, &bodylen, &nonsiglen,
1878 &sigpos, &siglen);
1879
Karthik Nayak452db392016-02-17 23:36:18 +05301880 if (atom->u.contents.option == C_SUB)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301881 v->s = copy_subject(subpos, sublen);
Hariom Verma905f0a42020-08-21 21:41:50 +00001882 else if (atom->u.contents.option == C_SUB_SANITIZE) {
1883 struct strbuf sb = STRBUF_INIT;
1884 format_sanitized_subject(&sb, subpos, sublen);
1885 v->s = strbuf_detach(&sb, NULL);
1886 } else if (atom->u.contents.option == C_BODY_DEP)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301887 v->s = xmemdupz(bodypos, bodylen);
Christian Couderb6839fd2020-07-16 14:19:40 +02001888 else if (atom->u.contents.option == C_LENGTH)
1889 v->s = xstrfmt("%"PRIuMAX, (uintmax_t)strlen(subpos));
Karthik Nayak452db392016-02-17 23:36:18 +05301890 else if (atom->u.contents.option == C_BODY)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301891 v->s = xmemdupz(bodypos, nonsiglen);
Karthik Nayak452db392016-02-17 23:36:18 +05301892 else if (atom->u.contents.option == C_SIG)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301893 v->s = xmemdupz(sigpos, siglen);
Karthik Nayak452db392016-02-17 23:36:18 +05301894 else if (atom->u.contents.option == C_LINES) {
Karthik Nayak1bb38e52015-09-11 20:34:16 +05301895 struct strbuf s = STRBUF_INIT;
brian m. carlson88bce0e2021-02-11 02:08:05 +00001896 const char *contents_end = bodypos + nonsiglen;
Karthik Nayak1bb38e52015-09-11 20:34:16 +05301897
Karthik Nayak1bb38e52015-09-11 20:34:16 +05301898 /* Size is the length of the message after removing the signature */
Karthik Nayak452db392016-02-17 23:36:18 +05301899 append_lines(&s, subpos, contents_end - subpos, atom->u.contents.nlines);
Karthik Nayak1bb38e52015-09-11 20:34:16 +05301900 v->s = strbuf_detach(&s, NULL);
Jacob Kellerb1d31c82016-11-18 16:58:15 -08001901 } else if (atom->u.contents.option == C_TRAILERS) {
Taylor Blau67a20a02017-10-01 22:25:23 -07001902 struct strbuf s = STRBUF_INIT;
Jacob Kellerb1d31c82016-11-18 16:58:15 -08001903
Taylor Blau67a20a02017-10-01 22:25:23 -07001904 /* Format the trailer info according to the trailer_opts given */
1905 format_trailers_from_commit(&s, subpos, &atom->u.contents.trailer_opts);
1906
1907 v->s = strbuf_detach(&s, NULL);
Karthik Nayak452db392016-02-17 23:36:18 +05301908 } else if (atom->u.contents.option == C_BARE)
1909 v->s = xstrdup(subpos);
brian m. carlson482c1192021-02-11 02:08:03 +00001910
Karthik Nayakc95b7582015-06-14 01:07:27 +05301911 }
brian m. carlson482c1192021-02-11 02:08:03 +00001912 free((void *)sigpos);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301913}
1914
1915/*
1916 * We want to have empty print-string for field requests
1917 * that do not apply (e.g. "authordate" for a tag object)
1918 */
1919static void fill_missing_values(struct atom_value *val)
1920{
1921 int i;
1922 for (i = 0; i < used_atom_cnt; i++) {
1923 struct atom_value *v = &val[i];
Junio C Hamanoafe8a902022-05-02 09:50:37 -07001924 if (!v->s)
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00001925 v->s = xstrdup("");
Karthik Nayakc95b7582015-06-14 01:07:27 +05301926 }
1927}
1928
1929/*
1930 * val is a list of atom_value to hold returned values. Extract
1931 * the values for atoms in used_atom array out of (obj, buf, sz).
1932 * when deref is false, (obj, buf, sz) is the object that is
1933 * pointed at by the ref itself; otherwise it is the object the
1934 * ref (which is a tag) refers to.
1935 */
ZheNing Hu311d0b82021-07-26 03:26:46 +00001936static void grab_values(struct atom_value *val, int deref, struct object *obj, struct expand_data *data)
Karthik Nayakc95b7582015-06-14 01:07:27 +05301937{
ZheNing Hu311d0b82021-07-26 03:26:46 +00001938 void *buf = data->content;
1939
Karthik Nayakc95b7582015-06-14 01:07:27 +05301940 switch (obj->type) {
1941 case OBJ_TAG:
Jeff Kinge0329192019-02-14 00:50:54 -05001942 grab_tag_values(val, deref, obj);
ZheNing Hu311d0b82021-07-26 03:26:46 +00001943 grab_sub_body_contents(val, deref, data);
Jeff King5c326d12019-02-14 00:51:03 -05001944 grab_person("tagger", val, deref, buf);
Kousik Sanagavarapuf5d18f82023-07-23 21:49:59 +05301945 grab_describe_values(val, deref, obj);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301946 break;
1947 case OBJ_COMMIT:
Jeff Kinge0329192019-02-14 00:50:54 -05001948 grab_commit_values(val, deref, obj);
ZheNing Hu311d0b82021-07-26 03:26:46 +00001949 grab_sub_body_contents(val, deref, data);
Jeff King5c326d12019-02-14 00:51:03 -05001950 grab_person("author", val, deref, buf);
1951 grab_person("committer", val, deref, buf);
Kousik Sanagavarapu26c9c032023-06-04 23:52:47 +05301952 grab_signature(val, deref, obj);
Kousik Sanagavarapuf5d18f82023-07-23 21:49:59 +05301953 grab_describe_values(val, deref, obj);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301954 break;
1955 case OBJ_TREE:
1956 /* grab_tree_values(val, deref, obj, buf, sz); */
ZheNing Hubd0708c2021-07-26 03:26:47 +00001957 grab_sub_body_contents(val, deref, data);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301958 break;
1959 case OBJ_BLOB:
1960 /* grab_blob_values(val, deref, obj, buf, sz); */
ZheNing Hubd0708c2021-07-26 03:26:47 +00001961 grab_sub_body_contents(val, deref, data);
Karthik Nayakc95b7582015-06-14 01:07:27 +05301962 break;
1963 default:
1964 die("Eh? Object of type %d?", obj->type);
1965 }
1966}
1967
1968static inline char *copy_advance(char *dst, const char *src)
1969{
1970 while (*src)
1971 *dst++ = *src++;
1972 return dst;
1973}
1974
Karthik Nayak1a0ca5e2017-01-10 14:19:48 +05301975static const char *lstrip_ref_components(const char *refname, int len)
Jeff King05719792016-01-25 22:00:05 -05001976{
Karthik Nayaka7984102017-01-10 14:19:44 +05301977 long remaining = len;
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00001978 const char *start = xstrdup(refname);
1979 const char *to_free = start;
Jeff King05719792016-01-25 22:00:05 -05001980
Karthik Nayak1a0ca5e2017-01-10 14:19:48 +05301981 if (len < 0) {
1982 int i;
1983 const char *p = refname;
Jeff King05719792016-01-25 22:00:05 -05001984
Karthik Nayak1a0ca5e2017-01-10 14:19:48 +05301985 /* Find total no of '/' separated path-components */
1986 for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
1987 ;
1988 /*
1989 * The number of components we need to strip is now
1990 * the total minus the components to be left (Plus one
1991 * because we count the number of '/', but the number
1992 * of components is one more than the no of '/').
1993 */
1994 remaining = i + len + 1;
1995 }
1996
1997 while (remaining > 0) {
Jeff King05719792016-01-25 22:00:05 -05001998 switch (*start++) {
1999 case '\0':
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002000 free((char *)to_free);
2001 return xstrdup("");
Jeff King05719792016-01-25 22:00:05 -05002002 case '/':
2003 remaining--;
2004 break;
2005 }
2006 }
Karthik Nayak1a0ca5e2017-01-10 14:19:48 +05302007
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002008 start = xstrdup(start);
2009 free((char *)to_free);
Jeff King05719792016-01-25 22:00:05 -05002010 return start;
2011}
2012
Karthik Nayak1a347282017-01-10 14:19:49 +05302013static const char *rstrip_ref_components(const char *refname, int len)
2014{
2015 long remaining = len;
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002016 const char *start = xstrdup(refname);
2017 const char *to_free = start;
Karthik Nayak1a347282017-01-10 14:19:49 +05302018
2019 if (len < 0) {
2020 int i;
2021 const char *p = refname;
2022
2023 /* Find total no of '/' separated path-components */
2024 for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
2025 ;
2026 /*
2027 * The number of components we need to strip is now
2028 * the total minus the components to be left (Plus one
2029 * because we count the number of '/', but the number
2030 * of components is one more than the no of '/').
2031 */
2032 remaining = i + len + 1;
2033 }
2034
2035 while (remaining-- > 0) {
2036 char *p = strrchr(start, '/');
Junio C Hamanoafe8a902022-05-02 09:50:37 -07002037 if (!p) {
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002038 free((char *)to_free);
2039 return xstrdup("");
2040 } else
Karthik Nayak1a347282017-01-10 14:19:49 +05302041 p[0] = '\0';
2042 }
2043 return start;
2044}
2045
Karthik Nayaka7984102017-01-10 14:19:44 +05302046static const char *show_ref(struct refname_atom *atom, const char *refname)
2047{
2048 if (atom->option == R_SHORT)
2049 return shorten_unambiguous_ref(refname, warn_ambiguous_refs);
Karthik Nayak17938f12017-01-10 14:19:46 +05302050 else if (atom->option == R_LSTRIP)
2051 return lstrip_ref_components(refname, atom->lstrip);
Karthik Nayak1a347282017-01-10 14:19:49 +05302052 else if (atom->option == R_RSTRIP)
2053 return rstrip_ref_components(refname, atom->rstrip);
Karthik Nayaka7984102017-01-10 14:19:44 +05302054 else
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002055 return xstrdup(refname);
Karthik Nayaka7984102017-01-10 14:19:44 +05302056}
2057
Karthik Nayak5339bda2016-02-17 23:36:17 +05302058static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
2059 struct branch *branch, const char **s)
2060{
2061 int num_ours, num_theirs;
Karthik Nayak3ba308c2017-01-10 14:19:45 +05302062 if (atom->u.remote_ref.option == RR_REF)
2063 *s = show_ref(&atom->u.remote_ref.refname, refname);
Karthik Nayak7743fcc2017-01-10 14:19:41 +05302064 else if (atom->u.remote_ref.option == RR_TRACK) {
Jeff Hostetlerd7d1b492018-01-09 18:50:15 +00002065 if (stat_tracking_info(branch, &num_ours, &num_theirs,
Damien Robertc646d092019-04-16 14:16:46 +02002066 NULL, atom->u.remote_ref.push,
2067 AHEAD_BEHIND_FULL) < 0) {
Karthik Nayak6eac70f2017-01-10 14:19:50 +05302068 *s = xstrdup(msgs.gone);
Karthik Nayak7743fcc2017-01-10 14:19:41 +05302069 } else if (!num_ours && !num_theirs)
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002070 *s = xstrdup("");
Karthik Nayak5339bda2016-02-17 23:36:17 +05302071 else if (!num_ours)
Karthik Nayak6eac70f2017-01-10 14:19:50 +05302072 *s = xstrfmt(msgs.behind, num_theirs);
Karthik Nayak5339bda2016-02-17 23:36:17 +05302073 else if (!num_theirs)
Karthik Nayak6eac70f2017-01-10 14:19:50 +05302074 *s = xstrfmt(msgs.ahead, num_ours);
Karthik Nayak5339bda2016-02-17 23:36:17 +05302075 else
Karthik Nayak6eac70f2017-01-10 14:19:50 +05302076 *s = xstrfmt(msgs.ahead_behind,
Karthik Nayak5339bda2016-02-17 23:36:17 +05302077 num_ours, num_theirs);
Karthik Nayak7743fcc2017-01-10 14:19:41 +05302078 if (!atom->u.remote_ref.nobracket && *s[0]) {
2079 const char *to_free = *s;
2080 *s = xstrfmt("[%s]", *s);
2081 free((void *)to_free);
2082 }
2083 } else if (atom->u.remote_ref.option == RR_TRACKSHORT) {
Jeff Hostetlerd7d1b492018-01-09 18:50:15 +00002084 if (stat_tracking_info(branch, &num_ours, &num_theirs,
Damien Robertc646d092019-04-16 14:16:46 +02002085 NULL, atom->u.remote_ref.push,
2086 AHEAD_BEHIND_FULL) < 0) {
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002087 *s = xstrdup("");
Karthik Nayak5339bda2016-02-17 23:36:17 +05302088 return;
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002089 }
Karthik Nayak5339bda2016-02-17 23:36:17 +05302090 if (!num_ours && !num_theirs)
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002091 *s = xstrdup("=");
Karthik Nayak5339bda2016-02-17 23:36:17 +05302092 else if (!num_ours)
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002093 *s = xstrdup("<");
Karthik Nayak5339bda2016-02-17 23:36:17 +05302094 else if (!num_theirs)
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002095 *s = xstrdup(">");
Karthik Nayak5339bda2016-02-17 23:36:17 +05302096 else
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002097 *s = xstrdup("<>");
Johannes Schindelincc723852017-10-05 14:19:09 +02002098 } else if (atom->u.remote_ref.option == RR_REMOTE_NAME) {
2099 int explicit;
2100 const char *remote = atom->u.remote_ref.push ?
2101 pushremote_for_branch(branch, &explicit) :
2102 remote_for_branch(branch, &explicit);
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002103 *s = xstrdup(explicit ? remote : "");
J Wyman9700fae2017-11-07 17:31:08 +01002104 } else if (atom->u.remote_ref.option == RR_REMOTE_REF) {
J Wyman9700fae2017-11-07 17:31:08 +01002105 const char *merge;
2106
Jeff Kingaf8ccd82020-03-03 17:12:22 +01002107 merge = remote_ref_for_branch(branch, atom->u.remote_ref.push);
2108 *s = xstrdup(merge ? merge : "");
Karthik Nayak3ba308c2017-01-10 14:19:45 +05302109 } else
Johannes Schindelin033abf92018-05-02 11:38:39 +02002110 BUG("unhandled RR_* enum");
Karthik Nayak5339bda2016-02-17 23:36:17 +05302111}
2112
Karthik Nayakd4919bb2017-01-10 14:19:38 +05302113char *get_head_description(void)
2114{
2115 struct strbuf desc = STRBUF_INIT;
2116 struct wt_status_state state;
2117 memset(&state, 0, sizeof(state));
Nguyễn Thái Ngọc Duy78845452018-11-10 06:48:50 +01002118 wt_status_get_state(the_repository, &state, 1);
Karthik Nayakd4919bb2017-01-10 14:19:38 +05302119 if (state.rebase_in_progress ||
Kaartic Sivaraama236f902018-04-03 10:01:00 +05302120 state.rebase_interactive_in_progress) {
2121 if (state.branch)
Ævar Arnfjörð Bjarmason2708ce62021-01-07 10:51:52 +01002122 strbuf_addf(&desc, _("(no branch, rebasing %s)"),
Kaartic Sivaraama236f902018-04-03 10:01:00 +05302123 state.branch);
2124 else
Ævar Arnfjörð Bjarmason2708ce62021-01-07 10:51:52 +01002125 strbuf_addf(&desc, _("(no branch, rebasing detached HEAD %s)"),
Kaartic Sivaraama236f902018-04-03 10:01:00 +05302126 state.detached_from);
2127 } else if (state.bisect_in_progress)
Ævar Arnfjörð Bjarmason2708ce62021-01-07 10:51:52 +01002128 strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
Karthik Nayakd4919bb2017-01-10 14:19:38 +05302129 state.branch);
2130 else if (state.detached_from) {
Karthik Nayakd4919bb2017-01-10 14:19:38 +05302131 if (state.detached_at)
Ævar Arnfjörð Bjarmason2708ce62021-01-07 10:51:52 +01002132 strbuf_addf(&desc, _("(HEAD detached at %s)"),
2133 state.detached_from);
Karthik Nayakd4919bb2017-01-10 14:19:38 +05302134 else
Ævar Arnfjörð Bjarmason2708ce62021-01-07 10:51:52 +01002135 strbuf_addf(&desc, _("(HEAD detached from %s)"),
2136 state.detached_from);
2137 } else
2138 strbuf_addstr(&desc, _("(no branch)"));
Matthew DeVore28438e82019-06-18 15:29:15 -07002139
Rubén Justoabcac2e2022-09-25 00:53:18 +02002140 wt_status_state_free_buffers(&state);
2141
Karthik Nayakd4919bb2017-01-10 14:19:38 +05302142 return strbuf_detach(&desc, NULL);
2143}
2144
Karthik Nayaka7984102017-01-10 14:19:44 +05302145static const char *get_symref(struct used_atom *atom, struct ref_array_item *ref)
2146{
2147 if (!ref->symref)
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002148 return xstrdup("");
Karthik Nayaka7984102017-01-10 14:19:44 +05302149 else
2150 return show_ref(&atom->u.refname, ref->symref);
2151}
2152
2153static const char *get_refname(struct used_atom *atom, struct ref_array_item *ref)
2154{
2155 if (ref->kind & FILTER_REFS_DETACHED_HEAD)
2156 return get_head_description();
2157 return show_ref(&atom->u.refname, ref->refname);
Karthik Nayakc95b7582015-06-14 01:07:27 +05302158}
2159
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00002160static int get_object(struct ref_array_item *ref, int deref, struct object **obj,
2161 struct expand_data *oi, struct strbuf *err)
Olga Telezhnaya2bbc6e82018-02-21 06:59:00 +00002162{
Olga Telezhnaya04f6ee12018-07-17 08:22:57 +00002163 /* parse_object_buffer() will set eaten to 0 if free() will be needed */
2164 int eaten = 1;
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00002165 if (oi->info.contentp) {
2166 /* We need to know that to use parse_object_buffer properly */
2167 oi->info.sizep = &oi->size;
2168 oi->info.typep = &oi->type;
Olga Telezhnayae2255172018-07-17 08:22:57 +00002169 }
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00002170 if (oid_object_info_extended(the_repository, &oi->oid, &oi->info,
2171 OBJECT_INFO_LOOKUP_REPLACE))
2172 return strbuf_addf_ret(err, -1, _("missing object %s for %s"),
2173 oid_to_hex(&oi->oid), ref->refname);
Olga Telezhnaya5305a552018-12-24 13:24:30 +00002174 if (oi->info.disk_sizep && oi->disk_size < 0)
2175 BUG("Object size is less than zero.");
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00002176
2177 if (oi->info.contentp) {
Junio C Hamanoc83149a2018-08-17 13:09:57 -07002178 *obj = parse_object_buffer(the_repository, &oi->oid, oi->type, oi->size, oi->content, &eaten);
Jeff Kingc6854502021-04-01 04:32:24 -04002179 if (!*obj) {
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00002180 if (!eaten)
2181 free(oi->content);
2182 return strbuf_addf_ret(err, -1, _("parse_object_buffer failed on %s for %s"),
2183 oid_to_hex(&oi->oid), ref->refname);
2184 }
ZheNing Hu311d0b82021-07-26 03:26:46 +00002185 grab_values(ref->value, deref, *obj, oi);
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00002186 }
2187
2188 grab_common_values(ref->value, deref, oi);
Olga Telezhnaya2bbc6e82018-02-21 06:59:00 +00002189 if (!eaten)
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00002190 free(oi->content);
2191 return 0;
Olga Telezhnaya2bbc6e82018-02-21 06:59:00 +00002192}
2193
Nickolai Belakovski25820832019-04-28 22:19:42 -07002194static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)
2195{
2196 int i;
2197
2198 for (i = 0; worktrees[i]; i++) {
2199 if (worktrees[i]->head_ref) {
2200 struct ref_to_worktree_entry *entry;
2201 entry = xmalloc(sizeof(*entry));
2202 entry->wt = worktrees[i];
Eric Wongd22245a2019-10-06 23:30:27 +00002203 hashmap_entry_init(&entry->ent,
2204 strhash(worktrees[i]->head_ref));
Nickolai Belakovski25820832019-04-28 22:19:42 -07002205
Eric Wongb94e5c12019-10-06 23:30:29 +00002206 hashmap_add(map, &entry->ent);
Nickolai Belakovski25820832019-04-28 22:19:42 -07002207 }
2208 }
2209}
2210
2211static void lazy_init_worktree_map(void)
2212{
2213 if (ref_to_worktree_map.worktrees)
2214 return;
2215
Eric Sunshine03f24652020-06-19 19:35:44 -04002216 ref_to_worktree_map.worktrees = get_worktrees();
Nickolai Belakovski25820832019-04-28 22:19:42 -07002217 hashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);
2218 populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);
2219}
2220
Jeff Kingfe6258c2023-02-24 01:34:44 -05002221static char *get_worktree_path(const struct ref_array_item *ref)
Nickolai Belakovski25820832019-04-28 22:19:42 -07002222{
Eric Wongf23a4652019-10-06 23:30:36 +00002223 struct hashmap_entry entry, *e;
Nickolai Belakovski25820832019-04-28 22:19:42 -07002224 struct ref_to_worktree_entry *lookup_result;
2225
2226 lazy_init_worktree_map();
2227
2228 hashmap_entry_init(&entry, strhash(ref->refname));
Eric Wongf23a4652019-10-06 23:30:36 +00002229 e = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);
Nickolai Belakovski25820832019-04-28 22:19:42 -07002230
Eric Wongf23a4652019-10-06 23:30:36 +00002231 if (!e)
Nickolai Belakovski25820832019-04-28 22:19:42 -07002232 return xstrdup("");
Eric Wongf23a4652019-10-06 23:30:36 +00002233
2234 lookup_result = container_of(e, struct ref_to_worktree_entry, ent);
2235
2236 return xstrdup(lookup_result->wt->path);
Nickolai Belakovski25820832019-04-28 22:19:42 -07002237}
2238
Karthik Nayakc95b7582015-06-14 01:07:27 +05302239/*
2240 * Parse the object referred by ref, and grab needed value.
2241 */
Olga Telezhnayae3396112018-03-29 12:49:45 +00002242static int populate_value(struct ref_array_item *ref, struct strbuf *err)
Karthik Nayakc95b7582015-06-14 01:07:27 +05302243{
Karthik Nayakc95b7582015-06-14 01:07:27 +05302244 struct object *obj;
Olga Telezhnaya2bbc6e82018-02-21 06:59:00 +00002245 int i;
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00002246 struct object_info empty = OBJECT_INFO_INIT;
Derrick Stolee49abcd22023-03-20 11:26:54 +00002247 int ahead_behind_atoms = 0;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302248
René Scharfeca56dad2021-03-13 17:17:22 +01002249 CALLOC_ARRAY(ref->value, used_atom_cnt);
Karthik Nayakc95b7582015-06-14 01:07:27 +05302250
2251 if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {
Karthik Nayakc95b7582015-06-14 01:07:27 +05302252 ref->symref = resolve_refdup(ref->refname, RESOLVE_REF_READING,
René Scharfeefbd4fd2017-10-01 09:29:03 +02002253 NULL, NULL);
Karthik Nayakc95b7582015-06-14 01:07:27 +05302254 if (!ref->symref)
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002255 ref->symref = xstrdup("");
Karthik Nayakc95b7582015-06-14 01:07:27 +05302256 }
2257
2258 /* Fill in specials first */
2259 for (i = 0; i < used_atom_cnt; i++) {
Karthik Nayakfd935cc2016-02-17 23:36:13 +05302260 struct used_atom *atom = &used_atom[i];
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002261 enum atom_type atom_type = atom->atom_type;
Karthik Nayakb072add2016-02-17 23:36:11 +05302262 const char *name = used_atom[i].name;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302263 struct atom_value *v = &ref->value[i];
2264 int deref = 0;
2265 const char *refname;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302266 struct branch *branch = NULL;
2267
ZheNing Hubd0708c2021-07-26 03:26:47 +00002268 v->s_size = ATOM_SIZE_UNSPECIFIED;
Karthik Nayak63d89fb2015-09-10 21:18:20 +05302269 v->handler = append_atom;
Karthik Nayakc58fc852017-01-10 14:19:35 +05302270 v->atom = atom;
Karthik Nayak63d89fb2015-09-10 21:18:20 +05302271
Karthik Nayakc95b7582015-06-14 01:07:27 +05302272 if (*name == '*') {
2273 deref = 1;
2274 name++;
2275 }
2276
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002277 if (atom_type == ATOM_REFNAME)
Karthik Nayaka7984102017-01-10 14:19:44 +05302278 refname = get_refname(atom, ref);
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002279 else if (atom_type == ATOM_WORKTREEPATH) {
Nickolai Belakovski25820832019-04-28 22:19:42 -07002280 if (ref->kind == FILTER_REFS_BRANCHES)
Jeff Kingfe6258c2023-02-24 01:34:44 -05002281 v->s = get_worktree_path(ref);
Nickolai Belakovski25820832019-04-28 22:19:42 -07002282 else
2283 v->s = xstrdup("");
2284 continue;
2285 }
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002286 else if (atom_type == ATOM_SYMREF)
Karthik Nayaka7984102017-01-10 14:19:44 +05302287 refname = get_symref(atom, ref);
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002288 else if (atom_type == ATOM_UPSTREAM) {
Karthik Nayakc95b7582015-06-14 01:07:27 +05302289 const char *branch_name;
2290 /* only local branches may have an upstream */
2291 if (!skip_prefix(ref->refname, "refs/heads/",
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002292 &branch_name)) {
2293 v->s = xstrdup("");
Karthik Nayakc95b7582015-06-14 01:07:27 +05302294 continue;
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002295 }
Karthik Nayakc95b7582015-06-14 01:07:27 +05302296 branch = branch_get(branch_name);
2297
2298 refname = branch_get_upstream(branch, NULL);
Karthik Nayak5339bda2016-02-17 23:36:17 +05302299 if (refname)
2300 fill_remote_ref_details(atom, refname, branch, &v->s);
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002301 else
2302 v->s = xstrdup("");
Karthik Nayak5339bda2016-02-17 23:36:17 +05302303 continue;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002304 } else if (atom_type == ATOM_PUSH && atom->u.remote_ref.push) {
Karthik Nayakc95b7582015-06-14 01:07:27 +05302305 const char *branch_name;
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002306 v->s = xstrdup("");
Karthik Nayakc95b7582015-06-14 01:07:27 +05302307 if (!skip_prefix(ref->refname, "refs/heads/",
2308 &branch_name))
2309 continue;
2310 branch = branch_get(branch_name);
2311
Johannes Schindelincc723852017-10-05 14:19:09 +02002312 if (atom->u.remote_ref.push_remote)
2313 refname = NULL;
2314 else {
2315 refname = branch_get_push(branch, NULL);
2316 if (!refname)
2317 continue;
2318 }
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002319 /* We will definitely re-init v->s on the next line. */
2320 free((char *)v->s);
Karthik Nayak5339bda2016-02-17 23:36:17 +05302321 fill_remote_ref_details(atom, refname, branch, &v->s);
2322 continue;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002323 } else if (atom_type == ATOM_COLOR) {
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002324 v->s = xstrdup(atom->u.color);
Karthik Nayakc95b7582015-06-14 01:07:27 +05302325 continue;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002326 } else if (atom_type == ATOM_FLAG) {
Karthik Nayakc95b7582015-06-14 01:07:27 +05302327 char buf[256], *cp = buf;
2328 if (ref->flag & REF_ISSYMREF)
2329 cp = copy_advance(cp, ",symref");
2330 if (ref->flag & REF_ISPACKED)
2331 cp = copy_advance(cp, ",packed");
2332 if (cp == buf)
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002333 v->s = xstrdup("");
Karthik Nayakc95b7582015-06-14 01:07:27 +05302334 else {
2335 *cp = '\0';
2336 v->s = xstrdup(buf + 1);
2337 }
2338 continue;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002339 } else if (!deref && atom_type == ATOM_OBJECTNAME &&
2340 grab_oid(name, "objectname", &ref->objectname, v, atom)) {
2341 continue;
2342 } else if (atom_type == ATOM_HEAD) {
Jeff King613a0e52017-05-19 02:12:12 -04002343 if (atom->u.head && !strcmp(ref->refname, atom->u.head))
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002344 v->s = xstrdup("*");
Karthik Nayakc95b7582015-06-14 01:07:27 +05302345 else
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002346 v->s = xstrdup(" ");
Karthik Nayakc95b7582015-06-14 01:07:27 +05302347 continue;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002348 } else if (atom_type == ATOM_ALIGN) {
Karthik Nayakce592082015-09-11 20:33:07 +05302349 v->handler = align_atom_handler;
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002350 v->s = xstrdup("");
Karthik Nayakce592082015-09-11 20:33:07 +05302351 continue;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002352 } else if (atom_type == ATOM_END) {
Karthik Nayakce592082015-09-11 20:33:07 +05302353 v->handler = end_atom_handler;
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002354 v->s = xstrdup("");
Karthik Nayakce592082015-09-11 20:33:07 +05302355 continue;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002356 } else if (atom_type == ATOM_IF) {
Karthik Nayak4f3e3b32017-01-10 14:19:36 +05302357 const char *s;
Karthik Nayak4f3e3b32017-01-10 14:19:36 +05302358 if (skip_prefix(name, "if:", &s))
2359 v->s = xstrdup(s);
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002360 else
2361 v->s = xstrdup("");
Karthik Nayakc58492d2017-01-10 14:19:34 +05302362 v->handler = if_atom_handler;
2363 continue;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002364 } else if (atom_type == ATOM_THEN) {
Karthik Nayakc58492d2017-01-10 14:19:34 +05302365 v->handler = then_atom_handler;
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002366 v->s = xstrdup("");
Karthik Nayakc58492d2017-01-10 14:19:34 +05302367 continue;
ZheNing Hu1197f1a2021-05-13 15:15:38 +00002368 } else if (atom_type == ATOM_ELSE) {
Karthik Nayakc58492d2017-01-10 14:19:34 +05302369 v->handler = else_atom_handler;
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002370 v->s = xstrdup("");
Karthik Nayakc58492d2017-01-10 14:19:34 +05302371 continue;
ZheNing Hub9dee072021-07-26 03:26:50 +00002372 } else if (atom_type == ATOM_REST) {
2373 if (ref->rest)
2374 v->s = xstrdup(ref->rest);
2375 else
2376 v->s = xstrdup("");
2377 continue;
Derrick Stolee49abcd22023-03-20 11:26:54 +00002378 } else if (atom_type == ATOM_AHEADBEHIND) {
2379 if (ref->counts) {
2380 const struct ahead_behind_count *count;
2381 count = ref->counts[ahead_behind_atoms++];
2382 v->s = xstrfmt("%d %d", count->ahead, count->behind);
2383 } else {
2384 /* Not a commit. */
2385 v->s = xstrdup("");
2386 }
2387 continue;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302388 } else
2389 continue;
2390
Karthik Nayakc95b7582015-06-14 01:07:27 +05302391 if (!deref)
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002392 v->s = xstrdup(refname);
Jeff Kinga5e03bf2015-09-24 17:07:12 -04002393 else
2394 v->s = xstrfmt("%s^{}", refname);
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002395 free((char *)refname);
Karthik Nayakc95b7582015-06-14 01:07:27 +05302396 }
2397
2398 for (i = 0; i < used_atom_cnt; i++) {
2399 struct atom_value *v = &ref->value[i];
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00002400 if (v->s == NULL && used_atom[i].source == SOURCE_NONE)
2401 return strbuf_addf_ret(err, -1, _("missing object %s for %s"),
2402 oid_to_hex(&ref->objectname), ref->refname);
Karthik Nayakc95b7582015-06-14 01:07:27 +05302403 }
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00002404
2405 if (need_tagged)
2406 oi.info.contentp = &oi.content;
2407 if (!memcmp(&oi.info, &empty, sizeof(empty)) &&
2408 !memcmp(&oi_deref.info, &empty, sizeof(empty)))
Olga Telezhnayae3396112018-03-29 12:49:45 +00002409 return 0;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302410
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00002411
2412 oi.oid = ref->objectname;
2413 if (get_object(ref, 0, &obj, &oi, err))
Olga Telezhnayae3396112018-03-29 12:49:45 +00002414 return -1;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302415
2416 /*
2417 * If there is no atom that wants to know about tagged
2418 * object, we are done.
2419 */
2420 if (!need_tagged || (obj->type != OBJ_TAG))
Olga Telezhnayae3396112018-03-29 12:49:45 +00002421 return 0;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302422
2423 /*
2424 * If it is a tag object, see if we use a value that derefs
2425 * the object, and if we do grab the object it refers to.
2426 */
René Scharfec77722b2019-09-05 21:59:42 +02002427 oi_deref.oid = *get_tagged_oid((struct tag *)obj);
Karthik Nayakc95b7582015-06-14 01:07:27 +05302428
2429 /*
2430 * NEEDSWORK: This derefs tag only once, which
2431 * is good to deal with chains of trust, but
2432 * is not consistent with what deref_tag() does
2433 * which peels the onion to the core.
2434 */
Olga Telezhnayaaa46a0d2018-07-17 08:22:57 +00002435 return get_object(ref, 1, &obj, &oi_deref, err);
Karthik Nayakc95b7582015-06-14 01:07:27 +05302436}
2437
2438/*
2439 * Given a ref, return the value for the atom. This lazily gets value
2440 * out of the object by calling populate value.
2441 */
Olga Telezhnayae3396112018-03-29 12:49:45 +00002442static int get_ref_atom_value(struct ref_array_item *ref, int atom,
2443 struct atom_value **v, struct strbuf *err)
Karthik Nayakc95b7582015-06-14 01:07:27 +05302444{
2445 if (!ref->value) {
Olga Telezhnayae3396112018-03-29 12:49:45 +00002446 if (populate_value(ref, err))
2447 return -1;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302448 fill_missing_values(ref->value);
2449 }
2450 *v = &ref->value[atom];
Olga Telezhnayae3396112018-03-29 12:49:45 +00002451 return 0;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302452}
2453
Jeff Kinga91aca42017-03-09 08:29:49 -05002454/*
Karthik Nayakc95b7582015-06-14 01:07:27 +05302455 * Return 1 if the refname matches one of the patterns, otherwise 0.
Karthik Nayakbef0e122015-09-10 21:18:26 +05302456 * A pattern can be a literal prefix (e.g. a refname "refs/heads/master"
2457 * matches a pattern "refs/heads/mas") or a wildcard (e.g. the same ref
2458 * matches "refs/heads/mas*", too).
2459 */
Jeff King284c55d2023-07-10 17:12:16 -04002460static int match_pattern(const char **patterns, const char *refname,
2461 int ignore_case)
Karthik Nayakbef0e122015-09-10 21:18:26 +05302462{
Nguyễn Thái Ngọc Duy3bb16a82016-12-04 09:52:25 +07002463 unsigned flags = 0;
2464
Jeff King284c55d2023-07-10 17:12:16 -04002465 if (ignore_case)
Nguyễn Thái Ngọc Duy3bb16a82016-12-04 09:52:25 +07002466 flags |= WM_CASEFOLD;
2467
Karthik Nayakbef0e122015-09-10 21:18:26 +05302468 /*
2469 * When no '--format' option is given we need to skip the prefix
2470 * for matching refs of tags and branches.
2471 */
2472 (void)(skip_prefix(refname, "refs/tags/", &refname) ||
2473 skip_prefix(refname, "refs/heads/", &refname) ||
2474 skip_prefix(refname, "refs/remotes/", &refname) ||
2475 skip_prefix(refname, "refs/", &refname));
2476
2477 for (; *patterns; patterns++) {
Ævar Arnfjörð Bjarmason55d34262017-06-22 21:38:08 +00002478 if (!wildmatch(*patterns, refname, flags))
Karthik Nayakbef0e122015-09-10 21:18:26 +05302479 return 1;
2480 }
2481 return 0;
2482}
2483
2484/*
2485 * Return 1 if the refname matches one of the patterns, otherwise 0.
Karthik Nayakc95b7582015-06-14 01:07:27 +05302486 * A pattern can be path prefix (e.g. a refname "refs/heads/master"
Karthik Nayakbef0e122015-09-10 21:18:26 +05302487 * matches a pattern "refs/heads/" but not "refs/heads/m") or a
2488 * wildcard (e.g. the same ref matches "refs/heads/m*", too).
Karthik Nayakc95b7582015-06-14 01:07:27 +05302489 */
Jeff King284c55d2023-07-10 17:12:16 -04002490static int match_name_as_path(const char **pattern, const char *refname,
2491 int ignore_case)
Karthik Nayakc95b7582015-06-14 01:07:27 +05302492{
2493 int namelen = strlen(refname);
Nguyễn Thái Ngọc Duy3bb16a82016-12-04 09:52:25 +07002494 unsigned flags = WM_PATHNAME;
2495
Jeff King284c55d2023-07-10 17:12:16 -04002496 if (ignore_case)
Nguyễn Thái Ngọc Duy3bb16a82016-12-04 09:52:25 +07002497 flags |= WM_CASEFOLD;
2498
Karthik Nayakc95b7582015-06-14 01:07:27 +05302499 for (; *pattern; pattern++) {
2500 const char *p = *pattern;
2501 int plen = strlen(p);
2502
2503 if ((plen <= namelen) &&
2504 !strncmp(refname, p, plen) &&
2505 (refname[plen] == '\0' ||
2506 refname[plen] == '/' ||
2507 p[plen-1] == '/'))
2508 return 1;
Aleksandr Makarov639ab5e2018-07-02 17:11:59 -04002509 if (!wildmatch(p, refname, flags))
Karthik Nayakc95b7582015-06-14 01:07:27 +05302510 return 1;
2511 }
2512 return 0;
2513}
2514
Karthik Nayakbef0e122015-09-10 21:18:26 +05302515/* Return 1 if the refname matches one of the patterns, otherwise 0. */
2516static int filter_pattern_match(struct ref_filter *filter, const char *refname)
2517{
2518 if (!*filter->name_patterns)
2519 return 1; /* No pattern always matches */
2520 if (filter->match_as_path)
Jeff King284c55d2023-07-10 17:12:16 -04002521 return match_name_as_path(filter->name_patterns, refname,
2522 filter->ignore_case);
2523 return match_pattern(filter->name_patterns, refname,
2524 filter->ignore_case);
Karthik Nayakbef0e122015-09-10 21:18:26 +05302525}
2526
Taylor Blau8255dd82023-07-10 17:12:19 -04002527static int filter_exclude_match(struct ref_filter *filter, const char *refname)
2528{
2529 if (!filter->exclude.nr)
2530 return 0;
2531 if (filter->match_as_path)
2532 return match_name_as_path(filter->exclude.v, refname,
2533 filter->ignore_case);
2534 return match_pattern(filter->exclude.v, refname, filter->ignore_case);
Karthik Nayakc95b7582015-06-14 01:07:27 +05302535}
2536
Jeff Kingcfe004a2017-05-22 16:17:54 +02002537/*
2538 * This is the same as for_each_fullref_in(), but it tries to iterate
2539 * only over the patterns we'll care about. Note that it _doesn't_ do a full
2540 * pattern match, so the callback still has to match each ref individually.
2541 */
2542static int for_each_fullref_in_pattern(struct ref_filter *filter,
2543 each_ref_fn cb,
Jeff King67985e42021-09-24 14:48:48 -04002544 void *cb_data)
Jeff Kingcfe004a2017-05-22 16:17:54 +02002545{
Jeff Kingcfe004a2017-05-22 16:17:54 +02002546 if (!filter->match_as_path) {
2547 /*
2548 * in this case, the patterns are applied after
2549 * prefixes like "refs/heads/" etc. are stripped off,
2550 * so we have to look at everything:
2551 */
Jeff King67985e42021-09-24 14:48:48 -04002552 return for_each_fullref_in("", cb, cb_data);
Jeff Kingcfe004a2017-05-22 16:17:54 +02002553 }
2554
Jeff Kinge674eb22018-07-02 17:12:42 -04002555 if (filter->ignore_case) {
2556 /*
2557 * we can't handle case-insensitive comparisons,
2558 * so just return everything and let the caller
2559 * sort it out.
2560 */
Jeff King67985e42021-09-24 14:48:48 -04002561 return for_each_fullref_in("", cb, cb_data);
Jeff Kinge674eb22018-07-02 17:12:42 -04002562 }
2563
Jeff Kingcfe004a2017-05-22 16:17:54 +02002564 if (!filter->name_patterns[0]) {
2565 /* no patterns; we have to look at everything */
Taylor Blau59c35fa2023-07-10 17:12:28 -04002566 return refs_for_each_fullref_in(get_main_ref_store(the_repository),
2567 "", filter->exclude.v, cb, cb_data);
Jeff Kingcfe004a2017-05-22 16:17:54 +02002568 }
2569
Jeff King91e2ab12022-12-13 06:11:10 -05002570 return refs_for_each_fullref_in_prefixes(get_main_ref_store(the_repository),
2571 NULL, filter->name_patterns,
Taylor Blau59c35fa2023-07-10 17:12:28 -04002572 filter->exclude.v,
Jeff King91e2ab12022-12-13 06:11:10 -05002573 cb, cb_data);
Jeff Kingcfe004a2017-05-22 16:17:54 +02002574}
2575
2576/*
Jeff Kingc79eddf2020-03-30 10:04:11 -04002577 * Given a ref (oid, refname), check if the ref belongs to the array
2578 * of oids. If the given ref is a tag, check if the given tag points
Jeff Kingd9e00622023-07-02 18:38:29 -04002579 * at one of the oids in the given oid array. Returns non-zero if a
2580 * match is found.
2581 *
Karthik Nayak68411042015-07-07 21:36:09 +05302582 * NEEDSWORK:
Jan Klötzke468887f2023-07-01 22:57:02 +02002583 * As the refs are cached we might know what refname peels to without
Karthik Nayak68411042015-07-07 21:36:09 +05302584 * the need to parse the object via parse_object(). peel_ref() might be a
2585 * more efficient alternative to obtain the pointee.
2586 */
Jeff Kingd9e00622023-07-02 18:38:29 -04002587static int match_points_at(struct oid_array *points_at,
2588 const struct object_id *oid,
2589 const char *refname)
Karthik Nayak68411042015-07-07 21:36:09 +05302590{
Karthik Nayak68411042015-07-07 21:36:09 +05302591 struct object *obj;
2592
brian m. carlson910650d2017-03-31 01:40:00 +00002593 if (oid_array_lookup(points_at, oid) >= 0)
Jeff Kingd9e00622023-07-02 18:38:29 -04002594 return 1;
Jeff King870eb532023-07-02 18:37:47 -04002595 obj = parse_object_with_flags(the_repository, oid,
2596 PARSE_OBJECT_SKIP_HASH_CHECK);
Jan Klötzke468887f2023-07-01 22:57:02 +02002597 while (obj && obj->type == OBJ_TAG) {
Jeff Kingb9584c52023-07-02 18:35:40 -04002598 struct tag *tag = (struct tag *)obj;
2599
2600 if (parse_tag(tag) < 0) {
2601 obj = NULL;
2602 break;
2603 }
2604
Jeff Kingd9e00622023-07-02 18:38:29 -04002605 if (oid_array_lookup(points_at, get_tagged_oid(tag)) >= 0)
2606 return 1;
Jeff Kingb9584c52023-07-02 18:35:40 -04002607
2608 obj = tag->tagged;
Jan Klötzke468887f2023-07-01 22:57:02 +02002609 }
Karthik Nayak68411042015-07-07 21:36:09 +05302610 if (!obj)
2611 die(_("malformed object at '%s'"), refname);
Jeff Kingd9e00622023-07-02 18:38:29 -04002612 return 0;
Karthik Nayak68411042015-07-07 21:36:09 +05302613}
2614
Jeff King0ffaa002018-04-06 14:59:26 -04002615/*
2616 * Allocate space for a new ref_array_item and copy the name and oid to it.
2617 *
2618 * Callers can then fill in other struct members at their leisure.
2619 */
Karthik Nayakc95b7582015-06-14 01:07:27 +05302620static struct ref_array_item *new_ref_array_item(const char *refname,
Jeff King0ffaa002018-04-06 14:59:26 -04002621 const struct object_id *oid)
Karthik Nayakc95b7582015-06-14 01:07:27 +05302622{
Jeff King96ffc062016-02-22 17:44:32 -05002623 struct ref_array_item *ref;
Jeff King0ffaa002018-04-06 14:59:26 -04002624
Jeff King96ffc062016-02-22 17:44:32 -05002625 FLEX_ALLOC_STR(ref, refname, refname);
Jeff King53df97a2018-04-06 14:58:32 -04002626 oidcpy(&ref->objectname, oid);
ZheNing Hub9dee072021-07-26 03:26:50 +00002627 ref->rest = NULL;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302628
2629 return ref;
2630}
2631
Jeff King427cbc92018-04-06 14:59:45 -04002632struct ref_array_item *ref_array_push(struct ref_array *array,
2633 const char *refname,
2634 const struct object_id *oid)
2635{
2636 struct ref_array_item *ref = new_ref_array_item(refname, oid);
2637
2638 ALLOC_GROW(array->items, array->nr + 1, array->alloc);
2639 array->items[array->nr++] = ref;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302640
2641 return ref;
2642}
2643
Lukas Puehringer2111aa72017-01-17 18:37:19 -05002644static int ref_kind_from_refname(const char *refname)
Karthik Nayak5b4f2852015-09-10 21:18:23 +05302645{
2646 unsigned int i;
2647
2648 static struct {
2649 const char *prefix;
2650 unsigned int kind;
2651 } ref_kind[] = {
2652 { "refs/heads/" , FILTER_REFS_BRANCHES },
2653 { "refs/remotes/" , FILTER_REFS_REMOTES },
2654 { "refs/tags/", FILTER_REFS_TAGS}
2655 };
2656
Lukas Puehringer2111aa72017-01-17 18:37:19 -05002657 if (!strcmp(refname, "HEAD"))
Karthik Nayak5b4f2852015-09-10 21:18:23 +05302658 return FILTER_REFS_DETACHED_HEAD;
2659
2660 for (i = 0; i < ARRAY_SIZE(ref_kind); i++) {
2661 if (starts_with(refname, ref_kind[i].prefix))
2662 return ref_kind[i].kind;
2663 }
2664
2665 return FILTER_REFS_OTHERS;
2666}
2667
Lukas Puehringer2111aa72017-01-17 18:37:19 -05002668static int filter_ref_kind(struct ref_filter *filter, const char *refname)
2669{
2670 if (filter->kind == FILTER_REFS_BRANCHES ||
2671 filter->kind == FILTER_REFS_REMOTES ||
2672 filter->kind == FILTER_REFS_TAGS)
2673 return filter->kind;
2674 return ref_kind_from_refname(refname);
2675}
2676
Derrick Stolee920f93c2018-07-20 16:33:08 +00002677struct ref_filter_cbdata {
2678 struct ref_array *array;
2679 struct ref_filter *filter;
2680 struct contains_cache contains_cache;
2681 struct contains_cache no_contains_cache;
2682};
2683
Karthik Nayakc95b7582015-06-14 01:07:27 +05302684/*
2685 * A call-back given to for_each_ref(). Filter refs and keep them for
2686 * later object processing.
2687 */
Karthik Nayak14de7fb2015-06-14 01:07:28 +05302688static int ref_filter_handler(const char *refname, const struct object_id *oid, int flag, void *cb_data)
Karthik Nayakc95b7582015-06-14 01:07:27 +05302689{
2690 struct ref_filter_cbdata *ref_cbdata = cb_data;
Karthik Nayak14de7fb2015-06-14 01:07:28 +05302691 struct ref_filter *filter = ref_cbdata->filter;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302692 struct ref_array_item *ref;
Karthik Nayak35257aa2015-07-07 21:36:12 +05302693 struct commit *commit = NULL;
Karthik Nayak5b4f2852015-09-10 21:18:23 +05302694 unsigned int kind;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302695
2696 if (flag & REF_BAD_NAME) {
Nguyễn Thái Ngọc Duy1823c612016-02-27 13:42:04 +07002697 warning(_("ignoring ref with broken name %s"), refname);
Karthik Nayakc95b7582015-06-14 01:07:27 +05302698 return 0;
2699 }
2700
Junio C Hamano7ebc8cb2015-08-03 11:01:10 -07002701 if (flag & REF_ISBROKEN) {
Nguyễn Thái Ngọc Duy1823c612016-02-27 13:42:04 +07002702 warning(_("ignoring broken ref %s"), refname);
Junio C Hamano7ebc8cb2015-08-03 11:01:10 -07002703 return 0;
2704 }
2705
Karthik Nayak5b4f2852015-09-10 21:18:23 +05302706 /* Obtain the current ref kind from filter_ref_kind() and ignore unwanted refs. */
2707 kind = filter_ref_kind(filter, refname);
2708 if (!(kind & filter->kind))
2709 return 0;
2710
Karthik Nayakbef0e122015-09-10 21:18:26 +05302711 if (!filter_pattern_match(filter, refname))
Karthik Nayakc95b7582015-06-14 01:07:27 +05302712 return 0;
2713
Taylor Blau8255dd82023-07-10 17:12:19 -04002714 if (filter_exclude_match(filter, refname))
2715 return 0;
2716
brian m. carlson4ce36212017-03-31 01:39:57 +00002717 if (filter->points_at.nr && !match_points_at(&filter->points_at, oid, refname))
Karthik Nayak68411042015-07-07 21:36:09 +05302718 return 0;
2719
Karthik Nayakc95b7582015-06-14 01:07:27 +05302720 /*
Karthik Nayak35257aa2015-07-07 21:36:12 +05302721 * A merge filter is applied on refs pointing to commits. Hence
2722 * obtain the commit using the 'oid' available and discard all
2723 * non-commits early. The actual filtering is done later.
2724 */
Aaron Lipman21bf9332020-09-15 22:08:40 -04002725 if (filter->reachable_from || filter->unreachable_from ||
2726 filter->with_commit || filter->no_commit || filter->verbose) {
2727 commit = lookup_commit_reference_gently(the_repository, oid, 1);
Karthik Nayak35257aa2015-07-07 21:36:12 +05302728 if (!commit)
2729 return 0;
Ævar Arnfjörð Bjarmasonac3f5a32017-03-24 18:40:57 +00002730 /* We perform the filtering for the '--contains' option... */
Karthik Nayakee2bd062015-07-07 21:36:16 +05302731 if (filter->with_commit &&
Ævar Arnfjörð Bjarmasonac3f5a32017-03-24 18:40:57 +00002732 !commit_contains(filter, commit, filter->with_commit, &ref_cbdata->contains_cache))
2733 return 0;
2734 /* ...or for the `--no-contains' option */
2735 if (filter->no_commit &&
2736 commit_contains(filter, commit, filter->no_commit, &ref_cbdata->no_contains_cache))
Karthik Nayakee2bd062015-07-07 21:36:16 +05302737 return 0;
Karthik Nayak35257aa2015-07-07 21:36:12 +05302738 }
2739
Karthik Nayakc95b7582015-06-14 01:07:27 +05302740 /*
2741 * We do not open the object yet; sort may only need refname
2742 * to do its job and the resulting list may yet to be pruned
2743 * by maxcount logic.
2744 */
Jeff King427cbc92018-04-06 14:59:45 -04002745 ref = ref_array_push(ref_cbdata->array, refname, oid);
Karthik Nayak35257aa2015-07-07 21:36:12 +05302746 ref->commit = commit;
Jeff King0ffaa002018-04-06 14:59:26 -04002747 ref->flag = flag;
Karthik Nayak5b4f2852015-09-10 21:18:23 +05302748 ref->kind = kind;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302749
Karthik Nayakc95b7582015-06-14 01:07:27 +05302750 return 0;
2751}
2752
2753/* Free memory allocated for a ref_array_item */
2754static void free_array_item(struct ref_array_item *item)
2755{
2756 free((char *)item->symref);
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002757 if (item->value) {
Martin Ågren14d30cd2019-07-10 20:36:39 +02002758 int i;
2759 for (i = 0; i < used_atom_cnt; i++)
2760 free((char *)item->value[i].s);
Olga Telezhnayaf0062d32018-10-18 07:28:54 +00002761 free(item->value);
2762 }
Derrick Stolee49abcd22023-03-20 11:26:54 +00002763 free(item->counts);
Karthik Nayakc95b7582015-06-14 01:07:27 +05302764 free(item);
2765}
2766
2767/* Free all memory allocated for ref_array */
2768void ref_array_clear(struct ref_array *array)
2769{
2770 int i;
2771
2772 for (i = 0; i < array->nr; i++)
2773 free_array_item(array->items[i]);
Ævar Arnfjörð Bjarmason6a83d902017-06-15 23:15:46 +00002774 FREE_AND_NULL(array->items);
Karthik Nayakc95b7582015-06-14 01:07:27 +05302775 array->nr = array->alloc = 0;
Martin Ågren14d30cd2019-07-10 20:36:39 +02002776
Andrzej Huntd7cf4182021-07-25 15:08:24 +02002777 for (i = 0; i < used_atom_cnt; i++) {
2778 struct used_atom *atom = &used_atom[i];
2779 if (atom->atom_type == ATOM_HEAD)
2780 free(atom->u.head);
2781 free((char *)atom->name);
2782 }
Martin Ågren14d30cd2019-07-10 20:36:39 +02002783 FREE_AND_NULL(used_atom);
2784 used_atom_cnt = 0;
2785
Nickolai Belakovski25820832019-04-28 22:19:42 -07002786 if (ref_to_worktree_map.worktrees) {
Elijah Newren6da1a252020-11-02 18:55:05 +00002787 hashmap_clear_and_free(&(ref_to_worktree_map.map),
Eric Wongc8e424c2019-10-06 23:30:40 +00002788 struct ref_to_worktree_entry, ent);
Nickolai Belakovski25820832019-04-28 22:19:42 -07002789 free_worktrees(ref_to_worktree_map.worktrees);
2790 ref_to_worktree_map.worktrees = NULL;
2791 }
Derrick Stolee49abcd22023-03-20 11:26:54 +00002792
2793 FREE_AND_NULL(array->counts);
Karthik Nayakc95b7582015-06-14 01:07:27 +05302794}
2795
Aaron Lipmana1b19aa2020-09-18 17:58:41 -04002796#define EXCLUDE_REACHED 0
2797#define INCLUDE_REACHED 1
2798static void reach_filter(struct ref_array *array,
Jeff King311bfe12023-07-10 17:12:10 -04002799 struct commit_list **check_reachable,
Aaron Lipmana1b19aa2020-09-18 17:58:41 -04002800 int include_reached)
Karthik Nayak35257aa2015-07-07 21:36:12 +05302801{
Karthik Nayak35257aa2015-07-07 21:36:12 +05302802 int i, old_nr;
René Scharfe5336d502020-09-26 10:37:29 +02002803 struct commit **to_clear;
Aaron Lipman21bf9332020-09-15 22:08:40 -04002804
Jeff King311bfe12023-07-10 17:12:10 -04002805 if (!*check_reachable)
Aaron Lipman21bf9332020-09-15 22:08:40 -04002806 return;
Karthik Nayak35257aa2015-07-07 21:36:12 +05302807
René Scharfeca56dad2021-03-13 17:17:22 +01002808 CALLOC_ARRAY(to_clear, array->nr);
Karthik Nayak35257aa2015-07-07 21:36:12 +05302809 for (i = 0; i < array->nr; i++) {
2810 struct ref_array_item *item = array->items[i];
Karthik Nayak35257aa2015-07-07 21:36:12 +05302811 to_clear[i] = item->commit;
2812 }
2813
Derrick Stoleecbfe3602023-03-20 11:26:55 +00002814 tips_reachable_from_bases(the_repository,
Jeff King311bfe12023-07-10 17:12:10 -04002815 *check_reachable,
Derrick Stoleecbfe3602023-03-20 11:26:55 +00002816 to_clear, array->nr,
2817 UNINTERESTING);
Karthik Nayak35257aa2015-07-07 21:36:12 +05302818
2819 old_nr = array->nr;
2820 array->nr = 0;
2821
2822 for (i = 0; i < old_nr; i++) {
2823 struct ref_array_item *item = array->items[i];
2824 struct commit *commit = item->commit;
2825
2826 int is_merged = !!(commit->object.flags & UNINTERESTING);
2827
Aaron Lipmana1b19aa2020-09-18 17:58:41 -04002828 if (is_merged == include_reached)
Karthik Nayak35257aa2015-07-07 21:36:12 +05302829 array->items[array->nr++] = array->items[i];
2830 else
2831 free_array_item(item);
2832 }
2833
René Scharfe5dee6d62017-12-25 18:44:12 +01002834 clear_commit_marks_many(old_nr, to_clear, ALL_REV_FLAGS);
Aaron Lipman21bf9332020-09-15 22:08:40 -04002835
Jeff King311bfe12023-07-10 17:12:10 -04002836 while (*check_reachable) {
2837 struct commit *merge_commit = pop_commit(check_reachable);
Aaron Lipman21bf9332020-09-15 22:08:40 -04002838 clear_commit_marks(merge_commit, ALL_REV_FLAGS);
2839 }
2840
Karthik Nayak35257aa2015-07-07 21:36:12 +05302841 free(to_clear);
2842}
2843
Derrick Stolee49abcd22023-03-20 11:26:54 +00002844void filter_ahead_behind(struct repository *r,
2845 struct ref_format *format,
2846 struct ref_array *array)
2847{
2848 struct commit **commits;
2849 size_t commits_nr = format->bases.nr + array->nr;
2850
2851 if (!format->bases.nr || !array->nr)
2852 return;
2853
2854 ALLOC_ARRAY(commits, commits_nr);
2855 for (size_t i = 0; i < format->bases.nr; i++)
2856 commits[i] = format->bases.items[i].util;
2857
2858 ALLOC_ARRAY(array->counts, st_mult(format->bases.nr, array->nr));
2859
2860 commits_nr = format->bases.nr;
2861 array->counts_nr = 0;
2862 for (size_t i = 0; i < array->nr; i++) {
2863 const char *name = array->items[i]->refname;
2864 commits[commits_nr] = lookup_commit_reference_by_name(name);
2865
2866 if (!commits[commits_nr])
2867 continue;
2868
2869 CALLOC_ARRAY(array->items[i]->counts, format->bases.nr);
2870 for (size_t j = 0; j < format->bases.nr; j++) {
2871 struct ahead_behind_count *count;
2872 count = &array->counts[array->counts_nr++];
2873 count->tip_index = commits_nr;
2874 count->base_index = j;
2875
2876 array->items[i]->counts[j] = count;
2877 }
2878 commits_nr++;
2879 }
2880
2881 ahead_behind(r, commits, commits_nr, array->counts, array->counts_nr);
2882 free(commits);
2883}
2884
Karthik Nayak14de7fb2015-06-14 01:07:28 +05302885/*
2886 * API for filtering a set of refs. Based on the type of refs the user
2887 * has requested, we iterate through those refs and apply filters
2888 * as per the given ref_filter structure and finally store the
2889 * filtered refs in the ref_array structure.
2890 */
2891int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type)
2892{
2893 struct ref_filter_cbdata ref_cbdata;
Jeff King359b01c2022-07-11 10:48:06 -04002894 int save_commit_buffer_orig;
Karthik Nayak35257aa2015-07-07 21:36:12 +05302895 int ret = 0;
Karthik Nayak14de7fb2015-06-14 01:07:28 +05302896
2897 ref_cbdata.array = array;
2898 ref_cbdata.filter = filter;
2899
Karthik Nayak5b4f2852015-09-10 21:18:23 +05302900 filter->kind = type & FILTER_REFS_KIND_MASK;
2901
Jeff King359b01c2022-07-11 10:48:06 -04002902 save_commit_buffer_orig = save_commit_buffer;
2903 save_commit_buffer = 0;
2904
Jeff Kinga91aca42017-03-09 08:29:49 -05002905 init_contains_cache(&ref_cbdata.contains_cache);
Ævar Arnfjörð Bjarmasonac3f5a32017-03-24 18:40:57 +00002906 init_contains_cache(&ref_cbdata.no_contains_cache);
Jeff Kinga91aca42017-03-09 08:29:49 -05002907
Karthik Nayak35257aa2015-07-07 21:36:12 +05302908 /* Simple per-ref filtering */
Karthik Nayak5b4f2852015-09-10 21:18:23 +05302909 if (!filter->kind)
Karthik Nayak14de7fb2015-06-14 01:07:28 +05302910 die("filter_refs: invalid type");
Karthik Nayak5b4f2852015-09-10 21:18:23 +05302911 else {
2912 /*
2913 * For common cases where we need only branches or remotes or tags,
2914 * we only iterate through those refs. If a mix of refs is needed,
2915 * we iterate over all refs and filter out required refs with the help
2916 * of filter_ref_kind().
2917 */
2918 if (filter->kind == FILTER_REFS_BRANCHES)
Jeff King67985e42021-09-24 14:48:48 -04002919 ret = for_each_fullref_in("refs/heads/", ref_filter_handler, &ref_cbdata);
Karthik Nayak5b4f2852015-09-10 21:18:23 +05302920 else if (filter->kind == FILTER_REFS_REMOTES)
Jeff King67985e42021-09-24 14:48:48 -04002921 ret = for_each_fullref_in("refs/remotes/", ref_filter_handler, &ref_cbdata);
Karthik Nayak5b4f2852015-09-10 21:18:23 +05302922 else if (filter->kind == FILTER_REFS_TAGS)
Jeff King67985e42021-09-24 14:48:48 -04002923 ret = for_each_fullref_in("refs/tags/", ref_filter_handler, &ref_cbdata);
Karthik Nayak5b4f2852015-09-10 21:18:23 +05302924 else if (filter->kind & FILTER_REFS_ALL)
Jeff King67985e42021-09-24 14:48:48 -04002925 ret = for_each_fullref_in_pattern(filter, ref_filter_handler, &ref_cbdata);
Karthik Nayak5b4f2852015-09-10 21:18:23 +05302926 if (!ret && (filter->kind & FILTER_REFS_DETACHED_HEAD))
2927 head_ref(ref_filter_handler, &ref_cbdata);
2928 }
2929
Jeff Kinga91aca42017-03-09 08:29:49 -05002930 clear_contains_cache(&ref_cbdata.contains_cache);
Ævar Arnfjörð Bjarmasonac3f5a32017-03-24 18:40:57 +00002931 clear_contains_cache(&ref_cbdata.no_contains_cache);
Karthik Nayak35257aa2015-07-07 21:36:12 +05302932
2933 /* Filters that need revision walking */
Jeff King311bfe12023-07-10 17:12:10 -04002934 reach_filter(array, &filter->reachable_from, INCLUDE_REACHED);
2935 reach_filter(array, &filter->unreachable_from, EXCLUDE_REACHED);
Karthik Nayak35257aa2015-07-07 21:36:12 +05302936
Jeff King359b01c2022-07-11 10:48:06 -04002937 save_commit_buffer = save_commit_buffer_orig;
Karthik Nayak35257aa2015-07-07 21:36:12 +05302938 return ret;
Karthik Nayak14de7fb2015-06-14 01:07:28 +05302939}
2940
Ævar Arnfjörð Bjarmason2708ce62021-01-07 10:51:52 +01002941static int compare_detached_head(struct ref_array_item *a, struct ref_array_item *b)
2942{
2943 if (!(a->kind ^ b->kind))
2944 BUG("ref_kind_from_refname() should only mark one ref as HEAD");
2945 if (a->kind & FILTER_REFS_DETACHED_HEAD)
2946 return -1;
2947 else if (b->kind & FILTER_REFS_DETACHED_HEAD)
2948 return 1;
2949 BUG("should have died in the xor check above");
2950 return 0;
2951}
2952
ZheNing Hubd0708c2021-07-26 03:26:47 +00002953static int memcasecmp(const void *vs1, const void *vs2, size_t n)
2954{
2955 const char *s1 = vs1, *s2 = vs2;
2956 const char *end = s1 + n;
2957
2958 for (; s1 < end; s1++, s2++) {
2959 int diff = tolower(*s1) - tolower(*s2);
2960 if (diff)
2961 return diff;
2962 }
2963 return 0;
2964}
2965
Junio C Hamano98e7ab62021-10-20 12:23:53 -07002966struct ref_sorting {
2967 struct ref_sorting *next;
2968 int atom; /* index into used_atom array (internal) */
2969 enum ref_sorting_order sort_flags;
2970};
2971
Karthik Nayakc95b7582015-06-14 01:07:27 +05302972static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, struct ref_array_item *b)
2973{
2974 struct atom_value *va, *vb;
2975 int cmp;
Ævar Arnfjörð Bjarmason4045f652021-01-07 10:51:53 +01002976 int cmp_detached_head = 0;
Karthik Nayakb072add2016-02-17 23:36:11 +05302977 cmp_type cmp_type = used_atom[s->atom].type;
Olga Telezhnayae3396112018-03-29 12:49:45 +00002978 struct strbuf err = STRBUF_INIT;
Karthik Nayakc95b7582015-06-14 01:07:27 +05302979
Olga Telezhnayae3396112018-03-29 12:49:45 +00002980 if (get_ref_atom_value(a, s->atom, &va, &err))
2981 die("%s", err.buf);
2982 if (get_ref_atom_value(b, s->atom, &vb, &err))
2983 die("%s", err.buf);
2984 strbuf_release(&err);
Ævar Arnfjörð Bjarmason2708ce62021-01-07 10:51:52 +01002985 if (s->sort_flags & REF_SORTING_DETACHED_HEAD_FIRST &&
2986 ((a->kind | b->kind) & FILTER_REFS_DETACHED_HEAD)) {
2987 cmp = compare_detached_head(a, b);
Ævar Arnfjörð Bjarmason4045f652021-01-07 10:51:53 +01002988 cmp_detached_head = 1;
Ævar Arnfjörð Bjarmason2708ce62021-01-07 10:51:52 +01002989 } else if (s->sort_flags & REF_SORTING_VERSION) {
Karthik Nayak90c00402015-09-10 21:18:25 +05302990 cmp = versioncmp(va->s, vb->s);
Ævar Arnfjörð Bjarmason75c50e52021-01-07 10:51:49 +01002991 } else if (cmp_type == FIELD_STR) {
ZheNing Hubd0708c2021-07-26 03:26:47 +00002992 if (va->s_size < 0 && vb->s_size < 0) {
2993 int (*cmp_fn)(const char *, const char *);
2994 cmp_fn = s->sort_flags & REF_SORTING_ICASE
2995 ? strcasecmp : strcmp;
2996 cmp = cmp_fn(va->s, vb->s);
2997 } else {
2998 size_t a_size = va->s_size < 0 ?
2999 strlen(va->s) : va->s_size;
3000 size_t b_size = vb->s_size < 0 ?
3001 strlen(vb->s) : vb->s_size;
3002 int (*cmp_fn)(const void *, const void *, size_t);
3003 cmp_fn = s->sort_flags & REF_SORTING_ICASE
3004 ? memcasecmp : memcmp;
3005
3006 cmp = cmp_fn(va->s, vb->s, b_size > a_size ?
3007 a_size : b_size);
3008 if (!cmp) {
3009 if (a_size > b_size)
3010 cmp = 1;
3011 else if (a_size < b_size)
3012 cmp = -1;
3013 }
3014 }
Ævar Arnfjörð Bjarmason75c50e52021-01-07 10:51:49 +01003015 } else {
Johannes Schindeline467dc12017-04-20 22:52:09 +02003016 if (va->value < vb->value)
Karthik Nayakc95b7582015-06-14 01:07:27 +05303017 cmp = -1;
Johannes Schindeline467dc12017-04-20 22:52:09 +02003018 else if (va->value == vb->value)
Jeff King7c5045f2020-05-03 05:13:09 -04003019 cmp = 0;
Karthik Nayakc95b7582015-06-14 01:07:27 +05303020 else
3021 cmp = 1;
Karthik Nayakc95b7582015-06-14 01:07:27 +05303022 }
Karthik Nayak90c00402015-09-10 21:18:25 +05303023
Ævar Arnfjörð Bjarmason4045f652021-01-07 10:51:53 +01003024 return (s->sort_flags & REF_SORTING_REVERSE && !cmp_detached_head)
3025 ? -cmp : cmp;
Karthik Nayakc95b7582015-06-14 01:07:27 +05303026}
3027
René Scharfe83fc4d62017-01-22 18:58:07 +01003028static int compare_refs(const void *a_, const void *b_, void *ref_sorting)
Karthik Nayakc95b7582015-06-14 01:07:27 +05303029{
3030 struct ref_array_item *a = *((struct ref_array_item **)a_);
3031 struct ref_array_item *b = *((struct ref_array_item **)b_);
3032 struct ref_sorting *s;
3033
3034 for (s = ref_sorting; s; s = s->next) {
3035 int cmp = cmp_ref_sorting(s, a, b);
3036 if (cmp)
3037 return cmp;
3038 }
Jeff King7c5045f2020-05-03 05:13:09 -04003039 s = ref_sorting;
Ævar Arnfjörð Bjarmason7c269a72021-01-07 10:51:51 +01003040 return s && s->sort_flags & REF_SORTING_ICASE ?
Jeff King7c5045f2020-05-03 05:13:09 -04003041 strcasecmp(a->refname, b->refname) :
3042 strcmp(a->refname, b->refname);
Karthik Nayakc95b7582015-06-14 01:07:27 +05303043}
3044
Ævar Arnfjörð Bjarmason7c269a72021-01-07 10:51:51 +01003045void ref_sorting_set_sort_flags_all(struct ref_sorting *sorting,
3046 unsigned int mask, int on)
Jeff King76f9e562020-05-03 05:11:57 -04003047{
Ævar Arnfjörð Bjarmason7c269a72021-01-07 10:51:51 +01003048 for (; sorting; sorting = sorting->next) {
3049 if (on)
3050 sorting->sort_flags |= mask;
3051 else
3052 sorting->sort_flags &= ~mask;
3053 }
Karthik Nayakc95b7582015-06-14 01:07:27 +05303054}
3055
3056void ref_array_sort(struct ref_sorting *sorting, struct ref_array *array)
3057{
René Scharfe83fc4d62017-01-22 18:58:07 +01003058 QSORT_S(array->items, array->nr, compare_refs, sorting);
Karthik Nayakc95b7582015-06-14 01:07:27 +05303059}
3060
Karthik Nayak574e96a2015-09-10 21:18:18 +05303061static void append_literal(const char *cp, const char *ep, struct ref_formatting_state *state)
Karthik Nayakc95b7582015-06-14 01:07:27 +05303062{
Karthik Nayak574e96a2015-09-10 21:18:18 +05303063 struct strbuf *s = &state->stack->output;
3064
Karthik Nayakc95b7582015-06-14 01:07:27 +05303065 while (*cp && (!ep || cp < ep)) {
3066 if (*cp == '%') {
3067 if (cp[1] == '%')
3068 cp++;
3069 else {
René Scharfed2330972016-09-03 17:59:20 +02003070 int ch = hex2chr(cp + 1);
Karthik Nayakc95b7582015-06-14 01:07:27 +05303071 if (0 <= ch) {
Karthik Nayak574e96a2015-09-10 21:18:18 +05303072 strbuf_addch(s, ch);
Karthik Nayakc95b7582015-06-14 01:07:27 +05303073 cp += 3;
3074 continue;
3075 }
3076 }
3077 }
Karthik Nayak574e96a2015-09-10 21:18:18 +05303078 strbuf_addch(s, *cp);
Karthik Nayakc95b7582015-06-14 01:07:27 +05303079 cp++;
3080 }
3081}
3082
Olga Telezhnaya3019eca2018-03-29 12:49:45 +00003083int format_ref_array_item(struct ref_array_item *info,
ZheNing Hue85fcb32021-07-26 03:26:49 +00003084 struct ref_format *format,
3085 struct strbuf *final_buf,
3086 struct strbuf *error_buf)
Karthik Nayakc95b7582015-06-14 01:07:27 +05303087{
3088 const char *cp, *sp, *ep;
Karthik Nayak574e96a2015-09-10 21:18:18 +05303089 struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
3090
Jeff King4a68e362017-07-13 11:01:18 -04003091 state.quote_style = format->quote_style;
Karthik Nayak574e96a2015-09-10 21:18:18 +05303092 push_stack_element(&state.stack);
Karthik Nayakc95b7582015-06-14 01:07:27 +05303093
Jeff King4a68e362017-07-13 11:01:18 -04003094 for (cp = format->format; *cp && (sp = find_next(cp)); cp = ep + 1) {
Karthik Nayakc95b7582015-06-14 01:07:27 +05303095 struct atom_value *atomv;
Olga Telezhnayae6ff7b32018-03-29 12:49:45 +00003096 int pos;
Karthik Nayakc95b7582015-06-14 01:07:27 +05303097
3098 ep = strchr(sp, ')');
3099 if (cp < sp)
Karthik Nayak574e96a2015-09-10 21:18:18 +05303100 append_literal(cp, sp, &state);
Olga Telezhnayae6ff7b32018-03-29 12:49:45 +00003101 pos = parse_ref_filter_atom(format, sp + 2, ep, error_buf);
Olga Telezhnayae3396112018-03-29 12:49:45 +00003102 if (pos < 0 || get_ref_atom_value(info, pos, &atomv, error_buf) ||
3103 atomv->handler(atomv, &state, error_buf)) {
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00003104 pop_stack_element(&state.stack);
3105 return -1;
3106 }
Karthik Nayakc95b7582015-06-14 01:07:27 +05303107 }
3108 if (*cp) {
3109 sp = cp + strlen(cp);
Karthik Nayak574e96a2015-09-10 21:18:18 +05303110 append_literal(cp, sp, &state);
Karthik Nayakc95b7582015-06-14 01:07:27 +05303111 }
Jeff Kingbf285ae2017-07-13 11:02:30 -04003112 if (format->need_color_reset_at_eol) {
ZheNing Hubd0708c2021-07-26 03:26:47 +00003113 struct atom_value resetv = ATOM_VALUE_INIT;
Jeff King51331aa2017-07-13 10:58:56 -04003114 resetv.s = GIT_COLOR_RESET;
Olga Telezhnaya3fc84392018-03-29 12:49:45 +00003115 if (append_atom(&resetv, &state, error_buf)) {
3116 pop_stack_element(&state.stack);
3117 return -1;
3118 }
Karthik Nayakc95b7582015-06-14 01:07:27 +05303119 }
Olga Telezhnaya3019eca2018-03-29 12:49:45 +00003120 if (state.stack->prev) {
3121 pop_stack_element(&state.stack);
3122 return strbuf_addf_ret(error_buf, -1, _("format: %%(end) atom missing"));
3123 }
Karthik Nayak99c6a712017-01-10 14:19:39 +05303124 strbuf_addbuf(final_buf, &state.stack->output);
Karthik Nayak574e96a2015-09-10 21:18:18 +05303125 pop_stack_element(&state.stack);
Olga Telezhnaya3019eca2018-03-29 12:49:45 +00003126 return 0;
Karthik Nayak99c6a712017-01-10 14:19:39 +05303127}
3128
Jeff King53df97a2018-04-06 14:58:32 -04003129void pretty_print_ref(const char *name, const struct object_id *oid,
ZheNing Hue85fcb32021-07-26 03:26:49 +00003130 struct ref_format *format)
Lukas Puehringer2111aa72017-01-17 18:37:19 -05003131{
3132 struct ref_array_item *ref_item;
ZheNing Hu22f69a82021-04-19 11:28:44 +00003133 struct strbuf output = STRBUF_INIT;
3134 struct strbuf err = STRBUF_INIT;
3135
Jeff King0ffaa002018-04-06 14:59:26 -04003136 ref_item = new_ref_array_item(name, oid);
Lukas Puehringer2111aa72017-01-17 18:37:19 -05003137 ref_item->kind = ref_kind_from_refname(name);
ZheNing Hu22f69a82021-04-19 11:28:44 +00003138 if (format_ref_array_item(ref_item, format, &output, &err))
3139 die("%s", err.buf);
3140 fwrite(output.buf, 1, output.len, stdout);
3141 putchar('\n');
3142
3143 strbuf_release(&err);
3144 strbuf_release(&output);
Lukas Puehringer2111aa72017-01-17 18:37:19 -05003145 free_array_item(ref_item);
3146}
3147
Jeff King29ef53c2017-07-13 11:02:58 -04003148static int parse_sorting_atom(const char *atom)
3149{
Jeff Kingab7ded32017-07-13 11:06:40 -04003150 /*
3151 * This parses an atom using a dummy ref_format, since we don't
3152 * actually care about the formatting details.
3153 */
3154 struct ref_format dummy = REF_FORMAT_INIT;
Jeff King29ef53c2017-07-13 11:02:58 -04003155 const char *end = atom + strlen(atom);
Olga Telezhnayae6ff7b32018-03-29 12:49:45 +00003156 struct strbuf err = STRBUF_INIT;
3157 int res = parse_ref_filter_atom(&dummy, atom, end, &err);
3158 if (res < 0)
3159 die("%s", err.buf);
3160 strbuf_release(&err);
3161 return res;
Jeff King29ef53c2017-07-13 11:02:58 -04003162}
3163
Karthik Nayakc95b7582015-06-14 01:07:27 +05303164/* If no sorting option is given, use refname to sort as default */
Junio C Hamano98e7ab62021-10-20 12:23:53 -07003165static struct ref_sorting *ref_default_sorting(void)
Karthik Nayakc95b7582015-06-14 01:07:27 +05303166{
3167 static const char cstr_name[] = "refname";
3168
3169 struct ref_sorting *sorting = xcalloc(1, sizeof(*sorting));
3170
3171 sorting->next = NULL;
Jeff King29ef53c2017-07-13 11:02:58 -04003172 sorting->atom = parse_sorting_atom(cstr_name);
Karthik Nayakc95b7582015-06-14 01:07:27 +05303173 return sorting;
3174}
3175
Junio C Hamano98e7ab62021-10-20 12:23:53 -07003176static void parse_ref_sorting(struct ref_sorting **sorting_tail, const char *arg)
Karthik Nayakc95b7582015-06-14 01:07:27 +05303177{
Karthik Nayakc95b7582015-06-14 01:07:27 +05303178 struct ref_sorting *s;
Karthik Nayakc95b7582015-06-14 01:07:27 +05303179
René Scharfeca56dad2021-03-13 17:17:22 +01003180 CALLOC_ARRAY(s, 1);
Karthik Nayakc95b7582015-06-14 01:07:27 +05303181 s->next = *sorting_tail;
3182 *sorting_tail = s;
3183
3184 if (*arg == '-') {
Ævar Arnfjörð Bjarmason7c269a72021-01-07 10:51:51 +01003185 s->sort_flags |= REF_SORTING_REVERSE;
Karthik Nayakc95b7582015-06-14 01:07:27 +05303186 arg++;
3187 }
Karthik Nayak90c00402015-09-10 21:18:25 +05303188 if (skip_prefix(arg, "version:", &arg) ||
3189 skip_prefix(arg, "v:", &arg))
Ævar Arnfjörð Bjarmason7c269a72021-01-07 10:51:51 +01003190 s->sort_flags |= REF_SORTING_VERSION;
Jeff King29ef53c2017-07-13 11:02:58 -04003191 s->atom = parse_sorting_atom(arg);
Jeff King18a25652017-07-13 11:02:44 -04003192}
3193
Junio C Hamano98e7ab62021-10-20 12:23:53 -07003194struct ref_sorting *ref_sorting_options(struct string_list *options)
Jeff King18a25652017-07-13 11:02:44 -04003195{
Junio C Hamano98e7ab62021-10-20 12:23:53 -07003196 struct string_list_item *item;
3197 struct ref_sorting *sorting = NULL, **tail = &sorting;
Jeff King95be7172019-03-20 16:22:15 -04003198
Junio C Hamano98e7ab62021-10-20 12:23:53 -07003199 if (!options->nr) {
3200 sorting = ref_default_sorting();
3201 } else {
3202 for_each_string_list_item(item, options)
3203 parse_ref_sorting(tail, item->string);
3204 }
3205
3206 /*
3207 * From here on, the ref_sorting list should be used to talk
3208 * about the sort order used for the output. The caller
3209 * should not touch the string form anymore.
3210 */
3211 string_list_clear(options, 0);
3212 return sorting;
Karthik Nayakc95b7582015-06-14 01:07:27 +05303213}
Karthik Nayak5afcb902015-07-07 21:36:11 +05303214
Ævar Arnfjörð Bjarmasone5fb0282021-10-20 20:27:20 +02003215void ref_sorting_release(struct ref_sorting *sorting)
3216{
3217 while (sorting) {
3218 struct ref_sorting *next = sorting->next;
3219 free(sorting);
3220 sorting = next;
3221 }
3222}
3223
Karthik Nayak5afcb902015-07-07 21:36:11 +05303224int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)
3225{
3226 struct ref_filter *rf = opt->value;
brian m. carlson1e43ed92017-05-06 22:10:09 +00003227 struct object_id oid;
Aaron Lipman21bf9332020-09-15 22:08:40 -04003228 struct commit *merge_commit;
Karthik Nayak5afcb902015-07-07 21:36:11 +05303229
Jeff King517fe802018-11-05 01:45:42 -05003230 BUG_ON_OPT_NEG(unset);
3231
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 15:58:46 +02003232 if (repo_get_oid(the_repository, arg, &oid))
Karthik Nayak5afcb902015-07-07 21:36:11 +05303233 die(_("malformed object name %s"), arg);
3234
Aaron Lipman21bf9332020-09-15 22:08:40 -04003235 merge_commit = lookup_commit_reference_gently(the_repository, &oid, 0);
3236
3237 if (!merge_commit)
Nguyễn Thái Ngọc Duy9440b832018-11-10 06:16:11 +01003238 return error(_("option `%s' must point to a commit"), opt->long_name);
Karthik Nayak5afcb902015-07-07 21:36:11 +05303239
Aaron Lipman21bf9332020-09-15 22:08:40 -04003240 if (starts_with(opt->long_name, "no"))
3241 commit_list_insert(merge_commit, &rf->unreachable_from);
3242 else
3243 commit_list_insert(merge_commit, &rf->reachable_from);
3244
Karthik Nayak5afcb902015-07-07 21:36:11 +05303245 return 0;
3246}
Jeff Kingb571fb92023-07-10 17:12:13 -04003247
3248void ref_filter_init(struct ref_filter *filter)
3249{
3250 struct ref_filter blank = REF_FILTER_INIT;
3251 memcpy(filter, &blank, sizeof(blank));
3252}
3253
3254void ref_filter_clear(struct ref_filter *filter)
3255{
Taylor Blau8255dd82023-07-10 17:12:19 -04003256 strvec_clear(&filter->exclude);
Jeff Kingb571fb92023-07-10 17:12:13 -04003257 oid_array_clear(&filter->points_at);
3258 free_commit_list(filter->with_commit);
3259 free_commit_list(filter->no_commit);
3260 free_commit_list(filter->reachable_from);
3261 free_commit_list(filter->unreachable_from);
3262 ref_filter_init(filter);
3263}