# [PATCH v3 1/2] trailer: use fprintf instead of printf

8 messages from 2016-01-13 to 2016-01-14. Participants: Tobias Klauser, Matthieu Moy, Eric Sunshine, Junio C Hamano.
Thread: https://gitlist.dev/t/41179

## Tobias Klauser, 2016-01-13 12:43

Subject: [PATCH v3 0/2] Add in-place editing support to git interpret-trailers
Message-ID: <1452688989-13746-1-git-send-email-tklauser@distanz.ch>
URL: https://gitlist.dev/e/1452688989-13746-1-git-send-email-tklauser%40distanz.ch

```
This patch series adds support for in-place editing to git interpret-trailers
akin to sed -i, perl -i.

v2->v3:
 - Rephrase two error messages according to the suggestions by Matthieu Moy.

v1->v2:
 - Split patch to make review easier, as suggested by Matthieu Moy.
 - Rename FILE * function parameters to a more readable name, as suggested by
   Matthieu Moy.
 - Write output to temporary file and rename after successfully written in full
   to avoid losing the original file in case of an error/interrupt. Pointed out
   by Eric Sunshine.

Tobias Klauser (2):
  trailer: use fprintf instead of printf
  interpret-trailers: add option for in-place editing

 Documentation/git-interpret-trailers.txt | 24 +++++++++++-
 builtin/interpret-trailers.c             | 13 +++++--
 t/t7513-interpret-trailers.sh            | 32 ++++++++++++++++
 trailer.c                                | 63 +++++++++++++++++++++++++-------
 trailer.h                                |  3 +-
 5 files changed, 115 insertions(+), 20 deletions(-)

-- 
2.7.0.1.g5e091f5

```

## Tobias Klauser, 2016-01-13 12:43

Subject: [PATCH v3 1/2] trailer: use fprintf instead of printf
Message-ID: <1452688989-13746-2-git-send-email-tklauser@distanz.ch>
URL: https://gitlist.dev/e/1452688989-13746-2-git-send-email-tklauser%40distanz.ch
In-Reply-To: <1452688989-13746-1-git-send-email-tklauser@distanz.ch>

```
Use fprintf instead of printf in trailer.c in order to allow printing
to a file other than stdout. This will be needed to support in-place
editing in git interpret-trailers.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
---
 trailer.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/trailer.c b/trailer.c
index 6f3416febaba..176fac213450 100644
--- a/trailer.c
+++ b/trailer.c
@@ -108,23 +108,23 @@ static char last_non_space_char(const char *s)
 	return '\0';
 }
 
-static void print_tok_val(const char *tok, const char *val)
+static void print_tok_val(FILE *outfile, const char *tok, const char *val)
 {
 	char c = last_non_space_char(tok);
 	if (!c)
 		return;
 	if (strchr(separators, c))
-		printf("%s%s\n", tok, val);
+		fprintf(outfile, "%s%s\n", tok, val);
 	else
-		printf("%s%c %s\n", tok, separators[0], val);
+		fprintf(outfile, "%s%c %s\n", tok, separators[0], val);
 }
 
-static void print_all(struct trailer_item *first, int trim_empty)
+static void print_all(FILE *outfile, struct trailer_item *first, int trim_empty)
 {
 	struct trailer_item *item;
 	for (item = first; item; item = item->next) {
 		if (!trim_empty || strlen(item->value) > 0)
-			print_tok_val(item->token, item->value);
+			print_tok_val(outfile, item->token, item->value);
 	}
 }
 
@@ -795,14 +795,15 @@ static int has_blank_line_before(struct strbuf **lines, int start)
 	return 0;
 }
 
-static void print_lines(struct strbuf **lines, int start, int end)
+static void print_lines(FILE *outfile, struct strbuf **lines, int start, int end)
 {
 	int i;
 	for (i = start; lines[i] && i < end; i++)
-		printf("%s", lines[i]->buf);
+		fprintf(outfile, "%s", lines[i]->buf);
 }
 
-static int process_input_file(struct strbuf **lines,
+static int process_input_file(FILE *outfile,
+			      struct strbuf **lines,
 			      struct trailer_item **in_tok_first,
 			      struct trailer_item **in_tok_last)
 {
@@ -818,10 +819,10 @@ static int process_input_file(struct strbuf **lines,
 	trailer_start = find_trailer_start(lines, trailer_end);
 
 	/* Print lines before the trailers as is */
-	print_lines(lines, 0, trailer_start);
+	print_lines(outfile, lines, 0, trailer_start);
 
 	if (!has_blank_line_before(lines, trailer_start - 1))
-		printf("\n");
+		fprintf(outfile, "\n");
 
 	/* Parse trailer lines */
 	for (i = trailer_start; i < trailer_end; i++) {
@@ -849,6 +850,7 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
 	struct trailer_item *arg_tok_first;
 	struct strbuf **lines;
 	int trailer_end;
+	FILE *outfile = stdout;
 
 	/* Default config must be setup first */
 	git_config(git_trailer_default_config, NULL);
@@ -857,18 +859,18 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
 	lines = read_input_file(file);
 
 	/* Print the lines before the trailers */
-	trailer_end = process_input_file(lines, &in_tok_first, &in_tok_last);
+	trailer_end = process_input_file(outfile, lines, &in_tok_first, &in_tok_last);
 
 	arg_tok_first = process_command_line_args(trailers);
 
 	process_trailers_lists(&in_tok_first, &in_tok_last, &arg_tok_first);
 
-	print_all(in_tok_first, trim_empty);
+	print_all(outfile, in_tok_first, trim_empty);
 
 	free_all(&in_tok_first);
 
 	/* Print the lines after the trailers as is */
-	print_lines(lines, trailer_end, INT_MAX);
+	print_lines(outfile, lines, trailer_end, INT_MAX);
 
 	strbuf_list_free(lines);
 }
-- 
2.7.0.1.g5e091f5

```

## Tobias Klauser, 2016-01-13 12:43

Subject: [PATCH v3 2/2] interpret-trailers: add option for in-place editing
Message-ID: <1452688989-13746-3-git-send-email-tklauser@distanz.ch>
URL: https://gitlist.dev/e/1452688989-13746-3-git-send-email-tklauser%40distanz.ch
In-Reply-To: <1452688989-13746-1-git-send-email-tklauser@distanz.ch>

```
Add a command line option --in-place to support in-place editing akin to
sed -i.  This allows to write commands like the following:

  git interpret-trailers --trailer "X: Y" a.txt > b.txt && mv b.txt a.txt

in a more concise way:

  git interpret-trailers --trailer "X: Y" --in-place a.txt

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
---
 Documentation/git-interpret-trailers.txt | 24 +++++++++++++++++++++-
 builtin/interpret-trailers.c             | 13 ++++++++----
 t/t7513-interpret-trailers.sh            | 32 +++++++++++++++++++++++++++++
 trailer.c                                | 35 +++++++++++++++++++++++++++++++-
 trailer.h                                |  3 ++-
 5 files changed, 100 insertions(+), 7 deletions(-)

diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt
index 0ecd497c4de7..a77b901f1d7b 100644
--- a/Documentation/git-interpret-trailers.txt
+++ b/Documentation/git-interpret-trailers.txt
@@ -8,7 +8,7 @@ git-interpret-trailers - help add structured information into commit messages
 SYNOPSIS
 --------
 [verse]
-'git interpret-trailers' [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]
+'git interpret-trailers' [--in-place] [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]
 
 DESCRIPTION
 -----------
@@ -64,6 +64,9 @@ folding rules, the encoding rules and probably many other rules.
 
 OPTIONS
 -------
+--in-place::
+	Edit the files in place.
+
 --trim-empty::
 	If the <value> part of any trailer contains only whitespace,
 	the whole trailer will be removed from the resulting message.
@@ -216,6 +219,25 @@ Signed-off-by: Alice <alice@example.com>
 Signed-off-by: Bob <bob@example.com>
 ------------
 
+* Use the '--in-place' option to edit a message file in place:
++
+------------
+$ cat msg.txt
+subject
+
+message
+
+Signed-off-by: Bob <bob@example.com>
+$ git interpret-trailers --trailer 'Acked-by: Alice <alice@example.com>' --in-place msg.txt
+$ cat msg.txt
+subject
+
+message
+
+Signed-off-by: Bob <bob@example.com>
+Acked-by: Alice <alice@example.com>
+------------
+
 * Extract the last commit as a patch, and add a 'Cc' and a
   'Reviewed-by' trailer to it:
 +
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index 46838d24a90a..b99ae4be8875 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -12,16 +12,18 @@
 #include "trailer.h"
 
 static const char * const git_interpret_trailers_usage[] = {
-	N_("git interpret-trailers [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]"),
+	N_("git interpret-trailers [--in-place] [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]"),
 	NULL
 };
 
 int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
 {
+	int in_place = 0;
 	int trim_empty = 0;
 	struct string_list trailers = STRING_LIST_INIT_DUP;
 
 	struct option options[] = {
+		OPT_BOOL(0, "in-place", &in_place, N_("edit files in place")),
 		OPT_BOOL(0, "trim-empty", &trim_empty, N_("trim empty trailers")),
 		OPT_STRING_LIST(0, "trailer", &trailers, N_("trailer"),
 				N_("trailer(s) to add")),
@@ -34,9 +36,12 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
 	if (argc) {
 		int i;
 		for (i = 0; i < argc; i++)
-			process_trailers(argv[i], trim_empty, &trailers);
-	} else
-		process_trailers(NULL, trim_empty, &trailers);
+			process_trailers(argv[i], in_place, trim_empty, &trailers);
+	} else {
+		if (in_place)
+			die(_("no input file given for in-place editing"));
+		process_trailers(NULL, in_place, trim_empty, &trailers);
+	}
 
 	string_list_clear(&trailers, 0);
 
diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh
index 322c436a494c..1103a4838b5c 100755
--- a/t/t7513-interpret-trailers.sh
+++ b/t/t7513-interpret-trailers.sh
@@ -326,6 +326,38 @@ test_expect_success 'with complex patch, args and --trim-empty' '
 	test_cmp expected actual
 '
 
+test_expect_success 'in-place editing with basic patch' '
+	cat basic_message >message &&
+	cat basic_patch >>message &&
+	cat basic_message >expected &&
+	echo >>expected &&
+	cat basic_patch >>expected &&
+	git interpret-trailers --in-place message &&
+	test_cmp expected message
+'
+
+test_expect_success 'in-place editing with additional trailer' '
+	cat basic_message >message &&
+	cat basic_patch >>message &&
+	cat basic_message >expected &&
+	echo >>expected &&
+	cat >>expected <<-\EOF &&
+		Reviewed-by: Alice
+	EOF
+	cat basic_patch >>expected &&
+	git interpret-trailers --trailer "Reviewed-by: Alice" --in-place message &&
+	test_cmp expected message
+'
+
+test_expect_success 'in-place editing on stdin' '
+	test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place < basic_message
+'
+
+test_expect_success 'in-place editing on non-existing file' '
+	test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place nonexisting &&
+	test_path_is_missing nonexisting
+'
+
 test_expect_success 'using "where = before"' '
 	git config trailer.bug.where "before" &&
 	cat complex_message_body >expected &&
diff --git a/trailer.c b/trailer.c
index 176fac213450..6834d1f8086a 100644
--- a/trailer.c
+++ b/trailer.c
@@ -2,6 +2,7 @@
 #include "string-list.h"
 #include "run-command.h"
 #include "commit.h"
+#include "tempfile.h"
 #include "trailer.h"
 /*
  * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
@@ -843,7 +844,9 @@ static void free_all(struct trailer_item **first)
 	}
 }
 
-void process_trailers(const char *file, int trim_empty, struct string_list *trailers)
+static struct tempfile trailers_tempfile;
+
+void process_trailers(const char *file, int in_place, int trim_empty, struct string_list *trailers)
 {
 	struct trailer_item *in_tok_first = NULL;
 	struct trailer_item *in_tok_last = NULL;
@@ -858,6 +861,31 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
 
 	lines = read_input_file(file);
 
+	if (in_place) {
+		struct stat st;
+		struct strbuf template = STRBUF_INIT;
+		const char *tail;
+
+		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)
+			strbuf_add(&template, file, tail - file + 1);
+		strbuf_addstr(&template, "git-interpret-trailers-XXXXXX");
+
+		xmks_tempfile_m(&trailers_tempfile, template.buf, st.st_mode);
+		strbuf_release(&template);
+		outfile = fdopen_tempfile(&trailers_tempfile, "w");
+		if (!outfile)
+			die_errno(_("could not open temporary file"));
+	}
+
 	/* Print the lines before the trailers */
 	trailer_end = process_input_file(outfile, lines, &in_tok_first, &in_tok_last);
 
@@ -872,5 +900,10 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
 	/* Print the lines after the trailers as is */
 	print_lines(outfile, lines, trailer_end, INT_MAX);
 
+	if (in_place) {
+		if (rename_tempfile(&trailers_tempfile, file))
+			die_errno(_("could not rename temporary file to %s"), file);
+	}
+
 	strbuf_list_free(lines);
 }
diff --git a/trailer.h b/trailer.h
index 8eb25d565e28..36b40b81761f 100644
--- a/trailer.h
+++ b/trailer.h
@@ -1,6 +1,7 @@
 #ifndef TRAILER_H
 #define TRAILER_H
 
-void process_trailers(const char *file, int trim_empty, struct string_list *trailers);
+void process_trailers(const char *file, int in_place, int trim_empty,
+		      struct string_list *trailers);
 
 #endif /* TRAILER_H */
-- 
2.7.0.1.g5e091f5

```

## Matthieu Moy, 2016-01-13 12:44

Subject: Re: [PATCH v3 0/2] Add in-place editing support to git interpret-trailers
Message-ID: <vpqmvs9mywq.fsf@anie.imag.fr>
URL: https://gitlist.dev/e/vpqmvs9mywq.fsf%40anie.imag.fr
In-Reply-To: <1452688989-13746-1-git-send-email-tklauser@distanz.ch>

```
Tobias Klauser <tklauser@distanz.ch> writes:

> This patch series adds support for in-place editing to git interpret-trailers
> akin to sed -i, perl -i.
>
> v2->v3:
>  - Rephrase two error messages according to the suggestions by Matthieu Moy.

Perfect, thanks.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

```

## Eric Sunshine, 2016-01-13 18:15

Subject: Re: [PATCH v3 2/2] interpret-trailers: add option for in-place editing
Message-ID: <CAPig+cSX04OSLQVk-LHm2UQOAqThQUJuFhuhUfoNmUvHmZpPsA@mail.gmail.com>
URL: https://gitlist.dev/e/CAPig%2BcSX04OSLQVk-LHm2UQOAqThQUJuFhuhUfoNmUvHmZpPsA%40mail.gmail.com
In-Reply-To: <1452688989-13746-3-git-send-email-tklauser@distanz.ch>

```
On Wed, Jan 13, 2016 at 7:43 AM, Tobias Klauser <tklauser@distanz.ch> wrote:
> Add a command line option --in-place to support in-place editing akin to
> sed -i.  This allows to write commands like the following:
>
>   git interpret-trailers --trailer "X: Y" a.txt > b.txt && mv b.txt a.txt
>
> in a more concise way:
>
>   git interpret-trailers --trailer "X: Y" --in-place a.txt
>
> Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
> ---
> diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh
> @@ -326,6 +326,38 @@ test_expect_success 'with complex patch, args and --trim-empty' '
> +test_expect_success 'in-place editing on stdin' '

Maybe say:

    "in-place editing on stdin disallowed"

or something?

> +       test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place < basic_message
> +'
> +
> +test_expect_success 'in-place editing on non-existing file' '
> +       test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place nonexisting &&
> +       test_path_is_missing nonexisting
> +'

An significant shortcoming of the first version of this patch series
was that it did not treat the input file as precious, and would
happily delete it if trailer processing failed for any reason. This is
behavior we'd like to protect against. Toward that end, have you
considered adding a test to verify that the input file is indeed
considered precious, and not deleted upon failure? One way to do so
would be to write a test which triggers one of the failure conditions
of the interpret-trailers framework. Looking at the source code, one
possible way would be to make trailer.c:read_input_file() fail, for
instance, by making the file unreadable (with 'chmod -r', though you'd
have to protect the test with the POSIXPERM prerequisite).

More below.

> diff --git a/trailer.c b/trailer.c
> @@ -858,6 +861,31 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
>
>         lines = read_input_file(file);
>
> +       if (in_place) {
> +               struct stat st;
> +               struct strbuf template = STRBUF_INIT;
> +               const char *tail;
> +
> +               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)
> +                       strbuf_add(&template, file, tail - file + 1);
> +               strbuf_addstr(&template, "git-interpret-trailers-XXXXXX");
> +
> +               xmks_tempfile_m(&trailers_tempfile, template.buf, st.st_mode);
> +               strbuf_release(&template);
> +               outfile = fdopen_tempfile(&trailers_tempfile, "w");
> +               if (!outfile)
> +                       die_errno(_("could not open temporary file"));
> +       }

Hmm, the current logic of process_trailers() is pretty easily
understood at a glance, but this new (relatively huge) chunk of code
obscures the overall operation. Have you considered factoring the new
code out into its own function in order to keep the overall flow of
process_trailers() clean? (Genuine question; I don't necessarily feel
so strongly about it to demand such a change.)

>         /* Print the lines before the trailers */
>         trailer_end = process_input_file(outfile, lines, &in_tok_first, &in_tok_last);
>
> @@ -872,5 +900,10 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
>         /* Print the lines after the trailers as is */
>         print_lines(outfile, lines, trailer_end, INT_MAX);
>
> +       if (in_place) {
> +               if (rename_tempfile(&trailers_tempfile, file))
> +                       die_errno(_("could not rename temporary file to %s"), file);
> +       }

You could drop the unnecessary braces.

>         strbuf_list_free(lines);
>  }

```

## Junio C Hamano, 2016-01-13 19:20

Subject: Re: [PATCH v3 1/2] trailer: use fprintf instead of printf
Message-ID: <xmqqd1t5nv6j.fsf@gitster.mtv.corp.google.com>
URL: https://gitlist.dev/e/xmqqd1t5nv6j.fsf%40gitster.mtv.corp.google.com
In-Reply-To: <1452688989-13746-2-git-send-email-tklauser@distanz.ch>

```
Tobias Klauser <tklauser@distanz.ch> writes:

> Use fprintf instead of printf in trailer.c in order to allow printing
> to a file other than stdout. This will be needed to support in-place
> editing in git interpret-trailers.
>
> Signed-off-by: Tobias Klauser <tklauser@distanz.ch>

Thanks.  I won't bother to amend it myself or request you to reroll
only for this, but that is a rather suboptimal title.

The distinction between fprintf/printf is an implementation detail;
what you want to do in this change is to allow writing to a file
other than the standard output, and that should be in the title.

```

## Tobias Klauser, 2016-01-14 09:31

Subject: Re: [PATCH v3 2/2] interpret-trailers: add option for in-place editing
Message-ID: <20160114093157.GF26950@distanz.ch>
URL: https://gitlist.dev/e/20160114093157.GF26950%40distanz.ch
In-Reply-To: <CAPig+cSX04OSLQVk-LHm2UQOAqThQUJuFhuhUfoNmUvHmZpPsA@mail.gmail.com>

```
On 2016-01-13 at 19:15:54 +0100, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Wed, Jan 13, 2016 at 7:43 AM, Tobias Klauser <tklauser@distanz.ch> wrote:
> > Add a command line option --in-place to support in-place editing akin to
> > sed -i.  This allows to write commands like the following:
> >
> >   git interpret-trailers --trailer "X: Y" a.txt > b.txt && mv b.txt a.txt
> >
> > in a more concise way:
> >
> >   git interpret-trailers --trailer "X: Y" --in-place a.txt
> >
> > Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
> > ---
> > diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh
> > @@ -326,6 +326,38 @@ test_expect_success 'with complex patch, args and --trim-empty' '
> > +test_expect_success 'in-place editing on stdin' '
> 
> Maybe say:
> 
>     "in-place editing on stdin disallowed"
> 
> or something?

Agree, will change in v4.

> > +       test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place < basic_message
> > +'
> > +
> > +test_expect_success 'in-place editing on non-existing file' '
> > +       test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place nonexisting &&
> > +       test_path_is_missing nonexisting
> > +'
> 
> An significant shortcoming of the first version of this patch series
> was that it did not treat the input file as precious, and would
> happily delete it if trailer processing failed for any reason. This is
> behavior we'd like to protect against. Toward that end, have you
> considered adding a test to verify that the input file is indeed
> considered precious, and not deleted upon failure? One way to do so
> would be to write a test which triggers one of the failure conditions
> of the interpret-trailers framework. Looking at the source code, one
> possible way would be to make trailer.c:read_input_file() fail, for
> instance, by making the file unreadable (with 'chmod -r', though you'd
> have to protect the test with the POSIXPERM prerequisite).

Good point. Yes, such a test should definitely be added, I forgot about
it during the reroll. I'll look into your suggestion and add a test in
v4.

> More below.
> 
> > diff --git a/trailer.c b/trailer.c
> > @@ -858,6 +861,31 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
> >
> >         lines = read_input_file(file);
> >
> > +       if (in_place) {
> > +               struct stat st;
> > +               struct strbuf template = STRBUF_INIT;
> > +               const char *tail;
> > +
> > +               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)
> > +                       strbuf_add(&template, file, tail - file + 1);
> > +               strbuf_addstr(&template, "git-interpret-trailers-XXXXXX");
> > +
> > +               xmks_tempfile_m(&trailers_tempfile, template.buf, st.st_mode);
> > +               strbuf_release(&template);
> > +               outfile = fdopen_tempfile(&trailers_tempfile, "w");
> > +               if (!outfile)
> > +                       die_errno(_("could not open temporary file"));
> > +       }
> 
> Hmm, the current logic of process_trailers() is pretty easily
> understood at a glance, but this new (relatively huge) chunk of code
> obscures the overall operation. Have you considered factoring the new
> code out into its own function in order to keep the overall flow of
> process_trailers() clean? (Genuine question; I don't necessarily feel
> so strongly about it to demand such a change.)

No, I haven't considered this yet. But I agree that moving this code to
a separate function certainly will keep process_trailers() much more
readable. Also it would simplify future reusability if anyone else would
need similar functionality.

> >         /* Print the lines before the trailers */
> >         trailer_end = process_input_file(outfile, lines, &in_tok_first, &in_tok_last);
> >
> > @@ -872,5 +900,10 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
> >         /* Print the lines after the trailers as is */
> >         print_lines(outfile, lines, trailer_end, INT_MAX);
> >
> > +       if (in_place) {
> > +               if (rename_tempfile(&trailers_tempfile, file))
> > +                       die_errno(_("could not rename temporary file to %s"), file);
> > +       }
> 
> You could drop the unnecessary braces.

Ok, I'll drop the braces for v4.

Thanks a lot for your review!

```

## Tobias Klauser, 2016-01-14 09:33

Subject: Re: [PATCH v3 1/2] trailer: use fprintf instead of printf
Message-ID: <20160114093345.GG26950@distanz.ch>
URL: https://gitlist.dev/e/20160114093345.GG26950%40distanz.ch
In-Reply-To: <xmqqd1t5nv6j.fsf@gitster.mtv.corp.google.com>

```
On 2016-01-13 at 20:20:04 +0100, Junio C Hamano <gitster@pobox.com> wrote:
> Tobias Klauser <tklauser@distanz.ch> writes:
> 
> > Use fprintf instead of printf in trailer.c in order to allow printing
> > to a file other than stdout. This will be needed to support in-place
> > editing in git interpret-trailers.
> >
> > Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
> 
> Thanks.  I won't bother to amend it myself or request you to reroll
> only for this, but that is a rather suboptimal title.

Agree.

> The distinction between fprintf/printf is an implementation detail;
> what you want to do in this change is to allow writing to a file
> other than the standard output, and that should be in the title.

Since I'll do a v4 anyhow to address Eric's review comments, I can
change the title in the reroll.

Thanks

```
