Re: [PATCH 2/3] archive: specfile support (--pretty=format: in archive files)

11 messages, 3 authors, 2016-06-15 · open the first message on its own page

Re: [PATCH 2/3] archive: specfile support (--pretty=format: in archive files)

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:43:33

René Scharfe [off-list ref] writes:
quoted
Maybe we should not so much name it by purpose, but by function.  How 
about "substformat" for the attribute name, and replacing any 
$Format:blablub$ inside those files with something a la 
--pretty=format:blablub?
I like the $Format:...$ notation.  How about naming the attribute
"template", as that's what a thus marked file is?
Sounds good, although I suspect "template" might confuse newbies
that checkout may apply the substitution as well.  How about
something with "export" in it?  export-subst, perhaps?

[PATCH 4/3] archive: specfile syntax change: "$Format:%PLCHLDR$" instead of just "%PLCHLDR"

From: René Scharfe <hidden>
Date: 2016-06-15 22:43:33

As suggested by Johannes, --pretty=format: placeholders in specfiles
need to be wrapped in $Format:...$ now.  This syntax change restricts
the expansion of placeholders and makes it easier to use with files
that contain non-placeholder percent signs.

Signed-off-by: Rene Scharfe <redacted>
---
 Documentation/gitattributes.txt |    5 +++-
 builtin-archive.c               |   52 +++++++++++++++++++++++++++++++++++---
 t/t5000-tar-tree.sh             |    4 +-
 3 files changed, 53 insertions(+), 8 deletions(-)
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 47a621b..37b3be8 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -432,7 +432,10 @@ several placeholders when adding this file to an archive.  The
 expansion depends on the availability of a commit ID, i.e. if
 gitlink:git-archive[1] has been given a tree instead of a commit or a
 tag then no replacement will be done.  The placeholders are the same
-as those for the option `--pretty=format:` of gitlink:git-log[1].
+as those for the option `--pretty=format:` of gitlink:git-log[1],
+except that they need to be wrapped like this: `$Format:PLACEHOLDERS$`
+in the file.  E.g. the string `$Format:%H$` will be replaced by the
+commit hash.
 
 
 GIT
diff --git a/builtin-archive.c b/builtin-archive.c
index faccce3..a8a0f01 100644
--- a/builtin-archive.c
+++ b/builtin-archive.c
@@ -81,14 +81,58 @@ static int run_remote_archiver(const char *remote, int argc,
 	return !!rv;
 }
 
+static void *format_specfile(const struct commit *commit, const char *format,
+                             unsigned long *sizep)
+{
+	unsigned long len = *sizep, result_len = 0;
+	const char *a = format;
+	char *result = NULL;
+
+	for (;;) {
+		const char *b, *c;
+		char *fmt, *formatted = NULL;
+		unsigned long a_len, fmt_len, formatted_len, allocated = 0;
+
+		b = memchr(a, '$', len);
+		if (!b || a + len < b + 9 || memcmp(b + 1, "Format:", 7))
+			break;
+		c = memchr(b + 8, '$', len - 8);
+		if (!c)
+			break;
+
+		a_len = b - a;
+		fmt_len = c - b - 8;
+		fmt = xmalloc(fmt_len + 1);
+		memcpy(fmt, b + 8, fmt_len);
+		fmt[fmt_len] = '\0';
+
+		formatted_len = format_commit_message(commit, fmt, &formatted,
+		                                      &allocated);
+		result = xrealloc(result, result_len + a_len + formatted_len);
+		memcpy(result + result_len, a, a_len);
+		memcpy(result + result_len + a_len, formatted, formatted_len);
+		result_len += a_len + formatted_len;
+		len -= c + 1 - a;
+		a = c + 1;
+	}
+
+	if (result && len) {
+		result = xrealloc(result, result_len + len);
+		memcpy(result + result_len, a, len);
+		result_len += len;
+	}
+
+	*sizep = result_len;
+
+	return result;
+}
+
 static void *convert_to_archive(const char *path,
                                 const void *src, unsigned long *sizep,
                                 const struct commit *commit)
 {
 	static struct git_attr *attr_specfile;
 	struct git_attr_check check[1];
-	char *interpolated = NULL;
-	unsigned long allocated = 0;
 
 	if (!commit)
 		return NULL;
@@ -102,9 +146,7 @@ static void *convert_to_archive(const char *path,
 	if (!ATTR_TRUE(check[0].value))
 		return NULL;
 
-	*sizep = format_commit_message(commit, src, &interpolated, &allocated);
-
-	return interpolated;
+	return format_specfile(commit, src, sizep);
 }
 
 void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 3d5d01b..6e89e07 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -36,7 +36,7 @@ test_expect_success \
      echo simple textfile >a/a &&
      mkdir a/bin &&
      cp /bin/sh a/bin &&
-     printf "%s" "$SPECFILEFORMAT" >a/specfile &&
+     printf "A\$Format:%s\$O" "$SPECFILEFORMAT" >a/specfile &&
      ln -s a a/l1 &&
      (p=long_path_to_a_file && cd a &&
       for depth in 1 2 3 4 5; do mkdir $p && cd $p; done &&
@@ -119,7 +119,7 @@ test_expect_success \
 
 test_expect_success \
      'validate specfile contents' \
-     'git log --max-count=1 "--pretty=format:$SPECFILEFORMAT" HEAD \
+     'git log --max-count=1 "--pretty=format:A${SPECFILEFORMAT}O" HEAD \
       >f/a/specfile.expected &&
       diff f/a/specfile.expected f/a/specfile'
 
-- 
1.5.3

[PATCH 5/3] archive: rename attribute specfile to export-subst

From: René Scharfe <hidden>
Date: 2016-06-15 22:43:33

Junio C Hamano schrieb:
René Scharfe [off-list ref] writes:
quoted
quoted
Maybe we should not so much name it by purpose, but by function.  How 
about "substformat" for the attribute name, and replacing any 
$Format:blablub$ inside those files with something a la 
--pretty=format:blablub?
I like the $Format:...$ notation.  How about naming the attribute
"template", as that's what a thus marked file is?
Sounds good, although I suspect "template" might confuse newbies
that checkout may apply the substitution as well.  How about
something with "export" in it?  export-subst, perhaps?
Well, including "export" in the name makes sense, yes.  I can't come up
with a better name, let's take this.
--- snip! ---
As suggested by Junio and Johannes, change the name of the former
attribute specfile to export-subst to indicate its function rather
than purpose and to make clear that it is not applied to working tree
files.

Signed-off-by: Rene Scharfe <redacted>
---

 Documentation/gitattributes.txt |    6 +++---
 builtin-archive.c               |   14 +++++++-------
 t/t5000-tar-tree.sh             |   18 +++++++++---------
 3 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 37b3be8..d0e951e 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -424,10 +424,10 @@ frotz	unspecified
 Creating an archive
 ~~~~~~~~~~~~~~~~~~~
 
-`specfile`
-^^^^^^^^^^
+`export-subst`
+^^^^^^^^^^^^^^
 
-If the attribute `specfile` is set for a file then git will expand
+If the attribute `export-subst` is set for a file then git will expand
 several placeholders when adding this file to an archive.  The
 expansion depends on the availability of a commit ID, i.e. if
 gitlink:git-archive[1] has been given a tree instead of a commit or a
diff --git a/builtin-archive.c b/builtin-archive.c
index a8a0f01..af14837 100644
--- a/builtin-archive.c
+++ b/builtin-archive.c
@@ -81,8 +81,8 @@ static int run_remote_archiver(const char *remote, int argc,
 	return !!rv;
 }
 
-static void *format_specfile(const struct commit *commit, const char *format,
-                             unsigned long *sizep)
+static void *format_subst(const struct commit *commit, const char *format,
+                          unsigned long *sizep)
 {
 	unsigned long len = *sizep, result_len = 0;
 	const char *a = format;
@@ -131,22 +131,22 @@ static void *convert_to_archive(const char *path,
                                 const void *src, unsigned long *sizep,
                                 const struct commit *commit)
 {
-	static struct git_attr *attr_specfile;
+	static struct git_attr *attr_export_subst;
 	struct git_attr_check check[1];
 
 	if (!commit)
 		return NULL;
 
-        if (!attr_specfile)
-                attr_specfile = git_attr("specfile", 8);
+        if (!attr_export_subst)
+                attr_export_subst = git_attr("export-subst", 12);
 
-	check[0].attr = attr_specfile;
+	check[0].attr = attr_export_subst;
 	if (git_checkattr(path, ARRAY_SIZE(check), check))
 		return NULL;
 	if (!ATTR_TRUE(check[0].value))
 		return NULL;
 
-	return format_specfile(commit, src, sizep);
+	return format_subst(commit, src, sizep);
 }
 
 void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 6e89e07..42e28ab 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -28,7 +28,7 @@ commit id embedding:
 TAR=${TAR:-tar}
 UNZIP=${UNZIP:-unzip}
 
-SPECFILEFORMAT=%H%n
+SUBSTFORMAT=%H%n
 
 test_expect_success \
     'populate workdir' \
@@ -36,7 +36,7 @@ test_expect_success \
      echo simple textfile >a/a &&
      mkdir a/bin &&
      cp /bin/sh a/bin &&
-     printf "A\$Format:%s\$O" "$SPECFILEFORMAT" >a/specfile &&
+     printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile &&
      ln -s a a/l1 &&
      (p=long_path_to_a_file && cd a &&
       for depth in 1 2 3 4 5; do mkdir $p && cd $p; done &&
@@ -108,20 +108,20 @@ test_expect_success \
     'diff -r a c/prefix/a'
 
 test_expect_success \
-    'create an archive with a specfile' \
-    'echo specfile specfile >a/.gitattributes &&
+    'create an archive with a substfile' \
+    'echo substfile export-subst >a/.gitattributes &&
      git archive HEAD >f.tar &&
      rm a/.gitattributes'
 
 test_expect_success \
-    'extract specfile' \
+    'extract substfile' \
     '(mkdir f && cd f && $TAR xf -) <f.tar'
 
 test_expect_success \
-     'validate specfile contents' \
-     'git log --max-count=1 "--pretty=format:A${SPECFILEFORMAT}O" HEAD \
-      >f/a/specfile.expected &&
-      diff f/a/specfile.expected f/a/specfile'
+     'validate substfile contents' \
+     'git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \
+      >f/a/substfile.expected &&
+      diff f/a/substfile.expected f/a/substfile'
 
 test_expect_success \
     'git archive --format=zip' \

Re: [PATCH 4/3] archive: specfile syntax change: "$Format:%PLCHLDR$" instead of just "%PLCHLDR"

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:43:33

Hi,

On Thu, 6 Sep 2007, René Scharfe wrote:
As suggested by Johannes, --pretty=format: placeholders in specfiles 
need to be wrapped in $Format:...$ now.
Thanks.
quoted hunk
diff --git a/builtin-archive.c b/builtin-archive.c
index faccce3..a8a0f01 100644
--- a/builtin-archive.c
+++ b/builtin-archive.c
@@ -81,14 +81,58 @@ static int run_remote_archiver(const char *remote, int argc,
 	return !!rv;
 }
 
+static void *format_specfile(const struct commit *commit, const char *format,
+                             unsigned long *sizep)
Should this not be "char *buffer" instead of "const char *format"?  Or 
even better: a "struct strbuf *"?
+{
+	unsigned long len = *sizep, result_len = 0;
+	const char *a = format;
+	char *result = NULL;
+
+	for (;;) {
+		const char *b, *c;
+		char *fmt, *formatted = NULL;
+		unsigned long a_len, fmt_len, formatted_len, allocated = 0;
Maybe initialise formatted_len, just to be on the safe side?
+
+		b = memchr(a, '$', len);
+		if (!b || a + len < b + 9 || memcmp(b + 1, "Format:", 7))
+			break;
Wouldn't memmem(buffer, len, "$Format:", 8) be better here?

A general comment: since you plan to output the result into a file anyway, 
it should be even easier to avoid realloc(), and do a 
print_formatted_specfile() instead of a format_specfile(), no?

Ciao,
Dscho

Re: [PATCH 5/3] archive: rename attribute specfile to export-subst

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:43:33

Hi,

On Thu, 6 Sep 2007, René Scharfe wrote:
As suggested by Junio and Johannes, change the name of the former
attribute specfile to export-subst to indicate its function rather
than purpose and to make clear that it is not applied to working tree
files.

Signed-off-by: Rene Scharfe <redacted>
ACK!

(Even if I did not really suggest "export-subst", which I like very 
much...)

The bigger question is now if these two patches should be folded back into 
your original patch series, or stand alone as commits of their own...

Ciao,
Dscho

Re: [PATCH 4/3] archive: specfile syntax change: "$Format:%PLCHLDR$" instead of just "%PLCHLDR"

From: René Scharfe <hidden>
Date: 2016-06-15 22:43:34

Johannes Schindelin schrieb:
quoted
+static void *format_specfile(const struct commit *commit, const char *format,
+                             unsigned long *sizep)
Should this not be "char *buffer" instead of "const char *format"?  Or 
even better: a "struct strbuf *"?
const is correct, because the data in the buffer shouldn't be (and
isn't) modified.

"buffer" is a generic term; "format" on the other hand indicates the
meaning of the data within the buffer.

Input and output might indeed be passed along as struct strbuf, even
more so since the new API encourages its use as generic buffer (format
can contain NULs).
quoted
+{
+	unsigned long len = *sizep, result_len = 0;
+	const char *a = format;
+	char *result = NULL;
+
+	for (;;) {
+		const char *b, *c;
+		char *fmt, *formatted = NULL;
+		unsigned long a_len, fmt_len, formatted_len, allocated = 0;
Maybe initialise formatted_len, just to be on the safe side?
I wish I could use C99 syntax and move its declaration down to its first
use, then it would be obvious that formatted_len is never used without
initialization.
quoted
+
+		b = memchr(a, '$', len);
+		if (!b || a + len < b + 9 || memcmp(b + 1, "Format:", 7))
+			break;
Wouldn't memmem(buffer, len, "$Format:", 8) be better here?
Oh, that's a nice GNU extension, didn't know it before.  We might import
it to compat etc., but I think that's better left for a follow-up patch.
A general comment: since you plan to output the result into a file anyway, 
it should be even easier to avoid realloc(), and do a 
print_formatted_specfile() instead of a format_specfile(), no?
Hmm, not sure what you mean.  At least archive-tar needs the expanded
contents in a buffer (not immediately written to stdout) because it
tries to mimic a real tar and always writes in blocks of 10k and
therefore needs to buffer the output.

Thanks!
René

Re: [PATCH 5/3] archive: rename attribute specfile to export-subst

From: René Scharfe <hidden>
Date: 2016-06-15 22:43:34

Johannes Schindelin schrieb:
The bigger question is now if these two patches should be folded back
into your original patch series, or stand alone as commits of their
own...
Yes, indeed.  I submitted them as add-on patches because I noticed the
first three are already in next, but I sure can make a fresh three-part
series based on master.  Junio?

Thanks,
René

Re: [PATCH 4/3] archive: specfile syntax change: "$Format:%PLCHLDR$" instead of just "%PLCHLDR"

From: René Scharfe <hidden>
Date: 2016-06-15 22:43:34

René Scharfe schrieb:
Johannes Schindelin schrieb:
quoted
quoted
+
+		b = memchr(a, '$', len);
+		if (!b || a + len < b + 9 || memcmp(b + 1, "Format:", 7))
+			break;
Wouldn't memmem(buffer, len, "$Format:", 8) be better here?
Oh, that's a nice GNU extension, didn't know it before.  We might import
it to compat etc., but I think that's better left for a follow-up patch.
Just noticed: if the memcmp() above finds a difference, the code should
*not* break out of the loop.  Ahem.  Perhaps I should first add memmem()
after all...

René

[PATCH 3.5/3] add memmem()

From: René Scharfe <hidden>
Date: 2016-06-15 22:43:34

memmem() is a nice GNU extension for searching a length limited string
in another one.

This compat version is based on the version found in glibc 2.2 (GPL 2);
I only removed the optimization of checking the first char by hand, and
generally tried to keep the code simple.  We can add it back if memcmp
shows up high in a profile, but for now I prefer to keep it (almost
trivially) simple.

Since I don't really know which platforms beside those with a glibc
have their own memmem(), I used a heuristic: if NO_STRCASESTR is set,
then NO_MEMMEM is set, too.

Signed-off-by: Rene Scharfe <redacted>
---
 Makefile          |   11 +++++++++++
 compat/memmem.c   |   29 +++++++++++++++++++++++++++++
 git-compat-util.h |    6 ++++++
 3 files changed, 46 insertions(+), 0 deletions(-)
 create mode 100644 compat/memmem.c
diff --git a/Makefile b/Makefile
index 51af531..bae073f 100644
--- a/Makefile
+++ b/Makefile
@@ -28,6 +28,8 @@ all::
 #
 # Define NO_STRCASESTR if you don't have strcasestr.
 #
+# Define NO_MEMMEM if you don't have memmem.
+#
 # Define NO_STRLCPY if you don't have strlcpy.
 #
 # Define NO_STRTOUMAX if you don't have strtoumax in the C library.
@@ -402,6 +404,7 @@ ifeq ($(uname_S),SunOS)
 	NEEDS_NSL = YesPlease
 	SHELL_PATH = /bin/bash
 	NO_STRCASESTR = YesPlease
+	NO_MEMMEM = YesPlease
 	NO_HSTRERROR = YesPlease
 	ifeq ($(uname_R),5.8)
 		NEEDS_LIBICONV = YesPlease
@@ -424,6 +427,7 @@ ifeq ($(uname_O),Cygwin)
 	NO_D_TYPE_IN_DIRENT = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease
 	NO_STRCASESTR = YesPlease
+	NO_MEMMEM = YesPlease
 	NO_SYMLINK_HEAD = YesPlease
 	NEEDS_LIBICONV = YesPlease
 	NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
@@ -442,6 +446,7 @@ ifeq ($(uname_S),FreeBSD)
 endif
 ifeq ($(uname_S),OpenBSD)
 	NO_STRCASESTR = YesPlease
+	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
 	BASIC_CFLAGS += -I/usr/local/include
 	BASIC_LDFLAGS += -L/usr/local/lib
@@ -456,6 +461,7 @@ ifeq ($(uname_S),NetBSD)
 endif
 ifeq ($(uname_S),AIX)
 	NO_STRCASESTR=YesPlease
+	NO_MEMMEM = YesPlease
 	NO_STRLCPY = YesPlease
 	NEEDS_LIBICONV=YesPlease
 endif
@@ -467,6 +473,7 @@ ifeq ($(uname_S),IRIX64)
 	NO_IPV6=YesPlease
 	NO_SETENV=YesPlease
 	NO_STRCASESTR=YesPlease
+	NO_MEMMEM = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_SOCKADDR_STORAGE=YesPlease
 	SHELL_PATH=/usr/gnu/bin/bash
@@ -661,6 +668,10 @@ ifdef NO_HSTRERROR
 	COMPAT_CFLAGS += -DNO_HSTRERROR
 	COMPAT_OBJS += compat/hstrerror.o
 endif
+ifdef NO_MEMMEM
+	COMPAT_CFLAGS += -DNO_MEMMEM
+	COMPAT_OBJS += compat/memmem.o
+endif
 
 ifeq ($(TCLTK_PATH),)
 NO_TCLTK=NoThanks
diff --git a/compat/memmem.c b/compat/memmem.c
new file mode 100644
index 0000000..cd0d877
--- /dev/null
+++ b/compat/memmem.c
@@ -0,0 +1,29 @@
+#include "../git-compat-util.h"
+
+void *gitmemmem(const void *haystack, size_t haystack_len,
+                const void *needle, size_t needle_len)
+{
+	const char *begin = haystack;
+	const char *last_possible = begin + haystack_len - needle_len;
+
+	/*
+	 * The first occurrence of the empty string is deemed to occur at
+	 * the beginning of the string.
+	 */
+	if (needle_len == 0)
+		return (void *)begin;
+
+	/*
+	 * Sanity check, otherwise the loop might search through the whole
+	 * memory.
+	 */
+	if (haystack_len < needle_len)
+		return NULL;
+
+	for (; begin <= last_possible; begin++) {
+		if (!memcmp(begin, needle, needle_len))
+			return (void *)begin;
+	}
+
+	return NULL;
+}
diff --git a/git-compat-util.h b/git-compat-util.h
index ca0a597..1bfbdeb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -172,6 +172,12 @@ extern uintmax_t gitstrtoumax(const char *, char **, int);
 extern const char *githstrerror(int herror);
 #endif
 
+#ifdef NO_MEMMEM
+#define memmem gitmemmem
+void *gitmemmem(const void *haystack, size_t haystacklen,
+                const void *needle, size_t needlelen);
+#endif
+
 extern void release_pack_memory(size_t, int);
 
 static inline char* xstrdup(const char *str)
-- 
1.5.3

[PATCH 4/3] archive: specfile syntax change: "$Format:%PLCHLDR$" instead of just "%PLCHLDR" (take 2)

From: René Scharfe <hidden>
Date: 2016-06-15 22:43:34

As suggested by Johannes, --pretty=format: placeholders in specfiles
need to be wrapped in $Format:...$ now.  This syntax change restricts
the expansion of placeholders and makes it easier to use with files
that contain non-placeholder percent signs.

Signed-off-by: Rene Scharfe <redacted>
---
This replacement patch fixes a bug in the "$Format:" search logic.  It
now uses memmem() and thus depends on patch 3.5 which introduces this
function.  Patch 5 still applies unchanged.

 Documentation/gitattributes.txt |    5 +++-
 builtin-archive.c               |   52 +++++++++++++++++++++++++++++++++++---
 t/t5000-tar-tree.sh             |    4 +-
 3 files changed, 53 insertions(+), 8 deletions(-)
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 47a621b..37b3be8 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -432,7 +432,10 @@ several placeholders when adding this file to an archive.  The
 expansion depends on the availability of a commit ID, i.e. if
 gitlink:git-archive[1] has been given a tree instead of a commit or a
 tag then no replacement will be done.  The placeholders are the same
-as those for the option `--pretty=format:` of gitlink:git-log[1].
+as those for the option `--pretty=format:` of gitlink:git-log[1],
+except that they need to be wrapped like this: `$Format:PLACEHOLDERS$`
+in the file.  E.g. the string `$Format:%H$` will be replaced by the
+commit hash.
 
 
 GIT
diff --git a/builtin-archive.c b/builtin-archive.c
index faccce3..65bf9cb 100644
--- a/builtin-archive.c
+++ b/builtin-archive.c
@@ -81,14 +81,58 @@ static int run_remote_archiver(const char *remote, int argc,
 	return !!rv;
 }
 
+static void *format_specfile(const struct commit *commit, const char *format,
+                             unsigned long *sizep)
+{
+	unsigned long len = *sizep, result_len = 0;
+	const char *a = format;
+	char *result = NULL;
+
+	for (;;) {
+		const char *b, *c;
+		char *fmt, *formatted = NULL;
+		unsigned long a_len, fmt_len, formatted_len, allocated = 0;
+
+		b = memmem(a, len, "$Format:", 8);
+		if (!b || a + len < b + 9)
+			break;
+		c = memchr(b + 8, '$', len - 8);
+		if (!c)
+			break;
+
+		a_len = b - a;
+		fmt_len = c - b - 8;
+		fmt = xmalloc(fmt_len + 1);
+		memcpy(fmt, b + 8, fmt_len);
+		fmt[fmt_len] = '\0';
+
+		formatted_len = format_commit_message(commit, fmt, &formatted,
+		                                      &allocated);
+		result = xrealloc(result, result_len + a_len + formatted_len);
+		memcpy(result + result_len, a, a_len);
+		memcpy(result + result_len + a_len, formatted, formatted_len);
+		result_len += a_len + formatted_len;
+		len -= c + 1 - a;
+		a = c + 1;
+	}
+
+	if (result && len) {
+		result = xrealloc(result, result_len + len);
+		memcpy(result + result_len, a, len);
+		result_len += len;
+	}
+
+	*sizep = result_len;
+
+	return result;
+}
+
 static void *convert_to_archive(const char *path,
                                 const void *src, unsigned long *sizep,
                                 const struct commit *commit)
 {
 	static struct git_attr *attr_specfile;
 	struct git_attr_check check[1];
-	char *interpolated = NULL;
-	unsigned long allocated = 0;
 
 	if (!commit)
 		return NULL;
@@ -102,9 +146,7 @@ static void *convert_to_archive(const char *path,
 	if (!ATTR_TRUE(check[0].value))
 		return NULL;
 
-	*sizep = format_commit_message(commit, src, &interpolated, &allocated);
-
-	return interpolated;
+	return format_specfile(commit, src, sizep);
 }
 
 void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 3d5d01b..6e89e07 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -36,7 +36,7 @@ test_expect_success \
      echo simple textfile >a/a &&
      mkdir a/bin &&
      cp /bin/sh a/bin &&
-     printf "%s" "$SPECFILEFORMAT" >a/specfile &&
+     printf "A\$Format:%s\$O" "$SPECFILEFORMAT" >a/specfile &&
      ln -s a a/l1 &&
      (p=long_path_to_a_file && cd a &&
       for depth in 1 2 3 4 5; do mkdir $p && cd $p; done &&
@@ -119,7 +119,7 @@ test_expect_success \
 
 test_expect_success \
      'validate specfile contents' \
-     'git log --max-count=1 "--pretty=format:$SPECFILEFORMAT" HEAD \
+     'git log --max-count=1 "--pretty=format:A${SPECFILEFORMAT}O" HEAD \
       >f/a/specfile.expected &&
       diff f/a/specfile.expected f/a/specfile'
 
-- 
1.5.3

Re: [PATCH 4/3] archive: specfile syntax change: "$Format:%PLCHLDR$" instead of just "%PLCHLDR"

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:43:34

Hi,

On Thu, 6 Sep 2007, René Scharfe wrote:
Johannes Schindelin schrieb:
quoted
quoted
+
+		b = memchr(a, '$', len);
+		if (!b || a + len < b + 9 || memcmp(b + 1, "Format:", 7))
+			break;
Wouldn't memmem(buffer, len, "$Format:", 8) be better here?
Oh, that's a nice GNU extension, didn't know it before.
Oh sorry, I didn't even realise that this is a GNU extension...
quoted
A general comment: since you plan to output the result into a file 
anyway, it should be even easier to avoid realloc(), and do a 
print_formatted_specfile() instead of a format_specfile(), no?
Hmm, not sure what you mean.  At least archive-tar needs the expanded 
contents in a buffer (not immediately written to stdout) because it 
tries to mimic a real tar and always writes in blocks of 10k and 
therefore needs to buffer the output.
Yeah, I missed that.  Thanks for explaining it to me!

Ciao,
Dscho
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help