interpolate.con commit correct argument checking test for git hash-object (8101407)
   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        free(oldval);
  15
  16        if (value)
  17                newval = xstrdup(value);
  18
  19        table[slot].value = newval;
  20}
  21
  22
  23void 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
  50unsigned 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}