diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib-settings/settings-parser.h | 281 |
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 |