| /* |
| * 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; |
| 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; |
| } |