#include "l2su.h" #include #include struct l2_subst__item { char *name; char *value; struct l2_subst__item *next; }; struct l2_subst { struct l2_subst__item *items; int status; }; int l2_subst_init(l2_subst_t **sp) { l2_subst_t *ret = calloc(1, sizeof(struct l2_subst)); if (!ret) return -1; *sp = ret; ret->items = NULL; ret->status = 0; return 0; } int l2_subst_add(l2_subst_t *sp, const char *name, const char *value) { if (sp->status < 0) return sp->status; char *namedup = strdup(name); char *valdup = strdup(value); struct l2_subst__item *item = calloc(1, sizeof(struct l2_subst__item)); if (!namedup || !valdup || !item) { free(namedup); free(valdup); free(item); sp->status = -1; return -1; } item->name = namedup; item->value = valdup; item->next = sp->items; sp->items = item; return 0; } const char *l2_subst__find(l2_subst_t *sp, const char *name, size_t len) { for (struct l2_subst__item *item = sp->items; item; item = item->next) { if (!strncmp(item->name, name, len)) return item->value; } return NULL; } int l2_subst__append(char **retbuf, size_t *sz, size_t *cap, const char *start, const char *end) { ptrdiff_t len = end - start; if (len <= 0) return 0; if (*sz + len > *cap) { size_t newcap = *cap ? *cap : 16; while (newcap && *sz + len > newcap) newcap <<= 1; if (!newcap) { goto cleanup; } char *newbuf = realloc(*retbuf, newcap); if (!newbuf) { goto cleanup; } *retbuf = newbuf; *cap = newcap; } memcpy(*retbuf + *sz, start, len); *sz += len; return 0; cleanup: free(*retbuf); return -1; } int l2_subst_apply(l2_subst_t *sp, const char *in, char **out) { if (sp->status < 0) return sp->status; char *retbuf = NULL, *temp; size_t size = 0; size_t cap = 0; const char *lastcpy = in; const char *open = NULL; const char *cur; for (cur = in; *cur; ++cur) { if (*cur == '$' && *(cur + 1) == '{') { if (l2_subst__append(&retbuf, &size, &cap, lastcpy, cur) < 0) return -1; lastcpy = cur; open = cur + 2; continue; } else if (*cur == '}' && open) { const char *rep = l2_subst__find(sp, open, cur - open); if (rep) { if (l2_subst__append(&retbuf, &size, &cap, rep, rep + strlen(rep)) < 0) return -1; lastcpy = cur + 1; } open = NULL; } } if (l2_subst__append(&retbuf, &size, &cap, lastcpy, cur + 1) < 0) return -1; temp = realloc(retbuf, size); if (temp) retbuf = temp; *out = retbuf; return 0; } void l2_subst_free(l2_subst_t *sp) { if (!sp) return; for (struct l2_subst__item *cur = sp->items, *temp; cur; cur = temp) { temp = cur->next; free(cur->name); free(cur->value); free(cur); } free(sp); return; }