return FALSE;
}
-static void settings_export(struct settings_export_context *ctx,
- const struct setting_parser_info *info,
- const void *set, const void *change_set)
+static void
+settings_export(struct settings_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;
hasn't changed, it's the default. even if
info->defaults has a different value. */
default_value = value;
+ } else if (parent_unique_deflist) {
+ /* value is set explicitly, but we don't know the
+ default here. assume it's not the default. */
+ dump_default = TRUE;
}
dump = FALSE;
break;
}
hash_table_insert(ctx->keys, key, key);
- ctx->callback(key, "0", TRUE, ctx->context);
+ ctx->callback(key, "0", CONFIG_KEY_LIST, ctx->context);
strings = array_get(val, &count);
i_assert(count % 2 == 0);
SETTINGS_SEPARATOR,
SETTINGS_SEPARATOR,
strings[i]);
- ctx->callback(str, strings[i+1], FALSE,
- ctx->context);
+ ctx->callback(str, strings[i+1],
+ CONFIG_KEY_NORMAL, ctx->context);
}
count = 0;
break;
key = p_strconcat(ctx->pool, str_c(ctx->prefix),
def->key, NULL);
if (hash_table_lookup(ctx->keys, key) == NULL) {
- ctx->callback(key, str_c(ctx->value),
- SETTING_TYPE_IS_DEFLIST(def->type),
+ enum config_key_type type;
+
+ if (def->offset == info->type_offset &&
+ parent_unique_deflist)
+ type = CONFIG_KEY_UNIQUE_KEY;
+ else if (SETTING_TYPE_IS_DEFLIST(def->type))
+ type = CONFIG_KEY_LIST;
+ else
+ type = CONFIG_KEY_NORMAL;
+ ctx->callback(key, str_c(ctx->value), type,
ctx->context);
hash_table_insert(ctx->keys, key, key);
}
str_append_c(ctx->prefix, SETTINGS_SEPARATOR);
str_printfa(ctx->prefix, "%u", i);
str_append_c(ctx->prefix, SETTINGS_SEPARATOR);
- settings_export(ctx, def->list_info, children[i],
- change_children[i]);
+ settings_export(ctx, def->list_info,
+ def->type == SET_DEFLIST_UNIQUE,
+ children[i], change_children[i]);
str_truncate(ctx->prefix, prefix_len);
}
!config_module_parser_is_in_service(parser, module))
continue;
- settings_export(&ctx, parser->root,
+ settings_export(&ctx, parser->root, FALSE,
settings_parser_get(parser->parser),
settings_parser_get_changes(parser->parser));
#include "array.h"
#include "env-util.h"
#include "ostream.h"
+#include "str.h"
#include "settings-parser.h"
#include "master-service.h"
#include "all-settings.h"
#include <stdio.h>
#include <unistd.h>
+struct prefix_stack {
+ unsigned int prefix_idx;
+ unsigned int str_pos;
+};
+ARRAY_DEFINE_TYPE(prefix_stack, struct prefix_stack);
+
struct config_request_get_string_ctx {
pool_t pool;
ARRAY_TYPE(const_string) strings;
};
+#define LIST_KEY_PREFIX "\001"
+#define UNIQUE_KEY_SUFFIX "\xff"
+
static void
config_request_get_strings(const char *key, const char *value,
- bool list, void *context)
+ enum config_key_type type, void *context)
{
struct config_request_get_string_ctx *ctx = context;
+ const char *p;
- value = p_strdup_printf(ctx->pool, list ? "-%s=%s" : "%s=%s",
- key, value);
+ switch (type) {
+ case CONFIG_KEY_NORMAL:
+ value = p_strdup_printf(ctx->pool, "%s=%s", key, value);
+ break;
+ case CONFIG_KEY_LIST:
+ 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",
+ t_strdup_until(key, p), p + 1, value);
+ break;
+ }
array_append(&ctx->strings, &value, 1);
}
return -1;
if (s2[i] == '=')
return 1;
+
return s1[i] - s2[i];
}
-static unsigned int prefix_stack_pop(ARRAY_TYPE(uint) *stack)
+static struct prefix_stack prefix_stack_pop(ARRAY_TYPE(prefix_stack) *stack)
{
- const unsigned int *indexes;
- unsigned int idx, count;
+ const struct prefix_stack *s;
+ struct prefix_stack sc;
+ unsigned int count;
- indexes = array_get(stack, &count);
- idx = count <= 1 ? -1U : indexes[count-2];
+ s = array_get(stack, &count);
+ i_assert(count > 0);
+ if (count == 1) {
+ sc.prefix_idx = -1U;
+ } else {
+ sc.prefix_idx = s[count-2].prefix_idx;
+ }
+ sc.str_pos = s[count-1].str_pos;
array_delete(stack, count-1, 1);
- return idx;
+ 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 = -1U;
}
static void config_connection_request_human(struct ostream *output,
const char *module,
enum config_dump_scope scope)
{
- static const char *ident_str = " ";
+ static const char *indent_str = " ";
ARRAY_TYPE(const_string) prefixes_arr;
- ARRAY_TYPE(uint) prefix_idx_stack;
+ ARRAY_TYPE(prefix_stack) prefix_stack;
+ struct prefix_stack prefix;
struct config_request_get_string_ctx ctx;
const char *const *strings, *const *args, *p, *str, *const *prefixes;
const char *key, *key2, *value;
unsigned int i, j, count, len, prefix_count, skip_len;
unsigned int indent = 0, prefix_idx = -1U;
+ string_t *list_prefix;
+ bool unique_key;
ctx.pool = pool_alloconly_create("config human strings", 10240);
i_array_init(&ctx.strings, 256);
strings = array_get(&ctx.strings, &count);
p_array_init(&prefixes_arr, ctx.pool, 32);
- for (i = 0; i < count && strings[i][0] == '-'; i++) T_BEGIN {
+ for (i = 0; i < count && strings[i][0] == LIST_KEY_PREFIX[0]; i++) T_BEGIN {
p = strchr(strings[i], '=');
i_assert(p != NULL);
for (args = t_strsplit(p + 1, " "); *args != NULL; args++) {
} T_END;
prefixes = array_get(&prefixes_arr, &prefix_count);
- p_array_init(&prefix_idx_stack, ctx.pool, 8);
+ list_prefix = str_new(ctx.pool, 128);
+ p_array_init(&prefix_stack, ctx.pool, 8);
for (; i < count; i++) T_BEGIN {
value = strchr(strings[i], '=');
i_assert(value != NULL);
- key = t_strdup_until(strings[i], value);
- value++;
+
+ key = t_strdup_until(strings[i], value++);
+ unique_key = FALSE;
+
+ 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;
+ }
again:
j = 0;
while (prefix_idx != -1U) {
len = strlen(prefixes[prefix_idx]);
if (strncmp(prefixes[prefix_idx], key, len) != 0) {
- prefix_idx = prefix_stack_pop(&prefix_idx_stack);
+ prefix = prefix_stack_pop(&prefix_stack);
indent--;
- o_stream_send(output, ident_str, indent*2);
- o_stream_send_str(output, "}\n");
+ if (prefix.str_pos != -1U)
+ str_truncate(list_prefix, prefix.str_pos);
+ else {
+ o_stream_send(output, indent_str, indent*2);
+ o_stream_send_str(output, "}\n");
+ }
+ prefix_idx = prefix.prefix_idx;
} else {
/* keep the prefix */
j = prefix_idx + 1;
if (strncmp(prefixes[j], key, len) == 0) {
key2 = key + (prefix_idx == -1U ? 0 :
strlen(prefixes[prefix_idx]));
- o_stream_send(output, ident_str, indent*2);
- o_stream_send_str(output, t_strcut(key2, '/'));
- o_stream_send_str(output, " {\n");
- indent++;
+ prefix.str_pos = !unique_key ? -1U :
+ str_len(list_prefix);
prefix_idx = j;
- array_append(&prefix_idx_stack, &prefix_idx, 1);
- goto again;
+ prefix.prefix_idx = prefix_idx;
+ array_append(&prefix_stack, &prefix, 1);
+
+ str_append_n(list_prefix, indent_str, indent*2);
+ p = strchr(key2, '/');
+ if (p != NULL)
+ str_append_n(list_prefix, key2, p - key2);
+ else
+ str_append(list_prefix, key2);
+ if (unique_key)
+ str_printfa(list_prefix, " %s", value);
+ str_append(list_prefix, " {\n");
+ indent++;
+
+ if (unique_key)
+ goto end;
+ else
+ goto again;
}
}
+ o_stream_send(output, str_data(list_prefix), str_len(list_prefix));
+ str_truncate(list_prefix, 0);
+ prefix_stack_reset_str(&prefix_stack);
+
skip_len = prefix_idx == -1U ? 0 : strlen(prefixes[prefix_idx]);
i_assert(skip_len == 0 ||
strncmp(prefixes[prefix_idx], strings[i], skip_len) == 0);
- o_stream_send(output, ident_str, indent*2);
+ o_stream_send(output, indent_str, indent*2);
key = strings[i] + skip_len;
+ if (unique_key) key++;
value = strchr(key, '=');
o_stream_send(output, key, value-key);
o_stream_send_str(output, " = ");
o_stream_send_str(output, value+1);
o_stream_send(output, "\n", 1);
+ end: ;
} T_END;
while (prefix_idx != -1U) {
- prefix_idx = prefix_stack_pop(&prefix_idx_stack);
+ prefix = prefix_stack_pop(&prefix_stack);
+ prefix_idx = prefix.prefix_idx;
indent--;
- o_stream_send(output, ident_str, indent*2);
+ o_stream_send(output, indent_str, indent*2);
o_stream_send_str(output, "}\n");
}
}
static void config_request_putenv(const char *key, const char *value,
- bool list ATTR_UNUSED,
+ enum config_key_type type ATTR_UNUSED,
void *context ATTR_UNUSED)
{
T_BEGIN {