X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=interpolate.c;h=7f03bd99c5b66afa6cc7fa11a2430301a3042656;hb=2b6f0b0a78a713be51149f27c2c1172fe4afc9cd;hp=fb30694f4741147bba62350f704111d3afbf8133;hpb=8a3fbdd9e6c37c74b12fd0e8bd7cde8372861288;p=git.git diff --git a/interpolate.c b/interpolate.c index fb30694f4..7f03bd99c 100644 --- a/interpolate.c +++ b/interpolate.c @@ -11,8 +11,7 @@ void interp_set_entry(struct interp *table, int slot, const char *value) char *oldval = table[slot].value; char *newval = NULL; - if (oldval) - free(oldval); + free(oldval); if (value) newval = xstrdup(value); @@ -44,63 +43,61 @@ void interp_clear_table(struct interp *table, int ninterps) * { "%%", "%"}, * } * - * Returns 1 on a successful substitution pass that fits in result, - * Returns 0 on a failed or overflowing substitution pass. + * Returns the length of the substituted string (not including the final \0). + * Like with snprintf, if the result is >= reslen, then it overflowed. */ -int interpolate(char *result, int reslen, +unsigned long interpolate(char *result, unsigned long reslen, const char *orig, const struct interp *interps, int ninterps) { const char *src = orig; char *dest = result; - int newlen = 0; + unsigned long newlen = 0; const char *name, *value; - int namelen, valuelen; + unsigned long namelen, valuelen; int i; char c; - memset(result, 0, reslen); - - while ((c = *src) && newlen < reslen - 1) { + while ((c = *src)) { if (c == '%') { /* Try to match an interpolation string. */ for (i = 0; i < ninterps; i++) { name = interps[i].name; namelen = strlen(name); - if (strncmp(src, name, namelen) == 0) { + if (strncmp(src, name, namelen) == 0) break; - } } /* Check for valid interpolation. */ if (i < ninterps) { value = interps[i].value; - valuelen = strlen(value); + if (!value) { + src += namelen; + continue; + } - if (newlen + valuelen < reslen - 1) { + valuelen = strlen(value); + if (newlen + valuelen < reslen) { /* Substitute. */ - strncpy(dest, value, valuelen); - newlen += valuelen; + memcpy(dest, value, valuelen); dest += valuelen; - src += namelen; - } else { - /* Something's not fitting. */ - return 0; } - - } else { - /* Skip bogus interpolation. */ - *dest++ = *src++; - newlen++; + newlen += valuelen; + src += namelen; + continue; } - - } else { - /* Straight copy one non-interpolation character. */ - *dest++ = *src++; - newlen++; } + /* Straight copy one non-interpolation character. */ + if (newlen + 1 < reslen) + *dest++ = *src; + src++; + newlen++; } - return newlen < reslen - 1; + /* XXX: the previous loop always keep room for the ending NUL, + we just need to check if there was room for a NUL in the first place */ + if (reslen > 0) + *dest = '\0'; + return newlen; }