If a non-empty value is given, it's an error.
if (set->type != CONFIG_KEY_LIST)
;
else if (set->list_count == 0 && set->value_stop_list &&
- set->def_type == SET_BOOLLIST) {
- /* filter empties a boollist setting */
+ (set->def_type == SET_BOOLLIST ||
+ set->def_type == SET_STRLIST)) {
+ /* filter empties a boollist/strlist setting */
} else {
/* these aren't needed */
return;
o_stream_nsend_str(ctx->output, "=");
o_stream_nsend_str(ctx->output, str_tabescape(set->value));
if (set->value_stop_list)
- o_stream_nsend_str(ctx->output, " # stop boollist");
+ o_stream_nsend_str(ctx->output, " # stop list");
o_stream_nsend_str(ctx->output, "\n");
} T_END;
}
if (set->type != CONFIG_KEY_LIST)
;
else if (set->list_count == 0 && set->value_stop_list &&
- set->def_type == SET_BOOLLIST) {
- /* filter empties a boollist setting */
+ (set->def_type == SET_BOOLLIST ||
+ set->def_type == SET_STRLIST)) {
+ /* filter empties a boollist/strlist setting */
} else {
/* these aren't needed */
return;
static int config_apply_strlist(struct config_parser_context *ctx,
const char *key, const char *value,
struct config_parser_key *config_key,
- ARRAY_TYPE(const_string) **strlistp)
+ ARRAY_TYPE(const_string) **strlistp,
+ bool *stop_list)
{
const char *suffix;
suffix = strchr(key, SETTINGS_SEPARATOR);
if (suffix == NULL) {
+ if (value[0] == '\0') {
+ /* clear out the whole strlist */
+ if (*strlistp != NULL)
+ array_clear(*strlistp);
+ else {
+ *strlistp = p_new(ctx->pool,
+ ARRAY_TYPE(const_string), 1);
+ p_array_init(*strlistp, ctx->pool, 5);
+ }
+ *stop_list = TRUE;
+ return 0;
+ }
+
ctx->error = p_strdup_printf(ctx->pool,
"Setting is a string list, use '%s {'", key);
return -1;
list within the same filter, and the previous setting might
have wanted to stop the list already. */
return config_apply_strlist(ctx, key, value, config_key,
- strlistp);
+ strlistp, stop_list);
}
/* replace the whole list */
switch (l->info->defines[config_key->define_idx].type) {
case SET_STRLIST:
if (config_apply_strlist(ctx, key, value, config_key,
- &l->settings[config_key->define_idx].array.values) < 0)
+ &l->settings[config_key->define_idx].array.values,
+ &l->settings[config_key->define_idx].array.stop_list) < 0)
return -1;
break;
case SET_BOOLLIST:
switch (p->info->defines[i].type) {
case SET_STRLIST:
case SET_BOOLLIST: {
+ if (p->settings[i].array.values == NULL)
+ break;
unsigned int j, count;
const char *const *strings =
array_get(p->settings[i].array.values, &count);
set->list_idx, p + 1, set->value);
break;
case CONFIG_KEY_LIST:
- if (set->list_count == 0 && set->def_type == SET_BOOLLIST) {
+ if (set->list_count == 0 &&
+ (set->def_type == SET_BOOLLIST ||
+ set->def_type == SET_STRLIST)) {
/* empty deflist - show as an empty string */
value = p_strdup_printf(ctx->pool, "%s=", set->key);
break;
}
- if (set->value_stop_list && set->def_type == SET_BOOLLIST) {
+ if (set->value_stop_list &&
+ (set->def_type == SET_BOOLLIST ||
+ set->def_type == SET_STRLIST)) {
value = p_strdup_printf(ctx->pool, "%s=", set->key);
array_push_back(&ctx->strings, &value);
}
return 0;
}
-static void
+static int
settings_parse_strlist(struct setting_parser_context *ctx,
ARRAY_TYPE(const_string) *array,
- const char *key, const char *value)
+ const char *key, const char *value, const char **error_r)
{
const char *const *items;
const char *vkey, *vvalue;
unsigned int i, count;
- key = strchr(key, SETTINGS_SEPARATOR);
- if (key == NULL)
- return;
- key = settings_section_unescape(key + 1);
+ /* If the next element after the visible array is set_array_stop, then
+ the strlist should not be modified any further. */
+ if (array_is_created(array)) {
+ items = array_get(array, &count);
+ if (items[count] == set_array_stop)
+ return 0;
+ }
+
+ const char *suffix = strchr(key, SETTINGS_SEPARATOR);
+ if (suffix == NULL) {
+ if (value[0] == '\0') {
+ /* clear out the whole strlist */
+ if (array_is_created(array))
+ array_clear(array);
+ return 0;
+ }
+
+ *error_r = t_strdup_printf(
+ "Setting is a string list, use %s/key=value'", key);
+ return -1;
+ }
+ key = settings_section_unescape(suffix + 1);
vvalue = p_strdup(ctx->set_pool, value);
if (!array_is_created(array))
for (i = 0; i < count; i += 2) {
if (strcmp(items[i], key) == 0) {
array_idx_set(array, i + 1, &vvalue);
- return;
+ return 0;
}
}
vkey = p_strdup(ctx->set_pool, key);
array_push_back(array, &vkey);
array_push_back(array, &vvalue);
+ return 0;
}
int settings_parse_boollist_string(const char *value, pool_t pool,
break;
case SET_STRLIST:
T_BEGIN {
- settings_parse_strlist(ctx, ptr, key, value);
+ ret = settings_parse_strlist(ctx, ptr, key, value,
+ &error);
+ if (ret < 0)
+ settings_parser_set_error(ctx, error);
} T_END;
+ if (ret < 0)
+ return -1;
break;
case SET_BOOLLIST:
T_BEGIN {
unsigned int key_idx)
{
i_assert(ctx->info->defines[key_idx].type == SET_FILTER_ARRAY ||
- ctx->info->defines[key_idx].type == SET_BOOLLIST);
+ ctx->info->defines[key_idx].type == SET_BOOLLIST ||
+ ctx->info->defines[key_idx].type == SET_STRLIST);
ARRAY_TYPE(const_string) *arr =
PTR_OFFSET(ctx->set_struct, ctx->info->defines[key_idx].offset);