test_end();
}
+static int
+test_var_expand_arrays_func1(const char *data ATTR_UNUSED, void *context,
+ const char **value_r,
+ const char **error_r ATTR_UNUSED)
+{
+ test_assert(strcmp(context, "context1") == 0);
+ *value_r = context;
+ return 1;
+}
+
+static int
+test_var_expand_arrays_func2(const char *data ATTR_UNUSED, void *context,
+ const char **value_r,
+ const char **error_r ATTR_UNUSED)
+{
+ test_assert(strcmp(context, "context2") == 0);
+ *value_r = context;
+ return 1;
+}
+
+static void test_var_expand_with_arrays(void)
+{
+ static const struct var_expand_table table1[] = {
+ { 'f', "firstvalue", "first" },
+ { '\0', NULL, NULL }
+ };
+ static const struct var_expand_table table2[] = {
+ { 's', "secondvalue", "second" },
+ { '\0', NULL, NULL }
+ };
+ static const struct var_expand_func_table func_table1[] = {
+ { "func1", test_var_expand_arrays_func1 },
+ { NULL, NULL }
+ };
+ static const struct var_expand_func_table func_table2[] = {
+ { "func2", test_var_expand_arrays_func2 },
+ { NULL, NULL }
+ };
+
+ static const struct var_expand_table *tables[] = {
+ table1, table2, NULL
+ };
+ static const struct var_expand_func_table *func_tables[] = {
+ func_table1, func_table2, NULL
+ };
+ static void *func_contexts[] = {
+ "context1", "context2",
+ };
+ const char *input = "%f, %s, %{first}, %{second}, %{func1}, %{func2}";
+ const char *output = "firstvalue, secondvalue, firstvalue, secondvalue, context1, context2";
+ string_t *str = t_str_new(128);
+ const char *error;
+
+ test_begin("var_expand_with_arrays");
+ test_assert(var_expand_with_arrays(str, input, tables, func_tables,
+ func_contexts, &error) == 1);
+ test_assert_strcmp(str_c(str), output);
+ test_end();
+}
+
static void test_var_get_key(void)
{
static const struct {
test_var_expand_builtin();
test_var_get_key_range();
test_var_expand_with_funcs();
+ test_var_expand_with_arrays();
test_var_get_key();
test_var_has_key();
test_var_expand_extensions();
for(;*parms != NULL; parms++) {
/* expand the parameters */
string_t *param = t_str_new(64);
- if ((ret = var_expand_with_funcs(param, *parms, ctx->table,
- ctx->func_table, ctx->context,
- error_r)) <= 0) {
+ ret = var_expand_with_arrays(param, *parms, ctx->tables,
+ ctx->func_tables, ctx->contexts,
+ error_r);
+ if (ret <= 0)
return ret;
- }
const char *p = str_c(param);
array_push_back(¶ms, &p);
}
#define VAR_EXPAND_PRIVATE_H 1
struct var_expand_context {
- /* current variables */
- const struct var_expand_table *table;
- /* caller provided function table */
- const struct var_expand_func_table *func_table;
- /* caller provided context */
- void *context;
+ /* NULL-terminated array of variable tables */
+ const struct var_expand_table *const *tables;
+ /* NULL-terminated array of function tables */
+ const struct var_expand_func_table *const *func_tables;
+ /* contexts for each function table */
+ void *const *contexts;
+
/* last offset, negative counts from end*/
int offset;
/* last width, negative counts from end */
{
const struct var_expand_table *t;
- if (ctx->table != NULL) {
- for (t = ctx->table; !TABLE_LAST(t); t++) {
+ for (unsigned int i = 0; ctx->tables[i] != NULL; i++) {
+ for (t = ctx->tables[i]; !TABLE_LAST(t); t++) {
if (t->key == key) {
*var_r = t->value != NULL ? t->value : "";
return 1;
}
}
- if (ctx->func_table != NULL) {
- for (unsigned int i = 0; ctx->func_table[i].key != NULL; i++) {
- if (ctx->func_table[i].key[0] == key &&
- ctx->func_table[i].key[1] == '\0') {
+ for (unsigned int j = 0; ctx->func_tables[j] != NULL; j++) {
+ const struct var_expand_func_table *func_table = ctx->func_tables[j];
+ for (unsigned int i = 0; func_table[i].key != NULL; i++) {
+ if (func_table[i].key[0] == key &&
+ func_table[i].key[1] == '\0') {
const char *value;
- int ret = ctx->func_table->func(
- "", ctx->context, &value, error_r);
+ int ret = func_table->func(
+ "", ctx->contexts[j], &value, error_r);
*var_r = value != NULL ? value : "";
return ret;
}
truncbits = I_MIN(truncbits, method->digest_size*8);
} else if (strcmp(k, "salt") == 0) {
str_truncate(salt, 0);
- ret = var_expand_with_funcs(salt, value, ctx->table,
- ctx->func_table,
- ctx->context, error_r);
+ ret = var_expand_with_arrays(salt, value, ctx->tables,
+ ctx->func_tables,
+ ctx->contexts, error_r);
if (ret <= 0)
return ret;
break;
}
static int
-var_expand_func(const struct var_expand_func_table *func_table,
- const char *key, const char *data, void *context,
+var_expand_func(const struct var_expand_func_table *const *func_tables,
+ const char *key, const char *data, void *const *contexts,
const char **var_r, const char **error_r)
{
const char *value = NULL;
*var_r = value != NULL ? value : "";
return 1;
}
- if (func_table != NULL) {
+ for (unsigned int i = 0; func_tables[i] != NULL; i++) {
+ const struct var_expand_func_table *func_table = func_tables[i];
for (; func_table->key != NULL; func_table++) {
if (strcmp(func_table->key, key) == 0) {
- ret = func_table->func(data, context, &value, error_r);
+ ret = func_table->func(data, contexts[i], &value, error_r);
if (*error_r == NULL)
*error_r = t_strdup_printf("Unknown variables in function %%%s", key);
*var_r = value != NULL ? value : "";
return ret;
}
}
- return var_expand_func(ctx->func_table, key, data,
- ctx->context, var_r, error_r);
+ return var_expand_func(ctx->func_tables, key, data,
+ ctx->contexts, var_r, error_r);
}
const char *key, *value = NULL;
int ret = 1;
- if (ctx->table != NULL) {
- for (t = ctx->table; !TABLE_LAST(t); t++) {
+ for (unsigned int i = 0; ctx->tables[i] != NULL; i++) {
+ for (t = ctx->tables[i]; !TABLE_LAST(t); t++) {
if (t->long_key != NULL &&
strncmp(t->long_key, key_start, key_len) == 0 &&
t->long_key[key_len] == '\0') {
const struct var_expand_func_table *func_table,
void *context, const char **error_r)
{
+ const struct var_expand_table *tables[2] = { table, NULL };
+ const struct var_expand_func_table *func_tables[2] = { func_table, NULL };
+ void *contexts[2] = { context, NULL };
+
+ return var_expand_with_arrays(dest, str, tables, func_tables,
+ contexts, error_r);
+}
+
+int var_expand_with_arrays(string_t *dest, const char *str,
+ const struct var_expand_table *const *tables,
+ const struct var_expand_func_table *const *func_tables,
+ void *const *func_contexts, const char **error_r)
+{
+ static const struct var_expand_table *empty_table = NULL;
+ static const struct var_expand_func_table *empty_func_table = NULL;
const struct var_expand_modifier *m;
const char *var;
struct var_expand_context ctx;
*error_r = NULL;
i_zero(&ctx);
- ctx.table = table;
- ctx.func_table = func_table;
- ctx.context = context;
+ ctx.tables = tables != NULL ? tables : &empty_table;
+ ctx.func_tables = func_tables != NULL ? func_tables : &empty_func_table;
+ ctx.contexts = func_contexts;
for (; *str != '\0'; str++) {
if (*str != '%')
const struct var_expand_table *table,
const struct var_expand_func_table *func_table,
void *func_context, const char **error_r) ATTR_NULL(3, 4, 5);
+/* Like var_expand_with_funcs(), but multiple separate tables can be given.
+ Each func_table[n] has a matching func_context[n] */
+int var_expand_with_arrays(string_t *dest, const char *str,
+ const struct var_expand_table *const *tables,
+ const struct var_expand_func_table *const *func_tables,
+ void *const *func_contexts, const char **error_r);
/* Returns the actual key character for given string, ie. skip any modifiers
that are before it. The string should be the data after the '%' character.
if (strcmp(k, "iv") == 0) {
str_truncate(ctx->iv, 0);
- if ((ret = var_expand_with_funcs(ctx->iv, value, ctx->ctx->table,
- ctx->ctx->func_table,
- ctx->ctx->context, error_r)) <= 0) {
+ if ((ret = var_expand_with_arrays(ctx->iv, value,
+ ctx->ctx->tables,
+ ctx->ctx->func_tables,
+ ctx->ctx->contexts,
+ error_r)) <= 0) {
return ret;
}
const char *hexiv = t_strdup(str_c(ctx->iv));
ctx->algo = value;
} else if (strcmp(k, "key") == 0) {
str_truncate(ctx->enckey, 0);
- if ((ret = var_expand_with_funcs(ctx->enckey, value,
- ctx->ctx->table,
- ctx->ctx->func_table,
- ctx->ctx->context,
- error_r)) <= 0) {
+ if ((ret = var_expand_with_arrays(ctx->enckey, value,
+ ctx->ctx->tables,
+ ctx->ctx->func_tables,
+ ctx->ctx->contexts,
+ error_r)) <= 0) {
return ret;
}
const char *hexkey = t_strdup(str_c(ctx->enckey));