ref-filter: --format=%(raw) support --perl

Because the perl language can handle binary data correctly, add the function perl_quote_buf_with_len(), which can specify the length of the data and prevent the data from being truncated at '\0' to help `--format="%(raw)"` support `--perl`. Reviewed-by: Jacob Keller <jacob.keller@gmail.com> Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: ZheNing Hu <adlternative@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

ZheNing Hu committed Jul 26, 2021 at 03:26 UTC 7121c4d4e2877115fb372b3f147fad4cd1306751
5 files changed +48 -8
Documentation/git-for-each-ref.txt
+2 -2
@@ -241,8 +241,8 @@ raw:size::
241 The raw data size of the object.
242
243 Note that `--format=%(raw)` can not be used with `--python`, `--shell`, `--tcl`,
244 -`--perl` because such language may not support arbitrary binary data in their
245 -string variable type.
244 +because such language may not support arbitrary binary data in their string
245 +variable type.
246
247 The message in a commit or a tag object is `contents`, from which
248 `contents:<part>` can be used to extract various parts out of:
quote.c
+17
@@ -471,6 +471,23 @@ void perl_quote_buf(struct strbuf *sb, const char *src)
471 strbuf_addch(sb, sq);
472 }
473
474 +void perl_quote_buf_with_len(struct strbuf *sb, const char *src, size_t len)
475 +{
476 + const char sq = '\'';
477 + const char bq = '\\';
478 + const char *c = src;
479 + const char *end = src + len;
480 +
481 + strbuf_addch(sb, sq);
482 + while (c != end) {
483 + if (*c == sq || *c == bq)
484 + strbuf_addch(sb, bq);
485 + strbuf_addch(sb, *c);
486 + c++;
487 + }
488 + strbuf_addch(sb, sq);
489 +}
490 +
491 void python_quote_buf(struct strbuf *sb, const char *src)
492 {
493 const char sq = '\'';
quote.h
+1
@@ -94,6 +94,7 @@ char *quote_path(const char *in, const char *prefix, struct strbuf *out, unsigne
94
95 /* quoting as a string literal for other languages */
96 void perl_quote_buf(struct strbuf *sb, const char *src);
97 +void perl_quote_buf_with_len(struct strbuf *sb, const char *src, size_t len);
98 void python_quote_buf(struct strbuf *sb, const char *src);
99 void tcl_quote_buf(struct strbuf *sb, const char *src);
100 void basic_regex_quote_buf(struct strbuf *sb, const char *src);
ref-filter.c
+11 -4
@@ -746,7 +746,10 @@ static void quote_formatting(struct strbuf *s, const char *str, ssize_t len, int
746 sq_quote_buf(s, str);
747 break;
748 case QUOTE_PERL:
749 - perl_quote_buf(s, str);
749 + if (len < 0)
750 + perl_quote_buf(s, str);
751 + else
752 + perl_quote_buf_with_len(s, str, len);
753 break;
754 case QUOTE_PYTHON:
755 python_quote_buf(s, str);
@@ -1009,10 +1012,14 @@ int verify_ref_format(struct ref_format *format)
1012 at = parse_ref_filter_atom(format, sp + 2, ep, &err);
1013 if (at < 0)
1014 die("%s", err.buf);
1012 - if (format->quote_style && used_atom[at].atom_type == ATOM_RAW &&
1013 - used_atom[at].u.raw_data.option == RAW_BARE)
1015 +
1016 + if ((format->quote_style == QUOTE_PYTHON ||
1017 + format->quote_style == QUOTE_SHELL ||
1018 + format->quote_style == QUOTE_TCL) &&
1019 + used_atom[at].atom_type == ATOM_RAW &&
1020 + used_atom[at].u.raw_data.option == RAW_BARE)
1021 die(_("--format=%.*s cannot be used with"
1015 - "--python, --shell, --tcl, --perl"), (int)(ep - sp - 2), sp + 2);
1022 + "--python, --shell, --tcl"), (int)(ep - sp - 2), sp + 2);
1023 cp = ep + 1;
1024
1025 if (skip_prefix(used_atom[at].name, "color:", &color))
t/t6300-for-each-ref.sh
+17 -2
@@ -915,8 +915,23 @@ test_expect_success '%(raw) with --tcl must fail' '
915 test_must_fail git for-each-ref --format="%(raw)" --tcl
916 '
917
918 -test_expect_success '%(raw) with --perl must fail' '
919 - test_must_fail git for-each-ref --format="%(raw)" --perl
918 +test_expect_success '%(raw) with --perl' '
919 + git for-each-ref --format="\$name= %(raw);
920 +print \"\$name\"" refs/myblobs/blob1 --perl | perl >actual &&
921 + cmp blob1 actual &&
922 + git for-each-ref --format="\$name= %(raw);
923 +print \"\$name\"" refs/myblobs/blob3 --perl | perl >actual &&
924 + cmp blob3 actual &&
925 + git for-each-ref --format="\$name= %(raw);
926 +print \"\$name\"" refs/myblobs/blob8 --perl | perl >actual &&
927 + cmp blob8 actual &&
928 + git for-each-ref --format="\$name= %(raw);
929 +print \"\$name\"" refs/myblobs/first --perl | perl >actual &&
930 + cmp one actual &&
931 + git cat-file tree refs/mytrees/first > expected &&
932 + git for-each-ref --format="\$name= %(raw);
933 +print \"\$name\"" refs/mytrees/first --perl | perl >actual &&
934 + cmp expected actual
935 '
936
937 test_expect_success '%(raw) with --shell must fail' '