From db64eb655b48ea2c635480c6cc992b0156817aeb Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Mon, 18 Nov 2013 23:09:13 +0530 Subject: [PATCH] for-each-ref: avoid color leakage To make sure that an invocation like the following doesn't leak color, $ git for-each-ref --format='%(subject)%(color:green)' auto-reset at the end of the format string when the last color token seen in the format string isn't a color-reset. Signed-off-by: Ramkumar Ramachandra Signed-off-by: Junio C Hamano --- builtin/for-each-ref.c | 28 +++++++++++++++++++++++----- t/t6300-for-each-ref.sh | 2 +- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index bc655b5042..5ff51d1d32 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -93,6 +93,7 @@ static struct { static const char **used_atom; static cmp_type *used_atom_type; static int used_atom_cnt, sort_atom_limit, need_tagged, need_symref; +static int need_color_reset_at_eol; /* * Used to parse format string and sort specifiers @@ -179,13 +180,21 @@ static const char *find_next(const char *cp) static int verify_format(const char *format) { const char *cp, *sp; + static const char color_reset[] = "color:reset"; + + need_color_reset_at_eol = 0; for (cp = format; *cp && (sp = find_next(cp)); ) { const char *ep = strchr(sp, ')'); + int at; + if (!ep) return error("malformed format string %s", sp); /* sp points at "%(" and ep points at the closing ")" */ - parse_atom(sp + 2, ep); + at = parse_atom(sp + 2, ep); cp = ep + 1; + + if (!memcmp(used_atom[at], "color:", 6)) + need_color_reset_at_eol = !!strcmp(used_atom[at], color_reset); } return 0; } @@ -914,11 +923,9 @@ static void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs qsort(refs, num_refs, sizeof(struct refinfo *), compare_refs); } -static void print_value(struct refinfo *ref, int atom, int quote_style) +static void print_value(struct atom_value *v, int quote_style) { - struct atom_value *v; struct strbuf sb = STRBUF_INIT; - get_value(ref, atom, &v); switch (quote_style) { case QUOTE_NONE: fputs(v->s, stdout); @@ -985,15 +992,26 @@ static void show_ref(struct refinfo *info, const char *format, int quote_style) const char *cp, *sp, *ep; for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) { + struct atom_value *atomv; + ep = strchr(sp, ')'); if (cp < sp) emit(cp, sp); - print_value(info, parse_atom(sp + 2, ep), quote_style); + get_value(info, parse_atom(sp + 2, ep), &atomv); + print_value(atomv, quote_style); } if (*cp) { sp = cp + strlen(cp); emit(cp, sp); } + if (need_color_reset_at_eol) { + struct atom_value resetv; + char color[COLOR_MAXLEN] = ""; + + color_parse("reset", "--format", color); + resetv.s = color; + print_value(&resetv, quote_style); + } putchar('\n'); } diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index 69e3155a62..46866bab01 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -356,7 +356,7 @@ $(git rev-parse --short refs/tags/two) $(get_color green)two$(get_color reset) EOF test_expect_success 'Check %(color:...) ' ' - git for-each-ref --format="%(objectname:short) %(color:green)%(refname:short)%(color:reset)" >actual && + git for-each-ref --format="%(objectname:short) %(color:green)%(refname:short)" >actual && test_cmp expected actual '