Introduce variable filtering in the config files

Prepending a '&' to a quoted string makes the given string to be
filtered trough an user-supplied function.
Right now it does return the value as-is.
This commit is contained in:
LemonBoy 2017-06-23 13:30:35 +02:00
commit a9a3dba50d
5 changed files with 66 additions and 9 deletions

View file

@ -703,6 +703,13 @@ int irssi_config_is_changed(const char *fname)
config_last_checksum != file_checksum(fname));
}
static gboolean filter_stub(const char *key, const char *value, char **new_value)
{
g_warning("Filtering %s in %s", value, key);
*new_value = (char *)value;
return TRUE;
}
static CONFIG_REC *parse_configfile(const char *fname)
{
CONFIG_REC *config;
@ -736,6 +743,8 @@ static CONFIG_REC *parse_configfile(const char *fname)
config = config_open(NULL, -1);
}
config_set_filter_function(filter_stub);
if (config->fname != NULL)
config_parse(config);
else

View file

@ -20,6 +20,8 @@
#include "module.h"
static ConfigFilterFunc filter_func = NULL;
CONFIG_NODE *config_node_find(CONFIG_NODE *node, const char *key)
{
GSList *tmp;
@ -165,7 +167,7 @@ CONFIG_NODE *config_node_traverse(CONFIG_REC *rec, const char *section, int crea
char *config_get_str(CONFIG_REC *rec, const char *section, const char *key, const char *def)
{
CONFIG_NODE *parent, *node;
char *path;
char *path, *value;
g_return_val_if_fail(rec != NULL, (char *) def);
g_return_val_if_fail(key != NULL, (char *) def);
@ -190,7 +192,18 @@ char *config_get_str(CONFIG_REC *rec, const char *section, const char *key, cons
}
}
return (node == NULL || !has_node_value(node)) ? (char *) def : node->value;
if (node == NULL || !has_node_value(node))
{
return (char *)def;
}
if (node->do_filter && filter_func)
{
return filter_func(key, node->value, &value) ?
value : (char *)def;
}
return node->value;
}
int config_get_int(CONFIG_REC *rec, const char *section, const char *key, int def)
@ -216,12 +229,24 @@ int config_get_bool(CONFIG_REC *rec, const char *section, const char *key, int d
char *config_node_get_str(CONFIG_NODE *parent, const char *key, const char *def)
{
CONFIG_NODE *node;
char *value;
if (parent == NULL) return (char *) def;
node = config_node_find(parent, key);
return (char *) ((node != NULL && has_node_value(node)) ?
node->value : def);
if (node == NULL || !has_node_value(node))
{
return (char *)def;
}
if (node->do_filter && filter_func)
{
return filter_func(key, node->value, &value) ?
value : (char *)def;
}
return node->value;
}
int config_node_get_int(CONFIG_NODE *parent, const char *key, int def)
@ -339,3 +364,8 @@ GSList *config_node_next(GSList *list)
list = list->next;
return config_node_first(list);
}
void config_set_filter_function(ConfigFilterFunc func)
{
filter_func = func;
}

View file

@ -18,7 +18,8 @@ typedef struct _CONFIG_NODE CONFIG_NODE;
typedef struct _CONFIG_REC CONFIG_REC;
struct _CONFIG_NODE {
int type;
int type : 8;
int do_filter : 1;
char *key;
void *value;
};
@ -46,6 +47,10 @@ struct _CONFIG_NODE {
*/
typedef gboolean (*ConfigFilterFunc)(const char *key,
const char *value,
char **new_value);
struct _CONFIG_REC {
char *fname;
int create_mode;
@ -72,6 +77,8 @@ CONFIG_REC *config_open(const char *fname, int create_mode);
void config_close(CONFIG_REC *rec);
/* Change file name of config file */
void config_change_file_name(CONFIG_REC *rec, const char *fname, int create_mode);
/* Set the default function to handle the variable filtering */
void config_set_filter_function(ConfigFilterFunc func);
/* Parse configuration file */
int config_parse(CONFIG_REC *rec);

View file

@ -131,7 +131,7 @@ static GTokenType config_parse_symbol(CONFIG_REC *rec, CONFIG_NODE *node)
{
CONFIG_NODE *newnode;
GTokenType last_char;
int print_warning;
int print_warning, do_filter;
char *key;
g_return_val_if_fail(rec != NULL, G_TOKEN_ERROR);
@ -151,12 +151,21 @@ static GTokenType config_parse_symbol(CONFIG_REC *rec, CONFIG_NODE *node)
config_parse_get_token(rec->scanner, node);
}
do_filter = FALSE;
switch (rec->scanner->token) {
case '&':
/* substitute value */
do_filter = TRUE;
config_parse_warn_missing(rec, node, G_TOKEN_STRING, TRUE);
g_assert(rec->scanner->token == G_TOKEN_STRING);
case G_TOKEN_STRING:
/* value */
config_node_set_str(rec, node, key, rec->scanner->value.v_string);
newnode = config_node_set_str(rec, node, key, rec->scanner->value.v_string);
g_free_not_null(key);
newnode->do_filter = do_filter;
print_warning = TRUE;
if (node->type == NODE_TYPE_LIST) {
/* if it's last item it doesn't need comma */
@ -167,7 +176,6 @@ static GTokenType config_parse_symbol(CONFIG_REC *rec, CONFIG_NODE *node)
config_parse_warn_missing(rec, node, last_char, print_warning);
break;
case '{':
/* block */
if (key == NULL && node->type != NODE_TYPE_LIST)

View file

@ -142,6 +142,7 @@ static int config_write_node(CONFIG_REC *rec, CONFIG_NODE *node, int line_feeds)
case NODE_TYPE_KEY:
if (config_write_word(rec, node->key, FALSE) == -1 ||
config_write_str(rec, " = ") == -1 ||
(node->do_filter && config_write_str(rec, "&") == -1) ||
config_write_word(rec, node->value, TRUE) == -1)
return -1;
break;
@ -212,6 +213,8 @@ static int config_node_get_length(CONFIG_REC *rec, CONFIG_NODE *node)
case NODE_TYPE_KEY:
/* "key = value; " */
len = 5 + strlen(node->key) + strlen(node->value);
/* optional '&' before the value */
len += node->do_filter ? 1 : 0;
break;
case NODE_TYPE_VALUE:
/* "value, " */