#include "service-settings.h"
#include "all-settings.h"
#include "config-filter.h"
+#include "config-request.h"
#include "config-parser.h"
#include <stdlib.h>
struct input_stack *cur_input;
struct config_filter_context *filter;
+ unsigned int expand_values:1;
};
static const enum settings_parser_flags settings_parser_flags =
CONFIG_LINE_TYPE_ERROR,
CONFIG_LINE_TYPE_KEYVALUE,
CONFIG_LINE_TYPE_KEYFILE,
+ CONFIG_LINE_TYPE_KEYVARIABLE,
CONFIG_LINE_TYPE_SECTION_BEGIN,
CONFIG_LINE_TYPE_SECTION_END,
CONFIG_LINE_TYPE_INCLUDE,
*value_r = line + 1;
return CONFIG_LINE_TYPE_KEYFILE;
}
+ if (*line == '$') {
+ *value_r = line + 1;
+ return CONFIG_LINE_TYPE_KEYVARIABLE;
+ }
len = strlen(line);
if (len > 0 &&
return ret;
}
-int config_parse_file(const char *path, bool expand_files,
+static const void *
+config_get_value(struct parser_context *ctx, const char *key,
+ enum setting_type *type_r)
+{
+ struct config_module_parser *l;
+ const void *value;
+
+ for (l = ctx->cur_section->parsers; l->root != NULL; l++) {
+ value = settings_parse_get_value(l->parser, key, type_r);
+ if (value != NULL)
+ return value;
+ }
+ return NULL;
+}
+
+static int config_write_value(struct parser_context *ctx,
+ string_t *str, enum config_line_type type,
+ const char *key, const char *value,
+ const char **errormsg_r)
+{
+ const void *var_value;
+ enum setting_type var_type;
+ bool dump;
+
+ switch (type) {
+ case CONFIG_LINE_TYPE_KEYVALUE:
+ str_append(str, value);
+ break;
+ case CONFIG_LINE_TYPE_KEYFILE:
+ if (!ctx->expand_values) {
+ str_append_c(str, '<');
+ str_append(str, value);
+ } else {
+ if (str_append_file(str, key, value, errormsg_r) < 0) {
+ /* file reading failed */
+ return -1;
+ }
+ }
+ break;
+ case CONFIG_LINE_TYPE_KEYVARIABLE:
+ if (!ctx->expand_values) {
+ str_append_c(str, '$');
+ str_append(str, value);
+ } else {
+ var_value = config_get_value(ctx, value, &var_type);
+ if (var_value == NULL) {
+ *errormsg_r = t_strconcat("Unknown variable: $",
+ value, NULL);
+ return -1;
+ }
+ if (!config_export_type(str, var_value, NULL,
+ var_type, TRUE, &dump)) {
+ *errormsg_r = t_strconcat("Invalid variable: $",
+ value, NULL);
+ return -1;
+ }
+ }
+ break;
+ default:
+ i_unreached();
+ }
+ return 0;
+}
+
+int config_parse_file(const char *path, bool expand_values,
const char **error_r)
{
struct input_stack root;
memset(&root, 0, sizeof(root));
root.path = path;
ctx.cur_input = &root;
+ ctx.expand_values = expand_values;
p_array_init(&ctx.all_parsers, ctx.pool, 128);
ctx.cur_section = p_new(ctx.pool, struct config_section_stack, 1);
break;
case CONFIG_LINE_TYPE_KEYVALUE:
case CONFIG_LINE_TYPE_KEYFILE:
+ case CONFIG_LINE_TYPE_KEYVARIABLE:
str_truncate(str, pathlen);
str_append(str, key);
str_append_c(str, '=');
- if (type != CONFIG_LINE_TYPE_KEYFILE)
- str_append(str, value);
- else if (!expand_files) {
- str_append_c(str, '<');
- str_append(str, value);
- } else if (str_append_file(str, key, value, &errormsg) < 0) {
- /* file reading failed */
+ if (config_write_value(&ctx, str, type, key, value, &errormsg) < 0)
break;
- }
(void)config_apply_line(&ctx, key, str_c(str), NULL, &errormsg);
break;
case CONFIG_LINE_TYPE_SECTION_BEGIN:
extern struct config_module_parser *config_module_parsers;
extern struct config_filter_context *config_filter;
-int config_parse_file(const char *path, bool expand_files,
+int config_parse_file(const char *path, bool expand_values,
const char **error_r);
void config_parse_load_modules(void);
return FALSE;
}
+bool config_export_type(string_t *str, const void *value,
+ const void *default_value,
+ enum setting_type type, bool dump_default,
+ bool *dump_r)
+{
+ switch (type) {
+ case SET_BOOL: {
+ const bool *val = value, *dval = default_value;
+
+ if (dump_default || dval == NULL || *val != *dval)
+ str_append(str, *val ? "yes" : "no");
+ break;
+ }
+ case SET_SIZE: {
+ const uoff_t *val = value, *dval = default_value;
+
+ if (dump_default || dval == NULL || *val != *dval)
+ str_printfa(str, "%llu", (unsigned long long)*val);
+ break;
+ }
+ case SET_UINT:
+ case SET_UINT_OCT:
+ case SET_TIME: {
+ const unsigned int *val = value, *dval = default_value;
+
+ if (dump_default || dval == NULL || *val != *dval) {
+ switch (type) {
+ case SET_UINT_OCT:
+ str_printfa(str, "0%o", *val);
+ break;
+ case SET_TIME:
+ str_printfa(str, "%u s", *val);
+ break;
+ default:
+ str_printfa(str, "%u", *val);
+ break;
+ }
+ }
+ break;
+ }
+ case SET_STR_VARS: {
+ const char *const *val = value, *sval;
+ const char *const *_dval = default_value;
+ const char *dval = _dval == NULL ? NULL : *_dval;
+
+ i_assert(*val == NULL ||
+ **val == SETTING_STRVAR_UNEXPANDED[0]);
+
+ sval = *val == NULL ? NULL : (*val + 1);
+ if ((dump_default || null_strcmp(sval, dval) != 0) &&
+ sval != NULL) {
+ str_append(str, sval);
+ *dump_r = TRUE;
+ }
+ break;
+ }
+ case SET_STR: {
+ const char *const *val = value;
+ const char *const *_dval = default_value;
+ const char *dval = _dval == NULL ? NULL : *_dval;
+
+ if ((dump_default || null_strcmp(*val, dval) != 0) &&
+ *val != NULL) {
+ str_append(str, *val);
+ *dump_r = TRUE;
+ }
+ break;
+ }
+ case SET_ENUM: {
+ const char *const *val = value;
+ const char *const *_dval = default_value;
+ const char *dval = _dval == NULL ? NULL : *_dval;
+ unsigned int len = strlen(*val);
+
+ if (dump_default || strncmp(*val, dval, len) != 0 ||
+ ((*val)[len] != ':' && (*val)[len] != '\0'))
+ str_append(str, *val);
+ break;
+ }
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
static void
settings_export(struct settings_export_context *ctx,
const struct setting_parser_info *info,
count = 0;
str_truncate(ctx->value, 0);
switch (def->type) {
- case SET_BOOL: {
- const bool *val = value, *dval = default_value;
- if (dump_default || dval == NULL || *val != *dval) {
- str_append(ctx->value,
- *val ? "yes" : "no");
- }
- break;
- }
- case SET_SIZE: {
- const uoff_t *val = value, *dval = default_value;
- if (dump_default || dval == NULL || *val != *dval) {
- str_printfa(ctx->value, "%llu",
- (unsigned long long)*val);
- }
- break;
- }
+ case SET_BOOL:
+ case SET_SIZE:
case SET_UINT:
case SET_UINT_OCT:
- case SET_TIME: {
- const unsigned int *val = value, *dval = default_value;
- if (dump_default || dval == NULL || *val != *dval) {
- switch (def->type) {
- case SET_UINT_OCT:
- str_printfa(ctx->value, "0%o", *val);
- break;
- case SET_TIME:
- str_printfa(ctx->value, "%u s", *val);
- break;
- default:
- str_printfa(ctx->value, "%u", *val);
- break;
- }
- }
+ case SET_TIME:
+ case SET_STR_VARS:
+ case SET_STR:
+ case SET_ENUM:
+ if (!config_export_type(ctx->value, value,
+ default_value, def->type,
+ dump_default, &dump))
+ i_unreached();
break;
- }
- case SET_STR_VARS: {
- const char *const *val = value, *sval;
- const char *const *_dval = default_value;
- const char *dval = _dval == NULL ? NULL : *_dval;
-
- i_assert(*val == NULL ||
- **val == SETTING_STRVAR_UNEXPANDED[0]);
-
- sval = *val == NULL ? NULL : (*val + 1);
- if ((dump_default || null_strcmp(sval, dval) != 0) &&
- sval != NULL) {
- str_append(ctx->value, sval);
- dump = TRUE;
- }
- break;
- }
- case SET_STR: {
- const char *const *val = value;
- const char *const *_dval = default_value;
- const char *dval = _dval == NULL ? NULL : *_dval;
-
- if ((dump_default || null_strcmp(*val, dval) != 0) &&
- *val != NULL) {
- str_append(ctx->value, *val);
- dump = TRUE;
- }
- break;
- }
- case SET_ENUM: {
- const char *const *val = value;
- const char *const *_dval = default_value;
- const char *dval = _dval == NULL ? NULL : *_dval;
- unsigned int len = strlen(*val);
-
- if (dump_default || strncmp(*val, dval, len) != 0 ||
- ((*val)[len] != ':' && (*val)[len] != '\0'))
- str_append(ctx->value, *val);
- break;
- }
case SET_DEFLIST:
case SET_DEFLIST_UNIQUE: {
const ARRAY_TYPE(void_array) *val = value;
#include "config-filter.h"
+enum setting_type;
+
enum config_dump_scope {
/* Dump all settings */
CONFIG_DUMP_SCOPE_ALL,
typedef void config_request_callback_t(const char *key, const char *value,
enum config_key_type type, void *context);
+bool config_export_type(string_t *str, const void *value,
+ const void *default_value,
+ enum setting_type type, bool dump_default,
+ bool *dump_r);
int config_request_handle(const struct config_filter *filter,
const char *module, enum config_dump_scope scope,
enum config_dump_flags flags,
return settings_find_key(ctx, key, &def, &link);
}
+const void *
+settings_parse_get_value(struct setting_parser_context *ctx,
+ const char *key, enum setting_type *type_r)
+{
+ const struct setting_define *def;
+ struct setting_link *link;
+
+ if (!settings_find_key(ctx, key, &def, &link))
+ return NULL;
+ if (link->set_struct == NULL)
+ return NULL;
+
+ *type_r = def->type;
+ return STRUCT_MEMBER_P(link->set_struct, def->offset);
+}
+
int settings_parse_line(struct setting_parser_context *ctx, const char *line)
{
const char *key, *value;
/* Returns TRUE if the given key is a valid setting. */
bool settings_parse_is_valid_key(struct setting_parser_context *ctx,
const char *key);
+/* Returns pointer to value for a key, or NULL if not found. */
+const void *
+settings_parse_get_value(struct setting_parser_context *ctx,
+ const char *key, enum setting_type *type_r);
/* Parse a single line. Returns 1 if OK, 0 if key is unknown, -1 if error. */
int settings_parse_line(struct setting_parser_context *ctx, const char *line);
/* Parse data already read in input stream. */