{"thread":{"id":"8537","subject":"[PATCH] git-svn: use git-log rather than rev-list | xargs cat-file","startedAt":"2007-06-10T09:00:45Z","lastAt":"2007-06-12T06:17:53Z","messageCount":5,"participants":["Sam Vilain","Eric Wong","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"44567","messageId":"20070610091259.48F8D13A4F8@magnus.utsl.gen.nz","threadId":"8537","inReplyTo":null,"subject":"[PATCH] git-svn: use git-log rather than rev-list | xargs cat-file","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2007-06-10T09:00:45Z","receivedAt":"2007-06-10T09:00:45Z","isPatch":true,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"This saves a bit of time when rebuilding the git-svn index.\n\nSigned-off-by: Sam Vilain <sam@vilain.net>\n---\n git-svn.perl |   30 +++++++++++++++++++-----------\n 1 files changed, 19 insertions(+), 11 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex e350061..610563c 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -802,10 +802,15 @@ sub cmt_metadata {\n \n sub working_head_info {\n \tmy ($head, $refs) = @_;\n-\tmy ($fh, $ctx) = command_output_pipe('rev-list', $head);\n-\twhile (my $hash = <$fh>) {\n-\t\tchomp($hash);\n-\t\tmy ($url, $rev, $uuid) = cmt_metadata($hash);\n+\tmy ($fh, $ctx) = command_output_pipe('log', $head);\n+\tmy $hash;\n+\twhile (<$fh>) {\n+\t\tif ( m{^commit ($::sha1)$} ) {\n+\t\t\t$hash = $1;\n+\t\t\tnext;\n+\t\t}\n+\t\tnext unless s{^\\s+(git-svn-id:)}{$1};\n+\t\tmy ($url, $rev, $uuid) = extract_metadata($_);\n \t\tif (defined $url && defined $rev) {\n \t\t\tif (my $gs = Git::SVN->find_by_url($url)) {\n \t\t\t\tmy $c = $gs->rev_db_get($rev);\n@@ -1964,16 +1969,19 @@ sub rebuild {\n \t\treturn;\n \t}\n \tprint \"Rebuilding $db_path ...\\n\";\n-\tmy ($rev_list, $ctx) = command_output_pipe(\"rev-list\", $self->refname);\n+\tmy ($log, $ctx) = command_output_pipe(\"log\", $self->refname);\n \tmy $latest;\n \tmy $full_url = $self->full_url;\n \tremove_username($full_url);\n \tmy $svn_uuid;\n-\twhile (<$rev_list>) {\n-\t\tchomp;\n-\t\tmy $c = $_;\n-\t\tdie \"Non-SHA1: $c\\n\" unless $c =~ /^$::sha1$/o;\n-\t\tmy ($url, $rev, $uuid) = ::cmt_metadata($c);\n+\tmy $c;\n+\twhile (<$log>) {\n+\t\tif ( m{^commit ($::sha1)$} ) {\n+\t\t\t$c = $1;\n+\t\t\tnext;\n+\t\t}\n+\t\tnext unless s{^\\s*(git-svn-id:)}{$1};\n+\t\tmy ($url, $rev, $uuid) = ::extract_metadata($_);\n \t\tremove_username($url);\n \n \t\t# ignore merges (from set-tree)\n@@ -1991,7 +1999,7 @@ sub rebuild {\n \t\t$self->rev_db_set($rev, $c);\n \t\tprint \"r$rev = $c\\n\";\n \t}\n-\tcommand_close_pipe($rev_list, $ctx);\n+\tcommand_close_pipe($log, $ctx);\n \tprint \"Done rebuilding $db_path\\n\";\n }\n \n-- \n1.5.0.4.210.gf8a7c-dirty\n"},{"id":"44641","messageId":"20070610212459.GA12222@muzzle","threadId":"8537","inReplyTo":"20070610091259.48F8D13A4F8@magnus.utsl.gen.nz","subject":"Re: [PATCH] git-svn: use git-log rather than rev-list | xargs cat-file","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2007-06-10T21:24:59Z","receivedAt":"2007-06-10T21:24:59Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Sam Vilain <sam@vilain.net> wrote:\n> This saves a bit of time when rebuilding the git-svn index.\n\nDoes git-log still have the 16k buffer limit?  If so then we can't use\nit because commit messages over 16k will be truncated and the git-svn-id\nline will not show up.  Also, if that limit is removed I'd prefer to\njust add --pretty=raw to rev-list because git-log is stil porcelain and\nmore likely to change.\n\n> Signed-off-by: Sam Vilain <sam@vilain.net>\n> ---\n>  git-svn.perl |   30 +++++++++++++++++++-----------\n>  1 files changed, 19 insertions(+), 11 deletions(-)\n> \n> diff --git a/git-svn.perl b/git-svn.perl\n> index e350061..610563c 100755\n> --- a/git-svn.perl\n> +++ b/git-svn.perl\n> @@ -802,10 +802,15 @@ sub cmt_metadata {\n>  \n>  sub working_head_info {\n>  \tmy ($head, $refs) = @_;\n> -\tmy ($fh, $ctx) = command_output_pipe('rev-list', $head);\n> -\twhile (my $hash = <$fh>) {\n> -\t\tchomp($hash);\n> -\t\tmy ($url, $rev, $uuid) = cmt_metadata($hash);\n> +\tmy ($fh, $ctx) = command_output_pipe('log', $head);\n> +\tmy $hash;\n> +\twhile (<$fh>) {\n> +\t\tif ( m{^commit ($::sha1)$} ) {\n> +\t\t\t$hash = $1;\n> +\t\t\tnext;\n> +\t\t}\n> +\t\tnext unless s{^\\s+(git-svn-id:)}{$1};\n> +\t\tmy ($url, $rev, $uuid) = extract_metadata($_);\n>  \t\tif (defined $url && defined $rev) {\n>  \t\t\tif (my $gs = Git::SVN->find_by_url($url)) {\n>  \t\t\t\tmy $c = $gs->rev_db_get($rev);\n> @@ -1964,16 +1969,19 @@ sub rebuild {\n>  \t\treturn;\n>  \t}\n>  \tprint \"Rebuilding $db_path ...\\n\";\n> -\tmy ($rev_list, $ctx) = command_output_pipe(\"rev-list\", $self->refname);\n> +\tmy ($log, $ctx) = command_output_pipe(\"log\", $self->refname);\n>  \tmy $latest;\n>  \tmy $full_url = $self->full_url;\n>  \tremove_username($full_url);\n>  \tmy $svn_uuid;\n> -\twhile (<$rev_list>) {\n> -\t\tchomp;\n> -\t\tmy $c = $_;\n> -\t\tdie \"Non-SHA1: $c\\n\" unless $c =~ /^$::sha1$/o;\n> -\t\tmy ($url, $rev, $uuid) = ::cmt_metadata($c);\n> +\tmy $c;\n> +\twhile (<$log>) {\n> +\t\tif ( m{^commit ($::sha1)$} ) {\n> +\t\t\t$c = $1;\n> +\t\t\tnext;\n> +\t\t}\n> +\t\tnext unless s{^\\s*(git-svn-id:)}{$1};\n> +\t\tmy ($url, $rev, $uuid) = ::extract_metadata($_);\n>  \t\tremove_username($url);\n>  \n>  \t\t# ignore merges (from set-tree)\n> @@ -1991,7 +1999,7 @@ sub rebuild {\n>  \t\t$self->rev_db_set($rev, $c);\n>  \t\tprint \"r$rev = $c\\n\";\n>  \t}\n> -\tcommand_close_pipe($rev_list, $ctx);\n> +\tcommand_close_pipe($log, $ctx);\n>  \tprint \"Done rebuilding $db_path\\n\";\n>  }\n>  \n> -- \n> 1.5.0.4.210.gf8a7c-dirty\n> \n\n-- \nEric Wong\n"},{"id":"44700","messageId":"7vhcpfrlk1.fsf@assigned-by-dhcp.pobox.com","threadId":"8537","inReplyTo":"20070610212459.GA12222@muzzle","subject":"Re: [PATCH] git-svn: use git-log rather than rev-list | xargs cat-file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-11T07:34:54Z","receivedAt":"2007-06-11T07:34:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Wong <normalperson@yhbt.net> writes:\n\n> Sam Vilain <sam@vilain.net> wrote:\n>> This saves a bit of time when rebuilding the git-svn index.\n>\n> Does git-log still have the 16k buffer limit?  If so then we can't use\n> it because commit messages over 16k will be truncated and the git-svn-id\n> line will not show up.  Also, if that limit is removed I'd prefer to\n> just add --pretty=raw to rev-list because git-log is stil porcelain and\n> more likely to change.\n\nHow about this?  It passes the test suite, but other than that\nhasn't seen much test yet.  I tried to be careful, but sanity\nchecking by extra sets of eyeballs would be needed.\n\nIt changes length from int unsigned long in several places, and\nyou would need to look out for a boolean test like this:\n\n\tif (current_length < limit_length - slop)\n        \t... do something ...\n\nas it now should be written like this:\n\n\tif (current_length + slop < limit_length)\n        \t... do something ...\n\n-- >8 --\nSubject: Lift 16kB limit of log message output\n\nTraditionally we had 16kB limit when formatting log messages for\noutput, because it was easier to arrange for the caller to have\na reasonably big buffer and pass it down without ever worrying\nabout reallocating.\n\nThis changes the calling convention of pretty_print_commit() to\nlift this limit.  Instead of the buffer and remaining length, it\nnow takes a pointer to the pointer that points at the allocated\nbuffer, and another pointer to the location that stores the\nallocated length, and reallocates the buffer as necessary.\n\nTo support the user format, the error return of interpolate()\nneeded to be changed.  It used to return a bool telling \"Ok the\nresult fits\", or \"Sorry, I had to truncate it\".  Now it returns\n0 on success, and returns the size of the buffer it wants in\norder to fit the whole result.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n builtin-branch.c      |   17 +++++++++-----\n builtin-log.c         |    6 +++-\n builtin-rev-list.c    |    8 ++++--\n builtin-show-branch.c |   23 +++++++++++---------\n commit.c              |   55 ++++++++++++++++++++++++++++++++++++++----------\n commit.h              |    2 +-\n interpolate.c         |   46 ++++++++++++++++++----------------------\n interpolate.h         |    6 ++--\n log-tree.c            |   35 ++++++++++++++++++++----------\n 9 files changed, 124 insertions(+), 74 deletions(-)\n\ndiff --git a/builtin-branch.c b/builtin-branch.c\nindex da48051..d7c321a 100644\n--- a/builtin-branch.c\n+++ b/builtin-branch.c\n@@ -242,7 +242,6 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n \tchar c;\n \tint color;\n \tstruct commit *commit;\n-\tchar subject[256];\n \n \tswitch (item->kind) {\n \tcase REF_LOCAL_BRANCH:\n@@ -263,17 +262,23 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n \t}\n \n \tif (verbose) {\n+\t\tchar *subject = NULL;\n+\t\tunsigned long subject_len = 0;\n+\t\tconst char *sub = \" **** invalid ref ****\";\n+\n \t\tcommit = lookup_commit(item->sha1);\n-\t\tif (commit && !parse_commit(commit))\n+\t\tif (commit && !parse_commit(commit)) {\n \t\t\tpretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,\n-\t\t\t\t\t    subject, sizeof(subject), 0,\n+\t\t\t\t\t    &subject, &subject_len, 0,\n \t\t\t\t\t    NULL, NULL, 0);\n-\t\telse\n-\t\t\tstrcpy(subject, \" **** invalid ref ****\");\n+\t\t\tsub = subject;\n+\t\t}\n \t\tprintf(\"%c %s%-*s%s %s %s\\n\", c, branch_get_color(color),\n \t\t       maxwidth, item->name,\n \t\t       branch_get_color(COLOR_BRANCH_RESET),\n-\t\t       find_unique_abbrev(item->sha1, abbrev), subject);\n+\t\t       find_unique_abbrev(item->sha1, abbrev), sub);\n+\t\tif (subject)\n+\t\t\tfree(subject);\n \t} else {\n \t\tprintf(\"%c %s%s%s\\n\", c, branch_get_color(color), item->name,\n \t\t       branch_get_color(COLOR_BRANCH_RESET));\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 0aede76..b9035ab 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -742,11 +742,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)\n \t\t\tsign = '-';\n \n \t\tif (verbose) {\n-\t\t\tstatic char buf[16384];\n+\t\t\tchar *buf = NULL;\n+\t\t\tunsigned long buflen = 0;\n \t\t\tpretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,\n-\t\t\t                    buf, sizeof(buf), 0, NULL, NULL, 0);\n+\t\t\t                    &buf, &buflen, 0, NULL, NULL, 0);\n \t\t\tprintf(\"%c %s %s\\n\", sign,\n \t\t\t       sha1_to_hex(commit->object.sha1), buf);\n+\t\t\tfree(buf);\n \t\t}\n \t\telse {\n \t\t\tprintf(\"%c %s\\n\", sign,\ndiff --git a/builtin-rev-list.c b/builtin-rev-list.c\nindex ebf53f5..813aadf 100644\n--- a/builtin-rev-list.c\n+++ b/builtin-rev-list.c\n@@ -92,11 +92,13 @@ static void show_commit(struct commit *commit)\n \t\tputchar('\\n');\n \n \tif (revs.verbose_header) {\n-\t\tstatic char pretty_header[16384];\n+\t\tchar *buf = NULL;\n+\t\tunsigned long buflen = 0;\n \t\tpretty_print_commit(revs.commit_format, commit, ~0,\n-\t\t\t\t    pretty_header, sizeof(pretty_header),\n+\t\t\t\t    &buf, &buflen,\n \t\t\t\t    revs.abbrev, NULL, NULL, revs.date_mode);\n-\t\tprintf(\"%s%c\", pretty_header, hdr_termination);\n+\t\tprintf(\"%s%c\", buf, hdr_termination);\n+\t\tfree(buf);\n \t}\n \tfflush(stdout);\n \tif (commit->parents) {\ndiff --git a/builtin-show-branch.c b/builtin-show-branch.c\nindex c892f1f..4fa87f6 100644\n--- a/builtin-show-branch.c\n+++ b/builtin-show-branch.c\n@@ -259,17 +259,19 @@ static void join_revs(struct commit_list **list_p,\n \n static void show_one_commit(struct commit *commit, int no_name)\n {\n-\tchar pretty[256], *cp;\n+\tchar *pretty = NULL;\n+\tconst char *pretty_str = \"(unavailable)\";\n+\tunsigned long pretty_len = 0;\n \tstruct commit_name *name = commit->util;\n-\tif (commit->object.parsed)\n+\n+\tif (commit->object.parsed) {\n \t\tpretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,\n-\t\t\t\t    pretty, sizeof(pretty), 0, NULL, NULL, 0);\n-\telse\n-\t\tstrcpy(pretty, \"(unavailable)\");\n-\tif (!prefixcmp(pretty, \"[PATCH] \"))\n-\t\tcp = pretty + 8;\n-\telse\n-\t\tcp = pretty;\n+\t\t\t\t    &pretty, &pretty_len,\n+\t\t\t\t    0, NULL, NULL, 0);\n+\t\tpretty_str = pretty;\n+\t}\n+\tif (!prefixcmp(pretty_str, \"[PATCH] \"))\n+\t\tpretty_str += 8;\n \n \tif (!no_name) {\n \t\tif (name && name->head_name) {\n@@ -286,7 +288,8 @@ static void show_one_commit(struct commit *commit, int no_name)\n \t\t\tprintf(\"[%s] \",\n \t\t\t       find_unique_abbrev(commit->object.sha1, 7));\n \t}\n-\tputs(cp);\n+\tputs(pretty_str);\n+\tfree(pretty);\n }\n \n static char *ref_name[MAX_REVS + 1];\ndiff --git a/commit.c b/commit.c\nindex 4ca4d44..d43a68e 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -776,7 +776,7 @@ static void fill_person(struct interp *table, const char *msg, int len)\n }\n \n static long format_commit_message(const struct commit *commit,\n-\t\tconst char *msg, char *buf, unsigned long space)\n+\t\tconst char *msg, char **buf_p, unsigned long *space_p)\n {\n \tstruct interp table[] = {\n \t\t{ \"%H\" },\t/* commit hash */\n@@ -905,16 +905,27 @@ static long format_commit_message(const struct commit *commit,\n \t\tif (!table[i].value)\n \t\t\tinterp_set_entry(table, i, \"<unknown>\");\n \n-\tinterpolate(buf, space, user_format, table, ARRAY_SIZE(table));\n+\tdo {\n+\t\tchar *buf = *buf_p;\n+\t\tunsigned long space = *space_p;\n+\n+\t\tspace = interpolate(buf, space, user_format,\n+\t\t\t\t    table, ARRAY_SIZE(table));\n+\t\tif (!space)\n+\t\t\tbreak;\n+\t\tbuf = xrealloc(buf, space);\n+\t\t*buf_p = buf;\n+\t\t*space_p = space;\n+\t} while (1);\n \tinterp_clear_table(table, ARRAY_SIZE(table));\n \n-\treturn strlen(buf);\n+\treturn strlen(*buf_p);\n }\n \n unsigned long pretty_print_commit(enum cmit_fmt fmt,\n \t\t\t\t  const struct commit *commit,\n \t\t\t\t  unsigned long len,\n-\t\t\t\t  char *buf, unsigned long space,\n+\t\t\t\t  char **buf_p, unsigned long *space_p,\n \t\t\t\t  int abbrev, const char *subject,\n \t\t\t\t  const char *after_subject,\n \t\t\t\t  enum date_mode dmode)\n@@ -927,9 +938,11 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,\n \tint plain_non_ascii = 0;\n \tchar *reencoded;\n \tconst char *encoding;\n+\tchar *buf;\n+\tunsigned long space, slop;\n \n \tif (fmt == CMIT_FMT_USERFORMAT)\n-\t\treturn format_commit_message(commit, msg, buf, space);\n+\t\treturn format_commit_message(commit, msg, buf_p, space_p);\n \n \tencoding = (git_log_output_encoding\n \t\t    ? git_log_output_encoding\n@@ -969,6 +982,26 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,\n \t\t}\n \t}\n \n+\tspace = *space_p;\n+\tbuf = *buf_p;\n+\n+\t/*\n+\t * We do not want to repeatedly realloc below, so\n+\t * preallocate with enough slop to hold MIME headers,\n+\t * \"Subject: \" prefix, etc.\n+\t */\n+\tslop = 1000;\n+\tif (subject)\n+\t\tslop += strlen(subject);\n+\tif (after_subject)\n+\t\tslop += strlen(after_subject);\n+\tif (space < strlen(msg) + slop) {\n+\t\tspace = strlen(msg) + slop;\n+\t\tbuf = xrealloc(buf, space);\n+\t\t*space_p = space;\n+\t\t*buf_p = buf;\n+\t}\n+\n \tfor (;;) {\n \t\tconst char *line = msg;\n \t\tint linelen = get_one_line(msg, len);\n@@ -976,14 +1009,12 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,\n \t\tif (!linelen)\n \t\t\tbreak;\n \n-\t\t/*\n-\t\t * We want some slop for indentation and a possible\n-\t\t * final \"...\". Thus the \"+ 20\".\n-\t\t */\n+\t\t/* 20 would cover indent and leave us some slop */\n \t\tif (offset + linelen + 20 > space) {\n-\t\t\tmemcpy(buf + offset, \"    ...\\n\", 8);\n-\t\t\toffset += 8;\n-\t\t\tbreak;\n+\t\t\tspace = offset + linelen + 20;\n+\t\t\tbuf = xrealloc(buf, space);\n+\t\t\t*buf_p = buf;\n+\t\t\t*space_p = space;\n \t\t}\n \n \t\tmsg += linelen;\ndiff --git a/commit.h b/commit.h\nindex a313b53..467872e 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -61,7 +61,7 @@ enum cmit_fmt {\n };\n \n extern enum cmit_fmt get_commit_format(const char *arg);\n-extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject, enum date_mode dmode);\n+extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char **buf_p, unsigned long *space_p, int abbrev, const char *subject, const char *after_subject, enum date_mode dmode);\n \n /** Removes the first commit from a list sorted by date, and adds all\n  * of its parents.\ndiff --git a/interpolate.c b/interpolate.c\nindex fb30694..0082677 100644\n--- a/interpolate.c\n+++ b/interpolate.c\n@@ -44,33 +44,33 @@ void interp_clear_table(struct interp *table, int ninterps)\n  *        { \"%%\", \"%\"},\n  *    }\n  *\n- * Returns 1 on a successful substitution pass that fits in result,\n- * Returns 0 on a failed or overflowing substitution pass.\n+ * Returns 0 on a successful substitution pass that fits in result,\n+ * Returns a number of bytes needed to hold the full substituted\n+ * string otherwise.\n  */\n \n-int interpolate(char *result, int reslen,\n+unsigned long interpolate(char *result, unsigned long reslen,\n \t\tconst char *orig,\n \t\tconst struct interp *interps, int ninterps)\n {\n \tconst char *src = orig;\n \tchar *dest = result;\n-\tint newlen = 0;\n+\tunsigned long newlen = 0;\n \tconst char *name, *value;\n-\tint namelen, valuelen;\n+\tunsigned long namelen, valuelen;\n \tint i;\n \tchar c;\n \n         memset(result, 0, reslen);\n \n-\twhile ((c = *src) && newlen < reslen - 1) {\n+\twhile ((c = *src)) {\n \t\tif (c == '%') {\n \t\t\t/* Try to match an interpolation string. */\n \t\t\tfor (i = 0; i < ninterps; i++) {\n \t\t\t\tname = interps[i].name;\n \t\t\t\tnamelen = strlen(name);\n-\t\t\t\tif (strncmp(src, name, namelen) == 0) {\n+\t\t\t\tif (strncmp(src, name, namelen) == 0)\n \t\t\t\t\tbreak;\n-\t\t\t\t}\n \t\t\t}\n \n \t\t\t/* Check for valid interpolation. */\n@@ -78,29 +78,25 @@ int interpolate(char *result, int reslen,\n \t\t\t\tvalue = interps[i].value;\n \t\t\t\tvaluelen = strlen(value);\n \n-\t\t\t\tif (newlen + valuelen < reslen - 1) {\n+\t\t\t\tif (newlen + valuelen + 1 < reslen) {\n \t\t\t\t\t/* Substitute. */\n \t\t\t\t\tstrncpy(dest, value, valuelen);\n-\t\t\t\t\tnewlen += valuelen;\n \t\t\t\t\tdest += valuelen;\n-\t\t\t\t\tsrc += namelen;\n-\t\t\t\t} else {\n-\t\t\t\t\t/* Something's not fitting. */\n-\t\t\t\t\treturn 0;\n \t\t\t\t}\n-\n-\t\t\t} else {\n-\t\t\t\t/* Skip bogus interpolation. */\n-\t\t\t\t*dest++ = *src++;\n-\t\t\t\tnewlen++;\n+\t\t\t\tnewlen += valuelen;\n+\t\t\t\tsrc += namelen;\n+\t\t\t\tcontinue;\n \t\t\t}\n-\n-\t\t} else {\n-\t\t\t/* Straight copy one non-interpolation character. */\n-\t\t\t*dest++ = *src++;\n-\t\t\tnewlen++;\n \t\t}\n+\t\t/* Straight copy one non-interpolation character. */\n+\t\tif (newlen + 1 < reslen)\n+\t\t\t*dest++ = *src;\n+\t\tsrc++;\n+\t\tnewlen++;\n \t}\n \n-\treturn newlen < reslen - 1;\n+\tif (newlen + 1 < reslen)\n+\t\treturn 0;\n+\telse\n+\t\treturn newlen + 2;\n }\ndiff --git a/interpolate.h b/interpolate.h\nindex 16a26b9..77407e6 100644\n--- a/interpolate.h\n+++ b/interpolate.h\n@@ -19,8 +19,8 @@ struct interp {\n extern void interp_set_entry(struct interp *table, int slot, const char *value);\n extern void interp_clear_table(struct interp *table, int ninterps);\n \n-extern int interpolate(char *result, int reslen,\n-\t\t       const char *orig,\n-\t\t       const struct interp *interps, int ninterps);\n+extern unsigned long interpolate(char *result, unsigned long reslen,\n+\t\t\t\t const char *orig,\n+\t\t\t\t const struct interp *interps, int ninterps);\n \n #endif /* INTERPOLATE_H */\ndiff --git a/log-tree.c b/log-tree.c\nindex 4bef909..0cf21bc 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -79,16 +79,25 @@ static int detect_any_signoff(char *letter, int size)\n \treturn seen_head && seen_name;\n }\n \n-static int append_signoff(char *buf, int buf_sz, int at, const char *signoff)\n+static unsigned long append_signoff(char **buf_p, unsigned long *buf_sz_p,\n+\t\t\t\t    unsigned long at, const char *signoff)\n {\n \tstatic const char signed_off_by[] = \"Signed-off-by: \";\n-\tint signoff_len = strlen(signoff);\n+\tsize_t signoff_len = strlen(signoff);\n \tint has_signoff = 0;\n-\tchar *cp = buf;\n-\n-\t/* Do we have enough space to add it? */\n-\tif (buf_sz - at <= strlen(signed_off_by) + signoff_len + 3)\n-\t\treturn at;\n+\tchar *cp;\n+\tchar *buf;\n+\tunsigned long buf_sz;\n+\n+\tbuf = *buf_p;\n+\tbuf_sz = *buf_sz_p;\n+\tif (buf_sz <= at + strlen(signed_off_by) + signoff_len + 3) {\n+\t\tbuf_sz += strlen(signed_off_by) + signoff_len + 3;\n+\t\tbuf = xrealloc(buf, buf_sz);\n+\t\t*buf_p = buf;\n+\t\t*buf_sz_p = buf_sz;\n+\t}\n+\tcp = buf;\n \n \t/* First see if we already have the sign-off by the signer */\n \twhile ((cp = strstr(cp, signed_off_by))) {\n@@ -133,7 +142,8 @@ static unsigned int digits_in_number(unsigned int number)\n \n void show_log(struct rev_info *opt, const char *sep)\n {\n-\tstatic char this_header[16384];\n+\tchar *msgbuf = NULL;\n+\tunsigned long msgbuf_len = 0;\n \tstruct log_info *log = opt->loginfo;\n \tstruct commit *commit = log->commit, *parent = log->parent;\n \tint abbrev = opt->diffopt.abbrev;\n@@ -278,14 +288,15 @@ void show_log(struct rev_info *opt, const char *sep)\n \t/*\n \t * And then the pretty-printed message itself\n \t */\n-\tlen = pretty_print_commit(opt->commit_format, commit, ~0u, this_header,\n-\t\t\t\t  sizeof(this_header), abbrev, subject,\n+\tlen = pretty_print_commit(opt->commit_format, commit, ~0u,\n+\t\t\t\t  &msgbuf, &msgbuf_len, abbrev, subject,\n \t\t\t\t  extra_headers, opt->date_mode);\n \n \tif (opt->add_signoff)\n-\t\tlen = append_signoff(this_header, sizeof(this_header), len,\n+\t\tlen = append_signoff(&msgbuf, &msgbuf_len, len,\n \t\t\t\t     opt->add_signoff);\n-\tprintf(\"%s%s%s\", this_header, extra, sep);\n+\tprintf(\"%s%s%s\", msgbuf, extra, sep);\n+\tfree(msgbuf);\n }\n \n int log_tree_diff_flush(struct rev_info *opt)\n"},{"id":"44795","messageId":"7vvedtlor9.fsf_-_@assigned-by-dhcp.pobox.com","threadId":"8537","inReplyTo":"7vhcpfrlk1.fsf@assigned-by-dhcp.pobox.com","subject":"[PATCH] Extend --pretty=oneline to cover the first paragraph, so that an ugly commit message like this can be handled sanely.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-12T05:34:34Z","receivedAt":"2007-06-12T05:34:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Currently, --pretty=oneline and --pretty=email (hence\nformat-patch) take and use only the first line of the commit log\nmessage.  This changes them to:\n\n - Take the first paragraph, where the definition of the first\n   paragraph is \"skip all blank lines from the beginning, and\n   then grab everything up to the next empty line\".\n\n - Replace all line breaks with a whitespace.\n\nThis change would not affect a well-behaved commit message that\nadheres to the convention of \"single line summary, a blank line,\nand then body of message\", as its first paragraph always\nconsists of a single line.  Commit messages from different\nculture, such as the ones imported from CVS/SVN, can however get\nchomped with the existing behaviour at the first linebreak in\nthe middle of sentence right now, which would become much easier\nto see with this change.\n\nThe Subject: and --pretty=oneline output would become very long\nand unsightly for non-conforming commits, but their messages are\nalready ugly anyway, and thischange at least avoids the loss of\ninformation.\n\nThe Subject: line from a multi-line paragraph is folded using\nRFC2822 line folding rules at the places where line breaks were\nin the original.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n * This is on top of the previous \"Lift 16kB limit\" clean-up.\n   I haven't checked what mailinfo does when it unfolds a folded\n   Subject: line yet, but it may have to be updated to match\n   this, so that \"format-patch --stdout | am\" behaves sanely on\n   commits with multi-line first paragraph.\n\n commit.c |  396 +++++++++++++++++++++++++++++++++++++++++---------------------\n 1 files changed, 262 insertions(+), 134 deletions(-)\n\ndiff --git a/commit.c b/commit.c\nindex d43a68e..e2fd9ba 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -529,6 +529,14 @@ static int add_rfc2047(char *buf, const char *line, int len,\n \treturn bp - buf;\n }\n \n+static unsigned long bound_rfc2047(unsigned long len, const char *encoding)\n+{\n+\t/* upper bound of q encoded string of length 'len' */\n+\tunsigned long elen = strlen(encoding);\n+\n+\treturn len * 3 + elen + 100;\n+}\n+\n static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf,\n \t\t\t const char *line, enum date_mode dmode,\n \t\t\t const char *encoding)\n@@ -922,6 +930,224 @@ static long format_commit_message(const struct commit *commit,\n \treturn strlen(*buf_p);\n }\n \n+#define ALLOC_GROW(buf, space, need) \\\n+\tdo { \\\n+\t\tif ((space) < (need)) { \\\n+\t\t\tbuf = xrealloc(buf, need); \\\n+\t\t\tspace = need; \\\n+\t\t} \\\n+\t} while (0)\n+\n+static void pp_header(enum cmit_fmt fmt,\n+\t\t      int abbrev,\n+\t\t      enum date_mode dmode,\n+\t\t      const char *encoding,\n+\t\t      const struct commit *commit,\n+\t\t      const char **msg_p,\n+\t\t      unsigned long *len_p,\n+\t\t      unsigned long *ofs_p,\n+\t\t      char **buf_p,\n+\t\t      unsigned long *space_p)\n+{\n+\tint parents_shown = 0;\n+\n+\tfor (;;) {\n+\t\tconst char *line = *msg_p;\n+\t\tchar *dst;\n+\t\tint linelen = get_one_line(*msg_p, *len_p);\n+\t\tunsigned long len;\n+\n+\t\tif (!linelen)\n+\t\t\treturn;\n+\t\t*msg_p += linelen;\n+\t\t*len_p -= linelen;\n+\n+\t\tif (linelen == 1)\n+\t\t\t/* End of header */\n+\t\t\treturn;\n+\n+\t\tALLOC_GROW(*buf_p, *space_p, linelen + *ofs_p + 20);\n+\t\tdst = *buf_p + *ofs_p;\n+\n+\t\tif (fmt == CMIT_FMT_RAW) {\n+\t\t\tmemcpy(dst, line, linelen);\n+\t\t\t*ofs_p += linelen;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (!memcmp(line, \"parent \", 7)) {\n+\t\t\tif (linelen != 48)\n+\t\t\t\tdie(\"bad parent line in commit\");\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (!parents_shown) {\n+\t\t\tstruct commit_list *parent;\n+\t\t\tint num;\n+\t\t\tfor (parent = commit->parents, num = 0;\n+\t\t\t     parent;\n+\t\t\t     parent = parent->next, num++)\n+\t\t\t\t;\n+\t\t\t/* with enough slop */\n+\t\t\tnum = *ofs_p + num * 50 + 20;\n+\t\t\tALLOC_GROW(*buf_p, *space_p, num);\n+\t\t\tdst = *buf_p + *ofs_p;\n+\t\t\t*ofs_p += add_merge_info(fmt, dst, commit, abbrev);\n+\t\t\tparents_shown = 1;\n+\t\t}\n+\n+\t\t/*\n+\t\t * MEDIUM == DEFAULT shows only author with dates.\n+\t\t * FULL shows both authors but not dates.\n+\t\t * FULLER shows both authors and dates.\n+\t\t */\n+\t\tif (!memcmp(line, \"author \", 7)) {\n+\t\t\tlen = linelen;\n+\t\t\tif (fmt == CMIT_FMT_EMAIL)\n+\t\t\t\tlen = bound_rfc2047(linelen, encoding);\n+\t\t\tALLOC_GROW(*buf_p, *space_p, *ofs_p + len);\n+\t\t\tdst = *buf_p + *ofs_p;\n+\t\t\t*ofs_p += add_user_info(\"Author\", fmt, dst,\n+\t\t\t\t\t\tline + 7, dmode, encoding);\n+\t\t}\n+\n+\t\tif (!memcmp(line, \"committer \", 10) &&\n+\t\t    (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) {\n+\t\t\tlen = linelen;\n+\t\t\tif (fmt == CMIT_FMT_EMAIL)\n+\t\t\t\tlen = bound_rfc2047(linelen, encoding);\n+\t\t\tALLOC_GROW(*buf_p, *space_p, *ofs_p + len);\n+\t\t\tdst = *buf_p + *ofs_p;\n+\t\t\t*ofs_p += add_user_info(\"Commit\", fmt, dst,\n+\t\t\t\t\t\tline + 10, dmode, encoding);\n+\t\t}\n+\t}\n+}\n+\n+static void pp_title_line(enum cmit_fmt fmt,\n+\t\t\t  const char **msg_p,\n+\t\t\t  unsigned long *len_p,\n+\t\t\t  unsigned long *ofs_p,\n+\t\t\t  char **buf_p,\n+\t\t\t  unsigned long *space_p,\n+\t\t\t  int indent,\n+\t\t\t  const char *subject,\n+\t\t\t  const char *after_subject,\n+\t\t\t  const char *encoding,\n+\t\t\t  int plain_non_ascii)\n+{\n+\tchar *title;\n+\tunsigned long title_alloc, title_len;\n+\tunsigned long len;\n+\n+\ttitle_len = 0;\n+\ttitle_alloc = 80;\n+\ttitle = xmalloc(title_alloc);\n+\tfor (;;) {\n+\t\tconst char *line = *msg_p;\n+\t\tint linelen = get_one_line(line, *len_p);\n+\t\t*msg_p += linelen;\n+\t\t*len_p -= linelen;\n+\n+\t\tif (!linelen || is_empty_line(line, &linelen))\n+\t\t\tbreak;\n+\n+\t\tif (title_alloc <= title_len + linelen + 2) {\n+\t\t\ttitle_alloc = title_len + linelen + 80;\n+\t\t\ttitle = xrealloc(title, title_alloc);\n+\t\t}\n+\t\tlen = 0;\n+\t\tif (title_len) {\n+\t\t\tif (fmt == CMIT_FMT_EMAIL) {\n+\t\t\t\tlen++;\n+\t\t\t\ttitle[title_len++] = '\\n';\n+\t\t\t}\n+\t\t\tlen++;\n+\t\t\ttitle[title_len++] = ' ';\n+\t\t}\n+\t\tmemcpy(title + title_len, line, linelen);\n+\t\ttitle_len += linelen;\n+\t}\n+\n+\t/* Enough slop for the MIME header and rfc2047 */\n+\tlen = bound_rfc2047(title_len, encoding)+ 1000;\n+\tif (subject)\n+\t\tlen += strlen(subject);\n+\tif (after_subject)\n+\t\tlen += strlen(after_subject);\n+\tif (encoding)\n+\t\tlen += strlen(encoding);\n+\tALLOC_GROW(*buf_p, *space_p, title_len + *ofs_p + len);\n+\n+\tif (subject) {\n+\t\tlen = strlen(subject);\n+\t\tmemcpy(*buf_p + *ofs_p, subject, len);\n+\t\t*ofs_p += len;\n+\t\t*ofs_p += add_rfc2047(*buf_p + *ofs_p,\n+\t\t\t\t      title, title_len, encoding);\n+\t} else {\n+\t\tmemcpy(*buf_p + *ofs_p, title, title_len);\n+\t\t*ofs_p += title_len;\n+\t}\n+\t(*buf_p)[(*ofs_p)++] = '\\n';\n+\tif (plain_non_ascii) {\n+\t\tconst char *header_fmt =\n+\t\t\t\"MIME-Version: 1.0\\n\"\n+\t\t\t\"Content-Type: text/plain; charset=%s\\n\"\n+\t\t\t\"Content-Transfer-Encoding: 8bit\\n\";\n+\t\t*ofs_p += snprintf(*buf_p + *ofs_p,\n+\t\t\t\t   *space_p - *ofs_p,\n+\t\t\t\t   header_fmt, encoding);\n+\t}\n+\tif (after_subject) {\n+\t\tlen = strlen(after_subject);\n+\t\tmemcpy(*buf_p + *ofs_p, after_subject, len);\n+\t\t*ofs_p += len;\n+\t}\n+\tfree(title);\n+\tif (fmt == CMIT_FMT_EMAIL) {\n+\t\tALLOC_GROW(*buf_p, *space_p, *ofs_p + 20);\n+\t\t(*buf_p)[(*ofs_p)++] = '\\n';\n+\t}\n+}\n+\n+static void pp_remainder(enum cmit_fmt fmt,\n+\t\t\t const char **msg_p,\n+\t\t\t unsigned long *len_p,\n+\t\t\t unsigned long *ofs_p,\n+\t\t\t char **buf_p,\n+\t\t\t unsigned long *space_p,\n+\t\t\t int indent)\n+{\n+\tint first = 1;\n+\tfor (;;) {\n+\t\tconst char *line = *msg_p;\n+\t\tint linelen = get_one_line(line, *len_p);\n+\t\t*msg_p += linelen;\n+\t\t*len_p -= linelen;\n+\n+\t\tif (!linelen)\n+\t\t\tbreak;\n+\n+\t\tif (is_empty_line(line, &linelen)) {\n+\t\t\tif (first)\n+\t\t\t\tcontinue;\n+\t\t\tif (fmt == CMIT_FMT_SHORT)\n+\t\t\t\tbreak;\n+\t\t}\n+\t\tfirst = 0;\n+\n+\t\tALLOC_GROW(*buf_p, *space_p, *ofs_p + linelen + indent + 20);\n+\t\tif (indent) {\n+\t\t\tmemset(*buf_p + *ofs_p, ' ', indent);\n+\t\t\t*ofs_p += indent;\n+\t\t}\n+\t\tmemcpy(*buf_p + *ofs_p, line, linelen);\n+\t\t*ofs_p += linelen;\n+\t\t(*buf_p)[(*ofs_p)++] = '\\n';\n+\t}\n+}\n+\n unsigned long pretty_print_commit(enum cmit_fmt fmt,\n \t\t\t\t  const struct commit *commit,\n \t\t\t\t  unsigned long len,\n@@ -930,16 +1156,14 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,\n \t\t\t\t  const char *after_subject,\n \t\t\t\t  enum date_mode dmode)\n {\n-\tint hdr = 1, body = 0, seen_title = 0;\n \tunsigned long offset = 0;\n+\tunsigned long beginning_of_body;\n \tint indent = 4;\n-\tint parents_shown = 0;\n \tconst char *msg = commit->buffer;\n \tint plain_non_ascii = 0;\n \tchar *reencoded;\n \tconst char *encoding;\n \tchar *buf;\n-\tunsigned long space, slop;\n \n \tif (fmt == CMIT_FMT_USERFORMAT)\n \t\treturn format_commit_message(commit, msg, buf_p, space_p);\n@@ -950,8 +1174,10 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,\n \tif (!encoding)\n \t\tencoding = \"utf-8\";\n \treencoded = logmsg_reencode(commit, encoding);\n-\tif (reencoded)\n+\tif (reencoded) {\n \t\tmsg = reencoded;\n+\t\tlen = strlen(reencoded);\n+\t}\n \n \tif (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)\n \t\tindent = 0;\n@@ -982,155 +1208,57 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,\n \t\t}\n \t}\n \n-\tspace = *space_p;\n-\tbuf = *buf_p;\n-\n-\t/*\n-\t * We do not want to repeatedly realloc below, so\n-\t * preallocate with enough slop to hold MIME headers,\n-\t * \"Subject: \" prefix, etc.\n-\t */\n-\tslop = 1000;\n-\tif (subject)\n-\t\tslop += strlen(subject);\n-\tif (after_subject)\n-\t\tslop += strlen(after_subject);\n-\tif (space < strlen(msg) + slop) {\n-\t\tspace = strlen(msg) + slop;\n-\t\tbuf = xrealloc(buf, space);\n-\t\t*space_p = space;\n-\t\t*buf_p = buf;\n+\tpp_header(fmt, abbrev, dmode, encoding,\n+\t\t  commit, &msg, &len,\n+\t\t  &offset, buf_p, space_p);\n+\tif (fmt != CMIT_FMT_ONELINE && !subject) {\n+\t\tALLOC_GROW(*buf_p, *space_p, offset + 20);\n+\t\t(*buf_p)[offset++] = '\\n';\n \t}\n \n+\t/* Skip excess blank lines at the beginning of body, if any... */\n \tfor (;;) {\n-\t\tconst char *line = msg;\n \t\tint linelen = get_one_line(msg, len);\n-\n+\t\tint ll = linelen;\n \t\tif (!linelen)\n \t\t\tbreak;\n-\n-\t\t/* 20 would cover indent and leave us some slop */\n-\t\tif (offset + linelen + 20 > space) {\n-\t\t\tspace = offset + linelen + 20;\n-\t\t\tbuf = xrealloc(buf, space);\n-\t\t\t*buf_p = buf;\n-\t\t\t*space_p = space;\n-\t\t}\n-\n+\t\tif (!is_empty_line(msg, &ll))\n+\t\t\tbreak;\n \t\tmsg += linelen;\n \t\tlen -= linelen;\n-\t\tif (hdr) {\n-\t\t\tif (linelen == 1) {\n-\t\t\t\thdr = 0;\n-\t\t\t\tif ((fmt != CMIT_FMT_ONELINE) && !subject)\n-\t\t\t\t\tbuf[offset++] = '\\n';\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (fmt == CMIT_FMT_RAW) {\n-\t\t\t\tmemcpy(buf + offset, line, linelen);\n-\t\t\t\toffset += linelen;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!memcmp(line, \"parent \", 7)) {\n-\t\t\t\tif (linelen != 48)\n-\t\t\t\t\tdie(\"bad parent line in commit\");\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\n-\t\t\tif (!parents_shown) {\n-\t\t\t\toffset += add_merge_info(fmt, buf + offset,\n-\t\t\t\t\t\t\t commit, abbrev);\n-\t\t\t\tparents_shown = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\t/*\n-\t\t\t * MEDIUM == DEFAULT shows only author with dates.\n-\t\t\t * FULL shows both authors but not dates.\n-\t\t\t * FULLER shows both authors and dates.\n-\t\t\t */\n-\t\t\tif (!memcmp(line, \"author \", 7))\n-\t\t\t\toffset += add_user_info(\"Author\", fmt,\n-\t\t\t\t\t\t\tbuf + offset,\n-\t\t\t\t\t\t\tline + 7,\n-\t\t\t\t\t\t\tdmode,\n-\t\t\t\t\t\t\tencoding);\n-\t\t\tif (!memcmp(line, \"committer \", 10) &&\n-\t\t\t    (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER))\n-\t\t\t\toffset += add_user_info(\"Commit\", fmt,\n-\t\t\t\t\t\t\tbuf + offset,\n-\t\t\t\t\t\t\tline + 10,\n-\t\t\t\t\t\t\tdmode,\n-\t\t\t\t\t\t\tencoding);\n-\t\t\tcontinue;\n-\t\t}\n+\t}\n \n-\t\tif (!subject)\n-\t\t\tbody = 1;\n+\t/* These formats treat the title line specially. */\n+\tif (fmt == CMIT_FMT_ONELINE\n+\t    || fmt == CMIT_FMT_EMAIL)\n+\t\tpp_title_line(fmt, &msg, &len, &offset,\n+\t\t\t      buf_p, space_p, indent,\n+\t\t\t      subject, after_subject, encoding,\n+\t\t\t      plain_non_ascii);\n \n-\t\tif (is_empty_line(line, &linelen)) {\n-\t\t\tif (!seen_title)\n-\t\t\t\tcontinue;\n-\t\t\tif (!body)\n-\t\t\t\tcontinue;\n-\t\t\tif (subject)\n-\t\t\t\tcontinue;\n-\t\t\tif (fmt == CMIT_FMT_SHORT)\n-\t\t\t\tbreak;\n-\t\t}\n+\tbeginning_of_body = offset;\n+\tif (fmt != CMIT_FMT_ONELINE)\n+\t\tpp_remainder(fmt, &msg, &len, &offset,\n+\t\t\t     buf_p, space_p, indent);\n \n-\t\tseen_title = 1;\n-\t\tif (subject) {\n-\t\t\tint slen = strlen(subject);\n-\t\t\tmemcpy(buf + offset, subject, slen);\n-\t\t\toffset += slen;\n-\t\t\toffset += add_rfc2047(buf + offset, line, linelen,\n-\t\t\t\t\t      encoding);\n-\t\t}\n-\t\telse {\n-\t\t\tmemset(buf + offset, ' ', indent);\n-\t\t\tmemcpy(buf + offset + indent, line, linelen);\n-\t\t\toffset += linelen + indent;\n-\t\t}\n-\t\tbuf[offset++] = '\\n';\n-\t\tif (fmt == CMIT_FMT_ONELINE)\n-\t\t\tbreak;\n-\t\tif (subject && plain_non_ascii) {\n-\t\t\tint sz;\n-\t\t\tchar header[512];\n-\t\t\tconst char *header_fmt =\n-\t\t\t\t\"MIME-Version: 1.0\\n\"\n-\t\t\t\t\"Content-Type: text/plain; charset=%s\\n\"\n-\t\t\t\t\"Content-Transfer-Encoding: 8bit\\n\";\n-\t\t\tsz = snprintf(header, sizeof(header), header_fmt,\n-\t\t\t\t      encoding);\n-\t\t\tif (sizeof(header) < sz)\n-\t\t\t\tdie(\"Encoding name %s too long\", encoding);\n-\t\t\tmemcpy(buf + offset, header, sz);\n-\t\t\toffset += sz;\n-\t\t}\n-\t\tif (after_subject) {\n-\t\t\tint slen = strlen(after_subject);\n-\t\t\tif (slen > space - offset - 1)\n-\t\t\t\tslen = space - offset - 1;\n-\t\t\tmemcpy(buf + offset, after_subject, slen);\n-\t\t\toffset += slen;\n-\t\t\tafter_subject = NULL;\n-\t\t}\n-\t\tsubject = NULL;\n-\t}\n-\twhile (offset && isspace(buf[offset-1]))\n+\twhile (offset && isspace((*buf_p)[offset-1]))\n \t\toffset--;\n+\n+\tALLOC_GROW(*buf_p, *space_p, offset + 20);\n+\tbuf = *buf_p;\n+\n \t/* Make sure there is an EOLN for the non-oneline case */\n \tif (fmt != CMIT_FMT_ONELINE)\n \t\tbuf[offset++] = '\\n';\n+\n \t/*\n-\t * make sure there is another EOLN to separate the headers from whatever\n-\t * body the caller appends if we haven't already written a body\n+\t * The caller may append additional body text in e-mail\n+\t * format.  Make sure we did not strip the blank line\n+\t * between the header and the body.\n \t */\n-\tif (fmt == CMIT_FMT_EMAIL && !body)\n+\tif (fmt == CMIT_FMT_EMAIL && offset <= beginning_of_body)\n \t\tbuf[offset++] = '\\n';\n \tbuf[offset] = '\\0';\n-\n \tfree(reencoded);\n \treturn offset;\n }\n-- \n1.5.2.1.1021.g1c0b0\n"},{"id":"44798","messageId":"20070612061753.GA4080@muzzle","threadId":"8537","inReplyTo":"7vhcpfrlk1.fsf@assigned-by-dhcp.pobox.com","subject":"Re: [PATCH] git-svn: use git-log rather than rev-list | xargs cat-file","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2007-06-12T06:17:53Z","receivedAt":"2007-06-12T06:17:53Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n> Eric Wong <normalperson@yhbt.net> writes:\n> \n> > Sam Vilain <sam@vilain.net> wrote:\n> >> This saves a bit of time when rebuilding the git-svn index.\n> >\n> > Does git-log still have the 16k buffer limit?  If so then we can't use\n> > it because commit messages over 16k will be truncated and the git-svn-id\n> > line will not show up.  Also, if that limit is removed I'd prefer to\n> > just add --pretty=raw to rev-list because git-log is stil porcelain and\n> > more likely to change.\n> \n> How about this?  It passes the test suite, but other than that\n> hasn't seen much test yet.  I tried to be careful, but sanity\n> checking by extra sets of eyeballs would be needed.\n\nThe patch looks and runs alright to me, but then again I haven't looked\nat the C portions of git in a while :x\n\nI expected the malloc/free overhead to be much greater, but it's hardly\nnoticeable (nor measureable with /usr/bin/time or bash built-in time).\nThere are just a handful more pagefaults measured with /usr/bin/time,\nbut the runtime performance is neck-and-neck with/without the patch.\n\nMaybe glibc (2.3.6 on x86 Debian Etch) and Linux (2.6.18) are just doing\na very good job with memory allocation... I wonder how well it runs on\nother platforms.\n\n-- \nEric Wong\n"}]}