Change semantics of interpolate to work like snprintf.

Also fix many off-by-ones and a useless memset.

Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Pierre Habouzit 2007-09-10 12:35:05 +02:00 committed by Junio C Hamano
parent f1696ee398
commit 4acfd1b799
2 changed files with 13 additions and 16 deletions

View File

@ -923,15 +923,14 @@ long format_commit_message(const struct commit *commit, const void *format,
do { do {
char *buf = *buf_p; char *buf = *buf_p;
unsigned long space = *space_p; unsigned long len;
space = interpolate(buf, space, format, len = interpolate(buf, *space_p, format,
table, ARRAY_SIZE(table)); table, ARRAY_SIZE(table));
if (!space) if (len < *space_p)
break; break;
buf = xrealloc(buf, space); ALLOC_GROW(buf, len + 1, *space_p);
*buf_p = buf; *buf_p = buf;
*space_p = space;
} while (1); } while (1);
interp_clear_table(table, ARRAY_SIZE(table)); interp_clear_table(table, ARRAY_SIZE(table));

View File

@ -44,9 +44,8 @@ void interp_clear_table(struct interp *table, int ninterps)
* { "%%", "%"}, * { "%%", "%"},
* } * }
* *
* Returns 0 on a successful substitution pass that fits in result, * Returns the length of the substituted string (not including the final \0).
* Returns a number of bytes needed to hold the full substituted * Like with snprintf, if the result is >= reslen, then it overflowed.
* string otherwise.
*/ */
unsigned long interpolate(char *result, unsigned long reslen, unsigned long interpolate(char *result, unsigned long reslen,
@ -61,8 +60,6 @@ unsigned long interpolate(char *result, unsigned long reslen,
int i; int i;
char c; char c;
memset(result, 0, reslen);
while ((c = *src)) { while ((c = *src)) {
if (c == '%') { if (c == '%') {
/* Try to match an interpolation string. */ /* Try to match an interpolation string. */
@ -78,9 +75,9 @@ unsigned long interpolate(char *result, unsigned long reslen,
value = interps[i].value; value = interps[i].value;
valuelen = strlen(value); valuelen = strlen(value);
if (newlen + valuelen + 1 < reslen) { if (newlen + valuelen < reslen) {
/* Substitute. */ /* Substitute. */
strncpy(dest, value, valuelen); memcpy(dest, value, valuelen);
dest += valuelen; dest += valuelen;
} }
newlen += valuelen; newlen += valuelen;
@ -95,8 +92,9 @@ unsigned long interpolate(char *result, unsigned long reslen,
newlen++; newlen++;
} }
if (newlen + 1 < reslen) /* XXX: the previous loop always keep room for the ending NUL,
return 0; we just need to check if there was room for a NUL in the first place */
else if (reslen > 0)
return newlen + 2; *dest = '\0';
return newlen;
} }