interpolate.con commit Merge branch 'maint' (bd6ba4d)
   1/*
   2 * Copyright 2006 Jon Loeliger
   3 */
   4
   5#include "git-compat-util.h"
   6#include "interpolate.h"
   7
   8
   9void 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
  24void 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
  51unsigned 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}