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);
}
}
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;
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++) {
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,
}
}
-static struct tempfile trailers_tempfile;
+static struct tempfile *trailers_tempfile;
static FILE *create_in_place_tempfile(const char *file)
{
strbuf_add(&template, file, tail - file + 1);
strbuf_addstr(&template, "git-interpret-trailers-XXXXXX");
- xmks_tempfile_m(&trailers_tempfile, template.buf, st.st_mode);
+ trailers_tempfile = xmks_tempfile_m(template.buf, st.st_mode);
strbuf_release(&template);
- outfile = fdopen_tempfile(&trailers_tempfile, "w");
+ outfile = fdopen_tempfile(trailers_tempfile, "w");
if (!outfile)
die_errno(_("could not open temporary 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;
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);
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);
+}