summaryrefslogtreecommitdiffstats
path: root/src/lib-settings/settings-parser.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib-settings/settings-parser.h281
1 files changed, 281 insertions, 0 deletions
diff --git a/src/lib-settings/settings-parser.h b/src/lib-settings/settings-parser.h
new file mode 100644
index 0000000..d7ffcb5
--- /dev/null
+++ b/src/lib-settings/settings-parser.h
@@ -0,0 +1,281 @@
+#ifndef SETTINGS_PARSER_H
+#define SETTINGS_PARSER_H
+
+struct var_expand_table;
+struct var_expand_func_table;
+
+#define SETTINGS_SEPARATOR '/'
+#define SETTINGS_SEPARATOR_S "/"
+
+/* STR_VARS pointer begins with either of these initially. Before actually
+ using the variables all variables in all unexpanded strings need to be
+ expanded. Afterwards the string pointers should be increased to skip
+ the initial '1' so it'll be easy to use them. */
+#define SETTING_STRVAR_UNEXPANDED "0"
+#define SETTING_STRVAR_EXPANDED "1"
+
+/* When parsing streams, this character is translated to LF. */
+#define SETTING_STREAM_LF_CHAR "\003"
+
+enum setting_type {
+ SET_BOOL,
+ SET_UINT,
+ SET_UINT_OCT,
+ SET_TIME,
+ SET_TIME_MSECS,
+ SET_SIZE,
+ SET_IN_PORT, /* internet port */
+ SET_STR,
+ SET_STR_VARS, /* string with %variables */
+ SET_ENUM,
+ SET_DEFLIST, /* of type array_t */
+ SET_DEFLIST_UNIQUE,
+ SET_STRLIST, /* of type ARRAY_TYPE(const_string) */
+ SET_ALIAS /* alias name for above setting definition */
+};
+enum setting_flags {
+ SET_FLAG_HIDDEN = BIT(0),
+};
+#define SETTING_TYPE_IS_DEFLIST(type) \
+ ((type) == SET_DEFLIST || (type) == SET_DEFLIST_UNIQUE)
+
+#define SETTING_DEFINE_LIST_END { 0, 0, NULL, 0, NULL }
+
+struct setting_define {
+ enum setting_type type;
+ enum setting_flags flags;
+ const char *key;
+
+ size_t offset;
+ const struct setting_parser_info *list_info;
+};
+
+#define SETTING_DEFINE_STRUCT_TYPE(_enum_type, _flags, _c_type, _key, _name, _struct_name) \
+ { .type = (_enum_type) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
+ ((_struct_name *)0)->_name, _c_type), \
+ .flags = _flags, .key = _key, \
+ .offset = offsetof(_struct_name, _name) }
+
+#define SETTING_DEFINE_STRUCT_BOOL(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_BOOL, 0, bool, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_UINT(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_UINT, 0, unsigned int, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_UINT_OCT(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_UINT_OCT, 0, unsigned int, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_TIME(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_TIME, 0, unsigned int, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_TIME_MSECS(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_TIME_MSECS, 0, unsigned int, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_SIZE(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_SIZE, 0, uoff_t, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_IN_PORT(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_IN_PORT, 0, in_port_t, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_STR(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_STR, 0, const char *, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_STR_VARS(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_STR_VARS, 0, const char *, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_ENUM(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_ENUM, 0, const char *, key, name, struct_name)
+
+#define SETTING_DEFINE_STRUCT_BOOL_HIDDEN(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_BOOL, SET_FLAG_HIDDEN, bool, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_UINT_HIDDEN(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_UINT, SET_FLAG_HIDDEN, unsigned int, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_UINT_OCT_HIDDEN(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_UINT_OCT, SET_FLAG_HIDDEN, unsigned int, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_TIME_HIDDEN(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_TIME, SET_FLAG_HIDDEN, unsigned int, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_TIME_MSECS_HIDDEN(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_TIME_MSECS, SET_FLAG_HIDDEN, unsigned int, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_SIZE_HIDDEN(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_SIZE, SET_FLAG_HIDDEN, uoff_t, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_IN_PORT_HIDDEN(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_IN_PORT, SET_FLAG_HIDDEN, in_port_t, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_STR_HIDDEN(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_STR, SET_FLAG_HIDDEN, const char *, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_STR_VARS_HIDDEN(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_STR_VARS, SET_FLAG_HIDDEN, const char *, key, name, struct_name)
+#define SETTING_DEFINE_STRUCT_ENUM_HIDDEN(key, name, struct_name) \
+ SETTING_DEFINE_STRUCT_TYPE(SET_ENUM, SET_FLAG_HIDDEN, const char *, key, name, struct_name)
+
+struct setting_parser_info {
+ const char *module_name;
+ const struct setting_define *defines;
+ const void *defaults;
+
+ size_t type_offset;
+ size_t struct_size;
+
+ size_t parent_offset;
+ const struct setting_parser_info *parent;
+
+ bool (*check_func)(void *set, pool_t pool, const char **error_r);
+ bool (*expand_check_func)(void *set, pool_t pool, const char **error_r);
+ const struct setting_parser_info *const *dependencies;
+ struct dynamic_settings_parser *dynamic_parsers;
+
+};
+ARRAY_DEFINE_TYPE(setting_parser_info, struct setting_parser_info);
+
+/* name=NULL-terminated list of parsers. These follow the static settings.
+ After this list follows the actual settings. */
+struct dynamic_settings_parser {
+ const char *name;
+ const struct setting_parser_info *info;
+ size_t struct_offset;
+};
+ARRAY_DEFINE_TYPE(dynamic_settings_parser, struct dynamic_settings_parser);
+
+enum settings_parser_flags {
+ SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS = 0x01,
+ SETTINGS_PARSER_FLAG_TRACK_CHANGES = 0x02
+};
+
+struct setting_parser_context;
+
+struct setting_parser_context *
+settings_parser_init(pool_t set_pool, const struct setting_parser_info *root,
+ enum settings_parser_flags flags);
+struct setting_parser_context *
+settings_parser_init_list(pool_t set_pool,
+ const struct setting_parser_info *const *roots,
+ unsigned int count, enum settings_parser_flags flags);
+void settings_parser_deinit(struct setting_parser_context **ctx);
+
+/* Return pointer to root setting structure. */
+void *settings_parser_get(struct setting_parser_context *ctx);
+/* If there are multiple roots, return a NULL-terminated list to all of
+ their settings. */
+void **settings_parser_get_list(const struct setting_parser_context *ctx);
+/* Like settings_parser_get(), but return change struct. */
+void *settings_parser_get_changes(struct setting_parser_context *ctx);
+/* Returns the setting parser's roots (same as given to init()). */
+const struct setting_parser_info *const *
+settings_parser_get_roots(const struct setting_parser_context *ctx);
+
+/* Return the last error. */
+const char *settings_parser_get_error(struct setting_parser_context *ctx);
+/* Return the parser info used for the previously parsed line. */
+const struct setting_parser_info *
+settings_parse_get_prev_info(struct setting_parser_context *ctx);
+
+/* Returns TRUE if the given key is a valid setting. */
+bool settings_parse_is_valid_key(struct setting_parser_context *ctx,
+ const char *key);
+/* If key is an alias, return the primary key name. If key exists, return key
+ itself. If key doesn't exist, return NULL. */
+const char *settings_parse_unalias(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);
+/* Returns TRUE if setting has been changed by this parser. */
+bool settings_parse_is_changed(struct setting_parser_context *ctx,
+ const char *key);
+/* 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 key/value pair. Returns 1 if OK, 0 if key is unknown, -1 if error. */
+int settings_parse_keyvalue(struct setting_parser_context *ctx,
+ const char *key, const char *value);
+/* Parse data already read in input stream. */
+int settings_parse_stream(struct setting_parser_context *ctx,
+ struct istream *input);
+/* Read data from input stream and parser it. returns -1 = error,
+ 0 = done, 1 = not finished yet (stream is non-blocking) */
+int settings_parse_stream_read(struct setting_parser_context *ctx,
+ struct istream *input);
+/* Open file and parse it. */
+int settings_parse_file(struct setting_parser_context *ctx,
+ const char *path, size_t max_line_length);
+int settings_parse_environ(struct setting_parser_context *ctx);
+/* Execute the given binary and wait for it to return the configuration. */
+int settings_parse_exec(struct setting_parser_context *ctx,
+ const char *bin_path, const char *config_path,
+ const char *service);
+/* Call all check_func()s to see if currently parsed settings are valid. */
+bool settings_parser_check(struct setting_parser_context *ctx, pool_t pool,
+ const char **error_r);
+bool settings_check(const struct setting_parser_info *info, pool_t pool,
+ void *set, const char **error_r);
+
+/* While parsing values, specifies if STR_VARS strings are already expanded. */
+void settings_parse_set_expanded(struct setting_parser_context *ctx,
+ bool is_expanded);
+/* Mark all the parsed settings with given keys as being already expanded. */
+void settings_parse_set_key_expanded(struct setting_parser_context *ctx,
+ pool_t pool, const char *key);
+void settings_parse_set_keys_expanded(struct setting_parser_context *ctx,
+ pool_t pool, const char *const *keys);
+/* Update variable string pointers to skip over the '1' or '0'.
+ This is mainly useful when you want to run settings_parser_check() without
+ actually knowing what the variables are. */
+void settings_parse_var_skip(struct setting_parser_context *ctx);
+/* Expand all unexpanded variables using the given table. Update the string
+ pointers so that they can be used without skipping over the '1'.
+ Returns the same as var_expand(). */
+int settings_var_expand(const struct setting_parser_info *info,
+ void *set, pool_t pool,
+ const struct var_expand_table *table,
+ const char **error_r);
+int settings_var_expand_with_funcs(const struct setting_parser_info *info,
+ void *set, pool_t pool,
+ const struct var_expand_table *table,
+ const struct var_expand_func_table *func_table,
+ void *func_context, const char **error_r);
+/* Go through all the settings and return the first one that has an unexpanded
+ setting containing the given %key. */
+bool settings_vars_have_key(const struct setting_parser_info *info, void *set,
+ char var_key, const char *long_var_key,
+ const char **key_r, const char **value_r);
+/* Duplicate the entire settings structure. */
+void *settings_dup(const struct setting_parser_info *info,
+ const void *set, pool_t pool);
+/* Same as settings_dup(), but assume that the old pointers can still be safely
+ used. This saves memory since strings don't have to be duplicated. */
+void *settings_dup_with_pointers(const struct setting_parser_info *info,
+ const void *set, pool_t pool);
+/* Duplicate the entire setting parser. */
+struct setting_parser_context *
+settings_parser_dup(const struct setting_parser_context *old_ctx,
+ pool_t new_pool);
+
+/* parsers is a name=NULL -terminated list. The parsers are appended as
+ dynamic_settings_list structures to their parent. All must have the same
+ parent. The new structures are allocated from the given pool. */
+void settings_parser_info_update(pool_t pool,
+ struct setting_parser_info *parent,
+ const struct dynamic_settings_parser *parsers);
+void settings_parser_dyn_update(pool_t pool,
+ const struct setting_parser_info *const **roots,
+ const struct dynamic_settings_parser *dyn_parsers);
+
+/* Return pointer to beginning of settings for given name, or NULL if there is
+ no such registered name. */
+const void *settings_find_dynamic(const struct setting_parser_info *info,
+ const void *base_set, const char *name);
+
+/* Copy changed settings from src to dest. If conflict_key_r is not NULL and
+ both src and dest have changed the same setting, return -1 and set the
+ key name. If it's NULL, the old setting is kept.
+
+ KLUDGE: For SET_STRLIST types if both source and destination have identical
+ keys, the duplicates in the source side are ignored. This is required to
+ make the current config code work correctly. */
+int settings_parser_apply_changes(struct setting_parser_context *dest,
+ const struct setting_parser_context *src,
+ pool_t pool, const char **conflict_key_r);
+
+/* Return section name escaped */
+const char *settings_section_escape(const char *name);
+/* Parse time interval string, return as seconds. */
+int settings_get_time(const char *str, unsigned int *secs_r,
+ const char **error_r);
+/* Parse time interval string, return as milliseconds. */
+int settings_get_time_msecs(const char *str, unsigned int *msecs_r,
+ const char **error_r);
+/* Parse size string, return as bytes. */
+int settings_get_size(const char *str, uoff_t *bytes_r,
+ const char **error_r);
+
+#endif