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