enum config_dump_flags flags;
const struct config_module_parser *module_parsers;
- unsigned int section_idx;
};
static void config_export_size(string_t *str, uoff_t size)
return TRUE;
}
-static void
-setting_export_section_name(string_t *str, const struct setting_define *def,
- const void *set, unsigned int idx)
-{
- const char *const *name;
- size_t name_offset1;
-
- if (def->type != SET_DEFLIST_UNIQUE) {
- /* not unique, use the index */
- str_printfa(str, "%u", idx);
- return;
- }
- name_offset1 = def->list_info->type_offset1;
- i_assert(name_offset1 != 0);
-
- name = CONST_PTR_OFFSET(set, name_offset1 - 1);
- if (*name == NULL || **name == '\0') {
- /* no name, this one isn't unique. use the index. */
- str_printfa(str, "%u", idx);
- } else T_BEGIN {
- str_append(str, settings_section_escape(*name));
- } T_END;
-}
-
static void
settings_export(struct config_export_context *ctx,
const struct setting_parser_info *info,
- bool parent_unique_deflist,
const void *set, const void *change_set)
{
const struct setting_define *def;
const void *value, *default_value, *change_value;
- void *const *children, *const *change_children = NULL;
- unsigned int i, count, count2;
- size_t prefix_len;
+ unsigned int i, count;
const char *str;
char *key;
bool dump, dump_default = FALSE;
/* hidden - dump default only if it's explicitly set */
/* fall through */
case CONFIG_DUMP_SCOPE_SET:
- if (def->type == SET_DEFLIST ||
- def->type == SET_DEFLIST_UNIQUE)
- break;
if (*((const uint8_t *)change_value) < CONFIG_PARSER_CHANGE_EXPLICIT) {
/* setting is unchanged in config file */
continue;
dump_default = TRUE;
break;
case CONFIG_DUMP_SCOPE_SET_AND_DEFAULT_OVERRIDES:
- if (def->type == SET_DEFLIST ||
- def->type == SET_DEFLIST_UNIQUE)
- break;
if (*((const uint8_t *)change_value) < CONFIG_PARSER_CHANGE_INTERNAL) {
/* setting is completely unchanged */
continue;
}
dump = FALSE;
- count = 0; children = NULL;
str_truncate(ctx->value, 0);
switch (def->type) {
case SET_BOOL:
dump_default, &dump))
i_unreached();
break;
- case SET_DEFLIST:
- case SET_DEFLIST_UNIQUE: {
- const ARRAY_TYPE(void_array) *val = value;
- const ARRAY_TYPE(void_array) *change_val = change_value;
-
- if (!array_is_created(val))
- break;
-
- children = array_get(val, &count);
- for (i = 0; i < count; i++) {
- if (i > 0)
- str_append_c(ctx->value, ' ');
- setting_export_section_name(ctx->value, def, children[i],
- ctx->section_idx + i);
- }
- change_children = array_get(change_val, &count2);
- i_assert(count == count2);
- break;
- }
case SET_STRLIST: {
const ARRAY_TYPE(const_string) *val = value;
const char *const *strings;
ctx->callback(str, strings[i+1],
CONFIG_KEY_NORMAL, ctx->context);
}
- count = 0;
break;
}
case SET_FILTER_ARRAY: {
if (hash_table_lookup(ctx->keys, key) == NULL) {
enum config_key_type type;
- if (def->offset + 1 == info->type_offset1 &&
- parent_unique_deflist)
- type = CONFIG_KEY_UNIQUE_KEY;
- else if (SETTING_TYPE_IS_DEFLIST(def->type))
- type = CONFIG_KEY_LIST;
- else if (def->type == SET_FILTER_ARRAY)
+ if (def->type == SET_FILTER_ARRAY)
type = CONFIG_KEY_FILTER_ARRAY;
else
type = CONFIG_KEY_NORMAL;
hash_table_insert(ctx->keys, key, key);
}
}
-
- i_assert(count == 0 || children != NULL);
- prefix_len = str_len(ctx->prefix);
- unsigned int section_start_idx = ctx->section_idx;
- ctx->section_idx += count;
- for (i = 0; i < count; i++) {
- str_append(ctx->prefix, def->key);
- str_append_c(ctx->prefix, SETTINGS_SEPARATOR);
- setting_export_section_name(ctx->prefix, def, children[i],
- section_start_idx + i);
- str_append_c(ctx->prefix, SETTINGS_SEPARATOR);
- settings_export(ctx, def->list_info,
- def->type == SET_DEFLIST_UNIQUE,
- children[i], change_children[i]);
-
- str_truncate(ctx->prefix, prefix_len);
- }
}
}
pool_unref(&ctx->pool);
}
-int config_export_all_parsers(struct config_export_context **_ctx,
- unsigned int *section_idx)
+int config_export_all_parsers(struct config_export_context **_ctx)
{
struct config_export_context *ctx = *_ctx;
const char *error;
*_ctx = NULL;
for (i = 0; ctx->module_parsers[i].root != NULL; i++) {
- if (config_export_parser(ctx, i, section_idx, &error) < 0) {
+ if (config_export_parser(ctx, i, &error) < 0) {
i_error("%s", error);
ret = -1;
break;
}
int config_export_parser(struct config_export_context *ctx,
- unsigned int parser_idx,
- unsigned int *section_idx, const char **error_r)
+ unsigned int parser_idx, const char **error_r)
{
const struct config_module_parser *module_parser =
&ctx->module_parsers[parser_idx];
return -1;
}
- ctx->section_idx = *section_idx;
T_BEGIN {
void *set = settings_parser_get_set(module_parser->parser);
- settings_export(ctx, module_parser->root, FALSE, set,
+ settings_export(ctx, module_parser->root, set,
settings_parser_get_changes(module_parser->parser));
} T_END;
-
- *section_idx = ctx->section_idx;
return 0;
}
struct prefix_stack {
unsigned int prefix_idx;
- unsigned int str_pos;
};
ARRAY_DEFINE_TYPE(prefix_stack, struct prefix_stack);
};
#define LIST_KEY_PREFIX "\001"
-#define UNIQUE_KEY_SUFFIX "\xff"
static struct config_parsed *config;
static const char *indent_str = " !!!!";
enum config_key_type type, void *context)
{
struct config_dump_human_context *ctx = context;
- const char *p;
switch (type) {
case CONFIG_KEY_NORMAL:
value = p_strdup_printf(ctx->pool, LIST_KEY_PREFIX"%s=%s",
key, value);
break;
- case CONFIG_KEY_UNIQUE_KEY:
- p = strrchr(key, '/');
- i_assert(p != NULL);
- value = p_strdup_printf(ctx->pool, "%.*s/"UNIQUE_KEY_SUFFIX"%s=%s",
- (int)(p - key), key, p + 1, value);
- break;
case CONFIG_KEY_FILTER_ARRAY:
return;
}
} else {
sc.prefix_idx = s[count-2].prefix_idx;
}
- sc.str_pos = s[count-1].str_pos;
array_delete(stack, count-1, 1);
return sc;
}
-static void prefix_stack_reset_str(ARRAY_TYPE(prefix_stack) *stack)
-{
- struct prefix_stack *s;
-
- array_foreach_modifiable(stack, s)
- s->str_pos = UINT_MAX;
-}
-
static struct config_dump_human_context *
config_dump_human_init(enum config_dump_scope scope)
{
ARRAY_TYPE(const_string) prefixes_arr;
ARRAY_TYPE(prefix_stack) prefix_stack;
struct prefix_stack prefix;
- const char *const *strings, *const *args, *p, *str, *const *prefixes;
+ const char *const *strings, *p, *str, *const *prefixes;
const char *key, *key2, *value;
unsigned int i, j, count, prefix_count;
unsigned int prefix_idx = UINT_MAX;
size_t len, skip_len, setting_name_filter_len;
size_t alt_setting_name_filter_len;
- unsigned int section_idx = 0;
- bool unique_key;
setting_name_filter_len = setting_name_filter == NULL ? 0 :
strlen(setting_name_filter);
alt_setting_name_filter_len = alt_setting_name_filter == NULL ? 0 :
strlen(alt_setting_name_filter);
- if (config_export_all_parsers(&ctx->export_ctx, §ion_idx) < 0)
+ if (config_export_all_parsers(&ctx->export_ctx) < 0)
i_unreached(); /* settings aren't checked - this can't happen */
array_sort(&ctx->strings, config_string_cmp);
p_array_init(&prefixes_arr, ctx->pool, 32);
for (i = 0; i < count && strings[i][0] == LIST_KEY_PREFIX[0]; i++) T_BEGIN {
p = strchr(strings[i], '=');
- i_assert(p != NULL);
- if (p[1] == '\0') {
- /* "strlist=" */
- str = p_strdup_printf(ctx->pool, "%s/",
- t_strcut(strings[i]+1, '='));
- array_push_back(&prefixes_arr, &str);
- } else {
- /* string is in format: "list=0 1 2" */
- for (args = t_strsplit(p + 1, " "); *args != NULL; args++) {
- str = p_strdup_printf(ctx->pool, "%s/%s/",
- t_strcut(strings[i]+1, '='),
- *args);
- array_push_back(&prefixes_arr, &str);
- }
- }
+ i_assert(p != NULL && p[1] == '\0');
+ /* "strlist=" */
+ str = p_strdup_printf(ctx->pool, "%s/",
+ t_strcut(strings[i]+1, '='));
+ array_push_back(&prefixes_arr, &str);
} T_END;
prefixes = array_get(&prefixes_arr, &prefix_count);
i_assert(value != NULL);
key = t_strdup_until(strings[i], value++);
- unique_key = FALSE;
bool hide_passwords = default_hide_passwords;
p = strrchr(key, '/');
- if (p != NULL && p[1] == UNIQUE_KEY_SUFFIX[0]) {
- key = t_strconcat(t_strdup_until(key, p + 1),
- p + 2, NULL);
- unique_key = TRUE;
- }
if (setting_name_filter_len > 0) {
/* See if this setting matches the name filter.
If we're asking for a full specific setting,
if (strncmp(prefixes[prefix_idx], key, len) != 0) {
prefix = prefix_stack_pop(&prefix_stack);
indent--;
- if (prefix.str_pos != UINT_MAX)
- str_truncate(ctx->list_prefix, prefix.str_pos);
- else if (!hide_key) {
+ if (!hide_key) {
o_stream_nsend(output, indent_str, indent*2);
o_stream_nsend_str(output, "}\n");
}
if (strncmp(prefixes[j], key, len) == 0) {
key2 = key + (prefix_idx == UINT_MAX ? 0 :
strlen(prefixes[prefix_idx]));
- prefix.str_pos = !unique_key ? UINT_MAX :
- str_len(ctx->list_prefix);
prefix_idx = j;
prefix.prefix_idx = prefix_idx;
array_push_back(&prefix_stack, &prefix);
str_append_data(ctx->list_prefix, key2, p - key2);
else
str_append(ctx->list_prefix, key2);
- if (unique_key && *value != '\0') {
- if (strchr(value, ' ') == NULL)
- str_printfa(ctx->list_prefix, " %s", value);
- else
- str_printfa(ctx->list_prefix, " \"%s\"", str_escape(value));
- }
str_append(ctx->list_prefix, " {\n");
indent++;
- if (unique_key)
- goto end;
- else
- goto again;
+ goto again;
}
}
if (!hide_key) {
str_len(ctx->list_prefix));
}
str_truncate(ctx->list_prefix, 0);
- prefix_stack_reset_str(&prefix_stack);
ctx->list_prefix_sent = TRUE;
skip_len = prefix_idx == UINT_MAX ? 0 : strlen(prefixes[prefix_idx]);
if (!hide_key)
o_stream_nsend(output, indent_str, indent*2);
key = strings[i] + skip_len;
- if (unique_key) key++;
const char *full_key = key;
if (strip_prefix != NULL && str_begins(key, strip_prefix, &key))
key++;
while (prefix_idx != UINT_MAX) {
prefix = prefix_stack_pop(&prefix_stack);
- if (prefix.str_pos != UINT_MAX)
- break;
prefix_idx = prefix.prefix_idx;
indent--;
if (!hide_key) {
const char *full_key;
/* Points to array inside parent->set_struct.
- SET_DEFLIST : array of set_structs
SET_STRLIST : array of const_strings */
ARRAY_TYPE(void_array) *array;
/* Pointer to structure containing the values */
/* Pointer to structure containing non-zero values for settings that
have been changed. */
void *change_struct;
- /* SET_DEFLIST: array of change_structs */
- ARRAY_TYPE(void_array) *change_array;
};
struct setting_parser_context {
HASH_TABLE_DEFINE_TYPE(setting_link, struct setting_link *,
struct setting_link *);
-static void
-setting_parser_copy_defaults(struct setting_parser_context *ctx,
- const struct setting_parser_info *info,
- struct setting_link *link);
-static int
-settings_apply(struct setting_link *dest_link,
- const struct setting_link *src_link,
- pool_t pool, const char **conflict_key_r);
-
-static void
-copy_unique_defaults(struct setting_parser_context *ctx,
- const struct setting_define *def,
- struct setting_link *link)
-{
- ARRAY_TYPE(void_array) *arr =
- STRUCT_MEMBER_P(link->set_struct, def->offset);
- ARRAY_TYPE(void_array) *carr = NULL;
- struct setting_link *new_link;
- struct setting_parser_info info;
- const char *const *keyp, *key, *prefix;
- void *const *children;
- void *new_set, *new_changes = NULL;
- char *full_key;
- unsigned int i, count;
-
- if (!array_is_created(arr))
- return;
-
- children = array_get(arr, &count);
- if (link->change_struct != NULL) {
- carr = STRUCT_MEMBER_P(link->change_struct, def->offset);
- i_assert(!array_is_created(carr));
- p_array_init(carr, ctx->set_pool, count + 4);
- }
- p_array_init(arr, ctx->set_pool, count + 4);
-
- i_zero(&info);
- info = *def->list_info;
-
- for (i = 0; i < count; i++) T_BEGIN {
- new_set = p_malloc(ctx->set_pool, info.struct_size);
- array_push_back(arr, &new_set);
-
- if (link->change_struct != NULL) {
- i_assert(carr != NULL);
- new_changes = p_malloc(ctx->set_pool, info.struct_size);
- array_push_back(carr, &new_changes);
- }
-
- keyp = CONST_PTR_OFFSET(children[i], info.type_offset1-1);
- key = settings_section_escape(*keyp);
-
- new_link = p_new(ctx->set_pool, struct setting_link, 1);
- prefix = link->full_key == NULL ?
- t_strconcat(def->key, SETTINGS_SEPARATOR_S, NULL) :
- t_strconcat(link->full_key, SETTINGS_SEPARATOR_S,
- def->key, SETTINGS_SEPARATOR_S,NULL);
- full_key = p_strconcat(ctx->set_pool, prefix, key, NULL);
- new_link->full_key = full_key;
- new_link->parent = link;
- new_link->info = def->list_info;
- new_link->array = arr;
- new_link->change_array = carr;
- new_link->set_struct = new_set;
- new_link->change_struct = new_changes;
- i_assert(hash_table_lookup(ctx->links, full_key) == NULL);
- hash_table_insert(ctx->links, full_key, new_link);
-
- info.defaults = children[i];
- setting_parser_copy_defaults(ctx, &info, new_link);
- } T_END;
-}
-
static void
setting_parser_copy_defaults(struct setting_parser_context *ctx,
const struct setting_parser_info *info,
}
break;
}
- case SET_DEFLIST_UNIQUE:
- copy_unique_defaults(ctx, def, link);
- break;
default:
break;
}
return 0;
}
-static void
-setting_link_init_set_struct(struct setting_parser_context *ctx,
- struct setting_link *link)
-{
- void *ptr;
-
- link->set_struct = p_malloc(ctx->set_pool, link->info->struct_size);
- if ((ctx->flags & SETTINGS_PARSER_FLAG_TRACK_CHANGES) != 0) {
- link->change_struct =
- p_malloc(ctx->set_pool, link->info->struct_size);
- array_push_back(link->change_array, &link->change_struct);
- }
-
- setting_parser_copy_defaults(ctx, link->info, link);
- array_push_back(link->array, &link->set_struct);
-
- if (link->info->parent_offset1 != 0 && link->parent != NULL) {
- ptr = STRUCT_MEMBER_P(link->set_struct,
- link->info->parent_offset1-1);
- *((void **)ptr) = link->parent->set_struct;
- }
-}
-
static int ATTR_NULL(2)
setting_link_add(struct setting_parser_context *ctx,
- const struct setting_define *def,
const struct setting_link *link_copy, char *key)
{
struct setting_link *link;
link = hash_table_lookup(ctx->links, key);
if (link != NULL) {
if (link->parent == link_copy->parent &&
- link->info == link_copy->info &&
- (def == NULL || def->type == SET_DEFLIST_UNIQUE))
+ link->info == link_copy->info)
return 0;
settings_parser_set_error(ctx,
t_strconcat(key, " already exists", NULL));
link->full_key = key;
i_assert(hash_table_lookup(ctx->links, key) == NULL);
hash_table_insert(ctx->links, key, link);
-
- if (link->info->struct_size != 0)
- setting_link_init_set_struct(ctx, link);
return 0;
}
static int ATTR_NULL(3, 8)
-get_deflist(struct setting_parser_context *ctx, struct setting_link *parent,
- const struct setting_define *def,
- const struct setting_parser_info *info,
- const char *key, const char *value, ARRAY_TYPE(void_array) *result,
- ARRAY_TYPE(void_array) *change_result)
+get_strlist(struct setting_parser_context *ctx, struct setting_link *parent,
+ const char *key, const char *value, ARRAY_TYPE(void_array) *result)
{
struct setting_link new_link;
const char *const *list;
char *full_key;
- i_assert(info->defines != NULL || info == &strlist_info);
-
if (!array_is_created(result))
p_array_init(result, ctx->set_pool, 5);
- if (change_result != NULL && !array_is_created(change_result))
- p_array_init(change_result, ctx->set_pool, 5);
i_zero(&new_link);
new_link.parent = parent;
- new_link.info = info;
+ new_link.info = &strlist_info;
new_link.array = result;
- new_link.change_array = change_result;
- if (info == &strlist_info) {
- /* there are no sections below strlist, so allow referencing it
- without the key (e.g. plugin/foo instead of plugin/0/foo) */
- full_key = p_strdup(ctx->parser_pool, key);
- if (setting_link_add(ctx, def, &new_link, full_key) < 0)
- return -1;
- }
+ /* there are no sections below strlist, so allow referencing it
+ without the key (e.g. plugin/foo instead of plugin/0/foo) */
+ full_key = p_strdup(ctx->parser_pool, key);
+ if (setting_link_add(ctx, &new_link, full_key) < 0)
+ return -1;
list = t_strsplit(value, ",\t ");
for (; *list != NULL; list++) {
full_key = p_strconcat(ctx->parser_pool, key,
SETTINGS_SEPARATOR_S, *list, NULL);
- if (setting_link_add(ctx, def, &new_link, full_key) < 0)
+ if (setting_link_add(ctx, &new_link, full_key) < 0)
return -1;
}
return 0;
ctx->prev_info = link->info;
- if (link->set_struct == NULL)
- setting_link_init_set_struct(ctx, link);
-
change_ptr = link->change_struct == NULL ? NULL :
STRUCT_MEMBER_P(link->change_struct, def->offset);
*(const char *const *)ptr2) < 0)
return -1;
break;
- case SET_DEFLIST:
- case SET_DEFLIST_UNIQUE:
- ctx->prev_info = def->list_info;
- return get_deflist(ctx, link, def, def->list_info,
- key, value, (ARRAY_TYPE(void_array) *)ptr,
- (ARRAY_TYPE(void_array) *)change_ptr);
case SET_STRLIST: {
ctx->prev_info = &strlist_info;
- if (get_deflist(ctx, link, NULL, &strlist_info, key, value,
- (ARRAY_TYPE(void_array) *)ptr, NULL) < 0)
+ if (get_strlist(ctx, link, key, value,
+ (ARRAY_TYPE(void_array) *)ptr) < 0)
return -1;
break;
}
}
*link_r = link;
- if (link->info == &strlist_info) {
- *def_r = NULL;
- return TRUE;
- } else {
- *def_r = setting_define_find(link->info, end + 1);
- return *def_r != NULL;
- }
+ i_assert(link->info == &strlist_info);
+ *def_r = NULL;
+ return TRUE;
}
static bool
bool settings_check(struct event *event, const struct setting_parser_info *info,
pool_t pool, void *set, const char **error_r)
{
- const struct setting_define *def;
- const ARRAY_TYPE(void_array) *val;
- void *const *children;
- unsigned int i, count;
bool valid;
if (info->check_func != NULL) {
if (!valid)
return FALSE;
}
-
- for (def = info->defines; def->key != NULL; def++) {
- if (!SETTING_TYPE_IS_DEFLIST(def->type))
- continue;
-
- val = CONST_PTR_OFFSET(set, def->offset);
- if (!array_is_created(val))
- continue;
-
- children = array_get(val, &count);
- for (i = 0; i < count; i++) {
- if (!settings_check(event, def->list_info, pool,
- children[i], error_r))
- return FALSE;
- }
- }
return TRUE;
}
const char **error_r)
{
const struct setting_define *def;
- void *value, *const *children;
+ void *value;
const char *error;
- unsigned int i, count;
int ret, final_ret = 1;
for (def = info->defines; def->key != NULL; def++) {
}
break;
}
- case SET_DEFLIST:
- case SET_DEFLIST_UNIQUE: {
- const ARRAY_TYPE(void_array) *val = value;
-
- if (!array_is_created(val))
- break;
-
- children = array_get(val, &count);
- for (i = 0; i < count; i++) {
- ret = settings_var_expand_info(def->list_info,
- children[i], pool, table, func_table,
- func_context, str, &error);
- if (final_ret > ret) {
- final_ret = ret;
- *error_r = error;
- }
- }
- break;
- }
}
}
&error);
}
-static void settings_set_parent(const struct setting_parser_info *info,
- void *child, void *parent)
-{
- void **ptr;
-
- if (info->parent_offset1 == 0)
- return;
-
- ptr = PTR_OFFSET(child, info->parent_offset1-1);
- *ptr = parent;
-}
-
-static bool
+static void
setting_copy(enum setting_type type, const void *src, void *dest, pool_t pool,
bool keep_values)
{
*dest_str = p_strdup(pool, *src_str);
break;
}
- case SET_DEFLIST:
- case SET_DEFLIST_UNIQUE:
- return FALSE;
case SET_STRLIST: {
const ARRAY_TYPE(const_string) *src_arr = src;
ARRAY_TYPE(const_string) *dest_arr = dest;
case SET_ALIAS:
break;
}
- return TRUE;
}
static void *settings_dup_full(const struct setting_parser_info *info,
{
const struct setting_define *def;
const void *src;
- void *dest_set, *dest, *const *children;
- unsigned int i, count;
+ void *dest_set, *dest;
if (info->struct_size == 0)
return NULL;
src = CONST_PTR_OFFSET(set, def->offset);
dest = PTR_OFFSET(dest_set, def->offset);
- if (!setting_copy(def->type, src, dest, pool, keep_values)) {
- const ARRAY_TYPE(void_array) *src_arr = src;
- ARRAY_TYPE(void_array) *dest_arr = dest;
- void *child_set;
-
- if (!array_is_created(src_arr))
- continue;
-
- children = array_get(src_arr, &count);
- p_array_init(dest_arr, pool, count);
- for (i = 0; i < count; i++) {
- child_set = settings_dup_full(def->list_info,
- children[i], pool,
- keep_values);
- array_push_back(dest_arr, &child_set);
- settings_set_parent(def->list_info, child_set,
- dest_set);
- }
- }
+ setting_copy(def->type, src, dest, pool, keep_values);
}
if (info->pool_offset1 > 0) {
{
const struct setting_define *def;
const void *src;
- void *dest_set, *dest, *const *children;
- unsigned int i, count;
+ void *dest_set, *dest;
if (change_set == NULL || info->struct_size == 0)
return NULL;
case SET_FILTER_ARRAY:
*((uint8_t *)dest) = *((const uint8_t *)src);
break;
- case SET_DEFLIST:
- case SET_DEFLIST_UNIQUE: {
- const ARRAY_TYPE(void_array) *src_arr = src;
- ARRAY_TYPE(void_array) *dest_arr = dest;
- void *child_set;
-
- if (!array_is_created(src_arr))
- break;
-
- children = array_get(src_arr, &count);
- p_array_init(dest_arr, pool, count);
- for (i = 0; i < count; i++) {
- child_set = settings_changes_dup(def->list_info,
- children[i],
- pool);
- array_push_back(dest_arr, &child_set);
- }
- break;
- }
case SET_FILTER_NAME:
case SET_ALIAS:
break;
return new_ctx;
}
-static void *
-settings_changes_init(const struct setting_parser_info *info,
- const void *change_set, pool_t pool)
-{
- const struct setting_define *def;
- const ARRAY_TYPE(void_array) *src_arr;
- ARRAY_TYPE(void_array) *dest_arr;
- void *dest_set, *set, *const *children;
- unsigned int i, count;
-
- if (info->struct_size == 0)
- return NULL;
-
- dest_set = p_malloc(pool, info->struct_size);
- for (def = info->defines; def->key != NULL; def++) {
- if (!SETTING_TYPE_IS_DEFLIST(def->type))
- continue;
-
- src_arr = CONST_PTR_OFFSET(change_set, def->offset);
- dest_arr = PTR_OFFSET(dest_set, def->offset);
-
- if (array_is_created(src_arr)) {
- children = array_get(src_arr, &count);
- i_assert(!array_is_created(dest_arr));
- p_array_init(dest_arr, pool, count);
- for (i = 0; i < count; i++) {
- set = settings_changes_init(def->list_info,
- children[i], pool);
- array_push_back(dest_arr, &set);
- }
- }
- }
- return dest_set;
-}
-
-static void settings_copy_deflist(const struct setting_define *def,
- const struct setting_link *src_link,
- struct setting_link *dest_link,
- pool_t pool)
-{
- const ARRAY_TYPE(void_array) *src_arr;
- ARRAY_TYPE(void_array) *dest_arr;
- void *const *children, *child_set;
- unsigned int i, count;
-
- src_arr = CONST_PTR_OFFSET(src_link->set_struct, def->offset);
- dest_arr = PTR_OFFSET(dest_link->set_struct, def->offset);
-
- if (!array_is_created(src_arr))
- return;
-
- children = array_get(src_arr, &count);
- if (!array_is_created(dest_arr))
- p_array_init(dest_arr, pool, count);
- for (i = 0; i < count; i++) {
- child_set = settings_dup(def->list_info, children[i], pool);
- array_push_back(dest_arr, &child_set);
- settings_set_parent(def->list_info, child_set,
- dest_link->set_struct);
- }
-
- /* copy changes */
- dest_arr = PTR_OFFSET(dest_link->change_struct, def->offset);
- if (!array_is_created(dest_arr))
- p_array_init(dest_arr, pool, count);
- for (i = 0; i < count; i++) {
- child_set = settings_changes_init(def->list_info,
- children[i], pool);
- array_push_back(dest_arr, &child_set);
- }
-}
-
-static int
-settings_copy_deflist_unique(const struct setting_define *def,
- const struct setting_link *src_link,
- struct setting_link *dest_link,
- pool_t pool, const char **conflict_key_r)
-{
- struct setting_link child_dest_link, child_src_link;
- const ARRAY_TYPE(void_array) *src_arr, *src_carr;
- ARRAY_TYPE(void_array) *dest_arr, *dest_carr;
- void *const *src_children, *const *src_cchildren;
- void *const *dest_children, *const *dest_cchildren, *child_set;
- const char *const *src_namep, *const *dest_namep;
- unsigned int i, j, src_count, dest_count, ccount;
- unsigned int type_offset;
-
- i_assert(def->list_info->type_offset1 != 0);
-
- src_arr = CONST_PTR_OFFSET(src_link->set_struct, def->offset);
- src_carr = CONST_PTR_OFFSET(src_link->change_struct, def->offset);
- dest_arr = PTR_OFFSET(dest_link->set_struct, def->offset);
- dest_carr = PTR_OFFSET(dest_link->change_struct, def->offset);
-
- if (!array_is_created(src_arr))
- return 0;
- type_offset = def->list_info->type_offset1-1;
-
- i_zero(&child_dest_link);
- i_zero(&child_src_link);
-
- child_dest_link.info = child_src_link.info = def->list_info;
-
- src_children = array_get(src_arr, &src_count);
- src_cchildren = array_get(src_carr, &ccount);
- i_assert(src_count == ccount);
- if (!array_is_created(dest_arr)) {
- p_array_init(dest_arr, pool, src_count);
- p_array_init(dest_carr, pool, src_count);
- }
- for (i = 0; i < src_count; i++) {
- src_namep = CONST_PTR_OFFSET(src_children[i], type_offset);
- dest_children = array_get(dest_arr, &dest_count);
- dest_cchildren = array_get(dest_carr, &ccount);
- i_assert(dest_count == ccount);
- for (j = 0; j < dest_count; j++) {
- dest_namep = CONST_PTR_OFFSET(dest_children[j],
- type_offset);
- if (strcmp(*src_namep, *dest_namep) == 0)
- break;
- }
-
- if (j < dest_count && **src_namep != '\0') {
- /* merge */
- child_src_link.set_struct = src_children[i];
- child_src_link.change_struct = src_cchildren[i];
- child_dest_link.set_struct = dest_children[j];
- child_dest_link.change_struct = dest_cchildren[j];
- if (settings_apply(&child_dest_link, &child_src_link,
- pool, conflict_key_r) < 0)
- return -1;
- } else {
- /* append */
- child_set = settings_dup(def->list_info,
- src_children[i], pool);
- array_push_back(dest_arr, &child_set);
- settings_set_parent(def->list_info, child_set,
- dest_link->set_struct);
-
- child_set = settings_changes_init(def->list_info,
- src_cchildren[i],
- pool);
- array_push_back(dest_carr, &child_set);
- }
- }
- return 0;
-}
-
-static int
-settings_apply(struct setting_link *dest_link,
- const struct setting_link *src_link,
- pool_t pool, const char **conflict_key_r)
-{
- const struct setting_define *def;
- const void *src, *csrc;
- void *dest, *cdest;
-
- for (def = dest_link->info->defines; def->key != NULL; def++) {
- csrc = CONST_PTR_OFFSET(src_link->change_struct, def->offset);
- cdest = PTR_OFFSET(dest_link->change_struct, def->offset);
-
- if (def->type == SET_DEFLIST || def->type == SET_STRLIST ||
- def->type == SET_FILTER_ARRAY) {
- /* just add the new values */
- } else if (def->type == SET_DEFLIST_UNIQUE) {
- /* merge sections */
- } else if (*((const uint8_t *)csrc) == 0) {
- /* unchanged */
- continue;
- } else if (def->type == SET_ALIAS) {
- /* ignore aliases */
- continue;
- } else if (*((const uint8_t *)cdest) != 0) {
- /* conflict */
- if (conflict_key_r != NULL) {
- *conflict_key_r = def->key;
- return -1;
- }
- continue;
- } else {
- *((uint8_t *)cdest) = *(const uint8_t *)csrc;
- }
-
- /* found a changed setting */
- src = CONST_PTR_OFFSET(src_link->set_struct, def->offset);
- dest = PTR_OFFSET(dest_link->set_struct, def->offset);
-
- if (setting_copy(def->type, src, dest, pool, FALSE)) {
- /* non-list */
- } else if (def->type == SET_DEFLIST) {
- settings_copy_deflist(def, src_link, dest_link, pool);
- } else {
- i_assert(def->type == SET_DEFLIST_UNIQUE);
- if (settings_copy_deflist_unique(def, src_link,
- dest_link, pool,
- conflict_key_r) < 0)
- return -1;
- }
- }
- return 0;
-}
-
const char *settings_section_escape(const char *name)
{
#define CHAR_NEED_ESCAPE(c) \