trailer.c 29.5 KB
Newer Older
1
#include "cache.h"
2
#include "config.h"
3
#include "string-list.h"
4
#include "run-command.h"
5
#include "commit.h"
6
#include "tempfile.h"
7
#include "trailer.h"
8
#include "list.h"
9 10 11 12 13 14 15 16
/*
 * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
 */

struct conf_info {
	char *name;
	char *key;
	char *command;
17 18 19
	enum trailer_where where;
	enum trailer_if_exists if_exists;
	enum trailer_if_missing if_missing;
20 21 22 23 24
};

static struct conf_info default_conf_info;

struct trailer_item {
25
	struct list_head list;
26 27 28 29
	/*
	 * If this is not a trailer line, the line is stored in value
	 * (excluding the terminating newline) and token is NULL.
	 */
30 31
	char *token;
	char *value;
32 33 34 35 36 37
};

struct arg_item {
	struct list_head list;
	char *token;
	char *value;
38 39 40
	struct conf_info conf;
};

41
static LIST_HEAD(conf_head);
42 43 44

static char *separators = ":";

45 46
static int configured;

47 48
#define TRAILER_ARG_STRING "$ARG"

49 50 51 52 53 54
static const char *git_generated_prefixes[] = {
	"Signed-off-by: ",
	"(cherry picked from commit ",
	NULL
};

55 56 57 58 59 60
/* Iterate over the elements of the list. */
#define list_for_each_dir(pos, head, is_reverse) \
	for (pos = is_reverse ? (head)->prev : (head)->next; \
		pos != (head); \
		pos = is_reverse ? pos->prev : pos->next)

61
static int after_or_end(enum trailer_where where)
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
{
	return (where == WHERE_AFTER) || (where == WHERE_END);
}

/*
 * Return the length of the string not including any final
 * punctuation. E.g., the input "Signed-off-by:" would return
 * 13, stripping the trailing punctuation but retaining
 * internal punctuation.
 */
static size_t token_len_without_separator(const char *token, size_t len)
{
	while (len > 0 && !isalnum(token[len - 1]))
		len--;
	return len;
}

79
static int same_token(struct trailer_item *a, struct arg_item *b)
80
{
81 82 83 84 85 86 87 88
	size_t a_len, b_len, min_len;

	if (!a->token)
		return 0;

	a_len = token_len_without_separator(a->token, strlen(a->token));
	b_len = token_len_without_separator(b->token, strlen(b->token));
	min_len = (a_len > b_len) ? b_len : a_len;
89 90 91 92

	return !strncasecmp(a->token, b->token, min_len);
}

93
static int same_value(struct trailer_item *a, struct arg_item *b)
94 95 96 97
{
	return !strcasecmp(a->value, b->value);
}

98
static int same_trailer(struct trailer_item *a, struct arg_item *b)
99 100 101
{
	return same_token(a, b) && same_value(a, b);
}
102

103
static inline int is_blank_line(const char *str)
104 105
{
	const char *s = str;
106
	while (*s && *s != '\n' && isspace(*s))
107
		s++;
108
	return !*s || *s == '\n';
109 110
}

111 112 113 114 115 116 117
static inline void strbuf_replace(struct strbuf *sb, const char *a, const char *b)
{
	const char *ptr = strstr(sb->buf, a);
	if (ptr)
		strbuf_splice(sb, ptr - sb->buf, strlen(a), b, strlen(b));
}

118
static void free_trailer_item(struct trailer_item *item)
119 120 121 122 123 124 125
{
	free(item->token);
	free(item->value);
	free(item);
}

static void free_arg_item(struct arg_item *item)
126 127 128 129
{
	free(item->conf.name);
	free(item->conf.key);
	free(item->conf.command);
130 131
	free(item->token);
	free(item->value);
132 133 134
	free(item);
}

135 136 137 138 139 140 141 142 143
static char last_non_space_char(const char *s)
{
	int i;
	for (i = strlen(s) - 1; i >= 0; i--)
		if (!isspace(s[i]))
			return s[i];
	return '\0';
}

144
static void print_tok_val(FILE *outfile, const char *tok, const char *val)
145
{
146 147 148 149 150 151 152 153
	char c;

	if (!tok) {
		fprintf(outfile, "%s\n", val);
		return;
	}

	c = last_non_space_char(tok);
154 155 156
	if (!c)
		return;
	if (strchr(separators, c))
157
		fprintf(outfile, "%s%s\n", tok, val);
158
	else
159
		fprintf(outfile, "%s%c %s\n", tok, separators[0], val);
160 161
}

162 163
static void print_all(FILE *outfile, struct list_head *head,
		      const struct process_trailer_options *opts)
164
{
165
	struct list_head *pos;
166
	struct trailer_item *item;
167 168
	list_for_each(pos, head) {
		item = list_entry(pos, struct trailer_item, list);
169 170
		if ((!opts->trim_empty || strlen(item->value) > 0) &&
		    (!opts->only_trailers || item->token))
171
			print_tok_val(outfile, item->token, item->value);
172 173 174
	}
}

175
static struct trailer_item *trailer_from_arg(struct arg_item *arg_tok)
176
{
177 178 179
	struct trailer_item *new_item = xcalloc(sizeof(*new_item), 1);
	new_item->token = arg_tok->token;
	new_item->value = arg_tok->value;
180 181
	arg_tok->token = arg_tok->value = NULL;
	free_arg_item(arg_tok);
182
	return new_item;
183 184 185
}

static void add_arg_to_input_list(struct trailer_item *on_tok,
186
				  struct arg_item *arg_tok)
187
{
188 189 190 191
	int aoe = after_or_end(arg_tok->conf.where);
	struct trailer_item *to_add = trailer_from_arg(arg_tok);
	if (aoe)
		list_add(&to_add->list, &on_tok->list);
192
	else
193
		list_add_tail(&to_add->list, &on_tok->list);
194 195 196
}

static int check_if_different(struct trailer_item *in_tok,
197
			      struct arg_item *arg_tok,
198 199
			      int check_all,
			      struct list_head *head)
200
{
201
	enum trailer_where where = arg_tok->conf.where;
202
	struct list_head *next_head;
203 204 205 206 207 208 209
	do {
		if (same_trailer(in_tok, arg_tok))
			return 0;
		/*
		 * if we want to add a trailer after another one,
		 * we have to check those before this one
		 */
210 211 212 213 214
		next_head = after_or_end(where) ? in_tok->list.prev
						: in_tok->list.next;
		if (next_head == head)
			break;
		in_tok = list_entry(next_head, struct trailer_item, list);
215 216 217 218
	} while (check_all);
	return 1;
}

219
static char *apply_command(const char *command, const char *arg)
220 221 222
{
	struct strbuf cmd = STRBUF_INIT;
	struct strbuf buf = STRBUF_INIT;
223
	struct child_process cp = CHILD_PROCESS_INIT;
224
	const char *argv[] = {NULL, NULL};
225
	char *result;
226 227 228 229 230 231 232 233 234 235 236

	strbuf_addstr(&cmd, command);
	if (arg)
		strbuf_replace(&cmd, TRAILER_ARG_STRING, arg);

	argv[0] = cmd.buf;
	cp.argv = argv;
	cp.env = local_repo_env;
	cp.no_stdin = 1;
	cp.use_shell = 1;

Jeff King's avatar
Jeff King committed
237
	if (capture_command(&cp, &buf, 1024)) {
238
		error(_("running trailer command '%s' failed"), cmd.buf);
239 240
		strbuf_release(&buf);
		result = xstrdup("");
Jeff King's avatar
Jeff King committed
241 242
	} else {
		strbuf_trim(&buf);
243
		result = strbuf_detach(&buf, NULL);
Jeff King's avatar
Jeff King committed
244
	}
245 246 247 248 249

	strbuf_release(&cmd);
	return result;
}

250
static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg_tok)
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
{
	if (arg_tok->conf.command) {
		const char *arg;
		if (arg_tok->value && arg_tok->value[0]) {
			arg = arg_tok->value;
		} else {
			if (in_tok && in_tok->value)
				arg = xstrdup(in_tok->value);
			else
				arg = xstrdup("");
		}
		arg_tok->value = apply_command(arg_tok->conf.command, arg);
		free((char *)arg);
	}
}

267
static void apply_arg_if_exists(struct trailer_item *in_tok,
268
				struct arg_item *arg_tok,
269
				struct trailer_item *on_tok,
270
				struct list_head *head)
271 272 273
{
	switch (arg_tok->conf.if_exists) {
	case EXISTS_DO_NOTHING:
274
		free_arg_item(arg_tok);
275 276
		break;
	case EXISTS_REPLACE:
277
		apply_item_command(in_tok, arg_tok);
278 279
		add_arg_to_input_list(on_tok, arg_tok);
		list_del(&in_tok->list);
280 281 282
		free_trailer_item(in_tok);
		break;
	case EXISTS_ADD:
283
		apply_item_command(in_tok, arg_tok);
284
		add_arg_to_input_list(on_tok, arg_tok);
285 286
		break;
	case EXISTS_ADD_IF_DIFFERENT:
287
		apply_item_command(in_tok, arg_tok);
288 289
		if (check_if_different(in_tok, arg_tok, 1, head))
			add_arg_to_input_list(on_tok, arg_tok);
290
		else
291
			free_arg_item(arg_tok);
292 293
		break;
	case EXISTS_ADD_IF_DIFFERENT_NEIGHBOR:
294
		apply_item_command(in_tok, arg_tok);
295 296
		if (check_if_different(on_tok, arg_tok, 0, head))
			add_arg_to_input_list(on_tok, arg_tok);
297
		else
298
			free_arg_item(arg_tok);
299
		break;
300
	default:
301
		BUG("trailer.c: unhandled value %d",
302
		    arg_tok->conf.if_exists);
303 304 305
	}
}

306
static void apply_arg_if_missing(struct list_head *head,
307
				 struct arg_item *arg_tok)
308
{
309
	enum trailer_where where;
310
	struct trailer_item *to_add;
311 312 313

	switch (arg_tok->conf.if_missing) {
	case MISSING_DO_NOTHING:
314
		free_arg_item(arg_tok);
315 316 317
		break;
	case MISSING_ADD:
		where = arg_tok->conf.where;
318
		apply_item_command(NULL, arg_tok);
319
		to_add = trailer_from_arg(arg_tok);
320
		if (after_or_end(where))
321
			list_add_tail(&to_add->list, head);
322
		else
323
			list_add(&to_add->list, head);
324 325
		break;
	default:
326
		BUG("trailer.c: unhandled value %d",
327
		    arg_tok->conf.if_missing);
328 329 330
	}
}

331
static int find_same_and_apply_arg(struct list_head *head,
332
				   struct arg_item *arg_tok)
333
{
334
	struct list_head *pos;
335 336 337
	struct trailer_item *in_tok;
	struct trailer_item *on_tok;

338
	enum trailer_where where = arg_tok->conf.where;
339 340
	int middle = (where == WHERE_AFTER) || (where == WHERE_BEFORE);
	int backwards = after_or_end(where);
341
	struct trailer_item *start_tok;
342

343 344
	if (list_empty(head))
		return 0;
345

346 347 348 349 350 351
	start_tok = list_entry(backwards ? head->prev : head->next,
			       struct trailer_item,
			       list);

	list_for_each_dir(pos, head, backwards) {
		in_tok = list_entry(pos, struct trailer_item, list);
352 353 354
		if (!same_token(in_tok, arg_tok))
			continue;
		on_tok = middle ? in_tok : start_tok;
355
		apply_arg_if_exists(in_tok, arg_tok, on_tok, head);
356 357 358 359 360
		return 1;
	}
	return 0;
}

361 362
static void process_trailers_lists(struct list_head *head,
				   struct list_head *arg_head)
363
{
364
	struct list_head *pos, *p;
365
	struct arg_item *arg_tok;
366

367
	list_for_each_safe(pos, p, arg_head) {
368
		int applied = 0;
369
		arg_tok = list_entry(pos, struct arg_item, list);
370

371
		list_del(pos);
372

373
		applied = find_same_and_apply_arg(head, arg_tok);
374 375

		if (!applied)
376
			apply_arg_if_missing(head, arg_tok);
377 378
	}
}
379

380
int trailer_set_where(enum trailer_where *item, const char *value)
381
{
382 383 384
	if (!value)
		*item = WHERE_DEFAULT;
	else if (!strcasecmp("after", value))
385
		*item = WHERE_AFTER;
386
	else if (!strcasecmp("before", value))
387
		*item = WHERE_BEFORE;
388
	else if (!strcasecmp("end", value))
389
		*item = WHERE_END;
390
	else if (!strcasecmp("start", value))
391
		*item = WHERE_START;
392 393 394 395 396
	else
		return -1;
	return 0;
}

397
int trailer_set_if_exists(enum trailer_if_exists *item, const char *value)
398
{
399 400 401
	if (!value)
		*item = EXISTS_DEFAULT;
	else if (!strcasecmp("addIfDifferent", value))
402
		*item = EXISTS_ADD_IF_DIFFERENT;
403
	else if (!strcasecmp("addIfDifferentNeighbor", value))
404
		*item = EXISTS_ADD_IF_DIFFERENT_NEIGHBOR;
405
	else if (!strcasecmp("add", value))
406
		*item = EXISTS_ADD;
407
	else if (!strcasecmp("replace", value))
408
		*item = EXISTS_REPLACE;
409
	else if (!strcasecmp("doNothing", value))
410
		*item = EXISTS_DO_NOTHING;
411 412 413 414 415
	else
		return -1;
	return 0;
}

416
int trailer_set_if_missing(enum trailer_if_missing *item, const char *value)
417
{
418 419 420
	if (!value)
		*item = MISSING_DEFAULT;
	else if (!strcasecmp("doNothing", value))
421
		*item = MISSING_DO_NOTHING;
422
	else if (!strcasecmp("add", value))
423
		*item = MISSING_ADD;
424 425 426 427 428
	else
		return -1;
	return 0;
}

429
static void duplicate_conf(struct conf_info *dst, const struct conf_info *src)
430 431
{
	*dst = *src;
432 433 434
	dst->name = xstrdup_or_null(src->name);
	dst->key = xstrdup_or_null(src->key);
	dst->command = xstrdup_or_null(src->command);
435 436
}

437
static struct arg_item *get_conf_item(const char *name)
438
{
439
	struct list_head *pos;
440
	struct arg_item *item;
441 442

	/* Look up item with same name */
443
	list_for_each(pos, &conf_head) {
444
		item = list_entry(pos, struct arg_item, list);
445 446 447 448 449
		if (!strcasecmp(item->conf.name, name))
			return item;
	}

	/* Item does not already exists, create it */
450
	item = xcalloc(sizeof(*item), 1);
451 452 453
	duplicate_conf(&item->conf, &default_conf_info);
	item->conf.name = xstrdup(name);

454
	list_add_tail(&item->list, &conf_head);
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482

	return item;
}

enum trailer_info_type { TRAILER_KEY, TRAILER_COMMAND, TRAILER_WHERE,
			 TRAILER_IF_EXISTS, TRAILER_IF_MISSING };

static struct {
	const char *name;
	enum trailer_info_type type;
} trailer_config_items[] = {
	{ "key", TRAILER_KEY },
	{ "command", TRAILER_COMMAND },
	{ "where", TRAILER_WHERE },
	{ "ifexists", TRAILER_IF_EXISTS },
	{ "ifmissing", TRAILER_IF_MISSING }
};

static int git_trailer_default_config(const char *conf_key, const char *value, void *cb)
{
	const char *trailer_item, *variable_name;

	if (!skip_prefix(conf_key, "trailer.", &trailer_item))
		return 0;

	variable_name = strrchr(trailer_item, '.');
	if (!variable_name) {
		if (!strcmp(trailer_item, "where")) {
483 484
			if (trailer_set_where(&default_conf_info.where,
					      value) < 0)
485 486 487
				warning(_("unknown value '%s' for key '%s'"),
					value, conf_key);
		} else if (!strcmp(trailer_item, "ifexists")) {
488 489
			if (trailer_set_if_exists(&default_conf_info.if_exists,
						  value) < 0)
490 491 492
				warning(_("unknown value '%s' for key '%s'"),
					value, conf_key);
		} else if (!strcmp(trailer_item, "ifmissing")) {
493 494
			if (trailer_set_if_missing(&default_conf_info.if_missing,
						   value) < 0)
495 496 497 498 499 500 501 502 503 504 505 506
				warning(_("unknown value '%s' for key '%s'"),
					value, conf_key);
		} else if (!strcmp(trailer_item, "separators")) {
			separators = xstrdup(value);
		}
	}
	return 0;
}

static int git_trailer_config(const char *conf_key, const char *value, void *cb)
{
	const char *trailer_item, *variable_name;
507
	struct arg_item *item;
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
	struct conf_info *conf;
	char *name = NULL;
	enum trailer_info_type type;
	int i;

	if (!skip_prefix(conf_key, "trailer.", &trailer_item))
		return 0;

	variable_name = strrchr(trailer_item, '.');
	if (!variable_name)
		return 0;

	variable_name++;
	for (i = 0; i < ARRAY_SIZE(trailer_config_items); i++) {
		if (strcmp(trailer_config_items[i].name, variable_name))
			continue;
		name = xstrndup(trailer_item,  variable_name - trailer_item - 1);
		type = trailer_config_items[i].type;
		break;
	}

	if (!name)
		return 0;

	item = get_conf_item(name);
	conf = &item->conf;
	free(name);

	switch (type) {
	case TRAILER_KEY:
		if (conf->key)
			warning(_("more than one %s"), conf_key);
		conf->key = xstrdup(value);
		break;
	case TRAILER_COMMAND:
		if (conf->command)
			warning(_("more than one %s"), conf_key);
		conf->command = xstrdup(value);
		break;
	case TRAILER_WHERE:
548
		if (trailer_set_where(&conf->where, value))
549 550 551
			warning(_("unknown value '%s' for key '%s'"), value, conf_key);
		break;
	case TRAILER_IF_EXISTS:
552
		if (trailer_set_if_exists(&conf->if_exists, value))
553 554 555
			warning(_("unknown value '%s' for key '%s'"), value, conf_key);
		break;
	case TRAILER_IF_MISSING:
556
		if (trailer_set_if_missing(&conf->if_missing, value))
557 558 559
			warning(_("unknown value '%s' for key '%s'"), value, conf_key);
		break;
	default:
560
		BUG("trailer.c: unhandled type %d", type);
561 562 563
	}
	return 0;
}
564

565 566 567 568 569 570
static void ensure_configured(void)
{
	if (configured)
		return;

	/* Default config must be setup first */
571 572 573
	default_conf_info.where = WHERE_END;
	default_conf_info.if_exists = EXISTS_ADD_IF_DIFFERENT_NEIGHBOR;
	default_conf_info.if_missing = MISSING_ADD;
574 575 576 577 578
	git_config(git_trailer_default_config, NULL);
	git_config(git_trailer_config, NULL);
	configured = 1;
}

579
static const char *token_from_item(struct arg_item *item, char *tok)
580 581 582 583 584 585 586 587
{
	if (item->conf.key)
		return item->conf.key;
	if (tok)
		return tok;
	return item->conf.name;
}

588
static int token_matches_item(const char *tok, struct arg_item *item, size_t tok_len)
589 590 591 592 593 594
{
	if (!strncasecmp(tok, item->conf.name, tok_len))
		return 1;
	return item->conf.key ? !strncasecmp(tok, item->conf.key, tok_len) : 0;
}

595
/*
596 597 598 599 600 601 602 603 604
 * If the given line is of the form
 * "<token><optional whitespace><separator>..." or "<separator>...", return the
 * location of the separator. Otherwise, return -1.  The optional whitespace
 * is allowed there primarily to allow things like "Bug #43" where <token> is
 * "Bug" and <separator> is "#".
 *
 * The separator-starts-line case (in which this function returns 0) is
 * distinguished from the non-well-formed-line case (in which this function
 * returns -1) because some callers of this function need such a distinction.
605
 */
606
static ssize_t find_separator(const char *line, const char *separators)
607
{
608 609 610 611 612 613 614 615 616 617 618 619 620 621
	int whitespace_found = 0;
	const char *c;
	for (c = line; *c; c++) {
		if (strchr(separators, *c))
			return c - line;
		if (!whitespace_found && (isalnum(*c) || *c == '-'))
			continue;
		if (c != line && (*c == ' ' || *c == '\t')) {
			whitespace_found = 1;
			continue;
		}
		break;
	}
	return -1;
622
}
623

624 625 626 627 628 629 630 631 632
/*
 * Obtain the token, value, and conf from the given trailer.
 *
 * separator_pos must not be 0, since the token cannot be an empty string.
 *
 * If separator_pos is -1, interpret the whole trailer as a token.
 */
static void parse_trailer(struct strbuf *tok, struct strbuf *val,
			 const struct conf_info **conf, const char *trailer,
633
			 ssize_t separator_pos)
634
{
635
	struct arg_item *item;
636
	size_t tok_len;
637
	struct list_head *pos;
638

639 640
	if (separator_pos != -1) {
		strbuf_add(tok, trailer, separator_pos);
641
		strbuf_trim(tok);
642
		strbuf_addstr(val, trailer + separator_pos + 1);
643 644 645 646 647 648 649
		strbuf_trim(val);
	} else {
		strbuf_addstr(tok, trailer);
		strbuf_trim(tok);
	}

	/* Lookup if the token matches something in the config */
650
	tok_len = token_len_without_separator(tok->buf, tok->len);
651 652
	if (conf)
		*conf = &default_conf_info;
653
	list_for_each(pos, &conf_head) {
654
		item = list_entry(pos, struct arg_item, list);
655 656
		if (token_matches_item(tok->buf, item, tok_len)) {
			char *tok_buf = strbuf_detach(tok, NULL);
657 658
			if (conf)
				*conf = &item->conf;
659 660 661 662
			strbuf_addstr(tok, token_from_item(item, tok_buf));
			free(tok_buf);
			break;
		}
663 664 665
	}
}

666 667
static struct trailer_item *add_trailer_item(struct list_head *head, char *tok,
					     char *val)
668
{
669 670 671 672 673
	struct trailer_item *new_item = xcalloc(sizeof(*new_item), 1);
	new_item->token = tok;
	new_item->value = val;
	list_add_tail(&new_item->list, head);
	return new_item;
674 675
}

676
static void add_arg_item(struct list_head *arg_head, char *tok, char *val,
677 678
			 const struct conf_info *conf,
			 const struct new_trailer_item *new_trailer_item)
679
{
680 681 682 683
	struct arg_item *new_item = xcalloc(sizeof(*new_item), 1);
	new_item->token = tok;
	new_item->value = val;
	duplicate_conf(&new_item->conf, conf);
684 685
	if (new_trailer_item) {
		if (new_trailer_item->where != WHERE_DEFAULT)
686
			new_item->conf.where = new_trailer_item->where;
687
		if (new_trailer_item->if_exists != EXISTS_DEFAULT)
688
			new_item->conf.if_exists = new_trailer_item->if_exists;
689
		if (new_trailer_item->if_missing != MISSING_DEFAULT)
690
			new_item->conf.if_missing = new_trailer_item->if_missing;
691
	}
692
	list_add_tail(&new_item->list, arg_head);
693 694
}

695
static void process_command_line_args(struct list_head *arg_head,
696
				      struct list_head *new_trailer_head)
697
{
698
	struct arg_item *item;
699 700 701
	struct strbuf tok = STRBUF_INIT;
	struct strbuf val = STRBUF_INIT;
	const struct conf_info *conf;
702
	struct list_head *pos;
703

704 705 706 707 708 709
	/*
	 * In command-line arguments, '=' is accepted (in addition to the
	 * separators that are defined).
	 */
	char *cl_separators = xstrfmt("=%s", separators);

710
	/* Add an arg item for each configured trailer with a command */
711
	list_for_each(pos, &conf_head) {
712
		item = list_entry(pos, struct arg_item, list);
713
		if (item->conf.command)
714 715 716
			add_arg_item(arg_head,
				     xstrdup(token_from_item(item, NULL)),
				     xstrdup(""),
717
				     &item->conf, NULL);
718
	}
719

720
	/* Add an arg item for each trailer on the command line */
721 722 723
	list_for_each(pos, new_trailer_head) {
		struct new_trailer_item *tr =
			list_entry(pos, struct new_trailer_item, list);
724
		ssize_t separator_pos = find_separator(tr->text, cl_separators);
725

726 727
		if (separator_pos == 0) {
			struct strbuf sb = STRBUF_INIT;
728
			strbuf_addstr(&sb, tr->text);
729 730 731 732 733
			strbuf_trim(&sb);
			error(_("empty trailer token in trailer '%.*s'"),
			      (int) sb.len, sb.buf);
			strbuf_release(&sb);
		} else {
734
			parse_trailer(&tok, &val, &conf, tr->text,
735
				      separator_pos);
736 737 738
			add_arg_item(arg_head,
				     strbuf_detach(&tok, NULL),
				     strbuf_detach(&val, NULL),
739
				     conf, tr);
740
		}
741 742
	}

743
	free(cl_separators);
744
}
745

746
static void read_input_file(struct strbuf *sb, const char *file)
747 748
{
	if (file) {
749
		if (strbuf_read_file(sb, file, 0) < 0)
750 751
			die_errno(_("could not read input file '%s'"), file);
	} else {
752
		if (strbuf_read(sb, fileno(stdin), 0) < 0)
753 754
			die_errno(_("could not read from stdin"));
	}
755
}
756

757 758 759 760 761
static const char *next_line(const char *str)
{
	const char *nl = strchrnul(str, '\n');
	return nl + !!*nl;
}
762

763 764 765
/*
 * Return the position of the start of the last line. If len is 0, return -1.
 */
766
static ssize_t last_line(const char *buf, size_t len)
767
{
768
	ssize_t i;
769 770 771 772 773 774 775 776 777 778
	if (len == 0)
		return -1;
	if (len == 1)
		return 0;
	/*
	 * Skip the last character (in addition to the null terminator),
	 * because if the last character is a newline, it is considered as part
	 * of the last line anyway.
	 */
	i = len - 2;
779

780 781 782 783 784
	for (; i >= 0; i--) {
		if (buf[i] == '\n')
			return i + 1;
	}
	return 0;
785 786 787
}

/*
788 789
 * Return the position of the start of the patch or the length of str if there
 * is no patch in the message.
790
 */
791
static size_t find_patch_start(const char *str)
792
{
793
	const char *s;
794

795
	for (s = str; *s; s = next_line(s)) {
796 797 798
		const char *v;

		if (skip_prefix(s, "---", &v) && isspace(*v))
799
			return s - str;
800 801
	}

802
	return s - str;
803 804 805
}

/*
806 807
 * Return the position of the first trailer line or len if there are no
 * trailers.
808
 */
809
static size_t find_trailer_start(const char *buf, size_t len)
810
{
811
	const char *s;
812 813
	ssize_t end_of_title, l;
	int only_spaces = 1;
814
	int recognized_prefix = 0, trailer_lines = 0, non_trailer_lines = 0;
815 816 817 818 819 820 821 822
	/*
	 * Number of possible continuation lines encountered. This will be
	 * reset to 0 if we encounter a trailer (since those lines are to be
	 * considered continuations of that trailer), and added to
	 * non_trailer_lines if we encounter a non-trailer (since those lines
	 * are to be considered non-trailers).
	 */
	int possible_continuation_lines = 0;
823 824

	/* The first paragraph is the title and cannot be trailers */
825 826
	for (s = buf; s < buf + len; s = next_line(s)) {
		if (s[0] == comment_line_char)
827
			continue;
828
		if (is_blank_line(s))
829 830
			break;
	}
831
	end_of_title = s - buf;
832 833

	/*
834 835 836 837
	 * Get the start of the trailers by looking starting from the end for a
	 * blank line before a set of non-blank lines that (i) are all
	 * trailers, or (ii) contains at least one Git-generated trailer and
	 * consists of at least 25% trailers.
838
	 */
839 840 841 842
	for (l = last_line(buf, len);
	     l >= end_of_title;
	     l = last_line(buf, l)) {
		const char *bol = buf + l;
843
		const char **p;
844
		ssize_t separator_pos;
845

846
		if (bol[0] == comment_line_char) {
847 848
			non_trailer_lines += possible_continuation_lines;
			possible_continuation_lines = 0;
849
			continue;
850
		}
851
		if (is_blank_line(bol)) {
852 853
			if (only_spaces)
				continue;
854
			non_trailer_lines += possible_continuation_lines;
855 856
			if (recognized_prefix &&
			    trailer_lines * 3 >= non_trailer_lines)
857 858 859 860
				return next_line(bol) - buf;
			else if (trailer_lines && !non_trailer_lines)
				return next_line(bol) - buf;
			return len;
861
		}
862 863 864
		only_spaces = 0;

		for (p = git_generated_prefixes; *p; p++) {
865
			if (starts_with(bol, *p)) {
866
				trailer_lines++;
867
				possible_continuation_lines = 0;
868 869 870
				recognized_prefix = 1;
				goto continue_outer_loop;
			}
871
		}
872

873 874
		separator_pos = find_separator(bol, separators);
		if (separator_pos >= 1 && !isspace(bol[0])) {
875 876 877
			struct list_head *pos;

			trailer_lines++;
878
			possible_continuation_lines = 0;
879 880 881 882 883
			if (recognized_prefix)
				continue;
			list_for_each(pos, &conf_head) {
				struct arg_item *item;
				item = list_entry(pos, struct arg_item, list);
884
				if (token_matches_item(bol, item,
885 886 887 888 889
						       separator_pos)) {
					recognized_prefix = 1;
					break;
				}
			}
890
		} else if (isspace(bol[0]))
891 892
			possible_continuation_lines++;
		else {
893
			non_trailer_lines++;
894 895
			non_trailer_lines += possible_continuation_lines;
			possible_continuation_lines = 0;
896
		}
897 898
continue_outer_loop:
		;
899 900
	}

901
	return len;
902 903
}

904
/* Return the position of the end of the trailers. */
905
static size_t find_trailer_end(const char *buf, size_t len)
906
{
907
	return len - ignore_non_trailer(buf, len);
908 909
}

910
static int ends_with_blank_line(const char *buf, size_t len)
911
{
912
	ssize_t ll = last_line(buf, len);
913 914 915
	if (ll < 0)
		return 0;
	return is_blank_line(buf + ll);
916 917
}

918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
static void unfold_value(struct strbuf *val)
{
	struct strbuf out = STRBUF_INIT;
	size_t i;

	strbuf_grow(&out, val->len);
	i = 0;
	while (i < val->len) {
		char c = val->buf[i++];
		if (c == '\n') {
			/* Collapse continuation down to a single space. */
			while (i < val->len && isspace(val->buf[i]))
				i++;
			strbuf_addch(&out, ' ');
		} else {
			strbuf_addch(&out, c);
		}
	}

	/* Empty lines may have left us with whitespace cruft at the edges */
	strbuf_trim(&out);

	/* output goes back to val as if we modified it in-place */
	strbuf_swap(&out, val);
	strbuf_release(&out);
}

945 946 947 948
static size_t process_input_file(FILE *outfile,
				 const char *str,
				 struct list_head *head,
				 const struct process_trailer_options *opts)
949
{
950
	struct trailer_info info;
951 952
	struct strbuf tok = STRBUF_INIT;
	struct strbuf val = STRBUF_INIT;
953
	size_t i;
954

955
	trailer_info_get(&info, str, opts);
956 957

	/* Print lines before the trailers as is */
958 959
	if (!opts->only_trailers)
		fwrite(str, 1, info.trailer_start - str, outfile);
960

961
	if (!opts->only_trailers && !info.blank_line_before_trailer)
962
		fprintf(outfile, "\n");
963

964
	for (i = 0; i < info.trailer_nr; i++) {
965
		int separator_pos;
966 967
		char *trailer = info.trailers[i];
		if (trailer[0] == comment_line_char)
968
			continue;
969
		separator_pos = find_separator(trailer, separators);
970
		if (separator_pos >= 1) {
971
			parse_trailer(&tok, &val, NULL, trailer,
972
				      separator_pos);
973 974
			if (opts->unfold)
				unfold_value(&val);
975 976 977
			add_trailer_item(head,
					 strbuf_detach(&tok, NULL),
					 strbuf_detach(&val, NULL));
978
		} else if (!opts->only_trailers) {
979
			strbuf_addstr(&val, trailer);
980 981 982 983
			strbuf_strip_suffix(&val, "\n");
			add_trailer_item(head,
					 NULL,
					 strbuf_detach(&val, NULL));
984
		}
985 986
	}

987 988 989
	trailer_info_release(&info);

	return info.trailer_end - str;
990
}
991

992
static void free_all(struct list_head *head)
993
{
994 995 996 997
	struct list_head *pos, *p;
	list_for_each_safe(pos, p, head) {
		list_del(pos);
		free_trailer_item(list_entry(pos, struct trailer_item, list));
998 999 1000
	}
}

1001
static struct tempfile *trailers_tempfile;
1002 1003 1004 1005

static FILE *create_in_place_tempfile(const char *file)
{
	struct stat st;
1006
	struct strbuf filename_template = STRBUF_INIT;
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
	const char *tail;
	FILE *outfile;

	if (stat(file, &st))
		die_errno(_("could not stat %s"), file);
	if (!S_ISREG(st.st_mode))
		die(_("file %s is not a regular file"), file);
	if (!(st.st_mode & S_IWUSR))
		die(_("file %s is not writable by user"), file);

	/* Create temporary file in the same directory as the original */
	tail = strrchr(file, '/');
	if (tail != NULL)
1020 1021
		strbuf_add(&filename_template, file, tail - file + 1);
	strbuf_addstr(&filename_template, "git-interpret-trailers-XXXXXX");
1022

1023 1024
	trailers_tempfile = xmks_tempfile_m(filename_template.buf, st.st_mode);
	strbuf_release(&filename_template);
1025
	outfile = fdopen_tempfile(trailers_tempfile, "w");
1026 1027 1028 1029 1030 1031
	if (!outfile)
		die_errno(_("could not open temporary file"));

	return outfile;
}

1032 1033
void process_trailers(const char *file,
		      const struct process_trailer_options *opts,
1034
		      struct list_head *new_trailer_head)
1035
{
1036
	LIST_HEAD(head);
1037
	struct strbuf sb = STRBUF_INIT;
1038
	size_t trailer_end;
1039
	FILE *outfile = stdout;
1040

1041
	ensure_configured();
1042

1043
	read_input_file(&sb, file);
1044

1045
	if (opts->in_place)
1046 1047
		outfile = create_in_place_tempfile(file);

1048
	/* Print the lines before the trailers */
1049
	trailer_end = process_input_file(outfile, sb.buf, &head, opts);
1050

1051 1052
	if (!opts->only_input) {
		LIST_HEAD(arg_head);
1053
		process_command_line_args(&arg_head, new_trailer_head);
1054 1055
		process_trailers_lists(&head, &arg_head);
	}
1056

1057
	print_all(outfile, &head, opts);
1058

1059
	free_all(&head);
1060 1061

	/* Print the lines after the trailers as is */
1062 1063
	if (!opts->only_trailers)
		fwrite(sb.buf + trailer_end, 1, sb.len - trailer_end, outfile);
1064

1065
	if (opts->in_place)
1066 1067 1068
		if (rename_tempfile(&trailers_tempfile, file))
			die_errno(_("could not rename temporary file to %s"), file);

1069
	strbuf_release(&sb);
1070
}
1071

1072 1073
void trailer_info_get(struct trailer_info *info, const char *str,
		      const struct process_trailer_options *opts)
1074 1075 1076 1077 1078 1079 1080 1081 1082
{
	int patch_start, trailer_end, trailer_start;
	struct strbuf **trailer_lines, **ptr;
	char **trailer_strings = NULL;
	size_t nr = 0, alloc = 0;
	char **last = NULL;

	ensure_configured();

1083 1084 1085 1086 1087
	if (opts->no_divider)
		patch_start = strlen(str);
	else
		patch_start = find_patch_start(str);

1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
	trailer_end = find_trailer_end(str, patch_start);
	trailer_start = find_trailer_start(str, trailer_end);

	trailer_lines = strbuf_split_buf(str + trailer_start,
					 trailer_end - trailer_start,
					 '\n',
					 0);
	for (ptr = trailer_lines; *ptr; ptr++) {
		if (last && isspace((*ptr)->buf[0])) {
			struct strbuf sb = STRBUF_INIT;
			strbuf_attach(&sb, *last, strlen(*last), strlen(*last));
			strbuf_addbuf(&sb, *ptr);
			*last = strbuf_detach(&sb, NULL);
			continue;
		}
		ALLOC_GROW(trailer_strings, nr + 1, alloc);
		trailer_strings[nr] = strbuf_detach(*ptr, NULL);
		last = find_separator(trailer_strings[nr], separators) >= 1
			? &trailer_strings[nr]
			: NULL;
		nr++;
	}
	strbuf_list_free(trailer_lines);

	info->blank_line_before_trailer = ends_with_blank_line(str,
							       trailer_start);
	info->trailer_start = str + trailer_start;
	info->trailer_end = str + trailer_end;
	info->trailers = trailer_strings;
	info->trailer_nr = nr;
}

void trailer_info_release(struct trailer_info *info)
{
1122
	size_t i;
1123 1124 1125 1126
	for (i = 0; i < info->trailer_nr; i++)
		free(info->trailers[i]);
	free(info->trailers);
}
1127 1128 1129 1130 1131

static void format_trailer_info(struct strbuf *out,
				const struct trailer_info *info,
				const struct process_trailer_options *opts)
{
1132
	size_t origlen = out->len;
1133
	size_t i;
1134 1135

	/* If we want the whole block untouched, we can take the fast path. */
1136
	if (!opts->only_trailers && !opts->unfold && !opts->filter && !opts->separator) {
1137 1138 1139 1140 1141 1142 1143
		strbuf_add(out, info->trailer_start,
			   info->trailer_end - info->trailer_start);
		return;
	}

	for (i = 0; i < info->trailer_nr; i++) {
		char *trailer = info->trailers[i];
1144
		ssize_t separator_pos = find_separator(trailer, separators);
1145 1146 1147 1148 1149 1150

		if (separator_pos >= 1) {
			struct strbuf tok = STRBUF_INIT;
			struct strbuf val = STRBUF_INIT;

			parse_trailer(&tok, &val, NULL, trailer, separator_pos);
1151 1152 1153
			if (!opts->filter || opts->filter(&tok, opts->filter_data)) {
				if (opts->unfold)
					unfold_value(&val);
1154 1155 1156

				if (opts->separator && out->len != origlen)
					strbuf_addbuf(out, opts->separator);
1157 1158 1159
				if (!opts->value_only)
					strbuf_addf(out, "%s: ", tok.buf);
				strbuf_addbuf(out, &val);
1160 1161
				if (!opts->separator)
					strbuf_addch(out, '\n');
1162
			}
1163 1164 1165 1166
			strbuf_release(&tok);
			strbuf_release(&val);

		} else if (!opts->only_trailers) {
1167 1168 1169
			if (opts->separator && out->len != origlen) {
				strbuf_addbuf(out, opts->separator);
			}
1170
			strbuf_addstr(out, trailer);
1171 1172 1173
			if (opts->separator) {
				strbuf_rtrim(out);
			}
1174 1175 1176
		}
	}

1177 1178 1179 1180 1181 1182 1183
}

void format_trailers_from_commit(struct strbuf *out, const char *msg,
				 const struct process_trailer_options *opts)
{
	struct trailer_info info;

1184
	trailer_info_get(&info, msg, opts);
1185 1186 1187
	format_trailer_info(out, &info, opts);
	trailer_info_release(&info);
}