fsmonitor: MINGW support for watchman integration
[gitweb.git] / trailer.c
index d441cd9ac6f6778629bedb6e5e6f0296f0ec0584..c30e3a0c0415db110bfce8d29514a8258647d7f7 100644 (file)
--- a/trailer.c
+++ b/trailer.c
@@ -159,13 +159,15 @@ static void print_tok_val(FILE *outfile, const char *tok, const char *val)
                fprintf(outfile, "%s%c %s\n", tok, separators[0], val);
 }
 
-static void print_all(FILE *outfile, struct list_head *head, int trim_empty)
+static void print_all(FILE *outfile, struct list_head *head,
+                     const struct process_trailer_options *opts)
 {
        struct list_head *pos;
        struct trailer_item *item;
        list_for_each(pos, head) {
                item = list_entry(pos, struct trailer_item, list);
-               if (!trim_empty || strlen(item->value) > 0)
+               if ((!opts->trim_empty || strlen(item->value) > 0) &&
+                   (!opts->only_trailers || item->token))
                        print_tok_val(outfile, item->token, item->value);
        }
 }
@@ -910,9 +912,37 @@ static int ends_with_blank_line(const char *buf, size_t len)
        return is_blank_line(buf + ll);
 }
 
+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);
+}
+
 static int process_input_file(FILE *outfile,
                              const char *str,
-                             struct list_head *head)
+                             struct list_head *head,
+                             const struct process_trailer_options *opts)
 {
        struct trailer_info info;
        struct strbuf tok = STRBUF_INIT;
@@ -922,9 +952,10 @@ static int process_input_file(FILE *outfile,
        trailer_info_get(&info, str);
 
        /* Print lines before the trailers as is */
-       fwrite(str, 1, info.trailer_start - str, outfile);
+       if (!opts->only_trailers)
+               fwrite(str, 1, info.trailer_start - str, outfile);
 
-       if (!info.blank_line_before_trailer)
+       if (!opts->only_trailers && !info.blank_line_before_trailer)
                fprintf(outfile, "\n");
 
        for (i = 0; i < info.trailer_nr; i++) {
@@ -936,10 +967,12 @@ static int process_input_file(FILE *outfile,
                if (separator_pos >= 1) {
                        parse_trailer(&tok, &val, NULL, trailer,
                                      separator_pos);
+                       if (opts->unfold)
+                               unfold_value(&val);
                        add_trailer_item(head,
                                         strbuf_detach(&tok, NULL),
                                         strbuf_detach(&val, NULL));
-               } else {
+               } else if (!opts->only_trailers) {
                        strbuf_addstr(&val, trailer);
                        strbuf_strip_suffix(&val, "\n");
                        add_trailer_item(head,
@@ -993,11 +1026,11 @@ static FILE *create_in_place_tempfile(const char *file)
        return outfile;
 }
 
-void process_trailers(const char *file, int in_place, int trim_empty,
+void process_trailers(const char *file,
+                     const struct process_trailer_options *opts,
                      struct list_head *new_trailer_head)
 {
        LIST_HEAD(head);
-       LIST_HEAD(arg_head);
        struct strbuf sb = STRBUF_INIT;
        int trailer_end;
        FILE *outfile = stdout;
@@ -1006,24 +1039,27 @@ void process_trailers(const char *file, int in_place, int trim_empty,
 
        read_input_file(&sb, file);
 
-       if (in_place)
+       if (opts->in_place)
                outfile = create_in_place_tempfile(file);
 
        /* Print the lines before the trailers */
-       trailer_end = process_input_file(outfile, sb.buf, &head);
-
-       process_command_line_args(&arg_head, new_trailer_head);
+       trailer_end = process_input_file(outfile, sb.buf, &head, opts);
 
-       process_trailers_lists(&head, &arg_head);
+       if (!opts->only_input) {
+               LIST_HEAD(arg_head);
+               process_command_line_args(&arg_head, new_trailer_head);
+               process_trailers_lists(&head, &arg_head);
+       }
 
-       print_all(outfile, &head, trim_empty);
+       print_all(outfile, &head, opts);
 
        free_all(&head);
 
        /* Print the lines after the trailers as is */
-       fwrite(sb.buf + trailer_end, 1, sb.len - trailer_end, outfile);
+       if (!opts->only_trailers)
+               fwrite(sb.buf + trailer_end, 1, sb.len - trailer_end, outfile);
 
-       if (in_place)
+       if (opts->in_place)
                if (rename_tempfile(&trailers_tempfile, file))
                        die_errno(_("could not rename temporary file to %s"), file);
 
@@ -1080,3 +1116,49 @@ void trailer_info_release(struct trailer_info *info)
                free(info->trailers[i]);
        free(info->trailers);
 }
+
+static void format_trailer_info(struct strbuf *out,
+                               const struct trailer_info *info,
+                               const struct process_trailer_options *opts)
+{
+       int i;
+
+       /* If we want the whole block untouched, we can take the fast path. */
+       if (!opts->only_trailers && !opts->unfold) {
+               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];
+               int separator_pos = find_separator(trailer, separators);
+
+               if (separator_pos >= 1) {
+                       struct strbuf tok = STRBUF_INIT;
+                       struct strbuf val = STRBUF_INIT;
+
+                       parse_trailer(&tok, &val, NULL, trailer, separator_pos);
+                       if (opts->unfold)
+                               unfold_value(&val);
+
+                       strbuf_addf(out, "%s: %s\n", tok.buf, val.buf);
+                       strbuf_release(&tok);
+                       strbuf_release(&val);
+
+               } else if (!opts->only_trailers) {
+                       strbuf_addstr(out, trailer);
+               }
+       }
+
+}
+
+void format_trailers_from_commit(struct strbuf *out, const char *msg,
+                                const struct process_trailer_options *opts)
+{
+       struct trailer_info info;
+
+       trailer_info_get(&info, msg);
+       format_trailer_info(out, &info, opts);
+       trailer_info_release(&info);
+}