diff options
Diffstat (limited to 'interpolate.c')
-rw-r--r-- | interpolate.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/interpolate.c b/interpolate.c new file mode 100644 index 0000000000..6ef53f2465 --- /dev/null +++ b/interpolate.c @@ -0,0 +1,104 @@ +/* + * Copyright 2006 Jon Loeliger + */ + +#include "git-compat-util.h" +#include "interpolate.h" + + +void interp_set_entry(struct interp *table, int slot, const char *value) +{ + char *oldval = table[slot].value; + char *newval = NULL; + + if (oldval) + free(oldval); + + if (value) + newval = xstrdup(value); + + table[slot].value = newval; +} + + +void interp_clear_table(struct interp *table, int ninterps) +{ + int i; + + for (i = 0; i < ninterps; i++) { + interp_set_entry(table, i, NULL); + } +} + + +/* + * Convert a NUL-terminated string in buffer orig + * into the supplied buffer, result, whose length is reslen, + * performing substitutions on %-named sub-strings from + * the table, interps, with ninterps entries. + * + * Example interps: + * { + * { "%H", "example.org"}, + * { "%port", "123"}, + * { "%%", "%"}, + * } + * + * Returns the length of the substituted string (not including the final \0). + * Like with snprintf, if the result is >= reslen, then it overflowed. + */ + +unsigned long interpolate(char *result, unsigned long reslen, + const char *orig, + const struct interp *interps, int ninterps) +{ + const char *src = orig; + char *dest = result; + unsigned long newlen = 0; + const char *name, *value; + unsigned long namelen, valuelen; + int i; + char c; + + 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) + break; + } + + /* Check for valid interpolation. */ + if (i < ninterps) { + value = interps[i].value; + if (!value) { + src += namelen; + continue; + } + + valuelen = strlen(value); + if (newlen + valuelen < reslen) { + /* Substitute. */ + memcpy(dest, value, valuelen); + dest += valuelen; + } + newlen += valuelen; + src += namelen; + continue; + } + } + /* Straight copy one non-interpolation character. */ + if (newlen + 1 < reslen) + *dest++ = *src; + src++; + newlen++; + } + + /* 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; +} |