27
28
struct trailer_item {
29
struct list_head list;
30
+ /*
31
+ * If this is not a trailer line, the line is stored in value
32
+ * (excluding the terminating newline) and token is NULL.
33
+ */
34
char *token;
35
char *value;
36
};
48
49
#define TRAILER_ARG_STRING "$ARG"
50
51
+static const char *git_generated_prefixes[] = {
52
+ "Signed-off-by: ",
53
+ "(cherry picked from commit ",
54
+ NULL
55
+};
56
+
57
/* Iterate over the elements of the list. */
58
#define list_for_each_dir(pos, head, is_reverse) \
59
for (pos = is_reverse ? (head)->prev : (head)->next; \
80
81
static int same_token(struct trailer_item *a, struct arg_item *b)
82
{
73
- size_t a_len = token_len_without_separator(a->token, strlen(a->token));
74
- size_t b_len = token_len_without_separator(b->token, strlen(b->token));
75
- size_t min_len = (a_len > b_len) ? b_len : a_len;
83
+ size_t a_len, b_len, min_len;
84
+
85
+ if (!a->token)
86
+ return 0;
87
+
88
+ a_len = token_len_without_separator(a->token, strlen(a->token));
89
+ b_len = token_len_without_separator(b->token, strlen(b->token));
90
+ min_len = (a_len > b_len) ? b_len : a_len;
91
92
return !strncasecmp(a->token, b->token, min_len);
93
}
145
146
static void print_tok_val(FILE *outfile, const char *tok, const char *val)
147
{
133
- char c = last_non_space_char(tok);
148
+ char c;
149
+
150
+ if (!tok) {
151
+ fprintf(outfile, "%s\n", val);
152
+ return;
153
+ }
154
+
155
+ c = last_non_space_char(tok);
156
if (!c)
157
return;
158
if (strchr(separators, c))
731
static int find_trailer_start(struct strbuf **lines, int count)
732
{
733
int start, end_of_title, only_spaces = 1;
734
+ int recognized_prefix = 0, trailer_lines = 0, non_trailer_lines = 0;
735
736
/* The first paragraph is the title and cannot be trailers */
737
for (start = 0; start < count; start++) {
743
end_of_title = start;
744
745
/*
723
- * Get the start of the trailers by looking starting from the end
724
- * for a line with only spaces before lines with one separator.
746
+ * Get the start of the trailers by looking starting from the end for a
747
+ * blank line before a set of non-blank lines that (i) are all
748
+ * trailers, or (ii) contains at least one Git-generated trailer and
749
+ * consists of at least 25% trailers.
750
*/
751
for (start = count - 1; start >= end_of_title; start--) {
752
+ const char **p;
753
+ int separator_pos;
754
+
755
if (lines[start]->buf[0] == comment_line_char)
756
continue;
757
if (contains_only_spaces(lines[start]->buf)) {
758
if (only_spaces)
759
continue;
732
- return start + 1;
760
+ if (recognized_prefix &&
761
+ trailer_lines * 3 >= non_trailer_lines)
762
+ return start + 1;
763
+ if (trailer_lines && !non_trailer_lines)
764
+ return start + 1;
765
+ return count;
766
}
734
- if (strcspn(lines[start]->buf, separators) < lines[start]->len) {
735
- if (only_spaces)
736
- only_spaces = 0;
737
- continue;
767
+ only_spaces = 0;
768
+
769
+ for (p = git_generated_prefixes; *p; p++) {
770
+ if (starts_with(lines[start]->buf, *p)) {
771
+ trailer_lines++;
772
+ recognized_prefix = 1;
773
+ goto continue_outer_loop;
774
+ }
775
}
739
- return count;
776
+
777
+ separator_pos = find_separator(lines[start]->buf);
778
+ if (separator_pos >= 1) {
779
+ struct list_head *pos;
780
+
781
+ trailer_lines++;
782
+ if (recognized_prefix)
783
+ continue;
784
+ list_for_each(pos, &conf_head) {
785
+ struct arg_item *item;
786
+ item = list_entry(pos, struct arg_item, list);
787
+ if (token_matches_item(lines[start]->buf, item,
788
+ separator_pos)) {
789
+ recognized_prefix = 1;
790
+ break;
791
+ }
792
+ }
793
+ } else
794
+ non_trailer_lines++;
795
+continue_outer_loop:
796
+ ;
797
}
798
742
- return only_spaces ? count : 0;
799
+ return count;
800
}
801
802
/* Get the index of the end of the trailers */
867
add_trailer_item(head,
868
strbuf_detach(&tok, NULL),
869
strbuf_detach(&val, NULL));
870
+ } else {
871
+ strbuf_addbuf(&val, lines[i]);
872
+ strbuf_strip_suffix(&val, "\n");
873
+ add_trailer_item(head,
874
+ NULL,
875
+ strbuf_detach(&val, NULL));
876
}
877
}
878