Removed memory leaks from interpolation table uses.
[git/git.git] / interpolate.c
1 /*
2 * Copyright 2006 Jon Loeliger
3 */
4
5 #include <string.h>
6
7 #include "git-compat-util.h"
8 #include "interpolate.h"
9
10
11 void interp_set_entry(struct interp *table, int slot, char *value)
12 {
13 char *oldval = table[slot].value;
14 char *newval = value;
15
16 if (oldval)
17 free(oldval);
18
19 if (value)
20 newval = xstrdup(value);
21
22 table[slot].value = newval;
23 }
24
25
26 void interp_clear_table(struct interp *table, int ninterps)
27 {
28 int i;
29
30 for (i = 0; i < ninterps; i++) {
31 interp_set_entry(table, i, NULL);
32 }
33 }
34
35
36 /*
37 * Convert a NUL-terminated string in buffer orig
38 * into the supplied buffer, result, whose length is reslen,
39 * performing substitutions on %-named sub-strings from
40 * the table, interps, with ninterps entries.
41 *
42 * Example interps:
43 * {
44 * { "%H", "example.org"},
45 * { "%port", "123"},
46 * { "%%", "%"},
47 * }
48 *
49 * Returns 1 on a successful substitution pass that fits in result,
50 * Returns 0 on a failed or overflowing substitution pass.
51 */
52
53 int interpolate(char *result, int reslen,
54 const char *orig,
55 const struct interp *interps, int ninterps)
56 {
57 const char *src = orig;
58 char *dest = result;
59 int newlen = 0;
60 char *name, *value;
61 int namelen, valuelen;
62 int i;
63 char c;
64
65 memset(result, 0, reslen);
66
67 while ((c = *src) && newlen < reslen - 1) {
68 if (c == '%') {
69 /* Try to match an interpolation string. */
70 for (i = 0; i < ninterps; i++) {
71 name = interps[i].name;
72 namelen = strlen(name);
73 if (strncmp(src, name, namelen) == 0) {
74 break;
75 }
76 }
77
78 /* Check for valid interpolation. */
79 if (i < ninterps) {
80 value = interps[i].value;
81 valuelen = strlen(value);
82
83 if (newlen + valuelen < reslen - 1) {
84 /* Substitute. */
85 strncpy(dest, value, valuelen);
86 newlen += valuelen;
87 dest += valuelen;
88 src += namelen;
89 } else {
90 /* Something's not fitting. */
91 return 0;
92 }
93
94 } else {
95 /* Skip bogus interpolation. */
96 *dest++ = *src++;
97 newlen++;
98 }
99
100 } else {
101 /* Straight copy one non-interpolation character. */
102 *dest++ = *src++;
103 newlen++;
104 }
105 }
106
107 return newlen < reslen - 1;
108 }