Merge branch 'maint'
[git] / interpolate.c
1 /*
2  * Copyright 2006 Jon Loeliger
3  */
4
5 #include "git-compat-util.h"
6 #include "interpolate.h"
7
8
9 void interp_set_entry(struct interp *table, int slot, const char *value)
10 {
11         char *oldval = table[slot].value;
12         char *newval = NULL;
13
14         free(oldval);
15
16         if (value)
17                 newval = xstrdup(value);
18
19         table[slot].value = newval;
20 }
21
22
23 void interp_clear_table(struct interp *table, int ninterps)
24 {
25         int i;
26
27         for (i = 0; i < ninterps; i++) {
28                 interp_set_entry(table, i, NULL);
29         }
30 }
31
32
33 /*
34  * Convert a NUL-terminated string in buffer orig
35  * into the supplied buffer, result, whose length is reslen,
36  * performing substitutions on %-named sub-strings from
37  * the table, interps, with ninterps entries.
38  *
39  * Example interps:
40  *    {
41  *        { "%H", "example.org"},
42  *        { "%port", "123"},
43  *        { "%%", "%"},
44  *    }
45  *
46  * Returns the length of the substituted string (not including the final \0).
47  * Like with snprintf, if the result is >= reslen, then it overflowed.
48  */
49
50 unsigned long interpolate(char *result, unsigned long reslen,
51                 const char *orig,
52                 const struct interp *interps, int ninterps)
53 {
54         const char *src = orig;
55         char *dest = result;
56         unsigned long newlen = 0;
57         const char *name, *value;
58         unsigned long namelen, valuelen;
59         int i;
60         char c;
61
62         while ((c = *src)) {
63                 if (c == '%') {
64                         /* Try to match an interpolation string. */
65                         for (i = 0; i < ninterps; i++) {
66                                 name = interps[i].name;
67                                 namelen = strlen(name);
68                                 if (strncmp(src, name, namelen) == 0)
69                                         break;
70                         }
71
72                         /* Check for valid interpolation. */
73                         if (i < ninterps) {
74                                 value = interps[i].value;
75                                 if (!value) {
76                                         src += namelen;
77                                         continue;
78                                 }
79
80                                 valuelen = strlen(value);
81                                 if (newlen + valuelen < reslen) {
82                                         /* Substitute. */
83                                         memcpy(dest, value, valuelen);
84                                         dest += valuelen;
85                                 }
86                                 newlen += valuelen;
87                                 src += namelen;
88                                 continue;
89                         }
90                 }
91                 /* Straight copy one non-interpolation character. */
92                 if (newlen + 1 < reslen)
93                         *dest++ = *src;
94                 src++;
95                 newlen++;
96         }
97
98         /* XXX: the previous loop always keep room for the ending NUL,
99            we just need to check if there was room for a NUL in the first place */
100         if (reslen > 0)
101                 *dest = '\0';
102         return newlen;
103 }