Skip to content

Commit 80583c0

Browse files
committed
Lift 16kB limit of log message output
Traditionally we had 16kB limit when formatting log messages for output, because it was easier to arrange for the caller to have a reasonably big buffer and pass it down without ever worrying about reallocating. This changes the calling convention of pretty_print_commit() to lift this limit. Instead of the buffer and remaining length, it now takes a pointer to the pointer that points at the allocated buffer, and another pointer to the location that stores the allocated length, and reallocates the buffer as necessary. To support the user format, the error return of interpolate() needed to be changed. It used to return a bool telling "Ok the result fits", or "Sorry, I had to truncate it". Now it returns 0 on success, and returns the size of the buffer it wants in order to fit the whole result. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 90ac368 commit 80583c0

File tree

9 files changed

+124
-74
lines changed

9 files changed

+124
-74
lines changed

builtin-branch.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,6 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
242242
char c;
243243
int color;
244244
struct commit *commit;
245-
char subject[256];
246245

247246
switch (item->kind) {
248247
case REF_LOCAL_BRANCH:
@@ -263,17 +262,23 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
263262
}
264263

265264
if (verbose) {
265+
char *subject = NULL;
266+
unsigned long subject_len = 0;
267+
const char *sub = " **** invalid ref ****";
268+
266269
commit = lookup_commit(item->sha1);
267-
if (commit && !parse_commit(commit))
270+
if (commit && !parse_commit(commit)) {
268271
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
269-
subject, sizeof(subject), 0,
272+
&subject, &subject_len, 0,
270273
NULL, NULL, 0);
271-
else
272-
strcpy(subject, " **** invalid ref ****");
274+
sub = subject;
275+
}
273276
printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color),
274277
maxwidth, item->name,
275278
branch_get_color(COLOR_BRANCH_RESET),
276-
find_unique_abbrev(item->sha1, abbrev), subject);
279+
find_unique_abbrev(item->sha1, abbrev), sub);
280+
if (subject)
281+
free(subject);
277282
} else {
278283
printf("%c %s%s%s\n", c, branch_get_color(color), item->name,
279284
branch_get_color(COLOR_BRANCH_RESET));

builtin-log.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -742,11 +742,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
742742
sign = '-';
743743

744744
if (verbose) {
745-
static char buf[16384];
745+
char *buf = NULL;
746+
unsigned long buflen = 0;
746747
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
747-
buf, sizeof(buf), 0, NULL, NULL, 0);
748+
&buf, &buflen, 0, NULL, NULL, 0);
748749
printf("%c %s %s\n", sign,
749750
sha1_to_hex(commit->object.sha1), buf);
751+
free(buf);
750752
}
751753
else {
752754
printf("%c %s\n", sign,

builtin-rev-list.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,13 @@ static void show_commit(struct commit *commit)
9292
putchar('\n');
9393

9494
if (revs.verbose_header) {
95-
static char pretty_header[16384];
95+
char *buf = NULL;
96+
unsigned long buflen = 0;
9697
pretty_print_commit(revs.commit_format, commit, ~0,
97-
pretty_header, sizeof(pretty_header),
98+
&buf, &buflen,
9899
revs.abbrev, NULL, NULL, revs.date_mode);
99-
printf("%s%c", pretty_header, hdr_termination);
100+
printf("%s%c", buf, hdr_termination);
101+
free(buf);
100102
}
101103
fflush(stdout);
102104
if (commit->parents) {

builtin-show-branch.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -259,17 +259,19 @@ static void join_revs(struct commit_list **list_p,
259259

260260
static void show_one_commit(struct commit *commit, int no_name)
261261
{
262-
char pretty[256], *cp;
262+
char *pretty = NULL;
263+
const char *pretty_str = "(unavailable)";
264+
unsigned long pretty_len = 0;
263265
struct commit_name *name = commit->util;
264-
if (commit->object.parsed)
266+
267+
if (commit->object.parsed) {
265268
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
266-
pretty, sizeof(pretty), 0, NULL, NULL, 0);
267-
else
268-
strcpy(pretty, "(unavailable)");
269-
if (!prefixcmp(pretty, "[PATCH] "))
270-
cp = pretty + 8;
271-
else
272-
cp = pretty;
269+
&pretty, &pretty_len,
270+
0, NULL, NULL, 0);
271+
pretty_str = pretty;
272+
}
273+
if (!prefixcmp(pretty_str, "[PATCH] "))
274+
pretty_str += 8;
273275

274276
if (!no_name) {
275277
if (name && name->head_name) {
@@ -286,7 +288,8 @@ static void show_one_commit(struct commit *commit, int no_name)
286288
printf("[%s] ",
287289
find_unique_abbrev(commit->object.sha1, 7));
288290
}
289-
puts(cp);
291+
puts(pretty_str);
292+
free(pretty);
290293
}
291294

292295
static char *ref_name[MAX_REVS + 1];

commit.c

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ static void fill_person(struct interp *table, const char *msg, int len)
776776
}
777777

778778
static long format_commit_message(const struct commit *commit,
779-
const char *msg, char *buf, unsigned long space)
779+
const char *msg, char **buf_p, unsigned long *space_p)
780780
{
781781
struct interp table[] = {
782782
{ "%H" }, /* commit hash */
@@ -905,16 +905,27 @@ static long format_commit_message(const struct commit *commit,
905905
if (!table[i].value)
906906
interp_set_entry(table, i, "<unknown>");
907907

908-
interpolate(buf, space, user_format, table, ARRAY_SIZE(table));
908+
do {
909+
char *buf = *buf_p;
910+
unsigned long space = *space_p;
911+
912+
space = interpolate(buf, space, user_format,
913+
table, ARRAY_SIZE(table));
914+
if (!space)
915+
break;
916+
buf = xrealloc(buf, space);
917+
*buf_p = buf;
918+
*space_p = space;
919+
} while (1);
909920
interp_clear_table(table, ARRAY_SIZE(table));
910921

911-
return strlen(buf);
922+
return strlen(*buf_p);
912923
}
913924

914925
unsigned long pretty_print_commit(enum cmit_fmt fmt,
915926
const struct commit *commit,
916927
unsigned long len,
917-
char *buf, unsigned long space,
928+
char **buf_p, unsigned long *space_p,
918929
int abbrev, const char *subject,
919930
const char *after_subject,
920931
enum date_mode dmode)
@@ -927,9 +938,11 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
927938
int plain_non_ascii = 0;
928939
char *reencoded;
929940
const char *encoding;
941+
char *buf;
942+
unsigned long space, slop;
930943

931944
if (fmt == CMIT_FMT_USERFORMAT)
932-
return format_commit_message(commit, msg, buf, space);
945+
return format_commit_message(commit, msg, buf_p, space_p);
933946

934947
encoding = (git_log_output_encoding
935948
? git_log_output_encoding
@@ -969,21 +982,39 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
969982
}
970983
}
971984

985+
space = *space_p;
986+
buf = *buf_p;
987+
988+
/*
989+
* We do not want to repeatedly realloc below, so
990+
* preallocate with enough slop to hold MIME headers,
991+
* "Subject: " prefix, etc.
992+
*/
993+
slop = 1000;
994+
if (subject)
995+
slop += strlen(subject);
996+
if (after_subject)
997+
slop += strlen(after_subject);
998+
if (space < strlen(msg) + slop) {
999+
space = strlen(msg) + slop;
1000+
buf = xrealloc(buf, space);
1001+
*space_p = space;
1002+
*buf_p = buf;
1003+
}
1004+
9721005
for (;;) {
9731006
const char *line = msg;
9741007
int linelen = get_one_line(msg, len);
9751008

9761009
if (!linelen)
9771010
break;
9781011

979-
/*
980-
* We want some slop for indentation and a possible
981-
* final "...". Thus the "+ 20".
982-
*/
1012+
/* 20 would cover indent and leave us some slop */
9831013
if (offset + linelen + 20 > space) {
984-
memcpy(buf + offset, " ...\n", 8);
985-
offset += 8;
986-
break;
1014+
space = offset + linelen + 20;
1015+
buf = xrealloc(buf, space);
1016+
*buf_p = buf;
1017+
*space_p = space;
9871018
}
9881019

9891020
msg += linelen;

commit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ enum cmit_fmt {
6161
};
6262

6363
extern enum cmit_fmt get_commit_format(const char *arg);
64-
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);
64+
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);
6565

6666
/** Removes the first commit from a list sorted by date, and adds all
6767
* of its parents.

interpolate.c

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,63 +44,59 @@ void interp_clear_table(struct interp *table, int ninterps)
4444
* { "%%", "%"},
4545
* }
4646
*
47-
* Returns 1 on a successful substitution pass that fits in result,
48-
* Returns 0 on a failed or overflowing substitution pass.
47+
* Returns 0 on a successful substitution pass that fits in result,
48+
* Returns a number of bytes needed to hold the full substituted
49+
* string otherwise.
4950
*/
5051

51-
int interpolate(char *result, int reslen,
52+
unsigned long interpolate(char *result, unsigned long reslen,
5253
const char *orig,
5354
const struct interp *interps, int ninterps)
5455
{
5556
const char *src = orig;
5657
char *dest = result;
57-
int newlen = 0;
58+
unsigned long newlen = 0;
5859
const char *name, *value;
59-
int namelen, valuelen;
60+
unsigned long namelen, valuelen;
6061
int i;
6162
char c;
6263

6364
memset(result, 0, reslen);
6465

65-
while ((c = *src) && newlen < reslen - 1) {
66+
while ((c = *src)) {
6667
if (c == '%') {
6768
/* Try to match an interpolation string. */
6869
for (i = 0; i < ninterps; i++) {
6970
name = interps[i].name;
7071
namelen = strlen(name);
71-
if (strncmp(src, name, namelen) == 0) {
72+
if (strncmp(src, name, namelen) == 0)
7273
break;
73-
}
7474
}
7575

7676
/* Check for valid interpolation. */
7777
if (i < ninterps) {
7878
value = interps[i].value;
7979
valuelen = strlen(value);
8080

81-
if (newlen + valuelen < reslen - 1) {
81+
if (newlen + valuelen + 1 < reslen) {
8282
/* Substitute. */
8383
strncpy(dest, value, valuelen);
84-
newlen += valuelen;
8584
dest += valuelen;
86-
src += namelen;
87-
} else {
88-
/* Something's not fitting. */
89-
return 0;
9085
}
91-
92-
} else {
93-
/* Skip bogus interpolation. */
94-
*dest++ = *src++;
95-
newlen++;
86+
newlen += valuelen;
87+
src += namelen;
88+
continue;
9689
}
97-
98-
} else {
99-
/* Straight copy one non-interpolation character. */
100-
*dest++ = *src++;
101-
newlen++;
10290
}
91+
/* Straight copy one non-interpolation character. */
92+
if (newlen + 1 < reslen)
93+
*dest++ = *src;
94+
src++;
95+
newlen++;
10396
}
10497

105-
return newlen < reslen - 1;
98+
if (newlen + 1 < reslen)
99+
return 0;
100+
else
101+
return newlen + 2;
106102
}

interpolate.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ struct interp {
1919
extern void interp_set_entry(struct interp *table, int slot, const char *value);
2020
extern void interp_clear_table(struct interp *table, int ninterps);
2121

22-
extern int interpolate(char *result, int reslen,
23-
const char *orig,
24-
const struct interp *interps, int ninterps);
22+
extern unsigned long interpolate(char *result, unsigned long reslen,
23+
const char *orig,
24+
const struct interp *interps, int ninterps);
2525

2626
#endif /* INTERPOLATE_H */

log-tree.c

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,25 @@ static int detect_any_signoff(char *letter, int size)
7979
return seen_head && seen_name;
8080
}
8181

82-
static int append_signoff(char *buf, int buf_sz, int at, const char *signoff)
82+
static unsigned long append_signoff(char **buf_p, unsigned long *buf_sz_p,
83+
unsigned long at, const char *signoff)
8384
{
8485
static const char signed_off_by[] = "Signed-off-by: ";
85-
int signoff_len = strlen(signoff);
86+
size_t signoff_len = strlen(signoff);
8687
int has_signoff = 0;
87-
char *cp = buf;
88-
89-
/* Do we have enough space to add it? */
90-
if (buf_sz - at <= strlen(signed_off_by) + signoff_len + 3)
91-
return at;
88+
char *cp;
89+
char *buf;
90+
unsigned long buf_sz;
91+
92+
buf = *buf_p;
93+
buf_sz = *buf_sz_p;
94+
if (buf_sz <= at + strlen(signed_off_by) + signoff_len + 3) {
95+
buf_sz += strlen(signed_off_by) + signoff_len + 3;
96+
buf = xrealloc(buf, buf_sz);
97+
*buf_p = buf;
98+
*buf_sz_p = buf_sz;
99+
}
100+
cp = buf;
92101

93102
/* First see if we already have the sign-off by the signer */
94103
while ((cp = strstr(cp, signed_off_by))) {
@@ -133,7 +142,8 @@ static unsigned int digits_in_number(unsigned int number)
133142

134143
void show_log(struct rev_info *opt, const char *sep)
135144
{
136-
static char this_header[16384];
145+
char *msgbuf = NULL;
146+
unsigned long msgbuf_len = 0;
137147
struct log_info *log = opt->loginfo;
138148
struct commit *commit = log->commit, *parent = log->parent;
139149
int abbrev = opt->diffopt.abbrev;
@@ -278,14 +288,15 @@ void show_log(struct rev_info *opt, const char *sep)
278288
/*
279289
* And then the pretty-printed message itself
280290
*/
281-
len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header,
282-
sizeof(this_header), abbrev, subject,
291+
len = pretty_print_commit(opt->commit_format, commit, ~0u,
292+
&msgbuf, &msgbuf_len, abbrev, subject,
283293
extra_headers, opt->date_mode);
284294

285295
if (opt->add_signoff)
286-
len = append_signoff(this_header, sizeof(this_header), len,
296+
len = append_signoff(&msgbuf, &msgbuf_len, len,
287297
opt->add_signoff);
288-
printf("%s%s%s", this_header, extra, sep);
298+
printf("%s%s%s", msgbuf, extra, sep);
299+
free(msgbuf);
289300
}
290301

291302
int log_tree_diff_flush(struct rev_info *opt)

0 commit comments

Comments
 (0)