]> git.ipfire.org Git - thirdparty/git.git/blobdiff - trailer.c
Merge branch 'rj/add-i-leak-fix'
[thirdparty/git.git] / trailer.c
index 5025be978999d7c95c82a011a157e3a034dd796d..c72ae687099f0d2d21d8dacddf553eabc6ddca8c 100644 (file)
--- a/trailer.c
+++ b/trailer.c
@@ -144,37 +144,6 @@ static char last_non_space_char(const char *s)
        return '\0';
 }
 
-static void print_tok_val(FILE *outfile, const char *tok, const char *val)
-{
-       char c;
-
-       if (!tok) {
-               fprintf(outfile, "%s\n", val);
-               return;
-       }
-
-       c = last_non_space_char(tok);
-       if (!c)
-               return;
-       if (strchr(separators, c))
-               fprintf(outfile, "%s%s\n", tok, val);
-       else
-               fprintf(outfile, "%s%c %s\n", tok, separators[0], val);
-}
-
-void format_trailers(const struct process_trailer_options *opts,
-                    struct list_head *trailers, FILE *outfile)
-{
-       struct list_head *pos;
-       struct trailer_item *item;
-       list_for_each(pos, trailers) {
-               item = list_entry(pos, struct trailer_item, list);
-               if ((!opts->trim_empty || strlen(item->value) > 0) &&
-                   (!opts->only_trailers || item->token))
-                       print_tok_val(outfile, item->token, item->value);
-       }
-}
-
 static struct trailer_item *trailer_from_arg(struct arg_item *arg_tok)
 {
        struct trailer_item *new_item = xcalloc(1, sizeof(*new_item));
@@ -833,16 +802,15 @@ static size_t find_end_of_log_message(const char *input, int no_divider)
        /* Assume the naive end of the input is already what we want. */
        end = strlen(input);
 
-       if (no_divider)
-               return end;
-
        /* Optionally skip over any patch part ("---" line and below). */
-       for (s = input; *s; s = next_line(s)) {
-               const char *v;
+       if (!no_divider) {
+               for (s = input; *s; s = next_line(s)) {
+                       const char *v;
 
-               if (skip_prefix(s, "---", &v) && isspace(*v)) {
-                       end = s - input;
-                       break;
+                       if (skip_prefix(s, "---", &v) && isspace(*v)) {
+                               end = s - input;
+                               break;
+                       }
                }
        }
 
@@ -871,7 +839,7 @@ static size_t find_trailer_block_start(const char *buf, size_t len)
 
        /* The first paragraph is the title and cannot be trailers */
        for (s = buf; s < buf + len; s = next_line(s)) {
-               if (s[0] == comment_line_char)
+               if (starts_with_mem(s, buf + len - s, comment_line_str))
                        continue;
                if (is_blank_line(s))
                        break;
@@ -891,7 +859,7 @@ static size_t find_trailer_block_start(const char *buf, size_t len)
                const char **p;
                ssize_t separator_pos;
 
-               if (bol[0] == comment_line_char) {
+               if (starts_with_mem(bol, buf + len - bol, comment_line_str)) {
                        non_trailer_lines += possible_continuation_lines;
                        possible_continuation_lines = 0;
                        continue;
@@ -997,12 +965,12 @@ void parse_trailers(const struct process_trailer_options *opts,
        struct strbuf val = STRBUF_INIT;
        size_t i;
 
-       trailer_info_get(info, str, opts);
+       trailer_info_get(opts, str, info);
 
        for (i = 0; i < info->trailer_nr; i++) {
                int separator_pos;
                char *trailer = info->trailers[i];
-               if (trailer[0] == comment_line_char)
+               if (starts_with(trailer, comment_line_str))
                        continue;
                separator_pos = find_separator(trailer, separators);
                if (separator_pos >= 1) {
@@ -1032,8 +1000,9 @@ void free_trailers(struct list_head *trailers)
        }
 }
 
-void trailer_info_get(struct trailer_info *info, const char *str,
-                     const struct process_trailer_options *opts)
+void trailer_info_get(const struct process_trailer_options *opts,
+                     const char *str,
+                     struct trailer_info *info)
 {
        size_t end_of_log_message = 0, trailer_block_start = 0;
        struct strbuf **trailer_lines, **ptr;
@@ -1083,36 +1052,32 @@ void trailer_info_release(struct trailer_info *info)
        free(info->trailers);
 }
 
-static void format_trailer_info(const struct process_trailer_options *opts,
-                               const struct trailer_info *info,
-                               const char *msg,
-                               struct strbuf *out)
+void format_trailers(const struct process_trailer_options *opts,
+                    struct list_head *trailers,
+                    struct strbuf *out)
 {
        size_t origlen = out->len;
-       size_t i;
-
-       /* If we want the whole block untouched, we can take the fast path. */
-       if (!opts->only_trailers && !opts->unfold && !opts->filter &&
-           !opts->separator && !opts->key_only && !opts->value_only &&
-           !opts->key_value_separator) {
-               strbuf_add(out, msg + info->trailer_block_start,
-                          info->trailer_block_end - info->trailer_block_start);
-               return;
-       }
-
-       for (i = 0; i < info->trailer_nr; i++) {
-               char *trailer = info->trailers[i];
-               ssize_t separator_pos = find_separator(trailer, separators);
+       struct list_head *pos;
+       struct trailer_item *item;
 
-               if (separator_pos >= 1) {
+       list_for_each(pos, trailers) {
+               item = list_entry(pos, struct trailer_item, list);
+               if (item->token) {
                        struct strbuf tok = STRBUF_INIT;
                        struct strbuf val = STRBUF_INIT;
+                       strbuf_addstr(&tok, item->token);
+                       strbuf_addstr(&val, item->value);
+
+                       /*
+                        * Skip key/value pairs where the value was empty. This
+                        * can happen from trailers specified without a
+                        * separator, like `--trailer "Reviewed-by"` (no
+                        * corresponding value).
+                        */
+                       if (opts->trim_empty && !strlen(item->value))
+                               continue;
 
-                       parse_trailer(&tok, &val, NULL, trailer, separator_pos);
                        if (!opts->filter || opts->filter(&tok, opts->filter_data)) {
-                               if (opts->unfold)
-                                       unfold_value(&val);
-
                                if (opts->separator && out->len != origlen)
                                        strbuf_addbuf(out, opts->separator);
                                if (!opts->value_only)
@@ -1120,8 +1085,11 @@ static void format_trailer_info(const struct process_trailer_options *opts,
                                if (!opts->key_only && !opts->value_only) {
                                        if (opts->key_value_separator)
                                                strbuf_addbuf(out, opts->key_value_separator);
-                                       else
-                                               strbuf_addstr(out, ": ");
+                                       else {
+                                               char c = last_non_space_char(tok.buf);
+                                               if (c && !strchr(separators, c))
+                                                       strbuf_addf(out, "%c ", separators[0]);
+                                       }
                                }
                                if (!opts->key_only)
                                        strbuf_addbuf(out, &val);
@@ -1135,23 +1103,34 @@ static void format_trailer_info(const struct process_trailer_options *opts,
                        if (opts->separator && out->len != origlen) {
                                strbuf_addbuf(out, opts->separator);
                        }
-                       strbuf_addstr(out, trailer);
-                       if (opts->separator) {
+                       strbuf_addstr(out, item->value);
+                       if (opts->separator)
                                strbuf_rtrim(out);
-                       }
+                       else
+                               strbuf_addch(out, '\n');
                }
        }
-
 }
 
 void format_trailers_from_commit(const struct process_trailer_options *opts,
                                 const char *msg,
                                 struct strbuf *out)
 {
+       LIST_HEAD(trailer_objects);
        struct trailer_info info;
 
-       trailer_info_get(&info, msg, opts);
-       format_trailer_info(opts, &info, msg, out);
+       parse_trailers(opts, &info, msg, &trailer_objects);
+
+       /* If we want the whole block untouched, we can take the fast path. */
+       if (!opts->only_trailers && !opts->unfold && !opts->filter &&
+           !opts->separator && !opts->key_only && !opts->value_only &&
+           !opts->key_value_separator) {
+               strbuf_add(out, msg + info.trailer_block_start,
+                          info.trailer_block_end - info.trailer_block_start);
+       } else
+               format_trailers(opts, &trailer_objects, out);
+
+       free_trailers(&trailer_objects);
        trailer_info_release(&info);
 }
 
@@ -1161,7 +1140,7 @@ void trailer_iterator_init(struct trailer_iterator *iter, const char *msg)
        strbuf_init(&iter->key, 0);
        strbuf_init(&iter->val, 0);
        opts.no_divider = 1;
-       trailer_info_get(&iter->internal.info, msg, &opts);
+       trailer_info_get(&opts, msg, &iter->internal.info);
        iter->internal.cur = 0;
 }