Merge branch 'maint'
[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, const char *value)
12 {
13         char *oldval = table[slot].value;
14         char *newval = NULL;
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 }